girder-flycut-studio 1.0.3__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (77) hide show
  1. girder_flycut_studio-1.0.3/LICENSE +27 -0
  2. girder_flycut_studio-1.0.3/MANIFEST.in +11 -0
  3. girder_flycut_studio-1.0.3/PKG-INFO +82 -0
  4. girder_flycut_studio-1.0.3/README.md +40 -0
  5. girder_flycut_studio-1.0.3/docs/CHANGELOG.md +30 -0
  6. girder_flycut_studio-1.0.3/docs/CONFIGURATION_FORM_VALIDATION.md +168 -0
  7. girder_flycut_studio-1.0.3/docs/CONVERSION_PLAN.md +883 -0
  8. girder_flycut_studio-1.0.3/docs/DASHBOARD_CONFIGURATION.md +152 -0
  9. girder_flycut_studio-1.0.3/docs/DEVELOPMENT.md +134 -0
  10. girder_flycut_studio-1.0.3/docs/HANDOFF.md +52 -0
  11. girder_flycut_studio-1.0.3/docs/INSTALLATION.md +40 -0
  12. girder_flycut_studio-1.0.3/docs/JSONFORMS_COMPATIBILITY.md +55 -0
  13. girder_flycut_studio-1.0.3/girder_flycut/__init__.py +81 -0
  14. girder_flycut_studio-1.0.3/girder_flycut/artifacts.py +99 -0
  15. girder_flycut_studio-1.0.3/girder_flycut/card.py +103 -0
  16. girder_flycut_studio-1.0.3/girder_flycut/catalog.json +938 -0
  17. girder_flycut_studio-1.0.3/girder_flycut/drafts.py +83 -0
  18. girder_flycut_studio-1.0.3/girder_flycut/engine.py +226 -0
  19. girder_flycut_studio-1.0.3/girder_flycut/excel.py +80 -0
  20. girder_flycut_studio-1.0.3/girder_flycut/generate.py +120 -0
  21. girder_flycut_studio-1.0.3/girder_flycut/import_storage.py +75 -0
  22. girder_flycut_studio-1.0.3/girder_flycut/inputs/templates/5x5-stack.json +162 -0
  23. girder_flycut_studio-1.0.3/girder_flycut/inputs/templates/5x5-stack.lbrn2 +499 -0
  24. girder_flycut_studio-1.0.3/girder_flycut/inputs/templates/6x2-test.json +84 -0
  25. girder_flycut_studio-1.0.3/girder_flycut/inputs/templates/6x2-test.lbrn2 +418 -0
  26. girder_flycut_studio-1.0.3/girder_flycut/inputs/templates/7x7-stack-fulliso.json +306 -0
  27. girder_flycut_studio-1.0.3/girder_flycut/inputs/templates/7x7-stack-fulliso.lbrn2 +483 -0
  28. girder_flycut_studio-1.0.3/girder_flycut/inputs/templates/7x7-stack.json +306 -0
  29. girder_flycut_studio-1.0.3/girder_flycut/inputs/templates/7x7-stack.lbrn2 +347 -0
  30. girder_flycut_studio-1.0.3/girder_flycut/inventory.py +34 -0
  31. girder_flycut_studio-1.0.3/girder_flycut/materials.py +54 -0
  32. girder_flycut_studio-1.0.3/girder_flycut/migrations.py +147 -0
  33. girder_flycut_studio-1.0.3/girder_flycut/models/__init__.py +12 -0
  34. girder_flycut_studio-1.0.3/girder_flycut/models/config.py +362 -0
  35. girder_flycut_studio-1.0.3/girder_flycut/portal_templates.py +84 -0
  36. girder_flycut_studio-1.0.3/girder_flycut/presets.json +23 -0
  37. girder_flycut_studio-1.0.3/girder_flycut/registration.py +54 -0
  38. girder_flycut_studio-1.0.3/girder_flycut/rest/__init__.py +41 -0
  39. girder_flycut_studio-1.0.3/girder_flycut/rest/catalog.py +6 -0
  40. girder_flycut_studio-1.0.3/girder_flycut/rest/config.py +369 -0
  41. girder_flycut_studio-1.0.3/girder_flycut/rest/gate.py +48 -0
  42. girder_flycut_studio-1.0.3/girder_flycut/rest/lifecycle.py +305 -0
  43. girder_flycut_studio-1.0.3/girder_flycut/rest/locking.py +97 -0
  44. girder_flycut_studio-1.0.3/girder_flycut/rest/settings.py +76 -0
  45. girder_flycut_studio-1.0.3/girder_flycut/rest/template.py +94 -0
  46. girder_flycut_studio-1.0.3/girder_flycut/schema.py +69 -0
  47. girder_flycut_studio-1.0.3/girder_flycut/settings.py +214 -0
  48. girder_flycut_studio-1.0.3/girder_flycut/storage.py +54 -0
  49. girder_flycut_studio-1.0.3/girder_flycut/template_identity.py +83 -0
  50. girder_flycut_studio-1.0.3/girder_flycut/validation.py +178 -0
  51. girder_flycut_studio-1.0.3/girder_flycut/web_client/dist/girder-plugin-flycut.umd.cjs +2 -0
  52. girder_flycut_studio-1.0.3/girder_flycut/web_client/dist/style.css +2 -0
  53. girder_flycut_studio-1.0.3/girder_flycut_studio.egg-info/PKG-INFO +82 -0
  54. girder_flycut_studio-1.0.3/girder_flycut_studio.egg-info/SOURCES.txt +75 -0
  55. girder_flycut_studio-1.0.3/girder_flycut_studio.egg-info/dependency_links.txt +1 -0
  56. girder_flycut_studio-1.0.3/girder_flycut_studio.egg-info/entry_points.txt +2 -0
  57. girder_flycut_studio-1.0.3/girder_flycut_studio.egg-info/requires.txt +3 -0
  58. girder_flycut_studio-1.0.3/girder_flycut_studio.egg-info/top_level.txt +1 -0
  59. girder_flycut_studio-1.0.3/pyproject.toml +3 -0
  60. girder_flycut_studio-1.0.3/setup.cfg +4 -0
  61. girder_flycut_studio-1.0.3/setup.py +61 -0
  62. girder_flycut_studio-1.0.3/tests/bundle.cjs +157 -0
  63. girder_flycut_studio-1.0.3/tests/complete_workflow.cjs +108 -0
  64. girder_flycut_studio-1.0.3/tests/conftest.py +29 -0
  65. girder_flycut_studio-1.0.3/tests/core.mjs +304 -0
  66. girder_flycut_studio-1.0.3/tests/status.mjs +87 -0
  67. girder_flycut_studio-1.0.3/tests/test_api.py +921 -0
  68. girder_flycut_studio-1.0.3/tests/test_dashboard.py +239 -0
  69. girder_flycut_studio-1.0.3/tests/test_jsonforms_hooks.py +80 -0
  70. girder_flycut_studio-1.0.3/tests/test_listing_cost.py +88 -0
  71. girder_flycut_studio-1.0.3/tests/test_locks.py +133 -0
  72. girder_flycut_studio-1.0.3/tests/test_migrations.py +171 -0
  73. girder_flycut_studio-1.0.3/tests/test_model_writes.py +170 -0
  74. girder_flycut_studio-1.0.3/tests/test_models.py +254 -0
  75. girder_flycut_studio-1.0.3/tests/test_save_config_parts.py +118 -0
  76. girder_flycut_studio-1.0.3/tests/test_validators.py +51 -0
  77. girder_flycut_studio-1.0.3/tests/workflow.cjs +96 -0
