@arbidocs/blocks 0.4.76 → 0.4.78

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (123) hide show
  1. package/dist/agents/index.cjs +346 -258
  2. package/dist/agents/index.js +5 -5
  3. package/dist/agents/tasks/TaskActivityTimeline.d.ts +1 -1
  4. package/dist/agents/tasks/WorkflowThreadStrip.d.ts +15 -4
  5. package/dist/agents/workflows/SchemaForm.d.ts +6 -1
  6. package/dist/agents/workflows/StepBarFrame.d.ts +75 -0
  7. package/dist/agents/workflows/StepParts.d.ts +109 -0
  8. package/dist/agents/workflows/WorkflowRunner.d.ts +15 -2
  9. package/dist/agents/workflows/WorkflowStepBar.d.ts +9 -11
  10. package/dist/agents/workflows/index.d.ts +5 -2
  11. package/dist/agents/workflows/planSteps.d.ts +8 -1
  12. package/dist/agents/workflows/run.d.ts +61 -8
  13. package/dist/agents/workflows/stepWindow.d.ts +59 -0
  14. package/dist/agents/workflows/types.d.ts +133 -4
  15. package/dist/agents/workflows/useWorkflowPreview.d.ts +2 -1
  16. package/dist/agents/workflows/useWorkflowView.d.ts +19 -0
  17. package/dist/chat/ChatPage.d.ts +1 -1
  18. package/dist/chat/WorkflowStepChip.d.ts +24 -0
  19. package/dist/chat/chat-page-types.d.ts +9 -0
  20. package/dist/chat/index.cjs +130 -122
  21. package/dist/chat/index.d.ts +1 -0
  22. package/dist/chat/index.js +2 -2
  23. package/dist/{chunk-TKB7TVMW.js → chunk-5OC5CGYX.js} +168 -100
  24. package/dist/chunk-5OC5CGYX.js.map +1 -0
  25. package/dist/{chunk-ZWA7UUZL.cjs → chunk-7YUFMNFW.cjs} +2 -54
  26. package/dist/chunk-7YUFMNFW.cjs.map +1 -0
  27. package/dist/chunk-A24C6BNA.js +92 -0
  28. package/dist/chunk-A24C6BNA.js.map +1 -0
  29. package/dist/chunk-AINNADMT.cjs +62 -0
  30. package/dist/chunk-AINNADMT.cjs.map +1 -0
  31. package/dist/chunk-CWAZNXC5.js +441 -0
  32. package/dist/chunk-CWAZNXC5.js.map +1 -0
  33. package/dist/{chunk-UIWLDSTF.js → chunk-EWSEQEPL.js} +71 -7
  34. package/dist/chunk-EWSEQEPL.js.map +1 -0
  35. package/dist/chunk-FE4ULGOR.js +151 -0
  36. package/dist/chunk-FE4ULGOR.js.map +1 -0
  37. package/dist/chunk-FT5FFXSJ.js +60 -0
  38. package/dist/chunk-FT5FFXSJ.js.map +1 -0
  39. package/dist/{chunk-WJEKRSPH.js → chunk-ICBAFX5B.js} +3 -3
  40. package/dist/{chunk-WJEKRSPH.js.map → chunk-ICBAFX5B.js.map} +1 -1
  41. package/dist/{chunk-7CVF3DK2.cjs → chunk-IF6VAYIA.cjs} +5 -5
  42. package/dist/{chunk-7CVF3DK2.cjs.map → chunk-IF6VAYIA.cjs.map} +1 -1
  43. package/dist/chunk-MLAHDAN5.cjs +450 -0
  44. package/dist/chunk-MLAHDAN5.cjs.map +1 -0
  45. package/dist/{chunk-IPGKTUF7.cjs → chunk-MP6FK43E.cjs} +71 -5
  46. package/dist/chunk-MP6FK43E.cjs.map +1 -0
  47. package/dist/{chunk-5EBGRG3X.js → chunk-OPA2Y6YZ.js} +3 -54
  48. package/dist/chunk-OPA2Y6YZ.js.map +1 -0
  49. package/dist/{chunk-7FKARMA3.cjs → chunk-SSDISIDW.cjs} +190 -122
  50. package/dist/chunk-SSDISIDW.cjs.map +1 -0
  51. package/dist/chunk-TZR36PPP.cjs +95 -0
  52. package/dist/chunk-TZR36PPP.cjs.map +1 -0
  53. package/dist/chunk-VFIZYSZB.cjs +2783 -0
  54. package/dist/chunk-VFIZYSZB.cjs.map +1 -0
  55. package/dist/chunk-WXRCMIAE.js +2707 -0
  56. package/dist/chunk-WXRCMIAE.js.map +1 -0
  57. package/dist/{chunk-HITAN7JF.cjs → chunk-XMBYDLZQ.cjs} +4 -4
  58. package/dist/{chunk-HITAN7JF.cjs.map → chunk-XMBYDLZQ.cjs.map} +1 -1
  59. package/dist/{chunk-MK6NJQGF.js → chunk-XQDM6T6C.js} +3 -3
  60. package/dist/{chunk-MK6NJQGF.js.map → chunk-XQDM6T6C.js.map} +1 -1
  61. package/dist/chunk-ZVBPRMHJ.cjs +153 -0
  62. package/dist/chunk-ZVBPRMHJ.cjs.map +1 -0
  63. package/dist/connect/docx.cjs +10 -88
  64. package/dist/connect/docx.cjs.map +1 -1
  65. package/dist/connect/docx.js +6 -86
  66. package/dist/connect/docx.js.map +1 -1
  67. package/dist/connect/index.cjs +468 -49
  68. package/dist/connect/index.cjs.map +1 -1
  69. package/dist/connect/index.d.ts +2 -0
  70. package/dist/connect/index.js +454 -37
  71. package/dist/connect/index.js.map +1 -1
  72. package/dist/connection/ConnectedTagMatrix.d.ts +20 -0
  73. package/dist/connection/ConnectedWorkflowRunner.d.ts +28 -2
  74. package/dist/connection/WorkflowRunThread.d.ts +21 -0
  75. package/dist/connection/WorkflowRunnerDialogs.d.ts +37 -0
  76. package/dist/connection/useWorkflowThread.d.ts +12 -0
  77. package/dist/document-tools/index.cjs +7 -143
  78. package/dist/document-tools/index.cjs.map +1 -1
  79. package/dist/document-tools/index.js +5 -144
  80. package/dist/document-tools/index.js.map +1 -1
  81. package/dist/docx/index.cjs +18 -17
  82. package/dist/docx/index.cjs.map +1 -1
  83. package/dist/docx/index.js +3 -2
  84. package/dist/docx/index.js.map +1 -1
  85. package/dist/facts/index.cjs +1 -1
  86. package/dist/facts/index.js +1 -1
  87. package/dist/files/index.cjs +1 -1
  88. package/dist/files/index.js +1 -1
  89. package/dist/home/index.cjs +1 -1
  90. package/dist/home/index.js +1 -1
  91. package/dist/index.cjs +560 -431
  92. package/dist/index.cjs.map +1 -1
  93. package/dist/index.d.ts +1 -0
  94. package/dist/index.js +10 -9
  95. package/dist/index.js.map +1 -1
  96. package/dist/shell/index.cjs +1 -1
  97. package/dist/shell/index.js +1 -1
  98. package/dist/studio/index.cjs +4 -4
  99. package/dist/studio/index.js +3 -3
  100. package/dist/tags/TagMatrix.d.ts +64 -0
  101. package/dist/tags/index.d.ts +3 -0
  102. package/dist/tags/tagMatrixModel.d.ts +39 -0
  103. package/dist/workflow-canvas/StepActionSettings.d.ts +132 -0
  104. package/dist/workflow-canvas/StepInspector.d.ts +25 -2
  105. package/dist/workflow-canvas/WorkflowBuilder.d.ts +11 -3
  106. package/dist/workflow-canvas/WorkflowCanvas.d.ts +27 -2
  107. package/dist/workflow-canvas/edit.d.ts +9 -1
  108. package/dist/workflow-canvas/index.cjs +882 -102
  109. package/dist/workflow-canvas/index.cjs.map +1 -1
  110. package/dist/workflow-canvas/index.js +849 -69
  111. package/dist/workflow-canvas/index.js.map +1 -1
  112. package/package.json +4 -4
  113. package/src/workflow-canvas/canvas.css +9 -0
  114. package/dist/chunk-22P5KNIM.js +0 -1422
  115. package/dist/chunk-22P5KNIM.js.map +0 -1
  116. package/dist/chunk-5EBGRG3X.js.map +0 -1
  117. package/dist/chunk-7FKARMA3.cjs.map +0 -1
  118. package/dist/chunk-IPGKTUF7.cjs.map +0 -1
  119. package/dist/chunk-TKB7TVMW.js.map +0 -1
  120. package/dist/chunk-UIWLDSTF.js.map +0 -1
  121. package/dist/chunk-VYRKO3XU.cjs +0 -1469
  122. package/dist/chunk-VYRKO3XU.cjs.map +0 -1
  123. package/dist/chunk-ZWA7UUZL.cjs.map +0 -1
