From 190b394001880a3b89cbe280adb860deb6ce0158 Mon Sep 17 00:00:00 2001 From: gsinghpal Date: Thu, 4 Jun 2026 00:22:42 -0400 Subject: [PATCH] feat(fusion_plating_shopfloor): workspace sign-off confirms saved signature, draws only when absent onFinishStep: if the user has a saved Plating Signature, show FpSignatureConfirm (one-tap, preview); otherwise open the draw-pad. Factored _openSignaturePad + _commitSignOff (sends null data URI when using the saved signature). Co-Authored-By: Claude Opus 4.8 (1M context) --- .../static/src/js/job_workspace.js | 62 ++++++++++++------- 1 file changed, 41 insertions(+), 21 deletions(-) diff --git a/fusion_plating/fusion_plating_shopfloor/static/src/js/job_workspace.js b/fusion_plating/fusion_plating_shopfloor/static/src/js/job_workspace.js index 87b2dd95..8db1fda6 100644 --- a/fusion_plating/fusion_plating_shopfloor/static/src/js/job_workspace.js +++ b/fusion_plating/fusion_plating_shopfloor/static/src/js/job_workspace.js @@ -25,6 +25,7 @@ import { useService } from "@web/core/utils/hooks"; import { WorkflowChip } from "./components/workflow_chip"; import { GateViz } from "./components/gate_viz"; import { FpSignaturePad } from "./components/signature_pad"; +import { FpSignatureConfirm } from "./components/signature_confirm"; import { FpHoldComposer } from "./components/hold_composer"; import { FpTabletLock } from "./tablet_lock"; import { FpRackPartsDialog } from "./rack_parts_dialog"; @@ -38,7 +39,7 @@ import { FileModel } from "@web/core/file_viewer/file_model"; export class FpJobWorkspace extends Component { static template = "fusion_plating_shopfloor.JobWorkspace"; static props = ["*"]; - static components = { WorkflowChip, GateViz, FpSignaturePad, FpHoldComposer, FpTabletLock, FpRackPartsDialog, FpDamageDialog, FpFinishBlockDialog, RackingPanel, FpMovePartsDialog }; + static components = { WorkflowChip, GateViz, FpSignaturePad, FpSignatureConfirm, FpHoldComposer, FpTabletLock, FpRackPartsDialog, FpDamageDialog, FpFinishBlockDialog, RackingPanel, FpMovePartsDialog }; setup() { this.notification = useService("notification"); @@ -363,26 +364,20 @@ export class FpJobWorkspace extends Component { async onFinishStep(step) { if (step.requires_signoff) { - this.dialog.add(FpSignaturePad, { - title: `Sign to finish ${step.name}`, - contextLabel: `${this.state.data.job.display_wo_name} · Step ${step.sequence_display}: ${step.name}`, - onSubmit: async (dataUri) => { - try { - const res = await fpRpc("/fp/workspace/sign_off", { - step_id: step.id, - signature_data_uri: dataUri, - }); - if (res && res.ok) { - this.notification.add("Step signed off and finished.", { type: "success" }); - await this.refresh(); - } else { - this.notification.add((res && res.error) || "Sign-off failed", { type: "danger" }); - } - } catch (err) { - this.notification.add(err.message, { type: "danger" }); - } - }, - }); + if (this.state.data.user_has_plating_signature) { + // One-tap confirm with a preview of the saved Plating Signature. + this.dialog.add(FpSignatureConfirm, { + title: `Sign to finish ${step.name}`, + contextLabel: `${this.state.data.job.display_wo_name} · Step ${step.sequence_display}: ${step.name}`, + signatureUrl: this.state.data.user_plating_signature, + onConfirm: () => this._commitSignOff(step, null), // use saved sig + onRedraw: () => this._openSignaturePad(step), // draw a new one + }); + } else { + // First time — draw once; the backend persists it to the + // user's Plating Signature so later sign-offs are one-tap. + this._openSignaturePad(step); + } return; } // Plain finish — route through /fp/workspace/finish_step which @@ -391,6 +386,31 @@ export class FpJobWorkspace extends Component { await this._callFinishStep(step, /* bypass */ false); } + _openSignaturePad(step) { + this.dialog.add(FpSignaturePad, { + title: `Sign to finish ${step.name}`, + contextLabel: `${this.state.data.job.display_wo_name} · Step ${step.sequence_display}: ${step.name}`, + onSubmit: (dataUri) => this._commitSignOff(step, dataUri), + }); + } + + async _commitSignOff(step, dataUri) { + try { + const res = await fpRpc("/fp/workspace/sign_off", { + step_id: step.id, + signature_data_uri: dataUri, // null -> backend uses the saved signature + }); + if (res && res.ok) { + this.notification.add("Step signed off and finished.", { type: "success" }); + await this.refresh(); + } else { + this.notification.add((res && res.error) || "Sign-off failed", { type: "danger" }); + } + } catch (err) { + this.notification.add(err.message, { type: "danger" }); + } + } + async _callFinishStep(step, bypassRequiredInputs) { try { const res = await rpc("/fp/workspace/finish_step", {