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

14 KiB
Raw Blame History

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)

-- 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

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) 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)

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 stepoperation; 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)