+
+
Schedule
+
patchSched({ enabled: !enabled })} style={{ display: 'flex', alignItems: 'center', gap: 7, cursor: 'pointer' }}>
+
{enabled ? 'On' : 'Off'}
+
+
+
+
+
+ {FREQS.map(([k, label]) => (
+
+ ))}
+
+
+ {freq === 'weekly' && (
+
+ {DAY_LABELS.map(([label, d], i) => (
+
+ ))}
+
+ )}
+
+ {freq === 'monthly' && (
+
+
Day of month
+
+
+ {ordinal(dom)}
+
+
+
+ )}
+
+ {freq !== 'interval' ? (
+
+ Run at
+ { const t = parseTimeInput(e.target.value); if (t) patchSched(t); }}
+ style={{ background: '#FFFFFF', border: '1px solid rgba(33,30,27,0.12)', borderRadius: 8, padding: '6px 9px', fontSize: 13, fontFamily: "'JetBrains Mono',monospace", color: WC.ink }}
+ />
+
+ ) : (
+
+
Run every
+
+ {
+ const v = Math.max(1, parseInt(e.target.value, 10) || 1);
+ patchSched({ repeat_every: intervalUnit === 'hour' ? v : Math.max(15, v) });
+ }}
+ style={{ width: 56, background: '#FFFFFF', border: '1px solid rgba(33,30,27,0.12)', borderRadius: 8, padding: '6px 9px', fontSize: 13, fontFamily: "'JetBrains Mono',monospace", color: WC.ink, textAlign: 'right' }}
+ />
+
+
+
+ )}
+
+
+
+
{describeSchedule(sched)}
+
+
+
+
Next run {nextRunText(workflow)}
+
+
+ );
+};
+
+export default ScheduleCard;
diff --git a/frontend/src/app/pages/Workflows/app/StepsCard.tsx b/frontend/src/app/pages/Workflows/app/StepsCard.tsx
new file mode 100644
index 00000000..ba477ec2
--- /dev/null
+++ b/frontend/src/app/pages/Workflows/app/StepsCard.tsx
@@ -0,0 +1,120 @@
+import React, { useEffect, useState } from 'react';
+import { useAppDispatch } from '@/shared/hooks';
+import { commitDraft, discardDraft } from '@/shared/state/workflowsSlice';
+import type { Workflow, WorkflowStep } from '@/shared/state/workflowsSlice';
+import { stepsSignature } from '@/app/pages/Workflows/scheduleUtils';
+import { WC, FONT_SERIF, FONT_SANS } from './uiKit';
+import { useWorkflowPatch } from './useWorkflowPatch';
+
+interface LocalStep { id: string; label: string; text: string; open: boolean; }
+
+function toLocal(steps: WorkflowStep[]): LocalStep[] {
+ return steps.map((s) => ({ id: s.id, label: s.label || s.text.slice(0, 48), text: s.text, open: false }));
+}
+function newStepId(): string {
+ return `step-${Date.now().toString(36)}-${Math.floor(Math.random() * 1e6).toString(36)}`;
+}
+
+const StepsCard: React.FC<{ workflow: Workflow }> = ({ workflow }) => {
+ const dispatch = useAppDispatch();
+ const patch = useWorkflowPatch();
+ const [local, setLocal] = useState