feat(jobs): Sub 14 polish — workflow state form layout + Simple Editor field

Two follow-ups on the workflow state work:

1) Form layout
   The "How triggers combine" help text was crammed into a 2-column
   group, taking ~25% of the available width. Pulled it out of the
   group and rendered as a full-width <div class="alert alert-info">
   below the trigger fields. Same fix applied to Notes — uses a
   <separator> + bare <field> for full sheet width.

2) Simple Recipe Editor support
   The trigger field was only exposed in the Tree Editor. Added it
   to the Simple Editor's inline library form too:

   * fp.step.template.triggers_workflow_state_id (new Many2one) —
     per-template default, snapshot-copied to recipe nodes when
     dropped into a recipe (added to _SNAPSHOT_FIELDS).
   * /fp/simple_recipe/workflow_states/list — new endpoint to feed
     the dropdown. Soft-fails when fusion_plating_jobs isn't
     installed (returns []).
   * Library editor JS — _fpEnsureWorkflowStatesLoaded helper
     caches the catalog on first open (create + edit paths both
     warm it). Save vals carry the trigger id.
   * Library editor XML — dropdown rendered after the flag
     checkboxes. Hidden when the catalog is empty so the form
     doesn't show a useless "— None —" pick.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
gsinghpal
2026-05-04 00:04:59 -04:00
parent 28bf6b5071
commit e54ffe7309
7 changed files with 157 additions and 19 deletions

View File

@@ -24,6 +24,7 @@ _SNAPSHOT_FIELDS = [
'voltage_target', 'viscosity_target',
'requires_signoff', 'requires_predecessor_done',
'parallel_start',
'triggers_workflow_state_id', # Sub 14 — workflow milestone trigger
'requires_rack_assignment', 'requires_transition_form',
'default_kind',
]
@@ -195,6 +196,15 @@ class SimpleRecipeController(http.Controller):
'requires_signoff': tpl.requires_signoff,
'requires_predecessor_done': tpl.requires_predecessor_done,
'parallel_start': tpl.parallel_start,
# Sub 14 — workflow trigger (id + name for display)
'triggers_workflow_state_id': (
tpl.triggers_workflow_state_id.id
if tpl.triggers_workflow_state_id else False
),
'triggers_workflow_state_name': (
tpl.triggers_workflow_state_id.name
if tpl.triggers_workflow_state_id else ''
),
'requires_rack_assignment': tpl.requires_rack_assignment,
'requires_transition_form': tpl.requires_transition_form,
'tank_ids': [
@@ -230,6 +240,7 @@ class SimpleRecipeController(http.Controller):
'name', 'code', 'icon', 'default_kind', 'description',
'requires_signoff', 'requires_predecessor_done',
'parallel_start',
'triggers_workflow_state_id', # Sub 14
'requires_rack_assignment', 'requires_transition_form',
'tank_ids',
}
@@ -320,6 +331,34 @@ class SimpleRecipeController(http.Controller):
],
}
@http.route('/fp/simple_recipe/workflow_states/list',
type='jsonrpc', auth='user')
def workflow_states_list(self):
"""Sub 14 — workflow-state picker for the inline library form.
Returns active states ordered by sequence so the dropdown
renders left-to-right matching the status bar.
Soft-fail when fp.job.workflow.state isn't installed (rare,
only when fusion_plating_jobs is missing) — empty list lets the
dropdown render disabled instead of throwing.
"""
WS = request.env.get('fp.job.workflow.state')
if WS is None:
return {'workflow_states': []}
return {
'workflow_states': [
{
'id': ws.id,
'name': ws.name or '',
'code': ws.code or '',
'sequence': ws.sequence,
}
for ws in WS.search(
[('active', '=', True)], order='sequence, id',
)
],
}
# ------------------------------------------------------------------ step
@http.route('/fp/simple_recipe/step/insert', type='jsonrpc', auth='user')
def step_insert(self, recipe_id, template_id=False, position=99, vals=None):