@@ -1,36 +1,46 @@
1
1
  "use client";
2
2
  import { useConnection } from '../chunk-OYMWV45N.js';
3
- import { workflowWhen, isoToLocalInput, describeRRule, RecurrenceBuilder, AgentSelect, useWorkflowPreview, localInputToIso } from '../chunk-TKB7TVMW.js';
3
+ import { workflowWhen, isoToLocalInput, describeRRule, RecurrenceBuilder, AgentSelect, useWorkflowPreview, localInputToIso } from '../chunk-5OC5CGYX.js';
4
4
  import '../chunk-CKB64Z4R.js';
5
5
  import '../chunk-P6GHJSLR.js';
6
- import { workflowSteps, dependsOn, stepLevels, isIncompleteSignal, stepDependencies, runFields, fromPlanSteps, layoutFromPlanSteps, validateWorkflowGraph, WorkflowRunner, skillToWorkflow, orderSteps, toPlanSteps } from '../chunk-22P5KNIM.js';
6
+ import { workflowSteps, dependsOn, stepLevels, isIncompleteSignal, runFields, upstreamSteps, stepDependencies, canAssign, fromPlanSteps, layoutFromPlanSteps, validateWorkflowGraph, stepConfigProblems, WorkflowRunner, skillToWorkflow, assigneeName, orderSteps, toPlanSteps } from '../chunk-WXRCMIAE.js';
7
7
  import '../chunk-4WWM3GQ5.js';
8
+ import '../chunk-DDF5GPIJ.js';
9
+ import '../chunk-XD2M6LIG.js';
8
10
  import '../chunk-RFXJYIDV.js';
9
11
  import '../chunk-DPLRHEJZ.js';
10
12
  import '../chunk-EVUEIBNU.js';
11
13
  import '../chunk-NUNKSZKU.js';
12
14
  import '../chunk-YU2KUMGE.js';
13
15
  import '../chunk-ZPLG7QYF.js';
14
- import '../chunk-DDF5GPIJ.js';
15
- import '../chunk-XD2M6LIG.js';
16
16
  import '../chunk-S7PSMMRG.js';
17
- import '../chunk-76JDDMSP.js';
18
17
  import '../chunk-HOXKR26S.js';
19
18
  import '../chunk-AA3PT6KR.js';
20
19
  import '../chunk-SLSBJRWW.js';
21
20
  import '../chunk-NPLYHR2E.js';
21
+ import '../chunk-76JDDMSP.js';
22
22
  import '../chunk-OXF2IFXG.js';
23
23
  import '../chunk-TX2ZICS7.js';
24
24
  import '../chunk-7F6CBP3Z.js';
25
25
  import '../chunk-VUNV25KB.js';
26
26
  import { useMemo, useState, useEffect, useCallback, useRef } from 'react';
27
- import { useWorkflows, useSkills, useAgents, useConversations, useCreateWorkflow, useUpdateWorkflow, useRunWorkflow } from '@arbidocs/react';
27
+ import { useWorkspaceUsers, useTags, useDocuments, useWorkflows, useSkills, useAgents, useConversations, useCreateWorkflow, useUpdateWorkflow, useRunWorkflow } from '@arbidocs/react';
28
28
  import { Label, Input, cn, Button, Textarea, Checkbox, Popover, PopoverTrigger, PopoverContent } from '@arbidocs/react/ui';
29
- import { X, Plus, Trash2, Maximize, ClipboardCheck, Bot, Upload, FileInput, PencilRuler, Eye, LayoutGrid, Settings2, Play, Loader2, Save, Zap, GitBranch, Check, AlertTriangle, MinusCircle } from 'lucide-react';
29
+ import { X, Plus, Trash2, Maximize, Table2, Mail, PenLine, ClipboardCheck, Bot, Upload, FileInput, PencilRuler, Eye, LayoutGrid, Settings2, Play, Loader2, Save, Zap, GitBranch, FilePenLine, UserRound, Hourglass, Check, AlertTriangle, MinusCircle } from 'lucide-react';
30
30
  import { jsxs, jsx, Fragment } from 'react/jsx-runtime';
31
31
  import { MarkerType, applyNodeChanges, ReactFlow, Background, BackgroundVariant, Controls, ControlButton, MiniMap, Handle, Position } from '@xyflow/react';
32
32
 
33
33
  // src/workflow-canvas/edit.ts
34
+ var WORKFLOW_STEP_KINDS = [
35
+ "form",
36
+ "upload",
37
+ "agent",
38
+ "review",
39
+ "sign",
40
+ "email_draft",
41
+ "tabular_review"
42
+ ];
43
+ var stepKindOf = (step) => step.kind === "action" ? step.action.type : step.kind;
34
44
  function newSteppedWorkflow(id, title) {
35
45
  return {
36
46
  id,
@@ -63,7 +73,10 @@ var DEFAULT_TITLES = {
63
73
  form: "Details",
64
74
  upload: "Upload files",
65
75
  agent: "Agent step",
66
- review: "Review"
76
+ review: "Review",
77
+ sign: "Sign",
78
+ email_draft: "Email draft",
79
+ tabular_review: "Tabular review"
67
80
  };
68
81
  function blankStep(kind, id, title) {
69
82
  switch (kind) {
@@ -75,6 +88,22 @@ function blankStep(kind, id, title) {
75
88
  return { id, kind, title };
76
89
  case "review":
77
90
  return { id, kind, title, instructions: "" };
91
+ case "sign":
92
+ return { id, kind: "action", title, action: { type: "sign", signers: [] } };
93
+ case "email_draft":
94
+ return {
95
+ id,
96
+ kind: "action",
97
+ title,
98
+ action: { type: "email_draft", to: [], subject: "", body: "" }
99
+ };
100
+ case "tabular_review":
101
+ return {
102
+ id,
103
+ kind: "action",
104
+ title,
105
+ action: { type: "tabular_review", tags: [], documents: "run_uploads" }
106
+ };
78
107
  }
79
108
  }
80
109
  function addStep(workflow, kind, options = {}) {
@@ -139,14 +168,49 @@ function renameInput(workflow, from, to) {
139
168
  return {
140
169
  ...s,
141
170
  with: s.with ? Object.fromEntries(Object.entries(s.with).map(([k, v]) => [k, renameIn(v, from, to)])) : s.with,
142
- run: s.run?.kind === "prompt" ? { ...s.run, promptTemplate: renameIn(s.run.promptTemplate, from, to) } : s.run
171
+ run: s.run?.kind === "prompt" ? { ...s.run, promptTemplate: renameIn(s.run.promptTemplate, from, to) } : s.run,
172
+ ...s.editDocument ? { editDocument: renameRef(s.editDocument, from, to) } : {}
143
173
  };
144
- if (s.kind === "review" && s.instructions)
145
- return { ...s, instructions: renameIn(s.instructions, from, to) };
146
- return s;
174
+ const assignee = s.assignee && renamePerson(s.assignee, from, to);
175
+ const base = assignee ? { ...s, assignee } : s;
176
+ if (base.kind === "review" && base.instructions)
177
+ return { ...base, instructions: renameIn(base.instructions, from, to) };
178
+ if (base.kind === "action") {
179
+ const a = base.action;
180
+ if (a.type === "sign")
181
+ return {
182
+ ...base,
183
+ action: {
184
+ ...a,
185
+ document: a.document && renameRef(a.document, from, to),
186
+ signers: a.signers.map((x) => renamePerson(x, from, to)),
187
+ ...a.message ? { message: renameIn(a.message, from, to) } : {}
188
+ }
189
+ };
190
+ if (a.type === "email_draft")
191
+ return {
192
+ ...base,
193
+ action: {
194
+ ...a,
195
+ to: a.to.map((t) => renameIn(t, from, to)),
196
+ ...a.cc ? { cc: a.cc.map((t) => renameIn(t, from, to)) } : {},
197
+ subject: renameIn(a.subject, from, to),
198
+ body: renameIn(a.body, from, to),
199
+ ...a.attachments ? { attachments: a.attachments.map((r) => renameRef(r, from, to)) } : {}
200
+ }
201
+ };
202
+ if (Array.isArray(a.documents))
203
+ return {
204
+ ...base,
205
+ action: { ...a, documents: a.documents.map((r) => renameRef(r, from, to)) }
206
+ };
207
+ }
208
+ return base;
147
209
  });
148
210
  return withSteps(workflow, steps);
149
211
  }
212
+ var renamePerson = (a, from, to) => "input" in a && a.input === from ? { input: to } : a;
213
+ var renameRef = (r, from, to) => "input" in r && r.input === from ? { input: to } : r;
150
214
  function moveStep(workflow, id, position) {
151
215
  return withSteps(workflow, workflowSteps(workflow), { ...layoutOf(workflow), [id]: position });
152
216
  }
@@ -381,6 +445,537 @@ function SignalsEditor({
381
445
  /* @__PURE__ */ jsx("p", { className: "text-xs text-muted-foreground", children: l.hint })
382
446
  ] });
383
447
  }
