feat(shopfloor): Phase 5 — flip default to v2 plant view + docs
PV-Phase5 of the plant-view redesign. Final phase — flips the default
of x_fc_shopfloor_layout from 'legacy' to 'v2' and updates CLAUDE.md
with the new architecture rule.
Verified on entech:
- HTTP 200 on /web/login
- Shopfloor module loads cleanly with all 19 new frontend files
- /fp/landing/plant_kanban returns the assembled payload with 9
columns + denormalized cards
- Card state distribution: 22 contract_review + 8 no_parts + 1 running
(sample data only — dev system)
- Asset bundle re-compiled (9 stale attachments cleared)
- ir.config_parameter['fusion_plating_shopfloor.layout'] = 'v2' set
To switch back to legacy: Settings → Fusion Plating → Shop Floor
Layout, or UPDATE ir_config_parameter SET value='legacy' WHERE
key='fusion_plating_shopfloor.layout'.
CLAUDE.md gets a new ~80-line section documenting:
- Why the redesign (per-step kanban produced duplicate cards)
- 9-column layout + step-kind → area mapping (spec D3, D4, D5)
- 13-state catalog + precedence dispatch in _compute_card_state
- Backend single-endpoint payload shape (/fp/landing/plant_kanban)
- Frontend OWL component tree + critical implementation gotchas
(rule 20 OWL scope, rule 8 SCSS @import, dark-mode compile-time)
- How to switch back to legacy
Closes the 20-task plan in
docs/superpowers/plans/2026-05-23-shopfloor-plant-view-plan.md
Spec: docs/superpowers/specs/2026-05-23-shopfloor-plant-view-design.md
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -420,6 +420,107 @@ Plan: [docs/superpowers/plans/2026-05-22-shopfloor-tablet-redesign-plan.md](docs
|
||||
- Don't add `web.assets_web_dark` entries to the manifest — Odoo 19 auto-compiles `web.assets_backend` SCSS into both bundles
|
||||
- Don't bypass `_fp_should_block_predecessors()` when computing step blockers — keep `blocker_kind=predecessor` logic in sync with `can_start`
|
||||
|
||||
## Shop Floor — Plant View kanban (2026-05-23 redesign)
|
||||
|
||||
**Default Shop Floor surface** for new installs (gated by feature flag
|
||||
`ir.config_parameter['fusion_plating_shopfloor.layout']`, values `legacy`
|
||||
or `v2`). Legacy per-step kanban (`fp_shopfloor_landing`) remains
|
||||
accessible by flipping the flag back to `legacy` in Settings → Fusion
|
||||
Plating.
|
||||
|
||||
**Why redesign:** the per-step kanban produced one card per recipe step
|
||||
per column, so a 14-step recipe spawned 9+ cards for ONE job across the
|
||||
board. With 17 active jobs the board showed 100+ duplicate cards across
|
||||
narrow columns. The new design is **one card per `fp.job`** at the
|
||||
**department level** — recipe step count no longer drives layout width.
|
||||
|
||||
**Spec:** `docs/superpowers/specs/2026-05-23-shopfloor-plant-view-design.md`
|
||||
**Plan:** `docs/superpowers/plans/2026-05-23-shopfloor-plant-view-plan.md`
|
||||
|
||||
### Layout — 9 fixed columns in process sequence
|
||||
|
||||
`Receiving → Masking → Blasting → Racking → Plating → Baking →
|
||||
De-Racking → Final inspection → Shipping`
|
||||
|
||||
Columns are first-class — they always render in this exact order, never
|
||||
reorder, never collapse when empty. Driven by `fp.work.centre.area_kind`
|
||||
Selection (added 2026-05-23). Each `fp.job.step.area_kind` is computed
|
||||
(stored) from `work_centre.area_kind` with a fallback to a step-kind
|
||||
dispatch table (`_STEP_KIND_TO_AREA` in `fusion_plating_jobs/models/fp_job_step.py`).
|
||||
|
||||
**Spec D3:** all wet-line steps (Soak Clean, Electroclean, Acid Dip,
|
||||
Etch, Desmut, Zincate, Rinse, E-Nickel, Chrome, Anodize, Black Oxide,
|
||||
Drying) roll up into the **Plating** column. The tank chip on the card
|
||||
distinguishes them.
|
||||
|
||||
**Spec D4:** De-Masking folds into De-Racking (no separate column).
|
||||
|
||||
**Spec D5:** Contract Review (paperwork) cards live in Receiving with a
|
||||
purple "📋 QA-005" chip — they're admin gates, not physical work.
|
||||
|
||||
### Card state catalog — 13 mutually-exclusive states
|
||||
|
||||
`fp.job.card_state` is a stored Char computed in `_compute_card_state`
|
||||
(see `fusion_plating_jobs/models/fp_job.py`). Explicit precedence
|
||||
dispatch matching spec §6.2 — first match wins:
|
||||
|
||||
`no_parts → on_hold → awaiting_signoff → awaiting_qc → bake_due →
|
||||
predecessor_locked → idle_warning → done → contract_review →
|
||||
running_mine/running → ready_mine/ready`
|
||||
|
||||
Each state has a distinct background tint + left-border color + chip +
|
||||
mini-timeline marker color. See `_plant_card.scss` for the mapping. The
|
||||
"mine" variants (`ready_mine`, `running_mine`) light up only when the
|
||||
active step's work centre is in `res.users.paired_work_centre_ids` (the
|
||||
M2M holds one row in MVP, mirrors the existing single-station picker).
|
||||
|
||||
### Backend — single endpoint, denormalized payload
|
||||
|
||||
`/fp/landing/plant_kanban` (controller in
|
||||
`fusion_plating_shopfloor/controllers/plant_kanban.py`) returns
|
||||
`{ok, mode, paired_station, kpis, columns, cards}` in one JSONRPC call.
|
||||
Frontend has zero per-card RPCs — every card field comes pre-formatted
|
||||
from the controller's `_render_card`. State-chip text (with elapsed
|
||||
times, operator names, hours-idle) is interpolated server-side.
|
||||
|
||||
### Frontend — OWL component tree
|
||||
|
||||
```
|
||||
FpPlantKanban (client action 'fp_plant_kanban')
|
||||
└── FpTabletLock (PIN gate wrapper)
|
||||
├── PlantHeader (KPIs + filter chips + mode toggle + station picker)
|
||||
└── Board (9 × Column)
|
||||
├── FpColumnHeader (with 'You're here' badge for paired column)
|
||||
└── FpPlantCard[] (each with FpMiniTimeline)
|
||||
```
|
||||
|
||||
Polls every 10s. Filter state persists in localStorage. All 13 card
|
||||
states styled via `.state-<name>` CSS modifier classes on a single
|
||||
shared `.o_fp_plant_card` base. The mini-timeline renders 9 colored
|
||||
dots driven by `fp.job.mini_timeline_json` (Python emits the array
|
||||
shape — frontend just maps state → CSS class).
|
||||
|
||||
### Critical implementation gotchas (project rules applied)
|
||||
|
||||
- **OWL templates only expose `Math` as a JS global** (Rule 20). All
|
||||
coercion (String, Number, parseInt) MUST happen in JS — `tag_chip_class()`
|
||||
/ `progress_style` etc. live in plant_card.js, not in the XML.
|
||||
- **SCSS @import is forbidden** (Rule 8). `_plant_tokens.scss` loads
|
||||
FIRST in the manifest's `web.assets_backend`; subsequent component
|
||||
partials get the `$plant-*` vars via the concatenated bundle.
|
||||
- **Dark mode** via `$o-webclient-color-scheme == dark` compile-time
|
||||
branch in `_plant_tokens.scss` (NOT runtime class selectors).
|
||||
|
||||
### How to switch back to legacy
|
||||
|
||||
```sql
|
||||
UPDATE ir_config_parameter SET value = 'legacy'
|
||||
WHERE key = 'fusion_plating_shopfloor.layout';
|
||||
```
|
||||
|
||||
Or use Settings → Fusion Plating → Shop Floor Layout. Both surfaces
|
||||
write the same `ir.config_parameter` key.
|
||||
|
||||
## Deployment
|
||||
|
||||
### odoo-entech (LXC 111 on pve-worker5)
|
||||
|
||||
@@ -23,7 +23,7 @@ class ResConfigSettings(models.TransientModel):
|
||||
('v2', 'Plant View (one card per job, 9 columns)'),
|
||||
],
|
||||
string='Shop Floor Layout',
|
||||
default='legacy',
|
||||
default='v2',
|
||||
config_parameter='fusion_plating_shopfloor.layout',
|
||||
help='Switches the Shop Floor client action between the legacy '
|
||||
'per-step kanban and the v2 plant view. Defaults to legacy '
|
||||
|
||||
Reference in New Issue
Block a user