@@ -0,0 +1,27 @@
1
+ Copyright (c) 2026, Max Berner and contributors
2
+ All rights reserved.
3
+
4
+ Redistribution and use in source and binary forms, with or without
5
+ modification, are permitted provided that the following conditions are met:
6
+
7
+ * Redistributions of source code must retain the above copyright notice, this
8
+ list of conditions and the following disclaimer.
9
+
10
+ * Redistributions in binary form must reproduce the above copyright notice,
11
+ this list of conditions and the following disclaimer in the documentation
12
+ and/or other materials provided with the distribution.
13
+
14
+ * Neither the name of girder-flycut-studio nor the names of its
15
+ contributors may be used to endorse or promote products derived from
16
+ this software without specific prior written permission.
17
+
18
+ THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
19
+ AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
20
+ IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
21
+ DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
22
+ FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
23
+ DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
24
+ SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
25
+ CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
26
+ OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
27
+ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
@@ -0,0 +1,11 @@
1
+ include README.md
2
+ include LICENSE
3
+ exclude .eslintrc.* CLAUDE.md requirements.txt requirements-dev.txt ruff.toml package-lock.json package.json
4
+ recursive-include girder_flycut *.py *.json *.lbrn2
5
+ prune girder_flycut/web_client
6
+ include girder_flycut/web_client/dist/girder-plugin-flycut.umd.cjs
7
+ include girder_flycut/web_client/dist/style.css
8
+ recursive-include tests *.py *.cjs *.mjs
9
+ prune test
10
+
11
+ recursive-include docs *.md
@@ -0,0 +1,82 @@
1
+ Metadata-Version: 2.4
2
+ Name: girder-flycut-studio
3
+ Version: 1.0.3
4
+ Summary: Flyer Studio configuration, generation, and IGSN registration for Girder
5
+ Home-page: https://github.com/htmdec/girder-flycut-studio
6
+ Author: Max Berner
7
+ Author-email: bernermaximus@gmail.com
8
+ Maintainer: Kacper Kowalik
9
+ Maintainer-email: xarthisius.kk@gmail.com
10
+ License: BSD-3-Clause
11
+ Project-URL: Source, https://github.com/htmdec/girder-flycut-studio
12
+ Project-URL: Issues, https://github.com/htmdec/girder-flycut-studio/issues
13
+ Classifier: Development Status :: 5 - Production/Stable
14
+ Classifier: Environment :: Web Environment
15
+ Classifier: Intended Audience :: Science/Research
16
+ Classifier: License :: OSI Approved :: BSD License
17
+ Classifier: Programming Language :: Python :: 3
18
+ Classifier: Programming Language :: Python :: 3.10
19
+ Classifier: Programming Language :: Python :: 3.11
20
+ Classifier: Programming Language :: Python :: 3.12
21
+ Classifier: Topic :: Scientific/Engineering
22
+ Requires-Python: >=3.10
23
+ Description-Content-Type: text/markdown
24
+ License-File: LICENSE
25
+ Requires-Dist: girder-dashboards>=0.2.0
26
+ Requires-Dist: girder-jsonforms>=2.1.1
27
+ Requires-Dist: redis
28
+ Dynamic: author
29
+ Dynamic: author-email
30
+ Dynamic: classifier
31
+ Dynamic: description
32
+ Dynamic: description-content-type
33
+ Dynamic: home-page
34
+ Dynamic: license
35
+ Dynamic: license-file
36
+ Dynamic: maintainer
37
+ Dynamic: maintainer-email
38
+ Dynamic: project-url
39
+ Dynamic: requires-dist
40
+ Dynamic: requires-python
41
+ Dynamic: summary
42
+
43
+ # girder-flyer-studio
44
+
45
+ A girder dashboard developed for use with [girder dashboards](https://github.com/Xarthisius/girder-dashboards/tree/main), [girder jsonforms](https://github.com/Xarthisius/girder-jsonforms/), and [LightBurn Software](https://lightburnsoftware.com/).
46
+
47
+ Facilitates the specification, creation, and registration of **Flyer Stacks**, which are an array of small circular discs used in laser impact experiments. This is accomplished through automatic specification of templated LightBurn project files through a simplified JSON form, packaging and capture of experimentally relevant metadata, and IGSN registration per flyer stack on girder.
48
+
49
+ ## Features
50
+
51
+ - Draft → submitted → generated → registered lifecycle.
52
+ - LightBurn layout, inventory CSV, and JSON metadata generation.
53
+ - Scans girder for foil IGSNs (denoting base material) by contains alternative identifier `foil-igsn`.
54
+ - Registration creates `<foil IGSN>-<stack ID>` as a child deposition using JSONForms.
55
+ - Metadata and experiment invariants validated.
56
+
57
+ ## Admin settings and shared storage
58
+
59
+ See [Configuration form validation](docs/CONFIGURATION_FORM_VALIDATION.md) for form requirements, acknowledgement rules, and downstream checks.
60
+
61
+ See [Dashboard configuration](docs/DASHBOARD_CONFIGURATION.md) for administrator setup instructions, a complete settings example, permissions, and the Complete Workflow module.
62
+
63
+ ## Offline drafts
64
+
65
+ Use **Copy** or **Download** in the JSON tab to export the current form, including
66
+ incomplete configurations. Upload a single configuration `.json` file per item
67
+ directly into the workspace's **Drafts** folder using Girder's file browser, then
68
+ refresh the studio's configuration list. The studio creates this folder when the
69
+ list is opened by an operator with workspace write access.
70
+
71
+ Matching JSON in either the current section format or the legacy builder format
72
+ appears as an editable, unvalidated draft. Imported drafts must still be submitted
73
+ through the form's normal validation before generating or registering a stack.
74
+ Malformed or unrelated JSON remains in the upload folder. Files must be no larger
75
+ than 256 KiB, and the operator must have write access to import them.
76
+
77
+ ## Authors and licence
78
+
79
+ Flyer Studio was written by [Max Berner](https://github.com/mxberner). The conversion to a
80
+ conventional Girder 5 plugin is by [Kacper Kowalik](https://github.com/Xarthisius).
81
+
82
+ Released under the [BSD 3-Clause licence](LICENSE).
@@ -0,0 +1,40 @@
1
+ # girder-flyer-studio
2
+
3
+ A girder dashboard developed for use with [girder dashboards](https://github.com/Xarthisius/girder-dashboards/tree/main), [girder jsonforms](https://github.com/Xarthisius/girder-jsonforms/), and [LightBurn Software](https://lightburnsoftware.com/).
4
+
5
+ Facilitates the specification, creation, and registration of **Flyer Stacks**, which are an array of small circular discs used in laser impact experiments. This is accomplished through automatic specification of templated LightBurn project files through a simplified JSON form, packaging and capture of experimentally relevant metadata, and IGSN registration per flyer stack on girder.
6
+
7
+ ## Features
8
+
9
+ - Draft → submitted → generated → registered lifecycle.
10
+ - LightBurn layout, inventory CSV, and JSON metadata generation.
11
+ - Scans girder for foil IGSNs (denoting base material) by contains alternative identifier `foil-igsn`.
12
+ - Registration creates `<foil IGSN>-<stack ID>` as a child deposition using JSONForms.
13
+ - Metadata and experiment invariants validated.
14
+
15
+ ## Admin settings and shared storage
16
+
17
+ See [Configuration form validation](docs/CONFIGURATION_FORM_VALIDATION.md) for form requirements, acknowledgement rules, and downstream checks.
18
+
19
+ See [Dashboard configuration](docs/DASHBOARD_CONFIGURATION.md) for administrator setup instructions, a complete settings example, permissions, and the Complete Workflow module.
20
+
21
+ ## Offline drafts
22
+
23
+ Use **Copy** or **Download** in the JSON tab to export the current form, including
24
+ incomplete configurations. Upload a single configuration `.json` file per item
25
+ directly into the workspace's **Drafts** folder using Girder's file browser, then
26
+ refresh the studio's configuration list. The studio creates this folder when the
27
+ list is opened by an operator with workspace write access.
28
+
29
+ Matching JSON in either the current section format or the legacy builder format
30
+ appears as an editable, unvalidated draft. Imported drafts must still be submitted
31
+ through the form's normal validation before generating or registering a stack.
32
+ Malformed or unrelated JSON remains in the upload folder. Files must be no larger
33
+ than 256 KiB, and the operator must have write access to import them.
34
+
35
+ ## Authors and licence
36
+
37
+ Flyer Studio was written by [Max Berner](https://github.com/mxberner). The conversion to a
38
+ conventional Girder 5 plugin is by [Kacper Kowalik](https://github.com/Xarthisius).
39
+
40
+ Released under the [BSD 3-Clause licence](LICENSE).
@@ -0,0 +1,30 @@
1
+ # Changelog
2
+
3
+ ## 1.0.3
4
+
5
+ - Publish under the requested PyPI distribution name girder-flycut-studio.
6
+
7
+ ## 1.0.2
8
+
9
+ - Remove the unsupported Girder classifier rejected by PyPI during the 1.0.1 upload.
10
+
11
+ ## 1.0.1
12
+
13
+ - Import offline JSON configurations from the workspace Drafts folder.
14
+ - Copy and download incomplete configurations without validation.
15
+ - Disable Stack ID autocomplete and fix configuration tooltips.
16
+ - Keep generated metadata fields free of duplicated configuration JSON.
17
+ - Correct the PyPI project link and create the GitHub release during publishing.
18
+
19
+ ## 1.0.0
20
+
21
+ Initial standalone source release of Flyer Studio for Girder.
22
+
23
+ - Configuration, generation, registration, and Complete Workflow modules (1-3).
24
+ - Configuration of JSON run-script through on portal JSON form, complete with data validation.
25
+ - Generation of "stack identity".
26
+ - `stack-metadata` holding stack relevant metadata.
27
+ - `stack-layout` holding automatically configured lightburn project file.
28
+ - `stack-inventory` holding live flyer inventorying data for future visualization and management.
29
+ - Dashboard-admin settings for dashboard configuration.
30
+ - Generated lightburn files pass on their capacity to function as a template.
@@ -0,0 +1,168 @@
1
+ # Configuration form: requirements and validation
2
+
3
+ This describes the current **01 Configuration** form, also used by **1–3 Complete
4
+ Workflow**. It distinguishes submission requirements from warnings and later
5
+ server checks. It documents implemented behavior, not additional desired rules.
6
+
7
+ ## Drafts and workflow entry
8
+
9
+ - **Save** stores a draft; it does not require a complete form or acknowledgement
10
+ of warnings. A draft may have an empty Stack ID and no material/template.
11
+ - **Copy** and **Download** in the JSON tab export the current form without
12
+ requiring completion or warning acknowledgement. Uploads into the workspace
13
+ **Drafts** folder are discovered when the configuration list refreshes and
14
+ remain unvalidated until submitted. See [offline drafts](../README.md#offline-drafts).
15
+ - Saved JSON must be an object no larger than 256 KiB and contain no non-finite
16
+ JSON numbers. The optional “Save as” name is limited to 160 characters.
17
+ - A blank draft name becomes `stack<ID>-config` when an ID is present, otherwise
18
+ `Untitled draft`. Submitted names always become `stack<ID>-config`.
19
+ - Submitted, generated, and registered configurations are read-only. The ordinary
20
+ Configuration module permits viewing them and editing a copy.
21
+ - Complete Workflow permits **New configuration** or an **editable draft** only.
22
+ It excludes submitted, generated, registered, and read-only draft records.
23
+ - Saving/updating requires the configured workspace and appropriate Write access.
24
+ Existing drafts must belong to that workspace. The dashboard must be enabled
25
+ and readable, and the user must be signed in.
26
+
27
+ ## Blocking requirements before submission
28
+
29
+ | Field or condition | Requirement |
30
+ | --- | --- |
31
+ | Stack ID | Required: `F###`, `F####`, or exactly five uppercase Crockford Base32 characters (`0123456789ABCDEFGHJKMNPQRSTVWXYZ`), after trimming whitespace. Cannot be bypassed by acknowledgement. |
32
+ | Foil material | Select a foil from the readable Girder foil catalog. The server resolves and validates the selection. |
33
+ | Template | Select a valid catalog or accessible portal template. |
34
+ | Laser settings | Enable at least one entry. |
35
+ | Custom fields | Every row with a nonblank value must have a nonblank name. Completely blank rows are ignored. |
36
+ | Registered Stack ID | Cannot be reused. |
37
+ | Generated Stack ID | Generated files must be deleted before reusing the ID. |
38
+ | Restricted Stack ID | Cannot replace a configuration outside the workspace or without Write access. |
39
+
40
+ Stack identity is checked again on submission. Concurrent changes can therefore
41
+ reject a submission even if the page previously showed it as available. An
42
+ unrelated folder already occupying the destination stack folder also blocks
43
+ submission. Existing submitted configurations can be replaced only after explicit
44
+ validation acknowledgement and with Write access.
45
+
46
+ Presets are disabled and hidden. Their required-field checks are inactive in the
47
+ current dashboard; submitted configurations store `preset: null`.
48
+
49
+ ## Warnings requiring acknowledgement
50
+
51
+ A complete form displays **Needs validation** for any of these conditions:
52
+
53
+ 1. The Stack ID already has a submitted configuration; submission will replace it.
54
+ 2. Operator is blank; the current user's login is used as a fallback.
55
+ 3. Any enabled laser entry still carries the default-parameters marker.
56
+ 4. Some template layers have no enabled assigned setting; their original template
57
+ laser parameters will remain.
58
+ 5. Any listed laser entry is disabled or unused by the chosen template.
59
+ 6. A named custom field has no value; it exports as JSON `null`.
60
+
61
+ Open **Status**, review the listed issues, and check the validation acknowledgement
62
+ before submitting. Missing blocking requirements cannot be acknowledged away.
63
+ Form edits clear acknowledgement; it applies only to the configuration reviewed.
64
+ The server independently checks warnings and requires the acknowledgement flag.
65
+
66
+ Status meanings:
67
+
68
+ | Status | Meaning |
69
+ | --- | --- |
70
+ | Incomplete | At least one blocking requirement is missing. |
71
+ | Needs validation | Blocking requirements pass, but warnings need acknowledgement. |
72
+ | Validated | Warnings have been acknowledged for the current form contents. |
73
+ | Complete | Blocking requirements pass and there are no warnings. |
74
+ | Submitted / Generated / Registered | Saved lifecycle state shown for read-only records. |
75
+
76
+ “Complete” is not a guarantee that later generation or registration will succeed.
77
+
78
+ ## Laser controls and assignment
79
+
80
+ The form allows up to 28 entries, named sequentially `F1` through `F28`. The last
81
+ remaining entry cannot be removed, but disabling all entries blocks submission.
82
+ Reordering changes the assignment order. Imported settings are initially locked.
83
+ Colors must be unique six-digit hex values such as `#3C8D40`; an invalid or duplicate
84
+ color is rejected by the color editor and independently during generation.
85
+
86
+ | Control | Declared browser input limits | Generation server checks |
87
+ | --- | --- | --- |
88
+ | Power (%) | 0–100; step 0.1 | Finite number ≥ 0; no upper-bound check. |
89
+ | Speed (mm/s) | ≥ 0.01; step 0.01 | Finite number ≥ 0. |
90
+ | QPulse (ns) | ≥ 0; step 1 | Finite number ≥ 0; no integer-only check. |
91
+ | Frequency (kHz) | ≥ 0; step 0.1 | Finite number ≥ 0. |
92
+ | Passes | ≥ 1; step 1 | Positive integer. |
93
+ | Repeat | Integer 1–10000 | Integer 1–10000, checked during submission and generation. |
94
+ | Wraparound | Checkbox | Boolean. |
95
+
96
+ The form uses custom validation with native form validation disabled. Numeric HTML
97
+ limits above are input guidance, **not all enforced submission rules**. Server
98
+ numeric laser validation happens during generation. The server also requires
99
+ 1–28 laser entries and boolean `enabled` values. Legacy disabled entries may retain
100
+ null numeric values; enabled entries must have valid numbers.
101
+
102
+ Repeat assigns each entry to that many successive template layers. Wraparound
103
+ cycles through the entries when needed. Disabled entries still occupy positions.
104
+ Uncovered layers retain their template settings rather than stopping submission;
105
+ unused/disabled entries and uncovered layers produce the warnings listed above.
106
+
107
+ ## Custom fields and special values
108
+
109
+ - Field names are trimmed when exported. Values are retained as strings; blank
110
+ values become `null`. There is no general required list while presets are disabled.
111
+ - Duplicate field names are not rejected: the last row with that trimmed name wins
112
+ in the exported object. This is current behavior, not a uniqueness guarantee.
113
+ - `test_run` is checked by the server at submission. Accepted true values are
114
+ `true`, `yes`, `1`, `on`; false values are `false`, `no`, `0`, `off`
115
+ (case-insensitive, surrounding whitespace ignored). An omitted, null, or empty
116
+ value means false. Other values are rejected.
117
+ - Thickness is not required or resolved during generation. Any supplied thickness
118
+ custom fields are preserved as ordinary custom fields; generated metadata omits
119
+ the thickness section and material thickness.
120
+
121
+ ## Additional generation checks
122
+
123
+ Generation checks the submitted configuration again, including:
124
+
125
+ - Stack ID length 1–120, no `/` or `\`, and no characters with code point below 32.
126
+ Thus an acknowledged unusual ID may submit but still fail generation.
127
+ - Foil/template still present and accessible; valid laser settings and assignment.
128
+ - Custom fields form a named mapping whose values are strings, numbers, or null.
129
+ - Template structure contains the referenced cut settings and expected stack-ID
130
+ placeholder; resolved thickness values are positive.
131
+ - Configuration is submitted, belongs to the workspace, and is writable. Another
132
+ generated/registered configuration cannot reserve the same Stack ID.
133
+
134
+ ## Imports and portal templates
135
+
136
+ - JSON import must parse as configuration JSON. The import reads at most 28 laser
137
+ entries. Importing does not bypass submission or generation checks.
138
+ - Excel import accepts an `.xlsx` workbook, 1 byte–5 MiB, with at most 30 MiB of
139
+ declared expanded ZIP content. Only the first worksheet is read.
140
+ - The first worksheet needs headers for `power` (or `maxpower`), `speed`,
141
+ `qpulsewidth`, `frequency`, and `passes` (or `numpasses`). Headers are trimmed
142
+ and case-insensitive. It must contain at least one parameter row. Completely
143
+ empty rows are skipped; at most 28 rows are imported. Numeric validity is checked
144
+ later during generation.
145
+ - A portal template must be accessible and identify a LightBurn file. If its item
146
+ contains multiple candidate files, an exact filename is required. Template
147
+ parsing/identity checks can reject unsupported or malformed files.
148
+
149
+ ## Complete Workflow
150
+
151
+ The same submission requirements and acknowledgement apply to **Submit, generate
152
+ & register**. It then runs generation and registration in order. Draft saving never
153
+ triggers those stages. Keep the page open until completion. A failed stage preserves
154
+ saved work and opens Generation or Registration for recovery; it does not undo the
155
+ successful earlier stages. Registration additionally requires generated files,
156
+ Write access to the parent foil and output items, valid creator settings, and an
157
+ available stack IGSN. These are registration requirements, not form status checks.
158
+
159
+ ## Implementation references
160
+
161
+ - `girder_flycut/web_client/core/assess.js`: the requirements and the six warnings.
162
+ - `girder_flycut/web_client/core/validate.js`: the export gate and the status label.
163
+ - `girder_flycut/web_client/views/StatusPanelView.js`: how both are reported.
164
+ - `girder_flycut/client_wrapper.js`: draft saving, submission, and workflow selection.
165
+ - `girder_flycut/validation.py`: server normalization, warnings, and generation validation.
166
+ - `girder_flycut/rest.py`: access, lifecycle, size limits, and submission endpoints.
167
+ - `girder_flycut/registration.py`, `generate.py`, `engine.py`, `excel.py`: special fields
168
+ and downstream checks.