448
+ var DEFAULT_STEP_ACTION_SETTINGS_LABELS = {
449
+ assignee: "Who does it",
450
+ assigneeAnyone: "Anyone on the run",
451
+ assigneeRunOwner: "Whoever started the run",
452
+ assigneeProjectLead: "The project lead",
453
+ assigneeFields: "The person in a form field",
454
+ assigneePeople: "A person",
455
+ remind: "Remind after (hours)",
456
+ remindHint: "Left that long, they are told again. Blank: no reminder.",
457
+ documentFrom: "Document",
458
+ docFromStep: "From an earlier step",
459
+ docFromInput: "From a run input",
460
+ docById: "A document",
461
+ chooseStep: "Choose a step\u2026",
462
+ chooseInput: "Choose an input\u2026",
463
+ chooseDocument: "Choose a document\u2026",
464
+ documentIdPlaceholder: "doc-\u2026",
465
+ signDocument: "Document to sign",
466
+ signers: "Signers",
467
+ addSigner: "Add signer",
468
+ signMessage: "Message to the signers",
469
+ expires: "Expires after (hours)",
470
+ expiresHint: "Unsigned by then, the step fails. Blank: no expiry.",
471
+ emailTo: "To",
472
+ emailCc: "Cc",
473
+ emailSubject: "Subject",
474
+ emailBody: "Body",
475
+ addressesHint: "Separate several with commas.",
476
+ variablesHint: "Variables (click to add to the body):",
477
+ attachments: "Attachments",
478
+ addAttachment: "Add attachment",
479
+ reviewColumns: "Columns (labels)",
480
+ noTags: "No labels in this workspace yet.",
481
+ reviewDocuments: "Documents",
482
+ reviewRunUploads: "The files this run collects",
483
+ reviewWorkspace: "Every document in the workspace",
484
+ reviewChosen: "Chosen documents",
485
+ addDocument: "Add document",
486
+ overwrite: "Fill cells that already have a value again",
487
+ editDocument: "Edit this document (tracked changes)",
488
+ editDocumentHint: "The instruction says what to change; the edited copy is saved as its next version, to accept or reject change by change."
489
+ };
490
+ var selectClass2 = "flex h-9 w-full rounded-md border border-input bg-background px-2 text-sm shadow-sm focus-visible:outline-none focus-visible:ring-1 focus-visible:ring-ring";
491
+ function Field({
492
+ label,
493
+ children,
494
+ hint
495
+ }) {
496
+ return /* @__PURE__ */ jsxs("div", { className: "space-y-1.5", children: [
497
+ /* @__PURE__ */ jsx(Label, { className: "text-xs", children: label }),
498
+ children,
499
+ hint && /* @__PURE__ */ jsx("p", { className: "text-xs text-muted-foreground", children: hint })
500
+ ] });
501
+ }
502
+ var assigneeValue = (a) => !a ? "" : "user" in a ? `user:${a.user}` : "input" in a ? `input:${a.input}` : "runOwner" in a ? "owner" : "lead";
503
+ var parseAssignee = (v) => v === "owner" ? { runOwner: true } : v === "lead" ? { projectLead: true } : v.startsWith("user:") ? { user: v.slice(5) } : v.startsWith("input:") ? { input: v.slice(6) } : void 0;
504
+ function AssigneeSelect({
505
+ value,
506
+ onChange,
507
+ ctx,
508
+ l,
509
+ anyone,
510
+ testId,
511
+ ariaLabel
512
+ }) {
513
+ const personFields = ctx.fields.filter((f) => f.type === "person");
514
+ const v = assigneeValue(value);
515
+ const known = !v.startsWith("user:") || ctx.people.some((p) => `user:${p.value}` === v) ? null : v.slice(5);
516
+ return /* @__PURE__ */ jsxs(
517
+ "select",
518
+ {
519
+ className: selectClass2,
520
+ value: v,
521
+ "aria-label": ariaLabel,
522
+ onChange: (e) => onChange(parseAssignee(e.target.value)),
523
+ "data-testid": testId,
524
+ children: [
525
+ anyone !== void 0 ? /* @__PURE__ */ jsx("option", { value: "", children: anyone }) : /* @__PURE__ */ jsx("option", { value: "", disabled: true }),
526
+ /* @__PURE__ */ jsx("option", { value: "owner", children: l.assigneeRunOwner }),
527
+ /* @__PURE__ */ jsx("option", { value: "lead", children: l.assigneeProjectLead }),
528
+ personFields.length > 0 && /* @__PURE__ */ jsx("optgroup", { label: l.assigneeFields, children: personFields.map((f) => /* @__PURE__ */ jsx("option", { value: `input:${f.name}`, children: f.label }, f.name)) }),
529
+ (ctx.people.length > 0 || known) && /* @__PURE__ */ jsxs("optgroup", { label: l.assigneePeople, children: [
530
+ ctx.people.map((p) => /* @__PURE__ */ jsx("option", { value: `user:${p.value}`, children: p.label }, p.value)),
531
+ known && /* @__PURE__ */ jsx("option", { value: v, children: known })
532
+ ] })
533
+ ]
534
+ }
535
+ );
536
+ }
537
+ function AssigneeSettings({
538
+ step,
539
+ patch,
540
+ ctx,
541
+ l,
542
+ testId
543
+ }) {
544
+ return /* @__PURE__ */ jsxs(Fragment, { children: [
545
+ /* @__PURE__ */ jsx(Field, { label: l.assignee, children: /* @__PURE__ */ jsx(
546
+ AssigneeSelect,
547
+ {
548
+ value: step.assignee,
549
+ onChange: (assignee) => patch({ assignee }),
550
+ ctx,
551
+ l,
552
+ anyone: l.assigneeAnyone,
553
+ testId: `${testId}-assignee`
554
+ }
555
+ ) }),
556
+ /* @__PURE__ */ jsx(Field, { label: l.remind, hint: l.remindHint, children: /* @__PURE__ */ jsx(
557
+ Input,
558
+ {
559
+ type: "number",
560
+ min: 1,
561
+ value: step.remindAfterHours ?? "",
562
+ onChange: (e) => {
563
+ const n = Number(e.target.value);
564
+ patch({ remindAfterHours: e.target.value && n > 0 ? n : void 0 });
565
+ },
566
+ className: "w-28",
567
+ "data-testid": `${testId}-remind`
568
+ }
569
+ ) })
570
+ ] });
571
+ }
572
+ var modeOf = (ref) => !ref ? "step" : "step" in ref ? "step" : "input" in ref ? "input" : "id";
573
+ function DocumentRefPicker({
574
+ value,
575
+ onChange,
576
+ ctx,
577
+ l,
578
+ testId
579
+ }) {
580
+ const mode = modeOf(value);
581
+ const inputs = ctx.fields.filter((f) => f.type === "documents" || f.type === "text");
582
+ return /* @__PURE__ */ jsxs("div", { className: "space-y-1.5", "data-testid": testId, children: [
583
+ /* @__PURE__ */ jsxs(
584
+ "select",
585
+ {
586
+ className: cn(selectClass2, "h-8"),
587
+ value: mode,
588
+ "aria-label": l.documentFrom,
589
+ onChange: (e) => {
590
+ const m = e.target.value;
591
+ onChange(m === "step" ? { step: "" } : m === "input" ? { input: "" } : { id: "" });
592
+ },
593
+ "data-testid": `${testId}-mode`,
594
+ children: [
595
+ /* @__PURE__ */ jsx("option", { value: "step", children: l.docFromStep }),
596
+ /* @__PURE__ */ jsx("option", { value: "input", children: l.docFromInput }),
597
+ /* @__PURE__ */ jsx("option", { value: "id", children: l.docById })
598
+ ]
599
+ }
600
+ ),
601
+ mode === "step" && /* @__PURE__ */ jsxs(
602
+ "select",
603
+ {
604
+ className: cn(selectClass2, "h-8"),
605
+ value: value && "step" in value ? value.step : "",
606
+ onChange: (e) => onChange({ step: e.target.value }),
607
+ "data-testid": `${testId}-step`,
608
+ children: [
609
+ /* @__PURE__ */ jsx("option", { value: "", disabled: true, children: l.chooseStep }),
610
+ ctx.earlier.map((s) => /* @__PURE__ */ jsx("option", { value: s.id, children: s.title }, s.id))
611
+ ]
612
+ }
613
+ ),
614
+ mode === "input" && /* @__PURE__ */ jsxs(
615
+ "select",
616
+ {
617
+ className: cn(selectClass2, "h-8"),
618
+ value: value && "input" in value ? value.input : "",
619
+ onChange: (e) => onChange({ input: e.target.value }),
620
+ "data-testid": `${testId}-input`,
621
+ children: [
622
+ /* @__PURE__ */ jsx("option", { value: "", disabled: true, children: l.chooseInput }),
623
+ inputs.map((f) => /* @__PURE__ */ jsx("option", { value: f.name, children: f.label }, f.name))
624
+ ]
625
+ }
626
+ ),
627
+ mode === "id" && (ctx.documents.length ? /* @__PURE__ */ jsxs(
628
+ "select",
629
+ {
630
+ className: cn(selectClass2, "h-8"),
631
+ value: value && "id" in value ? value.id : "",
632
+ onChange: (e) => onChange({ id: e.target.value }),
633
+ "data-testid": `${testId}-id`,
634
+ children: [
635
+ /* @__PURE__ */ jsx("option", { value: "", disabled: true, children: l.chooseDocument }),
636
+ ctx.documents.map((d) => /* @__PURE__ */ jsx("option", { value: d.value, children: d.label }, d.value))
637
+ ]
638
+ }
639
+ ) : /* @__PURE__ */ jsx(
640
+ Input,
641
+ {
642
+ className: "h-8",
643
+ value: value && "id" in value ? value.id : "",
644
+ placeholder: l.documentIdPlaceholder,
645
+ onChange: (e) => onChange({ id: e.target.value }),
646
+ "data-testid": `${testId}-id`
647
+ }
648
+ ))
649
+ ] });
650
+ }
651
+ function DocumentRefList({
652
+ value,
653
+ onChange,
654
+ ctx,
655
+ l,
656
+ addLabel,
657
+ testId
658
+ }) {
659
+ return /* @__PURE__ */ jsxs("div", { className: "space-y-2", children: [
660
+ value.map((ref, i) => /* @__PURE__ */ jsxs("div", { className: "flex items-start gap-1.5", children: [
661
+ /* @__PURE__ */ jsx("div", { className: "min-w-0 flex-1", children: /* @__PURE__ */ jsx(
662
+ DocumentRefPicker,
663
+ {
664
+ value: ref,
665
+ onChange: (next) => onChange(value.map((r, j) => j === i ? next : r)),
666
+ ctx,
667
+ l,
668
+ testId: `${testId}-${i}`
669
+ }
670
+ ) }),
671
+ /* @__PURE__ */ jsx(
672
+ "button",
673
+ {
674
+ type: "button",
675
+ className: "mt-2",
676
+ "aria-label": `${addLabel} \xD7`,
677
+ onClick: () => onChange(value.filter((_, j) => j !== i)),
678
+ children: /* @__PURE__ */ jsx(X, { className: "size-4 text-muted-foreground" })
679
+ }
680
+ )
681
+ ] }, i)),
682
+ /* @__PURE__ */ jsxs(
683
+ Button,
684
+ {
685
+ variant: "outline",
686
+ size: "sm",
687
+ onClick: () => onChange([...value, { step: "" }]),
688
+ "data-testid": `${testId}-add`,
689
+ children: [
690
+ /* @__PURE__ */ jsx(Plus, { className: "size-4" }),
691
+ " ",
692
+ addLabel
693
+ ]
694
+ }
695
+ )
696
+ ] });
697
+ }
698
+ var optionalNumber = (raw) => {
699
+ const n = Number(raw);
700
+ return raw && n > 0 ? n : void 0;
701
+ };
702
+ function SignSettings({
703
+ action,
704
+ onChange,
705
+ ctx,
706
+ l,
707
+ testId
708
+ }) {
709
+ const set = (p) => onChange({ ...action, ...p });
710
+ return /* @__PURE__ */ jsxs(Fragment, { children: [
711
+ /* @__PURE__ */ jsx(Field, { label: l.signDocument, children: /* @__PURE__ */ jsx(
712
+ DocumentRefPicker,
713
+ {
714
+ value: action.document,
715
+ onChange: (document) => set({ document }),
716
+ ctx,
717
+ l,
718
+ testId: `${testId}-document`
719
+ }
720
+ ) }),
721
+ /* @__PURE__ */ jsx(Field, { label: l.signers, children: /* @__PURE__ */ jsxs("div", { className: "space-y-1.5", "data-testid": `${testId}-signers`, children: [
722
+ action.signers.map((s, i) => /* @__PURE__ */ jsxs("div", { className: "flex items-center gap-1.5", children: [
723
+ /* @__PURE__ */ jsx(
724
+ AssigneeSelect,
725
+ {
726
+ value: s,
727
+ onChange: (next) => set({
728
+ signers: next ? action.signers.map((x, j) => j === i ? next : x) : action.signers.filter((_, j) => j !== i)
729
+ }),
730
+ ctx,
731
+ l,
732
+ ariaLabel: `${l.signers} ${i + 1}`,
733
+ testId: `${testId}-signer-${i}`
734
+ }
735
+ ),
736
+ /* @__PURE__ */ jsx(
737
+ "button",
738
+ {
739
+ type: "button",
740
+ "aria-label": `${l.signers} ${i + 1} \xD7`,
741
+ onClick: () => set({ signers: action.signers.filter((_, j) => j !== i) }),
742
+ children: /* @__PURE__ */ jsx(X, { className: "size-4 text-muted-foreground" })
743
+ }
744
+ )
745
+ ] }, i)),
746
+ /* @__PURE__ */ jsxs(
747
+ Button,
748
+ {
749
+ variant: "outline",
750
+ size: "sm",
751
+ onClick: () => set({ signers: [...action.signers, { runOwner: true }] }),
752
+ "data-testid": `${testId}-add-signer`,
753
+ children: [
754
+ /* @__PURE__ */ jsx(Plus, { className: "size-4" }),
755
+ " ",
756
+ l.addSigner
757
+ ]
758
+ }
759
+ )
760
+ ] }) }),
761
+ /* @__PURE__ */ jsx(Field, { label: l.signMessage, children: /* @__PURE__ */ jsx(
762
+ Textarea,
763
+ {
764
+ rows: 3,
765
+ value: action.message ?? "",
766
+ onChange: (e) => set({ message: e.target.value || void 0 }),
767
+ "data-testid": `${testId}-message`
768
+ }
769
+ ) }),
770
+ /* @__PURE__ */ jsx(Field, { label: l.expires, hint: l.expiresHint, children: /* @__PURE__ */ jsx(
771
+ Input,
772
+ {
773
+ type: "number",
774
+ min: 1,
775
+ className: "w-28",
776
+ value: action.expiresAfterHours ?? "",
777
+ onChange: (e) => set({ expiresAfterHours: optionalNumber(e.target.value) }),
778
+ "data-testid": `${testId}-expires`
779
+ }
780
+ ) })
781
+ ] });
782
+ }
783
+ var addresses = (list) => (list ?? []).join(", ");
784
+ var parseAddresses = (text) => text.split(",").map((t) => t.trim());
785
+ function templateVariables(ctx) {
786
+ return [
787
+ ...ctx.fields.map((f) => `{{${f.name}}}`),
788
+ ...ctx.earlier.filter((s) => s.kind === "agent").map((s) => `{{${s.id}.answer}}`)
789
+ ];
790
+ }
791
+ function EmailDraftSettings({
792
+ action,
793
+ onChange,
794
+ ctx,
795
+ l,
796
+ testId
797
+ }) {
798
+ const set = (p) => onChange({ ...action, ...p });
799
+ const vars = templateVariables(ctx);
800
+ return /* @__PURE__ */ jsxs(Fragment, { children: [
801
+ /* @__PURE__ */ jsx(Field, { label: l.emailTo, hint: l.addressesHint, children: /* @__PURE__ */ jsx(
802
+ Input,
803
+ {
804
+ value: addresses(action.to),
805
+ onChange: (e) => set({ to: parseAddresses(e.target.value) }),
806
+ placeholder: "{{client_email}}",
807
+ "data-testid": `${testId}-to`
808
+ }
809
+ ) }),
810
+ /* @__PURE__ */ jsx(Field, { label: l.emailCc, children: /* @__PURE__ */ jsx(
811
+ Input,
812
+ {
813
+ value: addresses(action.cc),
814
+ onChange: (e) => {
815
+ const cc = parseAddresses(e.target.value);
816
+ set({ cc: cc.some(Boolean) ? cc : void 0 });
817
+ },
818
+ "data-testid": `${testId}-cc`
819
+ }
820
+ ) }),
821
+ /* @__PURE__ */ jsx(Field, { label: l.emailSubject, children: /* @__PURE__ */ jsx(
822
+ Input,
823
+ {
824
+ value: action.subject,
825
+ onChange: (e) => set({ subject: e.target.value }),
826
+ "data-testid": `${testId}-subject`
827
+ }
828
+ ) }),
829
+ /* @__PURE__ */ jsx(Field, { label: l.emailBody, children: /* @__PURE__ */ jsx(
830
+ Textarea,
831
+ {
832
+ rows: 6,
833
+ value: action.body,
834
+ onChange: (e) => set({ body: e.target.value }),
835
+ "data-testid": `${testId}-body`
836
+ }
837
+ ) }),
838
+ vars.length > 0 && /* @__PURE__ */ jsxs("div", { className: "flex flex-wrap gap-1", "data-testid": `${testId}-variables`, children: [
839
+ /* @__PURE__ */ jsx("span", { className: "w-full text-xs text-muted-foreground", children: l.variablesHint }),
840
+ vars.map((v) => /* @__PURE__ */ jsx(
841
+ "button",
842
+ {
843
+ type: "button",
844
+ onClick: () => set({ body: `${action.body}${action.body ? " " : ""}${v}` }),
845
+ className: "rounded bg-muted px-1.5 py-0.5 font-mono text-[11px] text-muted-foreground hover:text-foreground",
846
+ title: v,
847
+ children: v
848
+ },
849
+ v
850
+ ))
851
+ ] }),
852
+ /* @__PURE__ */ jsx(Field, { label: l.attachments, children: /* @__PURE__ */ jsx(
853
+ DocumentRefList,
854
+ {
855
+ value: action.attachments ?? [],
856
+ onChange: (attachments) => set({ attachments: attachments.length ? attachments : void 0 }),
857
+ ctx,
858
+ l,
859
+ addLabel: l.addAttachment,
860
+ testId: `${testId}-attachments`
861
+ }
862
+ ) })
863
+ ] });
864
+ }
865
+ function TabularReviewSettings({
866
+ action,
867
+ onChange,
868
+ ctx,
869
+ l,
870
+ testId
871
+ }) {
872
+ const set = (p) => onChange({ ...action, ...p });
873
+ const mode = Array.isArray(action.documents) ? "chosen" : action.documents;
874
+ const toggle = (id) => set({
875
+ tags: action.tags.includes(id) ? action.tags.filter((t) => t !== id) : [...action.tags, id]
876
+ });
877
+ return /* @__PURE__ */ jsxs(Fragment, { children: [
878
+ /* @__PURE__ */ jsx(Field, { label: l.reviewColumns, children: /* @__PURE__ */ jsxs(
879
+ "div",
880
+ {
881
+ className: "max-h-44 space-y-1 overflow-y-auto rounded-md border border-border p-2",
882
+ "data-testid": `${testId}-tags`,
883
+ children: [
884
+ ctx.tags.length === 0 && /* @__PURE__ */ jsx("p", { className: "text-xs text-muted-foreground", children: l.noTags }),
885
+ ctx.tags.map((t) => /* @__PURE__ */ jsxs("label", { className: "flex items-center gap-2 text-sm", children: [
886
+ /* @__PURE__ */ jsx(
887
+ Checkbox,
888
+ {
889
+ checked: action.tags.includes(t.value),
890
+ onCheckedChange: () => toggle(t.value),
891
+ "data-testid": `${testId}-tag-${t.value}`
892
+ }
893
+ ),
894
+ /* @__PURE__ */ jsx("span", { className: "truncate", children: t.label })
895
+ ] }, t.value)),
896
+ action.tags.filter((t) => !ctx.tags.some((x) => x.value === t)).map((t) => /* @__PURE__ */ jsxs("label", { className: "flex items-center gap-2 text-sm text-muted-foreground", children: [
897
+ /* @__PURE__ */ jsx(Checkbox, { checked: true, onCheckedChange: () => toggle(t) }),
898
+ /* @__PURE__ */ jsx("code", { className: "text-xs", children: t })
899
+ ] }, t))
900
+ ]
901
+ }
902
+ ) }),
903
+ /* @__PURE__ */ jsx(Field, { label: l.reviewDocuments, children: /* @__PURE__ */ jsxs(
904
+ "select",
905
+ {
906
+ className: selectClass2,
907
+ value: mode,
908
+ onChange: (e) => {
909
+ const v = e.target.value;
910
+ set({ documents: v === "chosen" ? [] : v });
911
+ },
912
+ "data-testid": `${testId}-documents`,
913
+ children: [
914
+ /* @__PURE__ */ jsx("option", { value: "run_uploads", children: l.reviewRunUploads }),
915
+ /* @__PURE__ */ jsx("option", { value: "workspace", children: l.reviewWorkspace }),
916
+ /* @__PURE__ */ jsx("option", { value: "chosen", children: l.reviewChosen })
917
+ ]
918
+ }
919
+ ) }),
920
+ Array.isArray(action.documents) && /* @__PURE__ */ jsx(
921
+ DocumentRefList,
922
+ {
923
+ value: action.documents,
924
+ onChange: (documents) => set({ documents }),
925
+ ctx,
926
+ l,
927
+ addLabel: l.addDocument,
928
+ testId: `${testId}-chosen`
929
+ }
930
+ ),
931
+ /* @__PURE__ */ jsxs("label", { className: "flex items-center gap-2 text-sm", children: [
932
+ /* @__PURE__ */ jsx(
933
+ Checkbox,
934
+ {
935
+ checked: !!action.overwrite,
936
+ onCheckedChange: (v) => set({ overwrite: v === true || void 0 })
937
+ }
938
+ ),
939
+ l.overwrite
940
+ ] })
941
+ ] });
942
+ }
943
+ function EditDocumentSettings({
944
+ step,
945
+ patch,
946
+ ctx,
947
+ l,
948
+ testId
949
+ }) {
950
+ const on = !!step.editDocument;
951
+ return /* @__PURE__ */ jsxs("div", { className: "space-y-2", children: [
952
+ /* @__PURE__ */ jsxs("label", { className: "flex items-start gap-2 text-sm", children: [
953
+ /* @__PURE__ */ jsx(
954
+ Checkbox,
955
+ {
956
+ checked: on,
957
+ disabled: !!step.branch,
958
+ onCheckedChange: (v) => patch({ editDocument: v === true ? { step: "" } : void 0 }),
959
+ "data-testid": `${testId}-edit-document`
960
+ }
961
+ ),
962
+ /* @__PURE__ */ jsxs("span", { children: [
963
+ l.editDocument,
964
+ /* @__PURE__ */ jsx("span", { className: "block text-xs text-muted-foreground", children: l.editDocumentHint })
965
+ ] })
966
+ ] }),
967
+ on && /* @__PURE__ */ jsx(
968
+ DocumentRefPicker,
969
+ {
970
+ value: step.editDocument,
971
+ onChange: (editDocument) => patch({ editDocument }),
972
+ ctx,
973
+ l,
974
+ testId: `${testId}-edit-document-ref`
975
+ }
976
+ )
977
+ ] });
978
+ }
384
979
  var DEFAULT_STEP_INSPECTOR_LABELS = {
385
980
  workflow: "Workflow",
386
981
  title: "Title",
@@ -410,17 +1005,19 @@ var DEFAULT_STEP_INSPECTOR_LABELS = {
410
1005
  hint: "Hint",
411
1006
  instructions: "What to review",
412
1007
  instructionsHint: "Shown on the review task; {{field}} and {{steps.<id>}} work here.",
1008
+ reviewFields: "Filled in when approving",
1009
+ reviewFieldsHint: "E.g. a rating or a comment; the answers join the run\u2019s inputs.",
413
1010
  deleteStep: "Delete step"
414
1011
  };
415
- var FIELD_TYPES = ["text", "longtext", "boolean", "number", "date", "scope"];
416
- var selectClass2 = "flex h-9 w-full rounded-md border border-input bg-background px-2 text-sm shadow-sm focus-visible:outline-none focus-visible:ring-1 focus-visible:ring-ring";
417
- function Field({ label, children, hint }) {
418
- return /* @__PURE__ */ jsxs("div", { className: "space-y-1.5", children: [
419
- /* @__PURE__ */ jsx(Label, { className: "text-xs", children: label }),
420
- children,
421
- hint && /* @__PURE__ */ jsx("p", { className: "text-xs text-muted-foreground", children: hint })
422
- ] });
423
- }
1012
+ var FIELD_TYPES = [
1013
+ "text",
1014
+ "longtext",
1015
+ "boolean",
1016
+ "number",
1017
+ "date",
1018
+ "scope",
1019
+ "person"
1020
+ ];
424
1021
  var fieldName = (label, taken) => {
425
1022
  const base = label.toLowerCase().replace(/[^a-z0-9]+/g, "_").replace(/^_+|_+$/g, "").replace(/^[^a-z]+/, "") || "field";
426
1023
  let name = base;
@@ -434,7 +1031,11 @@ function StepInspector({
434
1031
  onChange,
435
1032
  onSelect,
436
1033
  workflows = [],
1034
+ people = [],
1035
+ tags = [],
1036
+ documents = [],
437
1037
  labels,
1038
+ actionLabels,
438
1039
  signalLabels,
439
1040
  testId = "step-inspector"
440
1041
  }) {
@@ -464,6 +1065,30 @@ function StepInspector({
464
1065
  ] });
465
1066
  }
466
1067
  const patch = (p) => onChange(updateStep(workflow, step.id, p));
1068
+ const al = { ...DEFAULT_STEP_ACTION_SETTINGS_LABELS, ...actionLabels };
1069
+ const ctx = {
1070
+ earlier: upstreamSteps(steps, step.id),
1071
+ fields: runFields(workflow),
1072
+ people,
1073
+ tags,
1074
+ documents
1075
+ };
1076
+ const takenBy = (id) => steps.flatMap(
1077
+ (s) => s.id === id ? [] : s.kind === "form" ? s.inputs : s.kind === "review" ? s.fields ?? [] : []
1078
+ ).map((f) => f.name);
1079
+ const setFields = (before, after, key) => {
1080
+ const renamed = before.flatMap(
1081
+ (f, i) => after[i] && after[i].name !== f.name ? [[f.name, after[i].name]] : []
1082
+ );
1083
+ onChange(
1084
+ renamed.reduce(
1085
+ (w, [from, to]) => renameInput(w, from, to),
1086
+ updateStep(workflow, step.id, {
1087
+ [key]: key === "fields" && !after.length ? void 0 : after
1088
+ })
1089
+ )
1090
+ );
1091
+ };
467
1092
  const deps = stepDependencies(steps, step.id);
468
1093
  const titleOf = (id) => steps.find((s) => s.id === id)?.title ?? id;
469
1094
  return /* @__PURE__ */ jsxs("div", { className: "space-y-4", "data-testid": `${testId}-step`, children: [
@@ -513,18 +1138,8 @@ function StepInspector({
513
1138
  FormFields,
514
1139
  {
515
1140
  fields: step.inputs,
516
- taken: steps.flatMap((s) => s.kind === "form" && s.id !== step.id ? s.inputs : []).map((f) => f.name),
517
- onChange: (inputs) => {
518
- const renamed = step.inputs.flatMap(
519
- (f, i) => inputs[i] && inputs[i].name !== f.name ? [[f.name, inputs[i].name]] : []
520
- );
521
- onChange(
522
- renamed.reduce(
523
- (w, [from, to]) => renameInput(w, from, to),
524
- updateStep(workflow, step.id, { inputs })
525
- )
526
- );
527
- },
1141
+ taken: takenBy(step.id),
1142
+ onChange: (inputs) => setFields(step.inputs, inputs, "inputs"),
528
1143
  l,
529
1144
  testId
530
1145
  }
@@ -548,26 +1163,73 @@ function StepInspector({
548
1163
  }
549
1164
  ) })
550
1165
  ] }),
551
- step.kind === "agent" && /* @__PURE__ */ jsx(
552
- AgentSettings,
1166
+ step.kind === "agent" && /* @__PURE__ */ jsxs(Fragment, { children: [
1167
+ /* @__PURE__ */ jsx(
1168
+ AgentSettings,
1169
+ {
1170
+ step,
1171
+ workflows,
1172
+ fields: runFields(workflow).map((f) => f.name),
1173
+ patch,
1174
+ l,
1175
+ testId
1176
+ }
1177
+ ),
1178
+ /* @__PURE__ */ jsx(EditDocumentSettings, { step, patch, ctx, l: al, testId })
1179
+ ] }),
1180
+ step.kind === "review" && /* @__PURE__ */ jsxs(Fragment, { children: [
1181
+ /* @__PURE__ */ jsx(Field, { label: l.instructions, hint: l.instructionsHint, children: /* @__PURE__ */ jsx(
1182
+ Textarea,
1183
+ {
1184
+ value: step.instructions ?? "",
1185
+ rows: 4,
1186
+ onChange: (e) => patch({ instructions: e.target.value || void 0 }),
1187
+ "data-testid": `${testId}-instructions`
1188
+ }
1189
+ ) }),
1190
+ /* @__PURE__ */ jsx(
1191
+ FormFields,
1192
+ {
1193
+ fields: step.fields ?? [],
1194
+ taken: takenBy(step.id),
1195
+ onChange: (fields) => setFields(step.fields ?? [], fields, "fields"),
1196
+ l: { ...l, fields: l.reviewFields },
1197
+ hint: l.reviewFieldsHint,
1198
+ testId: `${testId}-review`
1199
+ }
1200
+ )
1201
+ ] }),
1202
+ step.kind === "action" && step.action.type === "sign" && /* @__PURE__ */ jsx(
1203
+ SignSettings,
553
1204
  {
554
- step,
555
- workflows,
556
- fields: runFields(workflow).map((f) => f.name),
557
- patch,
558
- l,
559
- testId
1205
+ action: step.action,
1206
+ onChange: (action) => patch({ action }),
1207
+ ctx,
1208
+ l: al,
1209
+ testId: `${testId}-sign`
560
1210
  }
561
1211
  ),
562
- step.kind === "review" && /* @__PURE__ */ jsx(Field, { label: l.instructions, hint: l.instructionsHint, children: /* @__PURE__ */ jsx(
563
- Textarea,
1212
+ step.kind === "action" && step.action.type === "email_draft" && /* @__PURE__ */ jsx(
1213
+ EmailDraftSettings,
564
1214
  {
565
- value: step.instructions ?? "",
566
- rows: 4,
567
- onChange: (e) => patch({ instructions: e.target.value || void 0 }),
568
- "data-testid": `${testId}-instructions`
1215
+ action: step.action,
1216
+ onChange: (action) => patch({ action }),
1217
+ ctx,
1218
+ l: al,
1219
+ testId: `${testId}-email`
569
1220
  }
570
- ) }),
1221
+ ),
1222
+ step.kind === "action" && step.action.type === "tabular_review" && /* @__PURE__ */ jsx(
1223
+ TabularReviewSettings,
1224
+ {
1225
+ action: step.action,
1226
+ onChange: (action) => patch({ action }),
1227
+ ctx,
1228
+ l: al,
1229
+ testId: `${testId}-review-grid`
1230
+ }
1231
+ ),
1232
+ canAssign(step) && /* @__PURE__ */ jsx(AssigneeSettings, { step, patch, ctx, l: al, testId }),
571
1233
  /* @__PURE__ */ jsx(
572
1234
  SignalsEditor,
573
1235
  {
@@ -602,10 +1264,11 @@ function FormFields({
602
1264
  taken,
603
1265
  onChange,
604
1266
  l,
1267
+ hint,
605
1268
  testId
606
1269
  }) {
607
1270
  const set = (i, p) => onChange(fields.map((f, j) => j === i ? { ...f, ...p } : f));
608
- return /* @__PURE__ */ jsx(Field, { label: l.fields, children: /* @__PURE__ */ jsxs("div", { className: "space-y-2", "data-testid": `${testId}-fields`, children: [
1271
+ return /* @__PURE__ */ jsx(Field, { label: l.fields, hint, children: /* @__PURE__ */ jsxs("div", { className: "space-y-2", "data-testid": `${testId}-fields`, children: [
609
1272
  fields.map((f, i) => /* @__PURE__ */ jsxs("div", { className: "space-y-1.5 rounded-md border border-border p-2", children: [
610
1273
  /* @__PURE__ */ jsxs("div", { className: "flex items-center gap-2", children: [
611
1274
  /* @__PURE__ */ jsx(
@@ -641,7 +1304,9 @@ function FormFields({
641
1304
  className: cn(selectClass2, "h-8"),
642
1305
  value: f.type,
643
1306
  onChange: (e) => set(i, { type: e.target.value }),
644
- children: FIELD_TYPES.map((t) => /* @__PURE__ */ jsx("option", { value: t, children: t }, t))
1307
+ children: (FIELD_TYPES.includes(f.type) ? FIELD_TYPES : [...FIELD_TYPES, f.type]).map(
1308
+ (t) => /* @__PURE__ */ jsx("option", { value: t, children: t }, t)
1309
+ )
645
1310
  }
646
1311
  ),
647
1312
  /* @__PURE__ */ jsxs("label", { className: "flex shrink-0 items-center gap-1.5 text-xs", children: [
@@ -1132,12 +1797,19 @@ var DEFAULT_WORKFLOW_CANVAS_LABELS = {
1132
1797
  upload: "Upload",
1133
1798
  agent: "AI step",
1134
1799
  review: "Approval",
1800
+ sign: "Sign",
1801
+ email_draft: "Email draft",
1802
+ tabular_review: "Tabular review",
1803
+ redline: "Tracked changes",
1135
1804
  branch: "Branch",
1136
1805
  kindHints: {
1137
1806
  form: "Ask for details",
1138
1807
  upload: "Collect files",
1139
1808
  agent: "Run a skill or an instruction",
1140
- review: "A person approves"
1809
+ review: "A person approves",
1810
+ sign: "People e-sign a document",
1811
+ email_draft: "Prepare an email to send",
1812
+ tabular_review: "Review documents in a grid"
1141
1813
  },
1142
1814
  addNext: "Add the next step",
1143
1815
  runs: "Runs \u201C{name}\u201D",
@@ -1145,6 +1817,14 @@ var DEFAULT_WORKFLOW_CANVAS_LABELS = {
1145
1817
  fields: "{count} fields",
1146
1818
  noFields: "No fields yet",
1147
1819
  approvedBy: "A person approves",
1820
+ signers: "{count} signers",
1821
+ chooseDocument: "Choose the document to sign",
1822
+ emailTo: "To {to}",
1823
+ noRecipients: "Add a recipient",
1824
+ reviewColumns: "{count} columns",
1825
+ noColumns: "Choose the columns",
1826
+ assignee: "{name}",
1827
+ remind: "Reminds after {hours}h",
1148
1828
  emptyTitle: "Start your workflow",
1149
1829
  emptyHint: "Add the first step: what should happen when it starts?",
1150
1830
  fitView: "Fit view"
@@ -1154,9 +1834,12 @@ var STEP_KIND_ICONS = {
1154
1834
  form: FileInput,
1155
1835
  upload: Upload,
1156
1836
  agent: Bot,
1157
- review: ClipboardCheck
1837
+ review: ClipboardCheck,
1838
+ sign: PenLine,
1839
+ email_draft: Mail,
1840
+ tabular_review: Table2
1158
1841
  };
1159
- var KINDS = ["form", "upload", "agent", "review"];
1842
+ var KINDS = WORKFLOW_STEP_KINDS;
1160
1843
  function AddNext({
1161
1844
  from,
1162
1845
  onAdd,
@@ -1209,20 +1892,23 @@ function AddNext({
1209
1892
  }
1210
1893
  function PhaseMark({ phase }) {
1211
1894
  if (phase === "running") return /* @__PURE__ */ jsx(Loader2, { className: "wf-kind-text size-4 animate-spin" });
1895
+ if (phase === "waiting") return /* @__PURE__ */ jsx(Hourglass, { className: "wf-kind-text size-4" });
1212
1896
  if (phase === "done") return /* @__PURE__ */ jsx(Check, { className: "wf-kind-text size-4" });
1213
1897
  if (phase === "failed") return /* @__PURE__ */ jsx(AlertTriangle, { className: "size-4 text-destructive" });
1214
1898
  if (phase === "skipped") return /* @__PURE__ */ jsx(MinusCircle, { className: "size-4 text-muted-foreground" });
1215
1899
  return null;
1216
1900
  }
1217
1901
  function StepNode({ data }) {
1218
- const { step, phase, summary, icon, l, onAdd, testId } = data;
1219
- const KindIcon = STEP_KIND_ICONS[step.kind];
1902
+ const { step, phase, summary, assignee, icon, l, onAdd, testId } = data;
1903
+ const kind = stepKindOf(step);
1904
+ const KindIcon = STEP_KIND_ICONS[kind];
1905
+ const redline = step.kind === "agent" && !!step.editDocument;
1220
1906
  return /* @__PURE__ */ jsxs(
1221
1907
  "div",
1222
1908
  {
1223
1909
  className: cn(
1224
1910
  "wf-node w-64 py-3 pl-4 pr-3 text-left",
1225
- `wf-kind-${step.kind}`,
1911
+ `wf-kind-${kind}`,
1226
1912
  phase && `wf-phase-${phase}`
1227
1913
  ),
1228
1914
  "data-testid": `${testId}-node-${step.id}`,
@@ -1233,15 +1919,44 @@ function StepNode({ data }) {
1233
1919
  /* @__PURE__ */ jsx("span", { className: "wf-badge flex size-8 shrink-0 items-center justify-center rounded-lg [&_svg]:size-4", children: icon ?? /* @__PURE__ */ jsx(KindIcon, {}) }),
1234
1920
  /* @__PURE__ */ jsxs("div", { className: "min-w-0 flex-1", children: [
1235
1921
  /* @__PURE__ */ jsxs("div", { className: "flex items-center justify-between gap-2", children: [
1236
- /* @__PURE__ */ jsx("span", { className: "wf-kind-text text-[10px] font-semibold uppercase tracking-wider", children: l[step.kind] }),
1922
+ /* @__PURE__ */ jsx("span", { className: "wf-kind-text text-[10px] font-semibold uppercase tracking-wider", children: l[kind] }),
1237
1923
  /* @__PURE__ */ jsx(PhaseMark, { phase })
1238
1924
  ] }),
1239
1925
  /* @__PURE__ */ jsx("p", { className: "truncate text-sm font-semibold leading-snug", children: step.title }),
1240
1926
  summary && /* @__PURE__ */ jsx("p", { className: "mt-0.5 line-clamp-2 text-xs leading-snug text-muted-foreground", children: summary }),
1241
- step.kind === "agent" && step.branch && /* @__PURE__ */ jsxs("span", { className: "mt-1.5 inline-flex items-center gap-1 rounded-full bg-muted px-2 py-0.5 text-[10px] font-medium text-muted-foreground", children: [
1242
- /* @__PURE__ */ jsx(GitBranch, { className: "size-3" }),
1243
- " ",
1244
- l.branch
1927
+ (redline || step.kind === "agent" && step.branch || assignee) && /* @__PURE__ */ jsxs("div", { className: "mt-1.5 flex flex-wrap gap-1", children: [
1928
+ step.kind === "agent" && step.branch && /* @__PURE__ */ jsxs("span", { className: "inline-flex items-center gap-1 rounded-full bg-muted px-2 py-0.5 text-[10px] font-medium text-muted-foreground", children: [
1929
+ /* @__PURE__ */ jsx(GitBranch, { className: "size-3" }),
1930
+ " ",
1931
+ l.branch
1932
+ ] }),
1933
+ redline && /* @__PURE__ */ jsxs(
1934
+ "span",
1935
+ {
1936
+ className: "inline-flex items-center gap-1 rounded-full bg-muted px-2 py-0.5 text-[10px] font-medium text-muted-foreground",
1937
+ "data-testid": `${testId}-node-${step.id}-redline`,
1938
+ children: [
1939
+ /* @__PURE__ */ jsx(FilePenLine, { className: "size-3" }),
1940
+ " ",
1941
+ l.redline
1942
+ ]
1943
+ }
1944
+ ),
1945
+ assignee && /* @__PURE__ */ jsxs(
1946
+ "span",
1947
+ {
1948
+ className: "inline-flex max-w-full items-center gap-1 truncate rounded-full bg-muted px-2 py-0.5 text-[10px] font-medium text-muted-foreground",
1949
+ title: assignee,
1950
+ "data-testid": `${testId}-node-${step.id}-assignee`,
1951
+ children: [
1952
+ /* @__PURE__ */ jsx(UserRound, { className: "size-3 shrink-0" }),
1953
+ /* @__PURE__ */ jsx("span", { className: "truncate", children: l.assignee.replace(
1954
+ "{name}",
1955
+ assignee.charAt(0).toUpperCase() + assignee.slice(1)
1956
+ ) })
1957
+ ]
1958
+ }
1959
+ )
1245
1960
  ] })
1246
1961
  ] })
1247
1962
  ] }),
@@ -1290,6 +2005,16 @@ function summaryOf(step, l, workflowTitle) {
1290
2005
  return step.hint;
1291
2006
  case "review":
1292
2007
  return step.instructions ? firstWords(step.instructions) : l.approvedBy;
2008
+ case "action": {
2009
+ const a = step.action;
2010
+ if (a.type === "sign")
2011
+ return !a.document ? l.chooseDocument : a.signers.length ? l.signers.replace("{count}", String(a.signers.length)) : void 0;
2012
+ if (a.type === "email_draft") {
2013
+ const to = a.to.find((t) => t.trim());
2014
+ return to ? l.emailTo.replace("{to}", to) : l.noRecipients;
2015
+ }
2016
+ return a.tags.length ? l.reviewColumns.replace("{count}", String(a.tags.length)) : l.noColumns;
2017
+ }
1293
2018
  }
1294
2019
  }
1295
2020
  function WorkflowCanvas({
@@ -1301,6 +2026,7 @@ function WorkflowCanvas({
1301
2026
  onAddAfter,
1302
2027
  phases,
1303
2028
  workflowTitle,
2029
+ assigneeOf,
1304
2030
  trigger,
1305
2031
  renderIcon,
1306
2032
  labels,
@@ -1339,6 +2065,7 @@ function WorkflowCanvas({
1339
2065
  step,
1340
2066
  phase: phases?.[step.id],
1341
2067
  summary: summaryOf(step, l, workflowTitle),
2068
+ assignee: assigneeOf?.(step),
1342
2069
  icon: step.icon && renderIcon ? renderIcon(step.icon) : void 0,
1343
2070
  l,
1344
2071
  onAdd: onAddAfter,
@@ -1346,7 +2073,18 @@ function WorkflowCanvas({
1346
2073
  }
1347
2074
  }))
1348
2075
  ];
1349
- }, [workflow, selected, phases, workflowTitle, trigger, renderIcon, l, onAddAfter, testId]);
2076
+ }, [
2077
+ workflow,
2078
+ selected,
2079
+ phases,
2080
+ workflowTitle,
2081
+ assigneeOf,
2082
+ trigger,
2083
+ renderIcon,
2084
+ l,
2085
+ onAddAfter,
2086
+ testId
2087
+ ]);
1350
2088
  const [nodes, setNodes] = useState(built);
1351
2089
  useEffect(() => setNodes(built), [built]);
1352
2090
  const edges = useMemo(
@@ -1560,10 +2298,17 @@ var DEFAULT_WORKFLOW_BUILDER_LABELS = {
1560
2298
  unknown: "\u201C{step}\u201D waits for a step that does not exist.",
1561
2299
  cycle: "\u201C{step}\u201D waits for itself (a loop).",
1562
2300
  order: "\u201C{step}\u201D is listed before a step it waits for."
2301
+ },
2302
+ missing: {
2303
+ document: "\u201C{step}\u201D needs a document.",
2304
+ signers: "\u201C{step}\u201D needs at least one signer.",
2305
+ recipients: "\u201C{step}\u201D needs a recipient.",
2306
+ tags: "\u201C{step}\u201D needs at least one column.",
2307
+ documents: "\u201C{step}\u201D needs documents to review."
1563
2308
  }
1564
2309
  };
1565
2310
  var PANEL_WIDTH = 344;
1566
- var KINDS2 = ["form", "upload", "agent", "review"];
2311
+ var KINDS2 = WORKFLOW_STEP_KINDS;
1567
2312
  function WorkflowBuilder({
1568
2313
  value,
1569
2314
  onChange,
@@ -1572,6 +2317,9 @@ function WorkflowBuilder({
1572
2317
  eventKinds = [],
1573
2318
  tasks = [],
1574
2319
  signals = [],
2320
+ people = [],
2321
+ tags = [],
2322
+ documents = [],
1575
2323
  compose,
1576
2324
  renderIcon,
1577
2325
  actions,
@@ -1594,6 +2342,10 @@ function WorkflowBuilder({
1594
2342
  const { workflow, trigger } = value;
1595
2343
  const steps = workflowSteps(workflow);
1596
2344
  const problems = validateWorkflowGraph(steps);
2345
+ const missing = stepConfigProblems(steps);
2346
+ const nameOf = (id) => people.find((p) => p.value === id)?.label;
2347
+ const fields = runFields(workflow);
2348
+ const assigneeOf = (step) => canAssign(step) ? assigneeName(step.assignee, { nameOf, fields }) : void 0;
1597
2349
  const titles = useMemo(() => new Map(workflows.map((w) => [w.id, w.title])), [workflows]);
1598
2350
  const setWorkflow = (next) => onChange({ ...value, workflow: next });
1599
2351
  const addAfter = (from, kind) => {
@@ -1706,10 +2458,16 @@ function WorkflowBuilder({
1706
2458
  ] }),
1707
2459
  actions && /* @__PURE__ */ jsx("div", { className: "ml-auto flex flex-wrap items-center gap-2", children: actions })
1708
2460
  ] }),
1709
- problems.length > 0 && /* @__PURE__ */ jsx("ul", { className: "space-y-1 text-sm text-destructive", "data-testid": `${testId}-problems`, children: problems.map((p, i) => /* @__PURE__ */ jsx("li", { children: l.problems[p.code].replace(
1710
- "{step}",
1711
- steps.find((s) => s.id === p.step)?.title ?? p.step
1712
- ) }, i)) }),
2461
+ problems.length + missing.length > 0 && /* @__PURE__ */ jsxs("ul", { className: "space-y-1 text-sm text-destructive", "data-testid": `${testId}-problems`, children: [
2462
+ problems.map((p, i) => /* @__PURE__ */ jsx("li", { children: l.problems[p.code].replace(
2463
+ "{step}",
2464
+ steps.find((s) => s.id === p.step)?.title ?? p.step
2465
+ ) }, i)),
2466
+ missing.map((p, i) => /* @__PURE__ */ jsx("li", { "data-testid": `${testId}-missing-${p.step}-${p.missing}`, children: l.missing[p.missing].replace(
2467
+ "{step}",
2468
+ steps.find((s) => s.id === p.step)?.title ?? p.step
2469
+ ) }, `m${i}`))
2470
+ ] }),
1713
2471
  mode === "design" ? /* @__PURE__ */ jsxs("div", { className: "relative", children: [
1714
2472
  /* @__PURE__ */ jsx(
1715
2473
  WorkflowCanvas,
@@ -1722,6 +2480,7 @@ function WorkflowBuilder({
1722
2480
  onAddAfter: addAfter,
1723
2481
  trigger: { title: l.start, summary },
1724
2482
  workflowTitle: (id) => titles.get(id),
2483
+ assigneeOf,
1725
2484
  renderIcon,
1726
2485
  labels: canvasLabels,
1727
2486
  reserveRight: panelOpen ? PANEL_WIDTH : 0,
@@ -1771,6 +2530,9 @@ function WorkflowBuilder({
1771
2530
  onChange: setWorkflow,
1772
2531
  onSelect: setSelected,
1773
2532
  workflows,
2533
+ people,
2534
+ tags,
2535
+ documents,
1774
2536
  labels: inspectorLabels,
1775
2537
  testId: `${testId}-inspector`
1776
2538
  }
@@ -1866,7 +2628,22 @@ function ConnectedWorkflowBuilder({
1866
2628
  ...builderProps
1867
2629
  }) {
1868
2630
  const l = { ...DEFAULT_CONNECTED_WORKFLOW_BUILDER_LABELS, ...connectedLabels };
1869
- const { workspaceId } = useConnection();
2631
+ const { workspaceId, status, ensureWorkspaceOpen } = useConnection();
2632
+ const members = useWorkspaceUsers(workspaceId ?? void 0, {
2633
+ enabled: status === "authenticated" && !!workspaceId,
2634
+ beforeFetch: ensureWorkspaceOpen
2635
+ });
2636
+ const tagsQuery = useTags(workspaceId ?? void 0);
2637
+ const docsQuery = useDocuments(workspaceId ?? void 0);
2638
+ const people = (members.data ?? []).map((m) => ({
2639
+ value: m.user.external_id,
2640
+ label: [m.user.given_name, m.user.family_name].filter(Boolean).join(" ") || m.user.email
2641
+ }));
2642
+ const tagOptions = (tagsQuery.data ?? []).map((t) => ({ value: t.external_id, label: t.name }));
2643
+ const documentOptions = (docsQuery.data ?? []).map((d) => ({
2644
+ value: d.external_id,
2645
+ label: d.file_name ?? d.external_id
2646
+ }));
1870
2647
  const saved = useWorkflows();
1871
2648
  const skills = useSkills();
1872
2649
  const agentsQuery = useAgents();
@@ -1905,7 +2682,7 @@ function ConnectedWorkflowBuilder({
1905
2682
  }));
1906
2683
  const tasks = (conversations.data ?? []).filter((c) => c.status && c.status !== "done").map((c) => ({ value: c.external_id, label: c.title || c.external_id }));
1907
2684
  const options = { resolveWorkflow: (wid) => workflows.find((w) => w.id === wid), compose };
1908
- const problem = triggerProblem(value.trigger) ?? (validateWorkflowGraph(workflowSteps(value.workflow)).length ? "graph" : null);
2685
+ const problem = triggerProblem(value.trigger) ?? (validateWorkflowGraph(workflowSteps(value.workflow)).length || stepConfigProblems(workflowSteps(value.workflow)).length ? "graph" : null);
1909
2686
  const busy = create.isPending || update.isPending || run.isPending;
1910
2687
  const save = async () => {
1911
2688
  if (!workspaceId) return void 0;
@@ -1927,6 +2704,9 @@ function ConnectedWorkflowBuilder({
1927
2704
  agents,
1928
2705
  eventKinds,
1929
2706
  tasks,
2707
+ people,
2708
+ tags: tagOptions,
2709
+ documents: documentOptions,
1930
2710
  signals: declaredSignals(saved.data ?? []),
1931
2711
  compose,
1932
2712
  testId,