docs(simple-editor): design — bug fix + inline library authoring + breadcrumbs
Spec for the upcoming Simple Recipe Editor refinement: - Fix node_type bug so Simple-Editor recipes generate job steps - Inline + New Step / pencil-edit library authoring with prompts - Back button + breadcrumb-aware navigation (mirrors tree editor) Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -0,0 +1,323 @@
|
|||||||
|
# Simple Recipe Editor — Refinement (Bug Fix + Inline Library Authoring + Breadcrumbs)
|
||||||
|
|
||||||
|
**Status:** Design — pending implementation plan
|
||||||
|
**Date:** 2026-04-30
|
||||||
|
**Modules touched:** `fusion_plating`, `fusion_plating_jobs`
|
||||||
|
**Versions to bump:** `fusion_plating` 19.0.11.4.0 → 19.0.12.0.0 (migration), `fusion_plating_jobs` 19.0.7.x` (no schema change, optional)
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Problem
|
||||||
|
|
||||||
|
Three issues, surfaced together while a customer was trying to author recipes
|
||||||
|
using the Simple Editor:
|
||||||
|
|
||||||
|
1. **Generation bug — Simple-Editor recipes produce zero job steps.**
|
||||||
|
`walk_node()` in `fp_job.py:631` only creates `fp.job.step` rows for
|
||||||
|
`node.node_type == 'operation'`. The Simple Editor inserts library
|
||||||
|
templates with `node_type='step'` directly under the recipe root
|
||||||
|
(`simple_recipe_controller.py:178`). Top-level step children of a
|
||||||
|
recipe fall through. Verified on entech: `LGPS1104` has 19 flat step
|
||||||
|
rows under the recipe root — `fp_job` has 0 rows referencing it. Real
|
||||||
|
downstream consequence: no traveller content, no shopfloor tablet
|
||||||
|
queue entries, no CoC moves, nothing. The recipe is silently inert.
|
||||||
|
|
||||||
|
2. **Library authoring requires a menu trip.** Users have to leave the
|
||||||
|
Simple Editor, navigate to Configuration → Recipes & Steps → Step
|
||||||
|
Library, create a template, configure prompts in a list view, then
|
||||||
|
come back to the editor to drag it in. The template form is
|
||||||
|
manager-grade (notebook with 4 tabs); it's not the right tool for a
|
||||||
|
shop foreman who wants to capture a one-off step their facility
|
||||||
|
does.
|
||||||
|
|
||||||
|
3. **No way back from the Simple Editor.** Click "Open Simple Editor"
|
||||||
|
from the recipe form → full-screen client action with no back button,
|
||||||
|
no breadcrumb. Operator has to use Chrome's back arrow to escape.
|
||||||
|
The Tree Editor has had a custom "← Back to Recipes" button since
|
||||||
|
2026-04-22; the Simple Editor was never given one.
|
||||||
|
|
||||||
|
## Goals
|
||||||
|
|
||||||
|
- Simple-Editor-authored recipes produce correct job steps end-to-end —
|
||||||
|
WO traveller, shopfloor tablet, CoC, reports.
|
||||||
|
- A shop foreman can author a new library step (with prompts, kind,
|
||||||
|
stations, instructions) without leaving the Simple Editor.
|
||||||
|
- A shop foreman can edit an existing library step without leaving the
|
||||||
|
Simple Editor.
|
||||||
|
- Closing the Simple Editor returns to the recipe list (or part form, if
|
||||||
|
opened from the Process Composer).
|
||||||
|
- Existing tree-editor recipes are untouched. Existing simple-editor
|
||||||
|
recipes get migrated, with a chatter note explaining the change.
|
||||||
|
|
||||||
|
## Non-goals
|
||||||
|
|
||||||
|
- No new step kinds. The existing 23-value `default_kind` Selection
|
||||||
|
stays as-is. Free-text custom kinds are explicitly out of scope —
|
||||||
|
templates without a kind continue to behave as "Generic" (no auto-
|
||||||
|
seeded prompts, no auto-gates), which is fine.
|
||||||
|
- No change to the Tree Editor.
|
||||||
|
- No change to the manager-grade Step Library form view.
|
||||||
|
- No prompt-collection runtime behaviour change (`collect_measurements`,
|
||||||
|
per-input `collect`, etc. all keep working as today).
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Bucket 1 — Generation bug fix
|
||||||
|
|
||||||
|
### Migration (one-shot, fusion_plating 19.0.12.0.0/post-migrate.py)
|
||||||
|
|
||||||
|
```sql
|
||||||
|
-- Flip top-level step children of recipes → operation. Filter is
|
||||||
|
-- intentionally narrow: only nodes whose parent is a recipe root.
|
||||||
|
-- Tree-editor 'step' rows (which sit under operation parents) are
|
||||||
|
-- untouched.
|
||||||
|
UPDATE fusion_plating_process_node child
|
||||||
|
SET node_type = 'operation'
|
||||||
|
WHERE child.node_type = 'step'
|
||||||
|
AND child.parent_id IN (
|
||||||
|
SELECT id FROM fusion_plating_process_node WHERE node_type = 'recipe'
|
||||||
|
);
|
||||||
|
```
|
||||||
|
|
||||||
|
After the SQL runs, walk every distinct `recipe_root_id` whose children
|
||||||
|
were touched and post a chatter note:
|
||||||
|
|
||||||
|
> "Recipe migrated to v19.0.12.0.0 step layout. Step nodes that were
|
||||||
|
> direct children of this recipe (Simple Editor authoring) have been
|
||||||
|
> promoted to operation nodes so they generate work-order steps
|
||||||
|
> correctly. No data was lost — only `node_type` changed. If this
|
||||||
|
> recipe was already authored via the Tree Editor with explicit
|
||||||
|
> sub-process / operation hierarchy, this migration was a no-op for it."
|
||||||
|
|
||||||
|
### Controller change (going forward)
|
||||||
|
|
||||||
|
`simple_recipe_controller.py:178` —
|
||||||
|
```python
|
||||||
|
new_vals = {
|
||||||
|
'parent_id': recipe.id,
|
||||||
|
'node_type': 'operation', # was 'step' — fix Bucket 1 bug
|
||||||
|
'sequence': target_seq,
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
`_snapshot_step_into()` (template/import path) gets the same fix on
|
||||||
|
line 295.
|
||||||
|
|
||||||
|
### What "just works" after this
|
||||||
|
|
||||||
|
- `walk_node()` finds operation nodes, creates `fp.job.step` rows.
|
||||||
|
- WO traveller (`report_fp_job_traveller.xml`) iterates
|
||||||
|
`job.step_ids` — populated.
|
||||||
|
- Shopfloor tablet `/fp/shopfloor/scan` returns the same step rows.
|
||||||
|
- CoC chronological body uses `fp.job.step.move` rows that get created
|
||||||
|
on tablet operations against real step rows.
|
||||||
|
- Quality-point matching (`fp.quality.point._matches`) keys off
|
||||||
|
`step.kind`, which is mapped from `node.default_kind` in the same
|
||||||
|
walk_node code path. Templates with no kind get `step.kind='other'`
|
||||||
|
— behaves like a generic step. No regression.
|
||||||
|
|
||||||
|
### Verification checklist (manual, after deploy)
|
||||||
|
|
||||||
|
1. Create a new job against `LGPS1104` on entech.
|
||||||
|
2. Confirm `fp.job.step_ids` contains 19 rows (or however many the recipe has).
|
||||||
|
3. Print the WO Traveller — every step listed.
|
||||||
|
4. Open the operator tablet for that job — every step in My Queue.
|
||||||
|
5. Walk one step start → finish on the tablet — `fp.job.step.move` row created.
|
||||||
|
6. Generate a chronological CoC against the closed job — body lists each step heading.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Bucket 2 — Inline library authoring in Simple Editor
|
||||||
|
|
||||||
|
### UX
|
||||||
|
|
||||||
|
In the right-hand Step Library panel, above the search input:
|
||||||
|
```
|
||||||
|
┌──────────────────────────────┐
|
||||||
|
│ + New Step │
|
||||||
|
├──────────────────────────────┤
|
||||||
|
│ [Search… ] │
|
||||||
|
├──────────────────────────────┤
|
||||||
|
│ ⚙ Acid Dip ✎ │
|
||||||
|
│ 🔗 Adhesion Test ✎ │
|
||||||
|
│ ... │
|
||||||
|
└──────────────────────────────┘
|
||||||
|
```
|
||||||
|
|
||||||
|
- **+ New Step** opens an inline form (replaces the library list while
|
||||||
|
open, "Save" / "Cancel" return to list).
|
||||||
|
- Pencil ✎ next to each library row → same form, prefilled with the
|
||||||
|
template's current values.
|
||||||
|
|
||||||
|
### Inline form fields
|
||||||
|
|
||||||
|
Two-column grid:
|
||||||
|
|
||||||
|
```
|
||||||
|
NAME * KIND
|
||||||
|
[ ] [Generic — no automatic ▾]
|
||||||
|
|
||||||
|
ICON ALLOWED STATIONS
|
||||||
|
[⚙ Cog ▾] [tag1] [tag2] [+]
|
||||||
|
|
||||||
|
INSTRUCTIONS
|
||||||
|
[ ]
|
||||||
|
[ ]
|
||||||
|
[ ]
|
||||||
|
|
||||||
|
FLAGS
|
||||||
|
☐ Require QA Sign-off
|
||||||
|
☐ Require Predecessor Done
|
||||||
|
☐ Requires Rack Assignment
|
||||||
|
☐ Requires Transition Form
|
||||||
|
|
||||||
|
PROMPTS (Operation Measurements — what the operator records during this step)
|
||||||
|
┌───────┬──────────────────┬──────────┬─────┬─────┬────┬───┐
|
||||||
|
│Collect│ Prompt │ Type │ Min │ Max │Req │ × │
|
||||||
|
├───────┼──────────────────┼──────────┼─────┼─────┼────┼───┤
|
||||||
|
│ ☑ │ Actual Time │ Time(sec)│ │ │ │ × │
|
||||||
|
│ ☑ │ Bath ID │ Text │ │ │ │ × │
|
||||||
|
└───────┴──────────────────┴──────────┴─────┴─────┴────┴───┘
|
||||||
|
[+ Add prompt] [Seed defaults from kind]
|
||||||
|
|
||||||
|
[Save] [Cancel]
|
||||||
|
```
|
||||||
|
|
||||||
|
The PROMPTS table reuses the same column layout as the existing
|
||||||
|
per-recipe-step edit panel (`simple_recipe_editor.xml:127-200`). Same
|
||||||
|
input-type Selection (15 options), same min/max/req fields. Authors
|
||||||
|
get one consistent table whether they're editing a recipe step or a
|
||||||
|
library template.
|
||||||
|
|
||||||
|
The "Seed defaults from kind" button calls
|
||||||
|
`action_seed_default_inputs()` server-side and refreshes — gives the
|
||||||
|
shop foreman the same one-click seeding the manager form has.
|
||||||
|
|
||||||
|
### Controller endpoints (new)
|
||||||
|
|
||||||
|
```
|
||||||
|
POST /fp/simple_recipe/library/load { template_id }
|
||||||
|
POST /fp/simple_recipe/library/save { template_id|null, vals } # create or update
|
||||||
|
POST /fp/simple_recipe/library/seed_defaults { template_id } # action_seed_default_inputs
|
||||||
|
POST /fp/simple_recipe/library/input/add { template_id, payload }
|
||||||
|
POST /fp/simple_recipe/library/input/write { input_id, payload }
|
||||||
|
POST /fp/simple_recipe/library/input/remove { input_id }
|
||||||
|
```
|
||||||
|
|
||||||
|
`library/save` does an upsert: if `template_id` is null, creates;
|
||||||
|
otherwise writes. Returns the full template payload (same shape as
|
||||||
|
`library/load`) so the OWL component can refresh state in one call.
|
||||||
|
|
||||||
|
The existing `library/create`, `library/write`, `library/delete` stay
|
||||||
|
for back-compat (they're called by no other code today, so we could
|
||||||
|
delete them, but cheap to leave).
|
||||||
|
|
||||||
|
### Snapshot semantics (no change)
|
||||||
|
|
||||||
|
When the author saves a new template and then drags it into a recipe,
|
||||||
|
the existing `_copy_inputs_from_template()` ([simple_recipe_controller.py:223](fusion_plating/controllers/simple_recipe_controller.py:223))
|
||||||
|
copies all `input_template_ids` → recipe-step `input_ids`. Editing the
|
||||||
|
template later does NOT mutate recipes already built (Q4 = A locked
|
||||||
|
2026-04-27). This bucket changes nothing about that contract.
|
||||||
|
|
||||||
|
### What's excluded from inline form (still requires manager form)
|
||||||
|
|
||||||
|
- Time/Temp/Voltage/Viscosity targets (Advanced tab) — rarely set by
|
||||||
|
shop foreman, lots of pickers, would bloat the inline form. Stays on
|
||||||
|
the manager form.
|
||||||
|
- Transition Form fields — Sub 12b feature, more compliance-heavy,
|
||||||
|
needs the dedicated tab. Stays on the manager form.
|
||||||
|
- Common Audit Fields seeding — accessible via `action_add_common_audit_fields`
|
||||||
|
on the manager form. Could be added to the inline form later if
|
||||||
|
asked.
|
||||||
|
|
||||||
|
The pencil ✎ form has a small "Open in full editor" link in the
|
||||||
|
corner that does `action.doAction({type:'ir.actions.act_window', res_model:'fp.step.template', res_id:tpl.id})` for the manager-only escape hatch.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Bucket 3 — Breadcrumb / Back navigation
|
||||||
|
|
||||||
|
### Header layout (Simple Editor)
|
||||||
|
|
||||||
|
```
|
||||||
|
[← Back to Recipes] Recipe: LGPS1104 [Open in Tree Editor]
|
||||||
|
```
|
||||||
|
|
||||||
|
### Logic (mirrors recipe_tree_editor.js:548)
|
||||||
|
|
||||||
|
```js
|
||||||
|
onBackToList() {
|
||||||
|
const partId = this.props.action?.context?.part_id;
|
||||||
|
if (partId) {
|
||||||
|
this.action.doAction({
|
||||||
|
type: "ir.actions.act_window",
|
||||||
|
res_model: "fp.part.catalog",
|
||||||
|
res_id: partId,
|
||||||
|
views: [[false, "form"]],
|
||||||
|
target: "current",
|
||||||
|
}, { clearBreadcrumbs: true });
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
this.action.doAction("fusion_plating.action_fp_process_recipe", {
|
||||||
|
clearBreadcrumbs: true,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
`clearBreadcrumbs: true` is critical — without it, every part-form →
|
||||||
|
composer → editor → back leaves the intermediate pages on the breadcrumb
|
||||||
|
stack. Same battle-scar the Tree Editor learned from in 2026-04-22.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Bucket 4 — Downstream verification
|
||||||
|
|
||||||
|
No code expected. Manual checklist after Buckets 1–3 ship to entech:
|
||||||
|
|
||||||
|
- [ ] Job generated from LGPS1104 has 19 fp.job.step rows
|
||||||
|
- [ ] WO Traveller PDF lists every step
|
||||||
|
- [ ] Tablet "My Queue" lists every step on the operator with that job's work centre
|
||||||
|
- [ ] Step start → finish creates an `fp.job.step.move` row
|
||||||
|
- [ ] Closed-job CoC body (chronological style) lists every step heading
|
||||||
|
- [ ] User-added templates (Blasting, Surface Activation, Nickel Strip — Steel Line, Nickel Strip (S-1), Air Dry) flow through correctly
|
||||||
|
- [ ] Templates without `default_kind` flow through with `fp.job.step.kind='other'` and behave as plain steps (no auto-gates)
|
||||||
|
- [ ] Existing tree-editor recipes still produce the same number of steps as before (no regression)
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Risks + mitigations
|
||||||
|
|
||||||
|
| Risk | Mitigation |
|
||||||
|
|---|---|
|
||||||
|
| Migration touches a recipe authored by Tree Editor that happens to have a flat step under recipe root | Filter is `parent_id IN (recipe ids)`. Tree-editor `step` rows have `operation` parents, not `recipe`. Verified zero false positives on entech (only Simple-Editor recipes have `step` children of `recipe`). |
|
||||||
|
| New job-step rows surface a Sub 12b "Requires Rack Assignment" or Sub 8 racking-inspection gate operator wasn't expecting | All such gates check `requires_rack_assignment` / `default_kind=='racking'`. User-added Blasting / Surface Activation templates have neither set, so they'll behave as plain operations. |
|
||||||
|
| Inline form lets a foreman delete a library template that's used in 30 recipes | `library/delete` is already soft-delete (sets active=False) when used. Inline form keeps the same behaviour. |
|
||||||
|
| Author edits a library template's prompts and expects existing recipes to update | They won't — snapshot semantics still apply. UX mitigation: on save, post a notification "Saved. Existing recipes using this step keep their old prompts; new drops will use the new prompts." |
|
||||||
|
| Migration runs twice | SQL is idempotent (only flips `step` → `operation`; second run finds no `step` children of recipes, no-op). Chatter note is gated on `node_type` change so won't double-post. |
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Module versions
|
||||||
|
|
||||||
|
- `fusion_plating`: bump to 19.0.12.0.0 (migration + controller change + OWL changes)
|
||||||
|
- `fusion_plating_jobs`: no version bump required, but worth a smoke test
|
||||||
|
|
||||||
|
## Build order
|
||||||
|
|
||||||
|
1. Migration `fusion_plating/migrations/19.0.12.0.0/post-migrate.py` — flip + chatter
|
||||||
|
2. Controller — change `node_type='operation'` in two places + add 6 new `library/*` endpoints
|
||||||
|
3. OWL JS — `simple_recipe_editor.js` adds inline form state + handlers + back button
|
||||||
|
4. OWL XML — `simple_recipe_editor.xml` adds inline form template + back button + pencil
|
||||||
|
5. SCSS — minimal; reuse existing classes from edit panel
|
||||||
|
6. Bump `fusion_plating/__manifest__.py` version
|
||||||
|
7. Deploy to entech, run verification checklist
|
||||||
|
|
||||||
|
## Things explicitly NOT in this spec
|
||||||
|
|
||||||
|
- New step kinds (deferred — clients add templates as they go, kind stays optional)
|
||||||
|
- Tree Editor changes
|
||||||
|
- Step Library manager-grade form changes
|
||||||
|
- New report content
|
||||||
|
- New shopfloor tablet content
|
||||||
|
- Free-text custom kinds (rejected — would silently lose 4 functional behaviours)
|
||||||
Reference in New Issue
Block a user