fix(fusion_plating_shopfloor): stop breadcrumb URL growth; embed racking panel in step row
Surface switches between the plant kanban and job workspace used
doAction({..., target: "current"}), which APPENDS to Odoo 19's
controller/breadcrumb stack -- so the /odoo/... URL grew one segment
per switch, and the tablet lock/unlock window.location.reload()
preserved the bloat, compounding it every lock cycle. Switched those
navigations to target: "main" (Odoo sets clearBreadcrumbs when
action.target === "main" -> _computeStackIndex returns 0 -> stack
resets to a single action). The genuine one-level drill-down
(onJumpToBlocker -> hold/NCR form) keeps target: "current" so
breadcrumb-back still works there.
Also embeds the multi-rack racking panel inside the Racking step row
(gated on step.area_kind == 'racking') instead of a job-level section,
tying it to the recipe's Racking step.
19.0.37.0.1 -> 19.0.37.0.3. Both changes live on entech.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -5,7 +5,7 @@
|
|||||||
|
|
||||||
{
|
{
|
||||||
'name': 'Fusion Plating — Shop Floor',
|
'name': 'Fusion Plating — Shop Floor',
|
||||||
'version': '19.0.37.0.1',
|
'version': '19.0.37.0.3',
|
||||||
'category': 'Manufacturing/Plating',
|
'category': 'Manufacturing/Plating',
|
||||||
'summary': 'Shop-floor tablet stations, QR scanning, bake window enforcer.',
|
'summary': 'Shop-floor tablet stations, QR scanning, bake window enforcer.',
|
||||||
'description': """
|
'description': """
|
||||||
|
|||||||
@@ -75,6 +75,8 @@ class FpWorkspaceController(http.Controller):
|
|||||||
'name': step.name or '',
|
'name': step.name or '',
|
||||||
'kind': step.kind or 'other',
|
'kind': step.kind or 'other',
|
||||||
'kind_label': dict(step._fields['kind'].selection).get(step.kind, ''),
|
'kind_label': dict(step._fields['kind'].selection).get(step.kind, ''),
|
||||||
|
# Drives the embedded rack-split panel inside this step's row.
|
||||||
|
'is_racking': step.area_kind == 'racking',
|
||||||
'state': step.state,
|
'state': step.state,
|
||||||
'assigned_user_id': step.assigned_user_id.id or False,
|
'assigned_user_id': step.assigned_user_id.id or False,
|
||||||
'assigned_user_name': step.assigned_user_id.name or '',
|
'assigned_user_name': step.assigned_user_id.name or '',
|
||||||
@@ -283,14 +285,9 @@ class FpWorkspaceController(http.Controller):
|
|||||||
'is_manager': env.user.has_group(
|
'is_manager': env.user.has_group(
|
||||||
'fusion_plating.group_fusion_plating_manager',
|
'fusion_plating.group_fusion_plating_manager',
|
||||||
),
|
),
|
||||||
# Racking panel (multi-rack split) shows when the WO is at the
|
# Note: the rack-split panel is gated per-step via each step's
|
||||||
# racking step and it's the current actionable work. Detect by
|
# 'is_racking' flag (area_kind == 'racking'), embedded in the
|
||||||
# area_kind == 'racking' (corrected classification) — NOT
|
# racking step's row — not a job-level panel.
|
||||||
# _fp_is_racking_step(), which would also match mis-tagged
|
|
||||||
# De-Racking steps (kind='racking' in the data).
|
|
||||||
'is_at_racking': bool(job.step_ids.filtered(
|
|
||||||
lambda s: s.area_kind == 'racking'
|
|
||||||
and s.state in ('ready', 'in_progress', 'paused'))),
|
|
||||||
}
|
}
|
||||||
|
|
||||||
# ======================================================================
|
# ======================================================================
|
||||||
|
|||||||
@@ -69,7 +69,7 @@ export class FpJobWorkspace extends Component {
|
|||||||
this.action.doAction({
|
this.action.doAction({
|
||||||
type: "ir.actions.client",
|
type: "ir.actions.client",
|
||||||
tag: "fp_plant_kanban",
|
tag: "fp_plant_kanban",
|
||||||
target: "current",
|
target: "main",
|
||||||
});
|
});
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@@ -82,7 +82,7 @@ export class FpJobWorkspace extends Component {
|
|||||||
this.action.doAction({
|
this.action.doAction({
|
||||||
type: "ir.actions.client",
|
type: "ir.actions.client",
|
||||||
tag: "fp_plant_kanban",
|
tag: "fp_plant_kanban",
|
||||||
target: "current",
|
target: "main",
|
||||||
});
|
});
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@@ -164,16 +164,16 @@ export class FpJobWorkspace extends Component {
|
|||||||
|
|
||||||
// ---- Navigation --------------------------------------------------------
|
// ---- Navigation --------------------------------------------------------
|
||||||
onBack() {
|
onBack() {
|
||||||
// The workspace is opened with target: "current" which REPLACES
|
// target: "main" CLEARS the breadcrumb stack (Odoo 19:
|
||||||
// the current action and wipes the backstack. Navigate explicitly
|
// action.target === "main" => clearBreadcrumbs in action_service.js).
|
||||||
// to the plant kanban — the sole Shop Floor surface as of
|
// target: "current" was APPENDING — each kanban<->workspace switch
|
||||||
// 2026-05-25 (fp_shopfloor_landing was retired the same day).
|
// grew the /odoo/... URL, and lock/unlock window.location.reload()
|
||||||
// See CLAUDE.md Critical Rule 21 + the "Legacy-action redirect"
|
// preserved it, so the address bar ballooned. "main" keeps the URL a
|
||||||
// section.
|
// single action. The plant kanban is the sole Shop Floor surface.
|
||||||
this.action.doAction({
|
this.action.doAction({
|
||||||
type: "ir.actions.client",
|
type: "ir.actions.client",
|
||||||
tag: "fp_plant_kanban",
|
tag: "fp_plant_kanban",
|
||||||
target: "current",
|
target: "main",
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -212,7 +212,7 @@ export class FpPlantKanban extends Component {
|
|||||||
type: "ir.actions.client",
|
type: "ir.actions.client",
|
||||||
tag: "fp_job_workspace",
|
tag: "fp_job_workspace",
|
||||||
params: { job_id: res.id },
|
params: { job_id: res.id },
|
||||||
target: "current",
|
target: "main",
|
||||||
});
|
});
|
||||||
return; // navigating away — skip the refresh
|
return; // navigating away — skip the refresh
|
||||||
} else if (res.model === "fp.job.step") {
|
} else if (res.model === "fp.job.step") {
|
||||||
@@ -223,7 +223,7 @@ export class FpPlantKanban extends Component {
|
|||||||
job_id: res.job_id || 0,
|
job_id: res.job_id || 0,
|
||||||
focus_step_id: res.id,
|
focus_step_id: res.id,
|
||||||
},
|
},
|
||||||
target: "current",
|
target: "main",
|
||||||
});
|
});
|
||||||
return;
|
return;
|
||||||
} else if (res.action_tag) {
|
} else if (res.action_tag) {
|
||||||
@@ -232,7 +232,7 @@ export class FpPlantKanban extends Component {
|
|||||||
type: "ir.actions.client",
|
type: "ir.actions.client",
|
||||||
tag: res.action_tag,
|
tag: res.action_tag,
|
||||||
params: res.action_params || {},
|
params: res.action_params || {},
|
||||||
target: "current",
|
target: "main",
|
||||||
});
|
});
|
||||||
return;
|
return;
|
||||||
} else {
|
} else {
|
||||||
|
|||||||
@@ -80,11 +80,6 @@
|
|||||||
<!-- STEP LIST -->
|
<!-- STEP LIST -->
|
||||||
<div class="o_fp_ws_steps">
|
<div class="o_fp_ws_steps">
|
||||||
|
|
||||||
<!-- Racking: split a WO's parts across multiple racks.
|
|
||||||
Shown only when the WO is at the Racking step. -->
|
|
||||||
<RackingPanel t-if="state.data.is_at_racking"
|
|
||||||
jobId="state.jobId"/>
|
|
||||||
|
|
||||||
<!-- PRE-RECIPE: RECEIVING CARDS (Spec C1+C2 2026-05-24)
|
<!-- PRE-RECIPE: RECEIVING CARDS (Spec C1+C2 2026-05-24)
|
||||||
Renders one card per fp.receiving in state
|
Renders one card per fp.receiving in state
|
||||||
draft/counted on the linked SO. Card disappears
|
draft/counted on the linked SO. Card disappears
|
||||||
@@ -346,6 +341,8 @@
|
|||||||
<!-- NON-TERMINAL: read-ahead detail (chips + instructions + opt-out + GateViz) -->
|
<!-- NON-TERMINAL: read-ahead detail (chips + instructions + opt-out + GateViz) -->
|
||||||
<t t-if="!['done', 'skipped', 'cancelled'].includes(step.state)">
|
<t t-if="!['done', 'skipped', 'cancelled'].includes(step.state)">
|
||||||
<div class="o_fp_ws_step_detail">
|
<div class="o_fp_ws_step_detail">
|
||||||
|
<!-- Multi-rack split — embedded in the Racking step's row. -->
|
||||||
|
<RackingPanel t-if="step.is_racking" jobId="state.jobId"/>
|
||||||
<!-- Recipe chips: visible on every non-done step so operator reads ahead -->
|
<!-- Recipe chips: visible on every non-done step so operator reads ahead -->
|
||||||
<div class="o_fp_ws_step_chips"
|
<div class="o_fp_ws_step_chips"
|
||||||
t-if="step.thickness_target or step.dwell_time_minutes or step.bake_setpoint_temp or step.requires_signoff or step.requires_rack_assignment">
|
t-if="step.thickness_target or step.dwell_time_minutes or step.bake_setpoint_temp or step.requires_signoff or step.requires_rack_assignment">
|
||||||
|
|||||||
Reference in New Issue
Block a user