Feat v0.3.5 settings audit, ICD, clone + v0.3.6 roadmap
Some checks failed
CI/CD / detect-changes (pull_request) Successful in 20s
CI/CD / test-frontend (pull_request) Successful in 5s
CI/CD / test-go-pg (pull_request) Failing after 2m42s
CI/CD / test-sqlite (pull_request) Successful in 3m0s
CI/CD / build-and-deploy (pull_request) Has been skipped
Some checks failed
CI/CD / detect-changes (pull_request) Successful in 20s
CI/CD / test-frontend (pull_request) Successful in 5s
CI/CD / test-go-pg (pull_request) Failing after 2m42s
CI/CD / test-sqlite (pull_request) Successful in 3m0s
CI/CD / build-and-deploy (pull_request) Has been skipped
v0.3.5 deliverables: - Clone endpoint (POST /workflows/:id/clone) with deep stage copy - 7 engine integration tests (28 total): lifecycle, branch routing, public entry, signoff gate, rejection, cancel, error cases - Settings audit: staleness_timeout_hours + branch_rules UI in team-admin workflow editor - ICD: fixed stale schemas, added ~20 new endpoint paths for instances, assignments, signoffs, public entry, clone, team roles Roadmap additions (v0.3.6–v0.3.8): - v0.3.6: 4 example workflow packages + demo surface proving public entry, branch rules, Starlark automation, signoff gates, HTTP webhooks end-to-end - v0.3.7: package audit for non-chat packages - v0.3.8: builder image + bundled packages for zero-config first run Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -161,12 +161,15 @@ function WorkflowEditor({ teamId, workflow, onBack }) {
|
||||
e.preventDefault();
|
||||
const form = e.target;
|
||||
try {
|
||||
await sw.api.teams.updateWorkflow(teamId, workflow.id, {
|
||||
const patch = {
|
||||
name: form.name.value.trim(),
|
||||
description: form.description.value.trim(),
|
||||
entry_mode: form.entry_mode.value,
|
||||
is_active: form.is_active.checked,
|
||||
});
|
||||
};
|
||||
const sth = form.staleness_timeout_hours.value.trim();
|
||||
if (sth !== '') patch.staleness_timeout_hours = parseInt(sth, 10);
|
||||
await sw.api.teams.updateWorkflow(teamId, workflow.id, patch);
|
||||
sw.toast('Workflow updated', 'success');
|
||||
} catch (e) { sw.toast(e.message, 'error'); }
|
||||
}
|
||||
@@ -230,7 +233,13 @@ function WorkflowEditor({ teamId, workflow, onBack }) {
|
||||
</select>
|
||||
</div>
|
||||
</div>
|
||||
<div class="form-group"><label>Description</label><input name="description" value=${workflow.description || ''} /></div>
|
||||
<div class="form-row">
|
||||
<div class="form-group" style="flex:1;"><label>Description</label><input name="description" value=${workflow.description || ''} /></div>
|
||||
<div class="form-group" style="max-width:180px;"><label>Staleness (hours)</label>
|
||||
<input type="number" name="staleness_timeout_hours" min="0"
|
||||
value=${workflow.staleness_timeout_hours ?? ''} placeholder="disabled" />
|
||||
</div>
|
||||
</div>
|
||||
<label class="toggle-label" style="margin:8px 0;">
|
||||
<input type="checkbox" name="is_active" checked=${workflow.is_active !== false} />
|
||||
<span class="toggle-track"></span><span>Active</span>
|
||||
@@ -287,6 +296,9 @@ function StageForm({ stage, teams, onSave, onCancel }) {
|
||||
const [assignTeam, setAssignTeam] = useState(stage?.assignment_team_id || '');
|
||||
const [autoTransition, setAutoTransition] = useState(stage?.auto_transition || false);
|
||||
const [sla, setSla] = useState(stage?.sla_seconds || '');
|
||||
const [branchRules, setBranchRules] = useState(
|
||||
stage?.branch_rules ? (typeof stage.branch_rules === 'string' ? stage.branch_rules : JSON.stringify(stage.branch_rules, null, 2)) : ''
|
||||
);
|
||||
|
||||
// v0.3.4: stage_config fields
|
||||
const sc = stage?.stage_config ? (typeof stage.stage_config === 'string' ? JSON.parse(stage.stage_config || '{}') : stage.stage_config) : {};
|
||||
@@ -311,6 +323,10 @@ function StageForm({ stage, teams, onSave, onCancel }) {
|
||||
reject_action: valReject || 'cancel',
|
||||
};
|
||||
}
|
||||
let parsedBranch = null;
|
||||
if (branchRules.trim()) {
|
||||
try { parsedBranch = JSON.parse(branchRules); } catch { sw.toast('Invalid branch_rules JSON', 'error'); return; }
|
||||
}
|
||||
onSave({
|
||||
name,
|
||||
stage_mode: mode,
|
||||
@@ -321,6 +337,7 @@ function StageForm({ stage, teams, onSave, onCancel }) {
|
||||
auto_transition: autoTransition,
|
||||
sla_seconds: sla ? parseInt(sla, 10) : null,
|
||||
stage_config: Object.keys(stageConfig).length ? stageConfig : {},
|
||||
branch_rules: parsedBranch || [],
|
||||
});
|
||||
}
|
||||
|
||||
@@ -408,6 +425,14 @@ function StageForm({ stage, teams, onSave, onCancel }) {
|
||||
</div>
|
||||
</div>
|
||||
`}
|
||||
<details style="margin-top:8px;">
|
||||
<summary style="cursor:pointer;font-size:12px;color:var(--text-muted);">Branch Rules (advanced)</summary>
|
||||
<div class="form-group" style="margin-top:4px;">
|
||||
<textarea rows="3" value=${branchRules} onInput=${e => setBranchRules(e.target.value)}
|
||||
placeholder='[{"field":"priority","op":"eq","value":"high","target_stage":"escalation"}]'
|
||||
style="font-family:monospace;font-size:11px;width:100%;"></textarea>
|
||||
</div>
|
||||
</details>
|
||||
<label class="toggle-label">
|
||||
<input type="checkbox" checked=${autoTransition} onChange=${e => setAutoTransition(e.target.checked)} />
|
||||
<span class="toggle-track"></span><span>Auto-advance when complete</span>
|
||||
|
||||
Reference in New Issue
Block a user