Files
Odoo-Modules/fusion_plating/docs/superpowers/specs/2026-04-30-simple-editor-refinement-design.md
gsinghpal b8d064b180 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>
2026-04-30 16:08:34 -04:00

324 lines
14 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# 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 13 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)