diff --git a/build_form.js b/build_form.js
new file mode 100644
index 0000000..70fefe8
--- /dev/null
+++ b/build_form.js
@@ -0,0 +1,134 @@
+window.JSONEditor.defaults.callbacks.autocomplete = {
+ 'search_deposition': function (editor, input) {
+ if (input.length < 3) {
+ return [];
+ }
+
+ return restRequest({
+ url: 'deposition',
+ method: 'GET',
+ data: {
+ q: input,
+ limit: 10
+ }
+ })
+ },
+ 'render_deposition': function (editor, result, props) {
+ try {
+ const localId = result.metadata.alternateIdentifiers.find(
+ (id) => id.alternateIdentifierType.toLowerCase() === 'local'
+ );
+ return `
${result.igsn} (localId: ${localId.alternateIdentifier})`;
+ } catch (e) {
+ return ` ${result.igsn} (title: ${result.metadata.titles[0]['title']})`;
+ }
+ },
+ 'get_deposition_value': function (editor, result) {
+ try {
+ const localId = result.metadata.alternateIdentifiers.find(
+ (id) => id.alternateIdentifierType.toLowerCase() === 'local'
+ );
+ return `${result.igsn}`;
+ } catch (e) {
+ return `${result.igsn}`;
+ }
+ }
+};
+
+Handlebars.registerHelper('split', function (string, separator, index) {
+ try {
+ return string.split(separator)[index].trim();
+ } catch (e) {
+ return '';
+ }
+});
+
+Handlebars.registerHelper('replaceAll', function (string, search, replacement) {
+ return (string !== undefined && string !== null) ? string.replaceAll(search, replacement) : '';
+});
+Handlebars.registerHelper('joinarray', function (a, sep, prefix=false) {
+ if (!a || !Array.isArray(a) || a.length === 0) {
+ // Handle empty or undefined array
+ return '';
+ }
+ const result = a.join(sep);
+ if (result !== '' && prefix) {
+ return `${sep}${result}`;
+ }
+ return result;
+});
+
+Handlebars.registerHelper('formatBuildParams', function (params) {
+ if (!params || !Array.isArray(params) || params.length === 0) {
+ return '';
+ }
+
+ return params
+ .map(p => `${p.type}:${p.laserSpeed}:${p.laserPower}:${p.layerThickness}:${p.hatchSpacing}`)
+ .join('_');
+});
+
+JSONEditor.defaults.custom_validators.push(function (schema, value, path) {
+ // Only validate the buildParameters array
+ if (schema.title !== "Build Process Parameters") {
+ return [];
+ }
+
+ if (!Array.isArray(value)) {
+ return [];
+ }
+
+ const seen = new Set();
+ const duplicates = new Set();
+
+ value.forEach(item => {
+ if (item && item.type) {
+ if (seen.has(item.type)) {
+ duplicates.add(item.type);
+ }
+ seen.add(item.type);
+ }
+ });
+
+ if (duplicates.size > 0) {
+ return [{
+ path: path,
+ property: 'type',
+ message: `Duplicate build parameter type(s) not allowed: ${[...duplicates].join(', ')}.
+Each type (upskin, downskin, infill, contouring) may only appear once.`
+ }];
+ }
+
+ return [];
+});
+
+
+JSONEditor.defaults.custom_validators.push(function (schema, value, path) {
+ // Only validate the IGSNs field
+ if (schema.title !== "IGSNs") {
+ return [];
+ }
+
+ if (!Array.isArray(value)) {
+ return [];
+ }
+
+ const seen = new Set();
+ const duplicates = new Set();
+
+ value.forEach(v => {
+ if (seen.has(v)) {
+ duplicates.add(v);
+ }
+ seen.add(v);
+ });
+
+ if (duplicates.size > 0) {
+ return [{
+ path: path,
+ message: `Duplicate IGSN(s) are not allowed: ${[...duplicates].join(', ')}`
+ }];
+ }
+
+ return [];
+});
diff --git a/build_form.json b/build_form.json
new file mode 100644
index 0000000..e4fd3b8
--- /dev/null
+++ b/build_form.json
@@ -0,0 +1,123 @@
+{
+ "title": "Build Metadata Schema",
+ "description": "Schema for recording metadata of builds (build parameters)",
+ "type": "object",
+ "properties": {
+ "lookup": {
+ "type": "array",
+ "title": "IGSNs",
+ "description": "Select one or more IGSNs",
+ "minItems": 1,
+ "items": {
+ "type": "string",
+ "format": "autocomplete",
+ "options": {
+ "autocomplete": {
+ "search": "search_deposition",
+ "renderResult": "render_deposition",
+ "getResultValue": "get_deposition_value",
+ "autoSelect": true,
+ "debounceTime": 500
+ }
+ }
+ },
+ "propertyOrder": 0
+ },
+ "depositionId": {
+ "type": "string",
+ "title": "IGSN ID",
+ "description": "Unique identifier for the deposition",
+ "readOnly": true,
+ "propertyOrder": 999,
+ "watch": {
+ "igsn": "lookup"
+ },
+ "template": "{{split igsn ' - ' 1}}",
+ "options": {
+ "grid_columns": 12,
+ "hidden": true
+ }
+ },
+ "printerBuildID": {
+ "title": "Printer Build ID",
+ "description": "Automatically generated identifier for the printer build",
+ "type": "string",
+ "template": "{{formatBuildParams params}}",
+ "readOnly": true,
+ "propertyOrder": 2,
+ "watch": {
+ "params": "root.buildParameters"
+ },
+ "options": {
+ "grid_columns": 12
+ }
+ },
+ "buildParameters": {
+ "title": "Build Process Parameters",
+ "description": "Laser process parameters for all regions of the build. Each type (upskin, downskin, infill, contouring) can appear only once.",
+ "propertyOrder": 3,
+ "type": "array",
+ "minItems": 1,
+ "maxItems": 4,
+ "uniqueItemProperties": ["type"],
+ "items": {
+ "type": "object",
+ "format": "grid",
+ "options": {
+ "grid_columns": 12
+ },
+ "properties": {
+ "type": {
+ "type": "string",
+ "enum": ["upskin", "downskin", "infill", "contouring"],
+ "description": "Type of build region",
+ "propertyOrder": 1
+ },
+ "laserSpeed": {
+ "type": "number",
+ "minimum": 0,
+ "maximum": 10000,
+ "description": "PRC-3-2-9",
+ "propertyOrder": 2,
+ "options": {
+ "grid_row": 12
+ }
+ },
+ "laserPower": {
+ "type": "number",
+ "minimum": 0,
+ "maximum": 370,
+ "description": "PRC-3-2-3",
+ "propertyOrder": 3,
+ "options": {
+ "grid_row": 12
+ }
+ },
+ "layerThickness": {
+ "type": "number",
+ "minimum": 0,
+ "maximum": 100,
+ "description": "PRC-3-2-1",
+ "propertyOrder": 4,
+ "options": {
+ "grid_row": 12
+ }
+ },
+ "hatchSpacing": {
+ "type": "number",
+ "minimum": 0,
+ "maximum": 300,
+ "description": "PRC-3-2-6",
+ "propertyOrder": 5,
+ "options": {
+ "grid_row": 12
+ }
+ }
+ },
+ "required": ["type", "laserSpeed", "laserPower", "layerThickness", "hatchSpacing"],
+ "additionalProperties": false
+ }
+ }
+ },
+ "required": ["lookup", "buildParameters"]
+}
\ No newline at end of file
diff --git a/printer_build_schema.json b/printer_build_schema.json
index fde3311..1ade9aa 100644
--- a/printer_build_schema.json
+++ b/printer_build_schema.json
@@ -667,7 +667,10 @@
"enum": [
"Evan Adcock",
"Nick Lamprinakos",
- "Katie O'Donnell"
+ "Katie O'Donnell",
+ "Sierra Green",
+ "Justin Miner",
+ "David Reyes Ortiz"
]
},
"propertyOrder": 3