feat(workspace): per-kind step action buttons in Job Workspace
Fix: in the Job Workspace tablet view, the Start button was buried inside a parent t-if that required the step to already be in_progress or blocked. So ready/paused steps showed no buttons at all - operators couldn't advance the WO from this screen (the reason the user couldn't complete anything on WO-30057). Template restructure (job_workspace.xml): - Always-visible line 1 (icon + step# + name + ACTIVE/PAUSED badge + meta) - Non-terminal detail panel (chips + instructions + opt-out + GateViz) visible on every non-done step so operator reads ahead - Action row dispatched per-kind via getStepActions() helper Per-kind action dispatcher (job_workspace.js): - in_progress -> Record Inputs, Pause, Finish (or Finish & Sign Off) - paused -> Resume, Record Inputs, Finish - contract_review (ready) -> Open QA-005 Form - gating (ready) -> Mark Passed (1-click start+finish) - requires_rack_assignment -> Start (Assign Rack) - opens FpRackPartsDialog - else (ready) -> Start 5 new handlers: onPauseStep / onResumeStep / onMarkPassed / onOpenContractReview / onStartWithRack. Pause and Resume use ORM RPC (button_pause/button_resume) since no HTTP endpoint exists. New model method (fp.job.step.action_mark_gating_passed): - 1-click pass for gating steps - does button_start + button_finish in one transaction, posts chatter "Gate X marked passed by Y" - Raises UserError if called on a non-gating step (defensive) - Bypasses S21 required-inputs gate (gating steps have no inputs) Controller: workspace_controller.py adds requires_rack_assignment to the step payload so the JS dispatcher can route correctly. Spec: docs/superpowers/specs/2026-05-24-workspace-step-actions-design.md Sub-B (Record Inputs tablet polish: inputmode/prefill/date pickers/ signature pad/camera) is brainstormed but deferred. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -1397,6 +1397,50 @@ class FpJobStep(models.Model):
|
||||
},
|
||||
}
|
||||
|
||||
def action_mark_gating_passed(self):
|
||||
"""1-click pass for gating steps (kind=='gating').
|
||||
|
||||
Performs button_start (or button_resume if paused) followed by
|
||||
button_finish in the same transaction. Posts a chatter audit on
|
||||
the parent job naming the user.
|
||||
|
||||
Only valid for kind='gating' steps in state in (ready, pending,
|
||||
paused). NOOPs on already-terminal steps for idempotency. Raises
|
||||
UserError if called on a non-gating step (defensive — UI dispatcher
|
||||
only renders Mark Passed for gating kinds).
|
||||
|
||||
Bypasses the S21 required-inputs gate (gating steps have no
|
||||
required inputs by design — they're admin gates).
|
||||
|
||||
Spec: 2026-05-24-workspace-step-actions-design.md Change 5.
|
||||
"""
|
||||
for step in self:
|
||||
if step.state in ('done', 'skipped', 'cancelled'):
|
||||
continue
|
||||
kind_code = (
|
||||
step.recipe_node_id.kind_id.code
|
||||
if step.recipe_node_id and step.recipe_node_id.kind_id
|
||||
else None
|
||||
)
|
||||
if kind_code != 'gating':
|
||||
raise UserError(_(
|
||||
"Mark Passed is only valid for gating steps. "
|
||||
"This step's kind is %s."
|
||||
) % (kind_code or 'unknown'))
|
||||
if step.state not in ('ready', 'pending', 'paused'):
|
||||
continue
|
||||
if step.state == 'paused':
|
||||
step.button_resume()
|
||||
if step.state != 'in_progress':
|
||||
step.button_start()
|
||||
step.with_context(
|
||||
fp_skip_required_inputs_gate=True,
|
||||
).button_finish()
|
||||
step.job_id.message_post(body=_(
|
||||
'Gate "%(name)s" marked passed by %(user)s.'
|
||||
) % {'name': step.name, 'user': self.env.user.name})
|
||||
return True
|
||||
|
||||
def _fp_contract_review_redirect(self):
|
||||
"""Return an ir.actions.act_window opening the part's QA-005
|
||||
Contract Review form, or False to indicate "no redirect needed".
|
||||
|
||||
Reference in New Issue
Block a user