@arbidocs/blocks 0.4.76 → 0.4.77
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.
- package/dist/agents/index.cjs +331 -255
- package/dist/agents/index.js +2 -2
- package/dist/agents/tasks/TaskActivityTimeline.d.ts +1 -1
- package/dist/agents/tasks/WorkflowThreadStrip.d.ts +7 -1
- package/dist/agents/workflows/SchemaForm.d.ts +6 -1
- package/dist/agents/workflows/StepParts.d.ts +109 -0
- package/dist/agents/workflows/WorkflowRunner.d.ts +11 -2
- package/dist/agents/workflows/index.d.ts +3 -2
- package/dist/agents/workflows/planSteps.d.ts +8 -1
- package/dist/agents/workflows/run.d.ts +61 -8
- package/dist/agents/workflows/types.d.ts +133 -4
- package/dist/agents/workflows/useWorkflowPreview.d.ts +2 -1
- package/dist/agents/workflows/useWorkflowView.d.ts +19 -0
- package/dist/chat/ChatPage.d.ts +1 -1
- package/dist/chat/WorkflowStepChip.d.ts +24 -0
- package/dist/chat/chat-page-types.d.ts +4 -0
- package/dist/chat/index.cjs +130 -122
- package/dist/chat/index.d.ts +1 -0
- package/dist/chat/index.js +2 -2
- package/dist/{chunk-22P5KNIM.js → chunk-34UW6XUQ.js} +928 -38
- package/dist/chunk-34UW6XUQ.js.map +1 -0
- package/dist/{chunk-VYRKO3XU.cjs → chunk-3XR3IEGU.cjs} +944 -35
- package/dist/chunk-3XR3IEGU.cjs.map +1 -0
- package/dist/{chunk-ZWA7UUZL.cjs → chunk-7YUFMNFW.cjs} +2 -54
- package/dist/chunk-7YUFMNFW.cjs.map +1 -0
- package/dist/chunk-A24C6BNA.js +92 -0
- package/dist/chunk-A24C6BNA.js.map +1 -0
- package/dist/chunk-AINNADMT.cjs +62 -0
- package/dist/chunk-AINNADMT.cjs.map +1 -0
- package/dist/{chunk-7CVF3DK2.cjs → chunk-EKIUMNCN.cjs} +5 -5
- package/dist/{chunk-7CVF3DK2.cjs.map → chunk-EKIUMNCN.cjs.map} +1 -1
- package/dist/chunk-FE4ULGOR.js +151 -0
- package/dist/chunk-FE4ULGOR.js.map +1 -0
- package/dist/chunk-FT5FFXSJ.js +60 -0
- package/dist/chunk-FT5FFXSJ.js.map +1 -0
- package/dist/{chunk-HITAN7JF.cjs → chunk-GTXOV7IJ.cjs} +4 -4
- package/dist/{chunk-HITAN7JF.cjs.map → chunk-GTXOV7IJ.cjs.map} +1 -1
- package/dist/{chunk-TKB7TVMW.js → chunk-HEVVT6IT.js} +78 -14
- package/dist/chunk-HEVVT6IT.js.map +1 -0
- package/dist/{chunk-IPGKTUF7.cjs → chunk-HOD6OM7L.cjs} +68 -3
- package/dist/chunk-HOD6OM7L.cjs.map +1 -0
- package/dist/{chunk-7FKARMA3.cjs → chunk-JFUN4D7D.cjs} +101 -37
- package/dist/chunk-JFUN4D7D.cjs.map +1 -0
- package/dist/{chunk-UIWLDSTF.js → chunk-NIP5BOP7.js} +68 -5
- package/dist/chunk-NIP5BOP7.js.map +1 -0
- package/dist/{chunk-MK6NJQGF.js → chunk-OEM5ARVM.js} +3 -3
- package/dist/{chunk-MK6NJQGF.js.map → chunk-OEM5ARVM.js.map} +1 -1
- package/dist/{chunk-5EBGRG3X.js → chunk-OPA2Y6YZ.js} +3 -54
- package/dist/chunk-OPA2Y6YZ.js.map +1 -0
- package/dist/chunk-TZR36PPP.cjs +95 -0
- package/dist/chunk-TZR36PPP.cjs.map +1 -0
- package/dist/{chunk-WJEKRSPH.js → chunk-UEU23PTW.js} +3 -3
- package/dist/{chunk-WJEKRSPH.js.map → chunk-UEU23PTW.js.map} +1 -1
- package/dist/chunk-ZVBPRMHJ.cjs +153 -0
- package/dist/chunk-ZVBPRMHJ.cjs.map +1 -0
- package/dist/connect/docx.cjs +10 -88
- package/dist/connect/docx.cjs.map +1 -1
- package/dist/connect/docx.js +6 -86
- package/dist/connect/docx.js.map +1 -1
- package/dist/connect/index.cjs +293 -30
- package/dist/connect/index.cjs.map +1 -1
- package/dist/connect/index.js +278 -15
- package/dist/connect/index.js.map +1 -1
- package/dist/connection/ConnectedWorkflowRunner.d.ts +16 -2
- package/dist/connection/WorkflowRunnerDialogs.d.ts +37 -0
- package/dist/connection/useWorkflowThread.d.ts +12 -0
- package/dist/document-tools/index.cjs +7 -143
- package/dist/document-tools/index.cjs.map +1 -1
- package/dist/document-tools/index.js +5 -144
- package/dist/document-tools/index.js.map +1 -1
- package/dist/docx/index.cjs +18 -17
- package/dist/docx/index.cjs.map +1 -1
- package/dist/docx/index.js +3 -2
- package/dist/docx/index.js.map +1 -1
- package/dist/index.cjs +467 -383
- package/dist/index.js +5 -5
- package/dist/studio/index.cjs +3 -3
- package/dist/studio/index.js +2 -2
- package/dist/workflow-canvas/StepActionSettings.d.ts +132 -0
- package/dist/workflow-canvas/StepInspector.d.ts +25 -2
- package/dist/workflow-canvas/WorkflowBuilder.d.ts +11 -3
- package/dist/workflow-canvas/WorkflowCanvas.d.ts +27 -2
- package/dist/workflow-canvas/edit.d.ts +9 -1
- package/dist/workflow-canvas/index.cjs +879 -99
- package/dist/workflow-canvas/index.cjs.map +1 -1
- package/dist/workflow-canvas/index.js +846 -66
- package/dist/workflow-canvas/index.js.map +1 -1
- package/package.json +4 -4
- package/src/workflow-canvas/canvas.css +9 -0
- package/dist/chunk-22P5KNIM.js.map +0 -1
- package/dist/chunk-5EBGRG3X.js.map +0 -1
- package/dist/chunk-7FKARMA3.cjs.map +0 -1
- package/dist/chunk-IPGKTUF7.cjs.map +0 -1
- package/dist/chunk-TKB7TVMW.js.map +0 -1
- package/dist/chunk-UIWLDSTF.js.map +0 -1
- package/dist/chunk-VYRKO3XU.cjs.map +0 -1
- package/dist/chunk-ZWA7UUZL.cjs.map +0 -1
|
@@ -291,7 +291,8 @@ function FieldControl({
|
|
|
291
291
|
renderScope,
|
|
292
292
|
renderDocuments,
|
|
293
293
|
renderIcon,
|
|
294
|
-
onEnterSubmit
|
|
294
|
+
onEnterSubmit,
|
|
295
|
+
people
|
|
295
296
|
}) {
|
|
296
297
|
const id = `${idFor()}-control`;
|
|
297
298
|
const testId = idFor();
|
|
@@ -424,6 +425,34 @@ function FieldControl({
|
|
|
424
425
|
const picked = isWorkflowScope(value) ? value : { folders: [], labels: [], documents: [] };
|
|
425
426
|
return /* @__PURE__ */ jsxRuntime.jsx("div", { "data-testid": testId, children: renderDocuments?.(field, picked, onChange) });
|
|
426
427
|
}
|
|
428
|
+
case "person":
|
|
429
|
+
return people?.length ? /* @__PURE__ */ jsxRuntime.jsxs(
|
|
430
|
+
"select",
|
|
431
|
+
{
|
|
432
|
+
id,
|
|
433
|
+
"data-testid": testId,
|
|
434
|
+
value: String(value ?? ""),
|
|
435
|
+
"aria-required": field.required || void 0,
|
|
436
|
+
"aria-invalid": error ? true : void 0,
|
|
437
|
+
onChange: (e) => onChange(e.target.value),
|
|
438
|
+
className: "flex h-9 w-full rounded-md border border-input bg-background px-2 text-sm shadow-sm",
|
|
439
|
+
children: [
|
|
440
|
+
/* @__PURE__ */ jsxRuntime.jsx("option", { value: "", children: field.placeholder ?? "" }),
|
|
441
|
+
people.map((p) => /* @__PURE__ */ jsxRuntime.jsx("option", { value: p.value, children: p.label }, p.value))
|
|
442
|
+
]
|
|
443
|
+
}
|
|
444
|
+
) : /* @__PURE__ */ jsxRuntime.jsx(
|
|
445
|
+
ui.Input,
|
|
446
|
+
{
|
|
447
|
+
id,
|
|
448
|
+
"data-testid": testId,
|
|
449
|
+
value: String(value ?? ""),
|
|
450
|
+
placeholder: field.placeholder ?? "usr-\u2026",
|
|
451
|
+
"aria-required": field.required || void 0,
|
|
452
|
+
"aria-invalid": error ? true : void 0,
|
|
453
|
+
onChange: (e) => onChange(e.target.value)
|
|
454
|
+
}
|
|
455
|
+
);
|
|
427
456
|
}
|
|
428
457
|
}
|
|
429
458
|
function FormField(props) {
|
|
@@ -474,6 +503,7 @@ function SchemaForm({
|
|
|
474
503
|
renderDocuments,
|
|
475
504
|
renderIcon,
|
|
476
505
|
onEnterSubmit,
|
|
506
|
+
people,
|
|
477
507
|
testIdPrefix,
|
|
478
508
|
labels,
|
|
479
509
|
className
|
|
@@ -498,7 +528,8 @@ function SchemaForm({
|
|
|
498
528
|
renderScope,
|
|
499
529
|
renderDocuments,
|
|
500
530
|
renderIcon,
|
|
501
|
-
onEnterSubmit
|
|
531
|
+
onEnterSubmit,
|
|
532
|
+
people
|
|
502
533
|
},
|
|
503
534
|
field.name
|
|
504
535
|
);
|
|
@@ -588,33 +619,81 @@ function stepLevels(steps) {
|
|
|
588
619
|
}
|
|
589
620
|
var STEP_EVENTS = {
|
|
590
621
|
step_started: "running",
|
|
622
|
+
step_waiting: "waiting",
|
|
591
623
|
step_done: "done",
|
|
592
624
|
step_skipped: "skipped",
|
|
593
625
|
step_failed: "failed"
|
|
594
626
|
};
|
|
627
|
+
var str2 = (v) => typeof v === "string" && v ? v : void 0;
|
|
628
|
+
var ACTION_TYPES = ["sign", "email_draft", "tabular_review"];
|
|
629
|
+
var asAction = (v) => ACTION_TYPES.includes(v) ? v : void 0;
|
|
630
|
+
var asRecord = (v) => v && typeof v === "object" && !Array.isArray(v) ? v : void 0;
|
|
631
|
+
var asStrings = (v) => Array.isArray(v) ? v.filter((x) => typeof x === "string") : void 0;
|
|
632
|
+
function reopenedBy(detail) {
|
|
633
|
+
const to = str2(detail.to);
|
|
634
|
+
return asStrings(detail.reopened) ?? (to ? [to] : []);
|
|
635
|
+
}
|
|
595
636
|
function stepStatesFromActivity(events) {
|
|
596
637
|
const states = {};
|
|
597
638
|
for (const e of events) {
|
|
639
|
+
const detail = e.detail ?? {};
|
|
640
|
+
const step = str2(detail.step);
|
|
641
|
+
if (!step) continue;
|
|
642
|
+
if (e.kind === "step_sent_back") {
|
|
643
|
+
const to = str2(detail.to);
|
|
644
|
+
for (const id of reopenedBy(detail))
|
|
645
|
+
states[id] = id === to ? {
|
|
646
|
+
status: "pending",
|
|
647
|
+
sentBack: true,
|
|
648
|
+
hasNote: typeof detail.note_encrypted === "string"
|
|
649
|
+
} : { status: "pending" };
|
|
650
|
+
continue;
|
|
651
|
+
}
|
|
652
|
+
if (e.kind === "step_ready") {
|
|
653
|
+
states[step] = { ...states[step] ?? { status: "pending" }, announcedTo: str2(detail.to) };
|
|
654
|
+
continue;
|
|
655
|
+
}
|
|
656
|
+
if (e.kind === "step_progress") {
|
|
657
|
+
const before2 = states[step];
|
|
658
|
+
const waiting2 = asRecord(detail.waiting);
|
|
659
|
+
if (before2?.status === "waiting" && waiting2) states[step] = { ...before2, waiting: waiting2 };
|
|
660
|
+
continue;
|
|
661
|
+
}
|
|
598
662
|
const status = STEP_EVENTS[e.kind];
|
|
599
|
-
|
|
600
|
-
|
|
601
|
-
const responseId =
|
|
602
|
-
const
|
|
603
|
-
const
|
|
663
|
+
if (!status) continue;
|
|
664
|
+
const before = states[step];
|
|
665
|
+
const responseId = str2(detail.response_id) ?? before?.responseId ?? null;
|
|
666
|
+
const startedAt = status === "running" ? e.created_at : before?.startedAt;
|
|
667
|
+
const action = asAction(detail.action) ?? before?.action;
|
|
668
|
+
const documents = asStrings(detail.documents) ?? before?.documents;
|
|
669
|
+
const waiting = status === "waiting" ? asRecord(detail.waiting) : void 0;
|
|
670
|
+
const output = status === "done" ? asRecord(detail.output) : void 0;
|
|
671
|
+
const approved = Array.isArray(detail.approved) ? detail.approved.filter(asRecord) : void 0;
|
|
672
|
+
const finished2 = status === "done" || status === "skipped" || status === "failed";
|
|
673
|
+
const declinedBy = str2(detail.declined_by);
|
|
604
674
|
states[step] = {
|
|
605
675
|
status,
|
|
606
|
-
responseId
|
|
607
|
-
error,
|
|
608
|
-
...startedAt ? { startedAt } : {}
|
|
676
|
+
responseId,
|
|
677
|
+
error: str2(detail.error) ?? null,
|
|
678
|
+
...startedAt ? { startedAt } : {},
|
|
679
|
+
...action ? { action } : {},
|
|
680
|
+
...documents?.length ? { documents } : {},
|
|
681
|
+
...waiting ? { waiting } : {},
|
|
682
|
+
...output ? { output } : {},
|
|
683
|
+
...approved ? { approved } : {},
|
|
684
|
+
...finished2 ? { by: e.actor_ext_id ?? null } : {},
|
|
685
|
+
...finished2 && e.created_at ? { at: e.created_at } : {},
|
|
686
|
+
...declinedBy ? { declinedBy } : {}
|
|
609
687
|
};
|
|
610
688
|
}
|
|
611
689
|
return states;
|
|
612
690
|
}
|
|
691
|
+
function stepFields(step) {
|
|
692
|
+
return step.kind === "form" ? step.inputs : step.kind === "review" ? step.fields ?? [] : [];
|
|
693
|
+
}
|
|
694
|
+
var runFieldsOf = (steps) => steps.flatMap(stepFields);
|
|
613
695
|
function runFields(workflow) {
|
|
614
|
-
return [
|
|
615
|
-
...workflow.inputs,
|
|
616
|
-
...workflowSteps(workflow).flatMap((s) => s.kind === "form" ? s.inputs : [])
|
|
617
|
-
];
|
|
696
|
+
return [...workflow.inputs, ...workflowSteps(workflow).flatMap(stepFields)];
|
|
618
697
|
}
|
|
619
698
|
function initialRunInputs(workflow, inputs = {}) {
|
|
620
699
|
return { ...defaultInputs({ ...workflow, inputs: runFields(workflow) }), ...inputs };
|
|
@@ -626,7 +705,9 @@ function stepPhase(steps, states, id) {
|
|
|
626
705
|
return stepDependencies(steps, id).every((d) => finished(states[d])) ? "ready" : "blocked";
|
|
627
706
|
}
|
|
628
707
|
var isRunFinished = (steps, states) => steps.length > 0 && steps.every((s) => finished(states[s.id]));
|
|
629
|
-
var isPersonStep = (step) => step.kind !== "agent";
|
|
708
|
+
var isPersonStep = (step) => step.kind !== "agent" && step.kind !== "action";
|
|
709
|
+
var isPersonAction = (step) => step.kind === "action" && (step.action.type === "sign" || step.action.type === "email_draft");
|
|
710
|
+
var canAssign = (step) => isPersonStep(step) || isPersonAction(step);
|
|
630
711
|
function nextAction(steps, states, current) {
|
|
631
712
|
const i = steps.findIndex((s) => s.id === current);
|
|
632
713
|
const step = steps[i];
|
|
@@ -640,20 +721,76 @@ function nextAction(steps, states, current) {
|
|
|
640
721
|
return isRunFinished(steps, states) ? "finish" : "wait";
|
|
641
722
|
}
|
|
642
723
|
if (isPersonStep(step)) return "complete";
|
|
724
|
+
if (phase === "waiting" && step.kind === "action" && step.action.type === "email_draft")
|
|
725
|
+
return "complete";
|
|
643
726
|
if (phase !== "failed") return independentNext ? "move" : "wait";
|
|
644
727
|
const waitedFor = steps.slice(i + 1).some((s) => dependsOn(steps, s.id, step.id));
|
|
645
728
|
return waitedFor || !following ? "skip" : "move";
|
|
646
729
|
}
|
|
647
730
|
function validateStep(step, inputs) {
|
|
648
|
-
|
|
731
|
+
const fields = stepFields(step);
|
|
732
|
+
if (!fields.length) return {};
|
|
649
733
|
return validateInputs(
|
|
650
734
|
{
|
|
651
735
|
id: step.id,
|
|
652
736
|
title: step.title,
|
|
653
|
-
inputs:
|
|
737
|
+
inputs: fields},
|
|
654
738
|
inputs
|
|
655
739
|
);
|
|
656
740
|
}
|
|
741
|
+
function upstreamSteps(steps, id) {
|
|
742
|
+
return steps.filter((s) => s.id !== id && dependsOn(steps, id, s.id));
|
|
743
|
+
}
|
|
744
|
+
function sendBackTargets(steps, states, id) {
|
|
745
|
+
return upstreamSteps(steps, id).filter((s) => ["done", "skipped", "failed"].includes(states[s.id]?.status ?? "pending")).reverse();
|
|
746
|
+
}
|
|
747
|
+
var isBlankRef = (ref) => "step" in ref ? !ref.step : "input" in ref ? !ref.input : !ref.id.trim();
|
|
748
|
+
function stepConfigProblems(steps) {
|
|
749
|
+
const out = [];
|
|
750
|
+
for (const s of steps) {
|
|
751
|
+
if (s.kind === "action") {
|
|
752
|
+
const a = s.action;
|
|
753
|
+
if (a.type === "sign") {
|
|
754
|
+
if (!a.document || isBlankRef(a.document)) out.push({ step: s.id, missing: "document" });
|
|
755
|
+
if (!a.signers.length) out.push({ step: s.id, missing: "signers" });
|
|
756
|
+
} else if (a.type === "email_draft") {
|
|
757
|
+
if (!a.to.some((t) => t.trim())) out.push({ step: s.id, missing: "recipients" });
|
|
758
|
+
} else {
|
|
759
|
+
if (!a.tags.length) out.push({ step: s.id, missing: "tags" });
|
|
760
|
+
if (Array.isArray(a.documents) && !a.documents.length)
|
|
761
|
+
out.push({ step: s.id, missing: "documents" });
|
|
762
|
+
}
|
|
763
|
+
}
|
|
764
|
+
if (s.kind === "agent" && s.editDocument && isBlankRef(s.editDocument))
|
|
765
|
+
out.push({ step: s.id, missing: "document" });
|
|
766
|
+
}
|
|
767
|
+
return out;
|
|
768
|
+
}
|
|
769
|
+
function splitDocRef(ref) {
|
|
770
|
+
const m = /^(doc-[A-Za-z0-9]+)(?:@v(\d+))?$/.exec(ref);
|
|
771
|
+
return m ? { id: m[1], ...m[2] ? { version: Number(m[2]) } : {} } : { id: ref };
|
|
772
|
+
}
|
|
773
|
+
var DEFAULT_ASSIGNEE_WORDING = {
|
|
774
|
+
runOwner: "whoever started the run",
|
|
775
|
+
projectLead: "the project lead",
|
|
776
|
+
input: "the person in \u201C{field}\u201D"
|
|
777
|
+
};
|
|
778
|
+
function assigneeName(assignee, options = {}) {
|
|
779
|
+
const w = { ...DEFAULT_ASSIGNEE_WORDING, ...options.wording };
|
|
780
|
+
const name = (id) => options.nameOf?.(id) ?? id;
|
|
781
|
+
const told = options.announcedTo ? options.nameOf?.(options.announcedTo) : void 0;
|
|
782
|
+
if (told) return told;
|
|
783
|
+
if (!assignee) return void 0;
|
|
784
|
+
if ("user" in assignee) return name(assignee.user);
|
|
785
|
+
if ("input" in assignee) {
|
|
786
|
+
const value = options.inputs?.[assignee.input];
|
|
787
|
+
if (typeof value === "string" && value) return name(value);
|
|
788
|
+
const label = options.fields?.find((f) => f.name === assignee.input)?.label ?? assignee.input;
|
|
789
|
+
return w.input.replace("{field}", label);
|
|
790
|
+
}
|
|
791
|
+
if ("runOwner" in assignee) return w.runOwner;
|
|
792
|
+
return w.projectLead;
|
|
793
|
+
}
|
|
657
794
|
var asText = (value) => typeof value === "string" ? value.trim() : typeof value === "number" ? String(value) : "";
|
|
658
795
|
function fillStepInputs(templates, inputs) {
|
|
659
796
|
const out = {};
|
|
@@ -700,6 +837,111 @@ function composeStepPrompt(workflow, step, runInputs, { resolveWorkflow, compose
|
|
|
700
837
|
}
|
|
701
838
|
|
|
702
839
|
// src/agents/workflows/planSteps.ts
|
|
840
|
+
function toPlanAssignee(a) {
|
|
841
|
+
if ("user" in a) return { user: a.user };
|
|
842
|
+
if ("input" in a) return { input: a.input };
|
|
843
|
+
if ("runOwner" in a) return { run_owner: true };
|
|
844
|
+
return { project_lead: true };
|
|
845
|
+
}
|
|
846
|
+
function fromPlanAssignee(a) {
|
|
847
|
+
if (!a) return void 0;
|
|
848
|
+
if (a.user) return { user: a.user };
|
|
849
|
+
if (a.input) return { input: a.input };
|
|
850
|
+
if (a.run_owner) return { runOwner: true };
|
|
851
|
+
if (a.project_lead) return { projectLead: true };
|
|
852
|
+
return void 0;
|
|
853
|
+
}
|
|
854
|
+
function toPlanDocumentRef(ref) {
|
|
855
|
+
if ("step" in ref) return { step: ref.step };
|
|
856
|
+
if ("input" in ref) return { input: ref.input };
|
|
857
|
+
return ref.id.trim();
|
|
858
|
+
}
|
|
859
|
+
function fromPlanDocumentRef(ref) {
|
|
860
|
+
if (!ref) return void 0;
|
|
861
|
+
if (typeof ref === "string") return { id: ref };
|
|
862
|
+
if (ref.step) return { step: ref.step };
|
|
863
|
+
if (ref.input) return { input: ref.input };
|
|
864
|
+
return void 0;
|
|
865
|
+
}
|
|
866
|
+
var docRefs = (refs) => (refs ?? []).map(toPlanDocumentRef);
|
|
867
|
+
var fromDocRefs = (refs) => (refs ?? []).flatMap((r) => {
|
|
868
|
+
const ref = fromPlanDocumentRef(r);
|
|
869
|
+
return ref ? [ref] : [];
|
|
870
|
+
});
|
|
871
|
+
function toPlanAction(a) {
|
|
872
|
+
switch (a.type) {
|
|
873
|
+
case "sign":
|
|
874
|
+
return {
|
|
875
|
+
type: "sign",
|
|
876
|
+
// The builder may hold a signature step whose document is not chosen yet: the server
|
|
877
|
+
// refuses it, and the builder says so before saving (`stepConfigProblems`).
|
|
878
|
+
document: a.document ? toPlanDocumentRef(a.document) : "",
|
|
879
|
+
signers: a.signers.map(toPlanAssignee),
|
|
880
|
+
...a.message?.trim() ? { message: a.message.trim() } : {},
|
|
881
|
+
...a.expiresAfterHours ? { expires_after_hours: a.expiresAfterHours } : {}
|
|
882
|
+
};
|
|
883
|
+
case "email_draft":
|
|
884
|
+
return {
|
|
885
|
+
type: "email_draft",
|
|
886
|
+
to: a.to.map((t) => t.trim()).filter(Boolean),
|
|
887
|
+
cc: (a.cc ?? []).map((t) => t.trim()).filter(Boolean),
|
|
888
|
+
subject: a.subject,
|
|
889
|
+
body_template: a.body,
|
|
890
|
+
attachments: docRefs(a.attachments)
|
|
891
|
+
};
|
|
892
|
+
case "tabular_review":
|
|
893
|
+
return {
|
|
894
|
+
type: "tabular_review",
|
|
895
|
+
tags: a.tags,
|
|
896
|
+
documents: Array.isArray(a.documents) ? docRefs(a.documents) : a.documents,
|
|
897
|
+
overwrite: !!a.overwrite
|
|
898
|
+
};
|
|
899
|
+
}
|
|
900
|
+
}
|
|
901
|
+
function fromPlanAction(a) {
|
|
902
|
+
switch (a?.type) {
|
|
903
|
+
case "sign":
|
|
904
|
+
return {
|
|
905
|
+
type: "sign",
|
|
906
|
+
document: fromPlanDocumentRef(a.document),
|
|
907
|
+
signers: (a.signers ?? []).flatMap((s) => {
|
|
908
|
+
const one = fromPlanAssignee(s);
|
|
909
|
+
return one ? [one] : [];
|
|
910
|
+
}),
|
|
911
|
+
...a.message ? { message: a.message } : {},
|
|
912
|
+
...a.expires_after_hours ? { expiresAfterHours: a.expires_after_hours } : {}
|
|
913
|
+
};
|
|
914
|
+
case "email_draft":
|
|
915
|
+
return {
|
|
916
|
+
type: "email_draft",
|
|
917
|
+
to: a.to ?? [],
|
|
918
|
+
...a.cc?.length ? { cc: a.cc } : {},
|
|
919
|
+
subject: a.subject ?? "",
|
|
920
|
+
body: a.body_template ?? "",
|
|
921
|
+
...a.attachments?.length ? { attachments: fromDocRefs(a.attachments) } : {}
|
|
922
|
+
};
|
|
923
|
+
case "tabular_review":
|
|
924
|
+
return {
|
|
925
|
+
type: "tabular_review",
|
|
926
|
+
tags: a.tags ?? [],
|
|
927
|
+
documents: Array.isArray(a.documents) ? fromDocRefs(a.documents) : a.documents ?? "run_uploads",
|
|
928
|
+
...a.overwrite ? { overwrite: true } : {}
|
|
929
|
+
};
|
|
930
|
+
default:
|
|
931
|
+
return { type: "tabular_review", tags: [], documents: "run_uploads" };
|
|
932
|
+
}
|
|
933
|
+
}
|
|
934
|
+
function toStepField(f) {
|
|
935
|
+
return {
|
|
936
|
+
name: f.name,
|
|
937
|
+
type: f.type,
|
|
938
|
+
label: f.label,
|
|
939
|
+
required: !!f.required,
|
|
940
|
+
...f.options ? { options: f.options.map((o) => ({ value: o.value, label: o.label })) } : {},
|
|
941
|
+
...f.min !== void 0 ? { min: f.min } : {},
|
|
942
|
+
...f.max !== void 0 ? { max: f.max } : {}
|
|
943
|
+
};
|
|
944
|
+
}
|
|
703
945
|
var compact2 = (o) => Object.fromEntries(Object.entries(o).filter(([, v]) => v !== void 0 && v !== ""));
|
|
704
946
|
function placeholders(workflow) {
|
|
705
947
|
return Object.fromEntries(runFields(workflow).map((f) => [f.name, `{{${f.name}}}`]));
|
|
@@ -724,7 +966,7 @@ function toPlanSteps(workflow, options = {}) {
|
|
|
724
966
|
position: layout?.[step.id],
|
|
725
967
|
...step.kind === "form" ? { fields: step.inputs } : {},
|
|
726
968
|
...step.kind === "upload" ? { required: step.required, accept: step.accept, hint: step.hint } : {},
|
|
727
|
-
...step.kind === "review" ? { instructions: step.instructions } : {},
|
|
969
|
+
...step.kind === "review" ? { instructions: step.instructions, fields: step.fields?.length ? step.fields : void 0 } : {},
|
|
728
970
|
...step.kind === "agent" ? {
|
|
729
971
|
output: step.output,
|
|
730
972
|
workflow: step.workflow,
|
|
@@ -742,6 +984,12 @@ function toPlanSteps(workflow, options = {}) {
|
|
|
742
984
|
ui,
|
|
743
985
|
// An unfinished signal (still being typed) is not saved: the server would refuse it.
|
|
744
986
|
...step.signals?.some((s) => !isIncompleteSignal(s)) ? { signals: step.signals.filter((s) => !isIncompleteSignal(s)).map(toPlanSignal) } : {},
|
|
987
|
+
...step.assignee && canAssign(step) ? { assignee: toPlanAssignee(step.assignee) } : {},
|
|
988
|
+
...step.remindAfterHours && canAssign(step) ? { remind_after_hours: step.remindAfterHours } : {},
|
|
989
|
+
// A review's fields are what approving it is checked against (the server's `fields`).
|
|
990
|
+
...step.kind === "review" && step.fields?.length ? { fields: step.fields.map(toStepField) } : {},
|
|
991
|
+
...step.kind === "action" ? { action: toPlanAction(step.action) } : {},
|
|
992
|
+
...step.kind === "agent" && step.editDocument && !step.branch ? { edit_document: toPlanDocumentRef(step.editDocument) } : {},
|
|
745
993
|
...step.kind === "agent" ? agentStep(workflow, step, options) : { skill: null, inputs: null, prompt: null }
|
|
746
994
|
};
|
|
747
995
|
});
|
|
@@ -774,7 +1022,9 @@ function fromPlanSteps(steps) {
|
|
|
774
1022
|
commit: ui.commit,
|
|
775
1023
|
nextLabel: ui.next_label,
|
|
776
1024
|
...p.after != null ? { after: p.after } : {},
|
|
777
|
-
...p.signals?.length ? { signals: p.signals.map(fromPlanSignal) } : {}
|
|
1025
|
+
...p.signals?.length ? { signals: p.signals.map(fromPlanSignal) } : {},
|
|
1026
|
+
...fromPlanAssignee(p.assignee) ? { assignee: fromPlanAssignee(p.assignee) } : {},
|
|
1027
|
+
...p.remind_after_hours ? { remindAfterHours: p.remind_after_hours } : {}
|
|
778
1028
|
};
|
|
779
1029
|
switch (p.kind) {
|
|
780
1030
|
case "form":
|
|
@@ -782,7 +1032,15 @@ function fromPlanSteps(steps) {
|
|
|
782
1032
|
case "upload":
|
|
783
1033
|
return { ...base, kind: "upload", required: ui.required, accept: ui.accept, hint: ui.hint };
|
|
784
1034
|
case "review":
|
|
785
|
-
return {
|
|
1035
|
+
return {
|
|
1036
|
+
...base,
|
|
1037
|
+
kind: "review",
|
|
1038
|
+
instructions: ui.instructions,
|
|
1039
|
+
// The client's copy of the fields (labels, options) when it kept one, else the plan's.
|
|
1040
|
+
...ui.fields?.length ? { fields: ui.fields } : p.fields?.length ? { fields: p.fields.map(fromStepField) } : {}
|
|
1041
|
+
};
|
|
1042
|
+
case "action":
|
|
1043
|
+
return { ...base, kind: "action", action: fromPlanAction(p.action) };
|
|
786
1044
|
default: {
|
|
787
1045
|
const promptTemplate = ui.prompt_template ?? p.prompt ?? void 0;
|
|
788
1046
|
return {
|
|
@@ -792,7 +1050,8 @@ function fromPlanSteps(steps) {
|
|
|
792
1050
|
with: ui.with ?? p.inputs ?? void 0,
|
|
793
1051
|
run: !ui.workflow && !p.skill && promptTemplate ? { kind: "prompt", promptTemplate } : void 0,
|
|
794
1052
|
output: ui.output,
|
|
795
|
-
branch: p.branch || void 0
|
|
1053
|
+
branch: p.branch || void 0,
|
|
1054
|
+
...fromPlanDocumentRef(p.edit_document) ? { editDocument: fromPlanDocumentRef(p.edit_document) } : {}
|
|
796
1055
|
};
|
|
797
1056
|
}
|
|
798
1057
|
}
|
|
@@ -805,25 +1064,47 @@ function layoutFromPlanSteps(steps) {
|
|
|
805
1064
|
});
|
|
806
1065
|
return entries.length ? Object.fromEntries(entries) : void 0;
|
|
807
1066
|
}
|
|
1067
|
+
var FIELD_TYPES2 = /* @__PURE__ */ new Set([
|
|
1068
|
+
"text",
|
|
1069
|
+
"longtext",
|
|
1070
|
+
"boolean",
|
|
1071
|
+
"select",
|
|
1072
|
+
"number",
|
|
1073
|
+
"date",
|
|
1074
|
+
"scope",
|
|
1075
|
+
"documents",
|
|
1076
|
+
"person"
|
|
1077
|
+
]);
|
|
1078
|
+
function fromStepField(f) {
|
|
1079
|
+
return {
|
|
1080
|
+
name: f.name,
|
|
1081
|
+
type: FIELD_TYPES2.has(f.type) ? f.type : "text",
|
|
1082
|
+
label: f.label ?? f.name,
|
|
1083
|
+
...f.required ? { required: true } : {},
|
|
1084
|
+
...f.options?.length ? { options: f.options.map((o) => ({ value: o.value, label: o.label ?? o.value })) } : {},
|
|
1085
|
+
...f.min != null ? { min: f.min } : {},
|
|
1086
|
+
...f.max != null ? { max: f.max } : {}
|
|
1087
|
+
};
|
|
1088
|
+
}
|
|
808
1089
|
var errorMessage = (e) => e instanceof Error ? e.message : typeof e === "string" ? e : "Something went wrong.";
|
|
809
1090
|
function firstOpen(steps, states) {
|
|
810
1091
|
const open = steps.find((s) => !["done", "skipped"].includes(states[s.id]?.status ?? "pending"));
|
|
811
1092
|
return open?.id ?? (steps.length && isRunFinished(steps, states) ? null : steps[0]?.id ?? null);
|
|
812
1093
|
}
|
|
813
1094
|
function useWorkflowView(options) {
|
|
814
|
-
const { steps, states, inputs, setInput } = options;
|
|
1095
|
+
const { steps, states, inputs, setInput, loaded = true } = options;
|
|
815
1096
|
const [current, setCurrent] = react.useState(() => firstOpen(steps, states));
|
|
816
1097
|
const [showErrors, setShowErrors] = react.useState(false);
|
|
817
1098
|
const [busy, setBusy] = react.useState(false);
|
|
818
1099
|
const [actionError, setActionError] = react.useState(null);
|
|
819
1100
|
const optionsRef = react.useRef(options);
|
|
820
1101
|
optionsRef.current = options;
|
|
821
|
-
const placed = react.useRef(steps.length > 0);
|
|
1102
|
+
const placed = react.useRef(steps.length > 0 && loaded);
|
|
822
1103
|
react.useEffect(() => {
|
|
823
|
-
if (placed.current || steps.length === 0) return;
|
|
1104
|
+
if (placed.current || steps.length === 0 || !loaded) return;
|
|
824
1105
|
placed.current = true;
|
|
825
1106
|
setCurrent(firstOpen(steps, states));
|
|
826
|
-
}, [steps, states]);
|
|
1107
|
+
}, [steps, states, loaded]);
|
|
827
1108
|
const step = steps.find((s) => s.id === current);
|
|
828
1109
|
const following = react.useCallback(
|
|
829
1110
|
(id) => {
|
|
@@ -911,6 +1192,40 @@ function useWorkflowView(options) {
|
|
|
911
1192
|
// eslint-disable-next-line react-hooks/exhaustive-deps
|
|
912
1193
|
[act, !!options.retry]
|
|
913
1194
|
);
|
|
1195
|
+
const sendBack = react.useMemo(
|
|
1196
|
+
() => options.sendBack ? async (stepId, to, note) => {
|
|
1197
|
+
setBusy(true);
|
|
1198
|
+
setActionError(null);
|
|
1199
|
+
try {
|
|
1200
|
+
await optionsRef.current.sendBack?.(stepId, to, note);
|
|
1201
|
+
setShowErrors(false);
|
|
1202
|
+
setCurrent(to);
|
|
1203
|
+
} catch (e) {
|
|
1204
|
+
setActionError(errorMessage(e));
|
|
1205
|
+
} finally {
|
|
1206
|
+
setBusy(false);
|
|
1207
|
+
}
|
|
1208
|
+
} : void 0,
|
|
1209
|
+
// Only whether the host offers it matters here.
|
|
1210
|
+
// eslint-disable-next-line react-hooks/exhaustive-deps
|
|
1211
|
+
[!!options.sendBack]
|
|
1212
|
+
);
|
|
1213
|
+
const declineWithNote = react.useMemo(
|
|
1214
|
+
() => options.decline ? async (stepId, note) => {
|
|
1215
|
+
setBusy(true);
|
|
1216
|
+
setActionError(null);
|
|
1217
|
+
try {
|
|
1218
|
+
await optionsRef.current.decline?.(stepId, note);
|
|
1219
|
+
} catch (e) {
|
|
1220
|
+
setActionError(errorMessage(e));
|
|
1221
|
+
} finally {
|
|
1222
|
+
setBusy(false);
|
|
1223
|
+
}
|
|
1224
|
+
} : void 0,
|
|
1225
|
+
// Only whether the host offers it matters here.
|
|
1226
|
+
// eslint-disable-next-line react-hooks/exhaustive-deps
|
|
1227
|
+
[!!options.decline]
|
|
1228
|
+
);
|
|
914
1229
|
const isLocked = react.useCallback(
|
|
915
1230
|
(stepId) => optionsRef.current.isLocked?.(stepId) ?? false,
|
|
916
1231
|
[]
|
|
@@ -936,6 +1251,19 @@ function useWorkflowView(options) {
|
|
|
936
1251
|
goTo,
|
|
937
1252
|
skip,
|
|
938
1253
|
retry,
|
|
1254
|
+
sendBack,
|
|
1255
|
+
decline: declineWithNote,
|
|
1256
|
+
nameOf: options.nameOf,
|
|
1257
|
+
assigneeOf: (id) => {
|
|
1258
|
+
const s = steps.find((x) => x.id === id);
|
|
1259
|
+
if (!s || !canAssign(s)) return void 0;
|
|
1260
|
+
return assigneeName(s.assignee, {
|
|
1261
|
+
nameOf: options.nameOf,
|
|
1262
|
+
inputs,
|
|
1263
|
+
fields: runFieldsOf(steps),
|
|
1264
|
+
announcedTo: states[id]?.announcedTo
|
|
1265
|
+
});
|
|
1266
|
+
},
|
|
939
1267
|
restart: () => {
|
|
940
1268
|
setShowErrors(false);
|
|
941
1269
|
setActionError(null);
|
|
@@ -943,9 +1271,489 @@ function useWorkflowView(options) {
|
|
|
943
1271
|
}
|
|
944
1272
|
};
|
|
945
1273
|
}
|
|
1274
|
+
var DEFAULT_WORKFLOW_STEP_PARTS_LABELS = {
|
|
1275
|
+
waitingFor: "Waiting for {name}",
|
|
1276
|
+
sendBack: "Send back",
|
|
1277
|
+
sendBackTo: "Send back to",
|
|
1278
|
+
sendBackNote: "What needs to change? (optional)",
|
|
1279
|
+
cancel: "Cancel",
|
|
1280
|
+
sentBackHere: "This step was sent back to be done again.",
|
|
1281
|
+
approvedBy: "Approved by {name}",
|
|
1282
|
+
approvedAt: "{date}",
|
|
1283
|
+
approvedWhat: "What was approved",
|
|
1284
|
+
viewAnswer: "View the answer",
|
|
1285
|
+
fieldsHeading: "Recorded with the approval",
|
|
1286
|
+
signers: "Signers",
|
|
1287
|
+
signed: "Signed",
|
|
1288
|
+
notSigned: "Not signed yet",
|
|
1289
|
+
openAndSign: "Open and sign",
|
|
1290
|
+
decline: "Decline",
|
|
1291
|
+
declineNote: "Why are you declining? (optional)",
|
|
1292
|
+
declineConfirm: "Decline to sign",
|
|
1293
|
+
declined: "Declined by {name}.",
|
|
1294
|
+
signedVersion: "Open the signed version",
|
|
1295
|
+
preparingSign: "Preparing the signature request\u2026",
|
|
1296
|
+
expires: "Expires {date}",
|
|
1297
|
+
preparingDraft: "Preparing the draft\u2026",
|
|
1298
|
+
draftReady: "The draft is ready in native mail. Check it, send it, then mark it as sent.",
|
|
1299
|
+
openDraft: "Open draft",
|
|
1300
|
+
emailSent: "Sent.",
|
|
1301
|
+
reviewRunning: "Reviewing the documents\u2026",
|
|
1302
|
+
reviewDone: "Reviewed {docs} documents in {cols} columns.",
|
|
1303
|
+
openReview: "Open the review",
|
|
1304
|
+
openInWord: "Open in Word",
|
|
1305
|
+
redlineHint: "The edits are tracked changes: accept or reject each one in Word.",
|
|
1306
|
+
someone: "someone"
|
|
1307
|
+
};
|
|
1308
|
+
var formatDate = (iso) => {
|
|
1309
|
+
const t = iso ? Date.parse(iso) : NaN;
|
|
1310
|
+
return Number.isNaN(t) ? "" : new Date(t).toLocaleString(void 0, { dateStyle: "medium", timeStyle: "short" });
|
|
1311
|
+
};
|
|
1312
|
+
var docName = (ref, nameOfDoc) => {
|
|
1313
|
+
const { id, version } = splitDocRef(ref);
|
|
1314
|
+
const name = nameOfDoc?.(id) ?? id;
|
|
1315
|
+
return version ? `${name} \xB7 v${version}` : name;
|
|
1316
|
+
};
|
|
1317
|
+
function DocChip({
|
|
1318
|
+
docRef,
|
|
1319
|
+
actions,
|
|
1320
|
+
nameOfDoc,
|
|
1321
|
+
testId
|
|
1322
|
+
}) {
|
|
1323
|
+
const label = docName(docRef, nameOfDoc);
|
|
1324
|
+
const cls = "inline-flex max-w-full items-center gap-1 rounded-md border border-border px-1.5 py-0.5 text-xs";
|
|
1325
|
+
return actions?.openDocument ? /* @__PURE__ */ jsxRuntime.jsxs(
|
|
1326
|
+
"button",
|
|
1327
|
+
{
|
|
1328
|
+
type: "button",
|
|
1329
|
+
onClick: () => actions.openDocument?.(docRef),
|
|
1330
|
+
className: ui.cn(cls, "hover:border-primary/40 hover:text-primary"),
|
|
1331
|
+
title: docRef,
|
|
1332
|
+
"data-testid": testId,
|
|
1333
|
+
children: [
|
|
1334
|
+
/* @__PURE__ */ jsxRuntime.jsx(lucideReact.FileText, { className: "size-3 shrink-0" }),
|
|
1335
|
+
" ",
|
|
1336
|
+
/* @__PURE__ */ jsxRuntime.jsx("span", { className: "truncate", children: label })
|
|
1337
|
+
]
|
|
1338
|
+
}
|
|
1339
|
+
) : /* @__PURE__ */ jsxRuntime.jsxs("span", { className: cls, title: docRef, "data-testid": testId, children: [
|
|
1340
|
+
/* @__PURE__ */ jsxRuntime.jsx(lucideReact.FileText, { className: "size-3 shrink-0" }),
|
|
1341
|
+
" ",
|
|
1342
|
+
/* @__PURE__ */ jsxRuntime.jsx("span", { className: "truncate", children: label })
|
|
1343
|
+
] });
|
|
1344
|
+
}
|
|
1345
|
+
function AssigneeLine({
|
|
1346
|
+
run,
|
|
1347
|
+
stepId,
|
|
1348
|
+
l,
|
|
1349
|
+
testId
|
|
1350
|
+
}) {
|
|
1351
|
+
const name = run.assigneeOf(stepId);
|
|
1352
|
+
const phase = run.phaseOf(stepId);
|
|
1353
|
+
if (!name || !["ready", "waiting", "blocked"].includes(phase)) return null;
|
|
1354
|
+
return /* @__PURE__ */ jsxRuntime.jsxs(
|
|
1355
|
+
"p",
|
|
1356
|
+
{
|
|
1357
|
+
className: "flex items-center gap-1.5 text-xs text-muted-foreground",
|
|
1358
|
+
"data-testid": `${testId}-assignee`,
|
|
1359
|
+
children: [
|
|
1360
|
+
/* @__PURE__ */ jsxRuntime.jsx(lucideReact.UserRound, { className: "size-3.5" }),
|
|
1361
|
+
" ",
|
|
1362
|
+
l.waitingFor.replace("{name}", name)
|
|
1363
|
+
]
|
|
1364
|
+
}
|
|
1365
|
+
);
|
|
1366
|
+
}
|
|
1367
|
+
function SentBackNote({
|
|
1368
|
+
state,
|
|
1369
|
+
l,
|
|
1370
|
+
testId
|
|
1371
|
+
}) {
|
|
1372
|
+
if (!state?.sentBack) return null;
|
|
1373
|
+
return /* @__PURE__ */ jsxRuntime.jsxs(
|
|
1374
|
+
"p",
|
|
1375
|
+
{
|
|
1376
|
+
className: "flex items-center gap-1.5 rounded-md bg-amber-500/10 px-2 py-1 text-xs text-amber-700 dark:text-amber-300",
|
|
1377
|
+
"data-testid": `${testId}-sent-back`,
|
|
1378
|
+
children: [
|
|
1379
|
+
/* @__PURE__ */ jsxRuntime.jsx(lucideReact.CornerUpLeft, { className: "size-3.5" }),
|
|
1380
|
+
" ",
|
|
1381
|
+
l.sentBackHere
|
|
1382
|
+
]
|
|
1383
|
+
}
|
|
1384
|
+
);
|
|
1385
|
+
}
|
|
1386
|
+
function SendBackControl({
|
|
1387
|
+
run,
|
|
1388
|
+
step,
|
|
1389
|
+
l,
|
|
1390
|
+
testId
|
|
1391
|
+
}) {
|
|
1392
|
+
const states = Object.fromEntries(
|
|
1393
|
+
run.steps.map((s) => [s.id, run.stateOf(s.id) ?? { status: "pending" }])
|
|
1394
|
+
);
|
|
1395
|
+
const targets = sendBackTargets(run.steps, states, step.id);
|
|
1396
|
+
const [open, setOpen] = react.useState(false);
|
|
1397
|
+
const [to, setTo] = react.useState(targets[0]?.id ?? "");
|
|
1398
|
+
const [note, setNote] = react.useState("");
|
|
1399
|
+
if (!run.sendBack || run.phaseOf(step.id) !== "ready" || targets.length === 0) return null;
|
|
1400
|
+
if (!open)
|
|
1401
|
+
return /* @__PURE__ */ jsxRuntime.jsxs(
|
|
1402
|
+
ui.Button,
|
|
1403
|
+
{
|
|
1404
|
+
variant: "outline",
|
|
1405
|
+
size: "sm",
|
|
1406
|
+
onClick: () => setOpen(true),
|
|
1407
|
+
disabled: run.busy,
|
|
1408
|
+
"data-testid": `${testId}-send-back`,
|
|
1409
|
+
children: [
|
|
1410
|
+
/* @__PURE__ */ jsxRuntime.jsx(lucideReact.CornerUpLeft, { className: "size-4" }),
|
|
1411
|
+
" ",
|
|
1412
|
+
l.sendBack
|
|
1413
|
+
]
|
|
1414
|
+
}
|
|
1415
|
+
);
|
|
1416
|
+
const target = targets.some((t) => t.id === to) ? to : targets[0].id;
|
|
1417
|
+
return /* @__PURE__ */ jsxRuntime.jsxs(
|
|
1418
|
+
"div",
|
|
1419
|
+
{
|
|
1420
|
+
className: "space-y-2 rounded-md border border-border p-3",
|
|
1421
|
+
"data-testid": `${testId}-send-back-form`,
|
|
1422
|
+
children: [
|
|
1423
|
+
/* @__PURE__ */ jsxRuntime.jsxs("label", { className: "block space-y-1 text-xs font-medium", children: [
|
|
1424
|
+
l.sendBackTo,
|
|
1425
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
1426
|
+
"select",
|
|
1427
|
+
{
|
|
1428
|
+
className: "flex h-8 w-full rounded-md border border-input bg-background px-2 text-sm",
|
|
1429
|
+
value: target,
|
|
1430
|
+
onChange: (e) => setTo(e.target.value),
|
|
1431
|
+
"data-testid": `${testId}-send-back-to`,
|
|
1432
|
+
children: targets.map((t) => /* @__PURE__ */ jsxRuntime.jsx("option", { value: t.id, children: t.title }, t.id))
|
|
1433
|
+
}
|
|
1434
|
+
)
|
|
1435
|
+
] }),
|
|
1436
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
1437
|
+
ui.Textarea,
|
|
1438
|
+
{
|
|
1439
|
+
rows: 3,
|
|
1440
|
+
value: note,
|
|
1441
|
+
placeholder: l.sendBackNote,
|
|
1442
|
+
"aria-label": l.sendBackNote,
|
|
1443
|
+
onChange: (e) => setNote(e.target.value),
|
|
1444
|
+
"data-testid": `${testId}-send-back-note`
|
|
1445
|
+
}
|
|
1446
|
+
),
|
|
1447
|
+
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex justify-end gap-2", children: [
|
|
1448
|
+
/* @__PURE__ */ jsxRuntime.jsx(ui.Button, { variant: "ghost", size: "sm", onClick: () => setOpen(false), children: l.cancel }),
|
|
1449
|
+
/* @__PURE__ */ jsxRuntime.jsxs(
|
|
1450
|
+
ui.Button,
|
|
1451
|
+
{
|
|
1452
|
+
size: "sm",
|
|
1453
|
+
disabled: run.busy,
|
|
1454
|
+
onClick: () => void run.sendBack?.(step.id, target, note.trim() || void 0),
|
|
1455
|
+
"data-testid": `${testId}-send-back-confirm`,
|
|
1456
|
+
children: [
|
|
1457
|
+
/* @__PURE__ */ jsxRuntime.jsx(lucideReact.CornerUpLeft, { className: "size-4" }),
|
|
1458
|
+
" ",
|
|
1459
|
+
l.sendBack
|
|
1460
|
+
]
|
|
1461
|
+
}
|
|
1462
|
+
)
|
|
1463
|
+
] })
|
|
1464
|
+
]
|
|
1465
|
+
}
|
|
1466
|
+
);
|
|
1467
|
+
}
|
|
1468
|
+
var shownValue = (v, field, nameOf) => {
|
|
1469
|
+
if (v === void 0 || v === null || v === "") return "\u2014";
|
|
1470
|
+
if (typeof v === "boolean") return v ? "\u2713" : "\u2717";
|
|
1471
|
+
if (field.type === "person" && typeof v === "string") return nameOf?.(v) ?? v;
|
|
1472
|
+
if (field.type === "select") return field.options?.find((o) => o.value === v)?.label ?? String(v);
|
|
1473
|
+
return typeof v === "object" ? JSON.stringify(v) : String(v);
|
|
1474
|
+
};
|
|
1475
|
+
function ApprovalEvidence({
|
|
1476
|
+
run,
|
|
1477
|
+
step,
|
|
1478
|
+
actions,
|
|
1479
|
+
nameOfDoc,
|
|
1480
|
+
l,
|
|
1481
|
+
testId
|
|
1482
|
+
}) {
|
|
1483
|
+
const state = run.stateOf(step.id);
|
|
1484
|
+
if (state?.status !== "done") return null;
|
|
1485
|
+
const approver = state.by ? run.nameOf?.(state.by) ?? l.someone : void 0;
|
|
1486
|
+
const evidence = state.approved ?? [];
|
|
1487
|
+
const titleOf = (id) => run.steps.find((s) => s.id === id)?.title ?? id;
|
|
1488
|
+
return /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "space-y-2 rounded-md bg-muted/40 p-3", "data-testid": `${testId}-evidence`, children: [
|
|
1489
|
+
/* @__PURE__ */ jsxRuntime.jsxs("p", { className: "flex flex-wrap items-center gap-1.5 text-sm font-medium", children: [
|
|
1490
|
+
/* @__PURE__ */ jsxRuntime.jsx(lucideReact.ShieldCheck, { className: "size-4 text-primary" }),
|
|
1491
|
+
approver ? l.approvedBy.replace("{name}", approver) : null,
|
|
1492
|
+
state.at && /* @__PURE__ */ jsxRuntime.jsx("span", { className: "text-xs font-normal text-muted-foreground", children: l.approvedAt.replace("{date}", formatDate(state.at)) })
|
|
1493
|
+
] }),
|
|
1494
|
+
evidence.length > 0 && /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "space-y-1.5", children: [
|
|
1495
|
+
/* @__PURE__ */ jsxRuntime.jsx("p", { className: "text-xs font-semibold uppercase tracking-wide text-muted-foreground", children: l.approvedWhat }),
|
|
1496
|
+
evidence.map((e) => /* @__PURE__ */ jsxRuntime.jsxs(
|
|
1497
|
+
"div",
|
|
1498
|
+
{
|
|
1499
|
+
className: "flex flex-wrap items-center gap-1.5 text-xs",
|
|
1500
|
+
"data-testid": `${testId}-evidence-${e.step}`,
|
|
1501
|
+
children: [
|
|
1502
|
+
/* @__PURE__ */ jsxRuntime.jsx("span", { className: "font-medium", children: titleOf(e.step) }),
|
|
1503
|
+
e.response_id && (actions?.openMessage ? /* @__PURE__ */ jsxRuntime.jsxs(
|
|
1504
|
+
"button",
|
|
1505
|
+
{
|
|
1506
|
+
type: "button",
|
|
1507
|
+
onClick: () => actions.openMessage?.(e.response_id),
|
|
1508
|
+
className: "inline-flex items-center gap-1 text-primary hover:underline",
|
|
1509
|
+
"data-testid": `${testId}-evidence-${e.step}-answer`,
|
|
1510
|
+
children: [
|
|
1511
|
+
/* @__PURE__ */ jsxRuntime.jsx(lucideReact.MessageSquare, { className: "size-3" }),
|
|
1512
|
+
" ",
|
|
1513
|
+
l.viewAnswer
|
|
1514
|
+
]
|
|
1515
|
+
}
|
|
1516
|
+
) : null),
|
|
1517
|
+
(e.documents ?? []).map((d) => /* @__PURE__ */ jsxRuntime.jsx(DocChip, { docRef: d, actions, nameOfDoc }, d))
|
|
1518
|
+
]
|
|
1519
|
+
},
|
|
1520
|
+
e.step
|
|
1521
|
+
))
|
|
1522
|
+
] }),
|
|
1523
|
+
(step.fields ?? []).length > 0 && /* @__PURE__ */ jsxRuntime.jsx("dl", { className: "grid grid-cols-[auto_1fr] gap-x-3 gap-y-0.5 text-xs", children: (step.fields ?? []).map((f) => /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "contents", children: [
|
|
1524
|
+
/* @__PURE__ */ jsxRuntime.jsx("dt", { className: "text-muted-foreground", children: f.label }),
|
|
1525
|
+
/* @__PURE__ */ jsxRuntime.jsx("dd", { "data-testid": `${testId}-evidence-field-${f.name}`, children: shownValue(run.inputs[f.name], f, run.nameOf) })
|
|
1526
|
+
] }, f.name)) })
|
|
1527
|
+
] });
|
|
1528
|
+
}
|
|
1529
|
+
function RedlineOpen({
|
|
1530
|
+
step,
|
|
1531
|
+
state,
|
|
1532
|
+
actions,
|
|
1533
|
+
l,
|
|
1534
|
+
testId
|
|
1535
|
+
}) {
|
|
1536
|
+
const version = state?.status === "done" ? state.documents?.[0] : void 0;
|
|
1537
|
+
if (!step.editDocument || !version || !actions?.openRedline) return null;
|
|
1538
|
+
return /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex flex-wrap items-center gap-2", "data-testid": `${testId}-redline`, children: [
|
|
1539
|
+
/* @__PURE__ */ jsxRuntime.jsxs(
|
|
1540
|
+
ui.Button,
|
|
1541
|
+
{
|
|
1542
|
+
size: "sm",
|
|
1543
|
+
onClick: () => actions.openRedline?.(version),
|
|
1544
|
+
"data-testid": `${testId}-open-word`,
|
|
1545
|
+
children: [
|
|
1546
|
+
/* @__PURE__ */ jsxRuntime.jsx(lucideReact.FileText, { className: "size-4" }),
|
|
1547
|
+
" ",
|
|
1548
|
+
l.openInWord
|
|
1549
|
+
]
|
|
1550
|
+
}
|
|
1551
|
+
),
|
|
1552
|
+
/* @__PURE__ */ jsxRuntime.jsx("span", { className: "text-xs text-muted-foreground", children: l.redlineHint })
|
|
1553
|
+
] });
|
|
1554
|
+
}
|
|
1555
|
+
function ActionStepBody({
|
|
1556
|
+
step,
|
|
1557
|
+
run,
|
|
1558
|
+
actions,
|
|
1559
|
+
nameOfDoc,
|
|
1560
|
+
heading,
|
|
1561
|
+
l,
|
|
1562
|
+
testId
|
|
1563
|
+
}) {
|
|
1564
|
+
const state = run.stateOf(step.id);
|
|
1565
|
+
const phase = run.phaseOf(step.id);
|
|
1566
|
+
const name = (id) => run.nameOf?.(id) ?? id;
|
|
1567
|
+
const [declining, setDeclining] = react.useState(false);
|
|
1568
|
+
const [note, setNote] = react.useState("");
|
|
1569
|
+
const a = step.action;
|
|
1570
|
+
const working = (text) => /* @__PURE__ */ jsxRuntime.jsxs(
|
|
1571
|
+
"p",
|
|
1572
|
+
{
|
|
1573
|
+
className: "flex items-center gap-2 text-sm text-muted-foreground",
|
|
1574
|
+
"data-testid": `${testId}-working`,
|
|
1575
|
+
children: [
|
|
1576
|
+
/* @__PURE__ */ jsxRuntime.jsx(lucideReact.Loader2, { className: "size-4 animate-spin" }),
|
|
1577
|
+
" ",
|
|
1578
|
+
text
|
|
1579
|
+
]
|
|
1580
|
+
}
|
|
1581
|
+
);
|
|
1582
|
+
let body = null;
|
|
1583
|
+
if (a.type === "sign") {
|
|
1584
|
+
const waiting = state?.waiting;
|
|
1585
|
+
const signers = waiting?.signers ?? [];
|
|
1586
|
+
const signed = new Set(waiting?.signed ?? []);
|
|
1587
|
+
const mine = !actions?.me || signers.includes(actions.me) && !signed.has(actions.me);
|
|
1588
|
+
const signedRef = state?.status === "done" ? state.documents?.[0] : void 0;
|
|
1589
|
+
body = /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
|
|
1590
|
+
(phase === "ready" || phase === "running") && working(l.preparingSign),
|
|
1591
|
+
phase === "waiting" && waiting?.doc_ext_id && /* @__PURE__ */ jsxRuntime.jsx(
|
|
1592
|
+
DocChip,
|
|
1593
|
+
{
|
|
1594
|
+
docRef: `${waiting.doc_ext_id}${waiting.version ? `@v${waiting.version}` : ""}`,
|
|
1595
|
+
actions,
|
|
1596
|
+
nameOfDoc,
|
|
1597
|
+
testId: `${testId}-document`
|
|
1598
|
+
}
|
|
1599
|
+
),
|
|
1600
|
+
signers.length > 0 && /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "space-y-1", "data-testid": `${testId}-signers`, children: [
|
|
1601
|
+
/* @__PURE__ */ jsxRuntime.jsx("p", { className: "text-xs font-semibold uppercase tracking-wide text-muted-foreground", children: l.signers }),
|
|
1602
|
+
signers.map((id) => /* @__PURE__ */ jsxRuntime.jsxs(
|
|
1603
|
+
"p",
|
|
1604
|
+
{
|
|
1605
|
+
className: "flex items-center gap-2 text-sm",
|
|
1606
|
+
"data-signed": signed.has(id) || void 0,
|
|
1607
|
+
"data-testid": `${testId}-signer-${id}`,
|
|
1608
|
+
children: [
|
|
1609
|
+
signed.has(id) ? /* @__PURE__ */ jsxRuntime.jsx(lucideReact.Check, { className: "size-3.5 text-primary" }) : /* @__PURE__ */ jsxRuntime.jsx(lucideReact.Hourglass, { className: "size-3.5 text-muted-foreground" }),
|
|
1610
|
+
/* @__PURE__ */ jsxRuntime.jsx("span", { className: "font-medium", children: name(id) }),
|
|
1611
|
+
/* @__PURE__ */ jsxRuntime.jsx("span", { className: "text-xs text-muted-foreground", children: signed.has(id) ? l.signed : l.notSigned })
|
|
1612
|
+
]
|
|
1613
|
+
},
|
|
1614
|
+
id
|
|
1615
|
+
))
|
|
1616
|
+
] }),
|
|
1617
|
+
waiting?.expires_at && phase === "waiting" && /* @__PURE__ */ jsxRuntime.jsxs("p", { className: "flex items-center gap-1.5 text-xs text-muted-foreground", children: [
|
|
1618
|
+
/* @__PURE__ */ jsxRuntime.jsx(lucideReact.Clock, { className: "size-3.5" }),
|
|
1619
|
+
" ",
|
|
1620
|
+
l.expires.replace("{date}", formatDate(waiting.expires_at))
|
|
1621
|
+
] }),
|
|
1622
|
+
phase === "waiting" && mine && !declining && /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex flex-wrap gap-2", children: [
|
|
1623
|
+
actions?.sign && state && /* @__PURE__ */ jsxRuntime.jsxs(
|
|
1624
|
+
ui.Button,
|
|
1625
|
+
{
|
|
1626
|
+
size: "sm",
|
|
1627
|
+
onClick: () => actions.sign?.(step, state),
|
|
1628
|
+
"data-testid": `${testId}-open-sign`,
|
|
1629
|
+
children: [
|
|
1630
|
+
/* @__PURE__ */ jsxRuntime.jsx(lucideReact.PenLine, { className: "size-4" }),
|
|
1631
|
+
" ",
|
|
1632
|
+
l.openAndSign
|
|
1633
|
+
]
|
|
1634
|
+
}
|
|
1635
|
+
),
|
|
1636
|
+
run.decline && /* @__PURE__ */ jsxRuntime.jsxs(
|
|
1637
|
+
ui.Button,
|
|
1638
|
+
{
|
|
1639
|
+
size: "sm",
|
|
1640
|
+
variant: "ghost",
|
|
1641
|
+
onClick: () => setDeclining(true),
|
|
1642
|
+
"data-testid": `${testId}-decline`,
|
|
1643
|
+
children: [
|
|
1644
|
+
/* @__PURE__ */ jsxRuntime.jsx(lucideReact.X, { className: "size-4" }),
|
|
1645
|
+
" ",
|
|
1646
|
+
l.decline
|
|
1647
|
+
]
|
|
1648
|
+
}
|
|
1649
|
+
)
|
|
1650
|
+
] }),
|
|
1651
|
+
declining && /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "space-y-2", "data-testid": `${testId}-decline-form`, children: [
|
|
1652
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
1653
|
+
ui.Textarea,
|
|
1654
|
+
{
|
|
1655
|
+
rows: 2,
|
|
1656
|
+
value: note,
|
|
1657
|
+
placeholder: l.declineNote,
|
|
1658
|
+
"aria-label": l.declineNote,
|
|
1659
|
+
onChange: (e) => setNote(e.target.value),
|
|
1660
|
+
"data-testid": `${testId}-decline-note`
|
|
1661
|
+
}
|
|
1662
|
+
),
|
|
1663
|
+
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex justify-end gap-2", children: [
|
|
1664
|
+
/* @__PURE__ */ jsxRuntime.jsx(ui.Button, { variant: "ghost", size: "sm", onClick: () => setDeclining(false), children: l.cancel }),
|
|
1665
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
1666
|
+
ui.Button,
|
|
1667
|
+
{
|
|
1668
|
+
size: "sm",
|
|
1669
|
+
variant: "destructive",
|
|
1670
|
+
disabled: run.busy,
|
|
1671
|
+
onClick: async () => {
|
|
1672
|
+
await run.decline?.(step.id, note.trim() || void 0);
|
|
1673
|
+
setDeclining(false);
|
|
1674
|
+
},
|
|
1675
|
+
"data-testid": `${testId}-decline-confirm`,
|
|
1676
|
+
children: l.declineConfirm
|
|
1677
|
+
}
|
|
1678
|
+
)
|
|
1679
|
+
] })
|
|
1680
|
+
] }),
|
|
1681
|
+
phase === "failed" && state?.declinedBy && /* @__PURE__ */ jsxRuntime.jsx("p", { className: "text-sm text-destructive", "data-testid": `${testId}-declined`, children: l.declined.replace("{name}", name(state.declinedBy)) }),
|
|
1682
|
+
signedRef && /* @__PURE__ */ jsxRuntime.jsx("div", { className: "flex flex-wrap items-center gap-2", children: actions?.openDocument ? /* @__PURE__ */ jsxRuntime.jsxs(
|
|
1683
|
+
ui.Button,
|
|
1684
|
+
{
|
|
1685
|
+
size: "sm",
|
|
1686
|
+
variant: "outline",
|
|
1687
|
+
onClick: () => actions.openDocument?.(signedRef),
|
|
1688
|
+
"data-testid": `${testId}-signed-version`,
|
|
1689
|
+
children: [
|
|
1690
|
+
/* @__PURE__ */ jsxRuntime.jsx(lucideReact.ExternalLink, { className: "size-4" }),
|
|
1691
|
+
" ",
|
|
1692
|
+
l.signedVersion
|
|
1693
|
+
]
|
|
1694
|
+
}
|
|
1695
|
+
) : /* @__PURE__ */ jsxRuntime.jsx(DocChip, { docRef: signedRef, nameOfDoc }) })
|
|
1696
|
+
] });
|
|
1697
|
+
} else if (a.type === "email_draft") {
|
|
1698
|
+
const draftId = state?.waiting?.draft_id ?? (typeof state?.output?.draft_id === "string" ? state.output.draft_id : void 0);
|
|
1699
|
+
body = /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
|
|
1700
|
+
(phase === "ready" || phase === "running") && working(l.preparingDraft),
|
|
1701
|
+
phase === "waiting" && /* @__PURE__ */ jsxRuntime.jsx("p", { className: "text-sm text-muted-foreground", children: l.draftReady }),
|
|
1702
|
+
phase === "done" && /* @__PURE__ */ jsxRuntime.jsxs("p", { className: "flex items-center gap-1.5 text-sm", "data-testid": `${testId}-sent`, children: [
|
|
1703
|
+
/* @__PURE__ */ jsxRuntime.jsx(lucideReact.Check, { className: "size-4 text-primary" }),
|
|
1704
|
+
" ",
|
|
1705
|
+
l.emailSent
|
|
1706
|
+
] }),
|
|
1707
|
+
draftId && actions?.openDraft && phase !== "done" && /* @__PURE__ */ jsxRuntime.jsxs(
|
|
1708
|
+
ui.Button,
|
|
1709
|
+
{
|
|
1710
|
+
size: "sm",
|
|
1711
|
+
variant: "outline",
|
|
1712
|
+
onClick: () => actions.openDraft?.(draftId, state?.waiting?.mailbox),
|
|
1713
|
+
"data-testid": `${testId}-open-draft`,
|
|
1714
|
+
children: [
|
|
1715
|
+
/* @__PURE__ */ jsxRuntime.jsx(lucideReact.Mail, { className: "size-4" }),
|
|
1716
|
+
" ",
|
|
1717
|
+
l.openDraft
|
|
1718
|
+
]
|
|
1719
|
+
}
|
|
1720
|
+
)
|
|
1721
|
+
] });
|
|
1722
|
+
} else {
|
|
1723
|
+
const tags = state?.output?.tag_ext_ids ?? a.tags;
|
|
1724
|
+
const docs = state?.output?.doc_ext_ids ?? [];
|
|
1725
|
+
body = /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
|
|
1726
|
+
(phase === "ready" || phase === "running") && working(l.reviewRunning),
|
|
1727
|
+
phase === "done" && /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
|
|
1728
|
+
/* @__PURE__ */ jsxRuntime.jsx("p", { className: "text-sm text-muted-foreground", "data-testid": `${testId}-reviewed`, children: l.reviewDone.replace("{docs}", String(docs.length)).replace("{cols}", String(tags.length)) }),
|
|
1729
|
+
actions?.openReview && /* @__PURE__ */ jsxRuntime.jsxs(
|
|
1730
|
+
ui.Button,
|
|
1731
|
+
{
|
|
1732
|
+
size: "sm",
|
|
1733
|
+
onClick: () => actions.openReview?.(tags, docs),
|
|
1734
|
+
"data-testid": `${testId}-open-review`,
|
|
1735
|
+
children: [
|
|
1736
|
+
/* @__PURE__ */ jsxRuntime.jsx(lucideReact.Table2, { className: "size-4" }),
|
|
1737
|
+
" ",
|
|
1738
|
+
l.openReview
|
|
1739
|
+
]
|
|
1740
|
+
}
|
|
1741
|
+
)
|
|
1742
|
+
] })
|
|
1743
|
+
] });
|
|
1744
|
+
}
|
|
1745
|
+
return /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "space-y-3", children: [
|
|
1746
|
+
heading,
|
|
1747
|
+
/* @__PURE__ */ jsxRuntime.jsx(SentBackNote, { state, l, testId }),
|
|
1748
|
+
/* @__PURE__ */ jsxRuntime.jsx(AssigneeLine, { run, stepId: step.id, l, testId }),
|
|
1749
|
+
body,
|
|
1750
|
+
phase === "failed" && !state?.declinedBy && /* @__PURE__ */ jsxRuntime.jsx("p", { className: "text-sm text-destructive", "data-testid": `${testId}-failed`, children: state?.error || "" })
|
|
1751
|
+
] });
|
|
1752
|
+
}
|
|
946
1753
|
function PhaseMark({ phase, icon }) {
|
|
947
1754
|
if (phase === "done") return /* @__PURE__ */ jsxRuntime.jsx(lucideReact.Check, { className: "size-3.5 shrink-0" });
|
|
948
1755
|
if (phase === "running") return /* @__PURE__ */ jsxRuntime.jsx(lucideReact.Loader2, { className: "size-3.5 shrink-0 animate-spin" });
|
|
1756
|
+
if (phase === "waiting") return /* @__PURE__ */ jsxRuntime.jsx(lucideReact.Hourglass, { className: "size-3.5 shrink-0" });
|
|
949
1757
|
if (phase === "failed") return /* @__PURE__ */ jsxRuntime.jsx(lucideReact.AlertTriangle, { className: "size-3.5 shrink-0" });
|
|
950
1758
|
if (phase === "skipped") return /* @__PURE__ */ jsxRuntime.jsx(lucideReact.MinusCircle, { className: "size-3.5 shrink-0" });
|
|
951
1759
|
return icon ? /* @__PURE__ */ jsxRuntime.jsx("span", { className: "flex size-3.5 shrink-0 items-center justify-center [&_svg]:size-3.5", children: icon }) : null;
|
|
@@ -978,6 +1786,8 @@ function WorkflowStepBar({
|
|
|
978
1786
|
const pill = (s) => {
|
|
979
1787
|
const phase = run.phaseOf(s.id);
|
|
980
1788
|
const current = s.id === run.current;
|
|
1789
|
+
const assignee = ["ready", "waiting"].includes(phase) ? run.assigneeOf(s.id) : void 0;
|
|
1790
|
+
const title = assignee ? `${s.title} \xB7 ${assignee}` : s.title;
|
|
981
1791
|
return /* @__PURE__ */ jsxRuntime.jsxs(
|
|
982
1792
|
"button",
|
|
983
1793
|
{
|
|
@@ -987,16 +1797,27 @@ function WorkflowStepBar({
|
|
|
987
1797
|
className: ui.cn(
|
|
988
1798
|
PILL,
|
|
989
1799
|
"transition-colors disabled:cursor-default",
|
|
990
|
-
current ? "border-primary bg-primary/10 text-primary" : phase === "failed" ? "border-destructive/40 text-destructive" : phase === "done" || phase === "skipped" || phase === "running" ? "border-primary/30 bg-primary/5 text-primary" : "border-border text-muted-foreground"
|
|
1800
|
+
current ? "border-primary bg-primary/10 text-primary" : phase === "failed" ? "border-destructive/40 text-destructive" : phase === "done" || phase === "skipped" || phase === "running" || phase === "waiting" ? "border-primary/30 bg-primary/5 text-primary" : "border-border text-muted-foreground"
|
|
991
1801
|
),
|
|
992
1802
|
"aria-current": current ? "step" : void 0,
|
|
993
|
-
"aria-label":
|
|
994
|
-
title
|
|
1803
|
+
"aria-label": title,
|
|
1804
|
+
title,
|
|
995
1805
|
"data-phase": phase,
|
|
996
1806
|
"data-testid": tid(`step-${s.id}`),
|
|
997
1807
|
children: [
|
|
998
1808
|
/* @__PURE__ */ jsxRuntime.jsx(PhaseMark, { phase, icon: icon(s.icon) }),
|
|
999
|
-
(current || !compact3) && /* @__PURE__ */ jsxRuntime.jsx("span", { className: LABEL, "data-testid": tid(`step-${s.id}-label`), children: s.title })
|
|
1809
|
+
(current || !compact3) && /* @__PURE__ */ jsxRuntime.jsx("span", { className: LABEL, "data-testid": tid(`step-${s.id}-label`), children: s.title }),
|
|
1810
|
+
assignee && !compact3 && /* @__PURE__ */ jsxRuntime.jsxs(
|
|
1811
|
+
"span",
|
|
1812
|
+
{
|
|
1813
|
+
className: "min-w-0 max-w-[8rem] truncate font-normal opacity-75",
|
|
1814
|
+
"data-testid": tid(`step-${s.id}-assignee`),
|
|
1815
|
+
children: [
|
|
1816
|
+
"\xB7 ",
|
|
1817
|
+
assignee
|
|
1818
|
+
]
|
|
1819
|
+
}
|
|
1820
|
+
)
|
|
1000
1821
|
]
|
|
1001
1822
|
},
|
|
1002
1823
|
s.id
|
|
@@ -1101,7 +1922,8 @@ var DEFAULT_WORKFLOW_RUNNER_LABELS = {
|
|
|
1101
1922
|
fileReading: "Reading\u2026",
|
|
1102
1923
|
fileReady: "Ready",
|
|
1103
1924
|
fileFailed: "Could not be read",
|
|
1104
|
-
readingFiles: "Reading {current} of {count} files\u2026"
|
|
1925
|
+
readingFiles: "Reading {current} of {count} files\u2026",
|
|
1926
|
+
markSent: "Mark as sent"
|
|
1105
1927
|
};
|
|
1106
1928
|
function WorkflowRunner({
|
|
1107
1929
|
workflow,
|
|
@@ -1117,11 +1939,16 @@ function WorkflowRunner({
|
|
|
1117
1939
|
renderScope,
|
|
1118
1940
|
renderDocuments,
|
|
1119
1941
|
renderIcon,
|
|
1942
|
+
people,
|
|
1943
|
+
actions,
|
|
1944
|
+
nameOfDoc,
|
|
1120
1945
|
labels,
|
|
1946
|
+
partsLabels,
|
|
1121
1947
|
testIdPrefix = "workflow-run",
|
|
1122
1948
|
className
|
|
1123
1949
|
}) {
|
|
1124
1950
|
const l = { ...DEFAULT_WORKFLOW_RUNNER_LABELS, ...labels };
|
|
1951
|
+
const pl = { ...DEFAULT_WORKFLOW_STEP_PARTS_LABELS, ...partsLabels };
|
|
1125
1952
|
const { steps, step, isComplete, action } = run;
|
|
1126
1953
|
const completion = workflow.run.kind === "steps" ? workflow.run.completion : void 0;
|
|
1127
1954
|
const tid = (suffix) => `${testIdPrefix}-${suffix}`;
|
|
@@ -1130,7 +1957,7 @@ function WorkflowRunner({
|
|
|
1130
1957
|
const added = step?.kind === "upload" ? (files ?? []).filter((f) => f.addedFor === step.id) : [];
|
|
1131
1958
|
const unread = added.filter((f) => f.status === "processing").length;
|
|
1132
1959
|
const reading = action === "complete" && unread > 0;
|
|
1133
|
-
const nextLabel = reading ? l.readingFiles.replace("{current}", String(Math.min(added.length - unread + 1, added.length))).replace("{count}", String(added.length)) : action === "skip" ? l.skip : action === "finish" ? l.finish : action === "complete" && step?.kind === "review" ? l.approve : action === "wait" && (run.isRunning || run.busy) ? l.working : (step && !run.isLocked(step.id) ? step.nextLabel : void 0) ?? l.next;
|
|
1960
|
+
const nextLabel = reading ? l.readingFiles.replace("{current}", String(Math.min(added.length - unread + 1, added.length))).replace("{count}", String(added.length)) : action === "skip" ? l.skip : action === "finish" ? l.finish : action === "complete" && step?.kind === "review" ? l.approve : action === "complete" && step?.kind === "action" ? l.markSent : action === "wait" && (run.isRunning || run.busy) ? l.working : (step && !run.isLocked(step.id) ? step.nextLabel : void 0) ?? l.next;
|
|
1134
1961
|
return /* @__PURE__ */ jsxRuntime.jsxs("div", { className: ui.cn("space-y-6", className), "data-testid": testIdPrefix, children: [
|
|
1135
1962
|
/* @__PURE__ */ jsxRuntime.jsx(
|
|
1136
1963
|
WorkflowStepBar,
|
|
@@ -1162,6 +1989,8 @@ function WorkflowRunner({
|
|
|
1162
1989
|
stepDependencies(steps, step.id).map((d) => steps.find((s) => s.id === d)?.title ?? d).join(", ")
|
|
1163
1990
|
) }) }) : step.kind === "form" ? /* @__PURE__ */ jsxRuntime.jsxs(ui.Card, { className: "max-w-2xl space-y-4 p-6", "data-testid": tid(step.id), children: [
|
|
1164
1991
|
/* @__PURE__ */ jsxRuntime.jsx(StepHeading, { step, icon: icon(step.icon), testId: tid(`${step.id}-title`) }),
|
|
1992
|
+
/* @__PURE__ */ jsxRuntime.jsx(SentBackNote, { state: run.stateOf(step.id), l: pl, testId: tid(step.id) }),
|
|
1993
|
+
/* @__PURE__ */ jsxRuntime.jsx(AssigneeLine, { run, stepId: step.id, l: pl, testId: tid(step.id) }),
|
|
1165
1994
|
/* @__PURE__ */ jsxRuntime.jsx("fieldset", { disabled: run.isLocked(step.id), className: "contents", children: /* @__PURE__ */ jsxRuntime.jsx(
|
|
1166
1995
|
SchemaForm,
|
|
1167
1996
|
{
|
|
@@ -1172,6 +2001,7 @@ function WorkflowRunner({
|
|
|
1172
2001
|
renderScope,
|
|
1173
2002
|
renderDocuments,
|
|
1174
2003
|
renderIcon,
|
|
2004
|
+
people,
|
|
1175
2005
|
onEnterSubmit: () => void run.next(),
|
|
1176
2006
|
testIdPrefix: tid("field")
|
|
1177
2007
|
}
|
|
@@ -1179,6 +2009,8 @@ function WorkflowRunner({
|
|
|
1179
2009
|
run.actionError && /* @__PURE__ */ jsxRuntime.jsx("p", { className: "text-sm text-destructive", "data-testid": tid("action-error"), children: run.actionError }),
|
|
1180
2010
|
renderStepNote?.(step, run)
|
|
1181
2011
|
] }) : step.kind === "upload" ? /* @__PURE__ */ jsxRuntime.jsxs(ui.Card, { className: "max-w-2xl space-y-4 p-6", "data-testid": tid(step.id), children: [
|
|
2012
|
+
/* @__PURE__ */ jsxRuntime.jsx(SentBackNote, { state: run.stateOf(step.id), l: pl, testId: tid(step.id) }),
|
|
2013
|
+
/* @__PURE__ */ jsxRuntime.jsx(AssigneeLine, { run, stepId: step.id, l: pl, testId: tid(step.id) }),
|
|
1182
2014
|
renderUpload?.(step) ?? /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
|
|
1183
2015
|
/* @__PURE__ */ jsxRuntime.jsx(
|
|
1184
2016
|
chunkDETZZBG2_cjs.UploadDropzone,
|
|
@@ -1207,9 +2039,52 @@ function WorkflowRunner({
|
|
|
1207
2039
|
renderStepNote?.(step, run)
|
|
1208
2040
|
] }) : step.kind === "review" ? /* @__PURE__ */ jsxRuntime.jsxs(ui.Card, { className: "max-w-2xl space-y-4 p-6", "data-testid": tid(step.id), children: [
|
|
1209
2041
|
/* @__PURE__ */ jsxRuntime.jsx(StepHeading, { step, icon: icon(step.icon) }),
|
|
2042
|
+
/* @__PURE__ */ jsxRuntime.jsx(SentBackNote, { state: run.stateOf(step.id), l: pl, testId: tid(step.id) }),
|
|
1210
2043
|
/* @__PURE__ */ jsxRuntime.jsx("p", { className: "whitespace-pre-line text-sm text-muted-foreground", children: reviewInstructions(step, run.inputs) }),
|
|
1211
|
-
/* @__PURE__ */ jsxRuntime.jsx(
|
|
2044
|
+
/* @__PURE__ */ jsxRuntime.jsx(AssigneeLine, { run, stepId: step.id, l: pl, testId: tid(step.id) }),
|
|
2045
|
+
!(run.phaseOf(step.id) === "done" && run.stateOf(step.id)?.by) && /* @__PURE__ */ jsxRuntime.jsx("p", { className: "text-sm", "data-testid": tid(`${step.id}-status`), children: run.phaseOf(step.id) === "done" ? l.approved : run.phaseOf(step.id) === "skipped" ? l.skipped : l.awaitingReview }),
|
|
2046
|
+
(step.fields ?? []).length > 0 && run.phaseOf(step.id) === "ready" && /* @__PURE__ */ jsxRuntime.jsx(
|
|
2047
|
+
SchemaForm,
|
|
2048
|
+
{
|
|
2049
|
+
fields: step.fields ?? [],
|
|
2050
|
+
values: run.inputs,
|
|
2051
|
+
onChange: run.setInput,
|
|
2052
|
+
errors: run.errors,
|
|
2053
|
+
renderScope,
|
|
2054
|
+
renderDocuments,
|
|
2055
|
+
renderIcon,
|
|
2056
|
+
people,
|
|
2057
|
+
testIdPrefix: tid("field")
|
|
2058
|
+
}
|
|
2059
|
+
),
|
|
2060
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
2061
|
+
ApprovalEvidence,
|
|
2062
|
+
{
|
|
2063
|
+
run,
|
|
2064
|
+
step,
|
|
2065
|
+
actions,
|
|
2066
|
+
nameOfDoc,
|
|
2067
|
+
l: pl,
|
|
2068
|
+
testId: tid(step.id)
|
|
2069
|
+
}
|
|
2070
|
+
),
|
|
1212
2071
|
run.phaseOf(step.id) === "ready" && renderReview?.(step),
|
|
2072
|
+
/* @__PURE__ */ jsxRuntime.jsx(SendBackControl, { run, step, l: pl, testId: tid(step.id) }),
|
|
2073
|
+
run.actionError && /* @__PURE__ */ jsxRuntime.jsx("p", { className: "text-sm text-destructive", children: run.actionError }),
|
|
2074
|
+
renderStepNote?.(step, run)
|
|
2075
|
+
] }) : step.kind === "action" ? /* @__PURE__ */ jsxRuntime.jsxs(ui.Card, { className: "max-w-2xl space-y-4 p-6", "data-testid": tid(step.id), children: [
|
|
2076
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
2077
|
+
ActionStepBody,
|
|
2078
|
+
{
|
|
2079
|
+
step,
|
|
2080
|
+
run,
|
|
2081
|
+
actions,
|
|
2082
|
+
nameOfDoc,
|
|
2083
|
+
heading: /* @__PURE__ */ jsxRuntime.jsx(StepHeading, { step, icon: icon(step.icon) }),
|
|
2084
|
+
l: pl,
|
|
2085
|
+
testId: tid(step.id)
|
|
2086
|
+
}
|
|
2087
|
+
),
|
|
1213
2088
|
run.actionError && /* @__PURE__ */ jsxRuntime.jsx("p", { className: "text-sm text-destructive", children: run.actionError }),
|
|
1214
2089
|
renderStepNote?.(step, run)
|
|
1215
2090
|
] }) : /* @__PURE__ */ jsxRuntime.jsx(
|
|
@@ -1220,6 +2095,19 @@ function WorkflowRunner({
|
|
|
1220
2095
|
renderAgentOutput,
|
|
1221
2096
|
icon: icon(step.icon),
|
|
1222
2097
|
renderStepNote,
|
|
2098
|
+
extra: /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
|
|
2099
|
+
/* @__PURE__ */ jsxRuntime.jsx(SentBackNote, { state: run.stateOf(step.id), l: pl, testId: tid(step.id) }),
|
|
2100
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
2101
|
+
RedlineOpen,
|
|
2102
|
+
{
|
|
2103
|
+
step,
|
|
2104
|
+
state: run.stateOf(step.id),
|
|
2105
|
+
actions,
|
|
2106
|
+
l: pl,
|
|
2107
|
+
testId: tid(step.id)
|
|
2108
|
+
}
|
|
2109
|
+
)
|
|
2110
|
+
] }),
|
|
1223
2111
|
l,
|
|
1224
2112
|
tid
|
|
1225
2113
|
}
|
|
@@ -1350,6 +2238,7 @@ function AgentStepBody({
|
|
|
1350
2238
|
renderAgentOutput,
|
|
1351
2239
|
icon,
|
|
1352
2240
|
renderStepNote,
|
|
2241
|
+
extra,
|
|
1353
2242
|
l,
|
|
1354
2243
|
tid
|
|
1355
2244
|
}) {
|
|
@@ -1392,7 +2281,8 @@ function AgentStepBody({
|
|
|
1392
2281
|
}
|
|
1393
2282
|
),
|
|
1394
2283
|
phase === "failed" && /* @__PURE__ */ jsxRuntime.jsx("p", { className: "text-sm text-destructive", "data-testid": tid(`${step.id}-failed`), children: state?.error || l.failed }),
|
|
1395
|
-
phase === "skipped" && /* @__PURE__ */ jsxRuntime.jsx("p", { className: "text-sm text-muted-foreground", children: l.skipped })
|
|
2284
|
+
phase === "skipped" && /* @__PURE__ */ jsxRuntime.jsx("p", { className: "text-sm text-muted-foreground", children: l.skipped }),
|
|
2285
|
+
extra
|
|
1396
2286
|
] });
|
|
1397
2287
|
if (step.output === "artifact") {
|
|
1398
2288
|
return /* @__PURE__ */ jsxRuntime.jsxs(
|
|
@@ -1419,14 +2309,22 @@ function AgentStepBody({
|
|
|
1419
2309
|
] });
|
|
1420
2310
|
}
|
|
1421
2311
|
|
|
2312
|
+
exports.ActionStepBody = ActionStepBody;
|
|
2313
|
+
exports.ApprovalEvidence = ApprovalEvidence;
|
|
2314
|
+
exports.AssigneeLine = AssigneeLine;
|
|
2315
|
+
exports.DEFAULT_ASSIGNEE_WORDING = DEFAULT_ASSIGNEE_WORDING;
|
|
1422
2316
|
exports.DEFAULT_SCHEMA_FORM_LABELS = DEFAULT_SCHEMA_FORM_LABELS;
|
|
1423
2317
|
exports.DEFAULT_WORKFLOW_RUNNER_LABELS = DEFAULT_WORKFLOW_RUNNER_LABELS;
|
|
2318
|
+
exports.DEFAULT_WORKFLOW_STEP_PARTS_LABELS = DEFAULT_WORKFLOW_STEP_PARTS_LABELS;
|
|
1424
2319
|
exports.EMPTY_WORKFLOW_SCOPE = EMPTY_WORKFLOW_SCOPE;
|
|
1425
2320
|
exports.SKILL_PROMPT_FALLBACK_PLACEHOLDER = SKILL_PROMPT_FALLBACK_PLACEHOLDER;
|
|
1426
2321
|
exports.SKILL_PROMPT_LABEL = SKILL_PROMPT_LABEL;
|
|
1427
2322
|
exports.SchemaForm = SchemaForm;
|
|
2323
|
+
exports.SendBackControl = SendBackControl;
|
|
1428
2324
|
exports.WorkflowRunner = WorkflowRunner;
|
|
2325
|
+
exports.assigneeName = assigneeName;
|
|
1429
2326
|
exports.buildLaunch = buildLaunch;
|
|
2327
|
+
exports.canAssign = canAssign;
|
|
1430
2328
|
exports.composeStepPrompt = composeStepPrompt;
|
|
1431
2329
|
exports.composeWorkflowPrompt = composeWorkflowPrompt;
|
|
1432
2330
|
exports.defaultInputs = defaultInputs;
|
|
@@ -1434,11 +2332,14 @@ exports.dependsOn = dependsOn;
|
|
|
1434
2332
|
exports.fieldToFrontmatter = fieldToFrontmatter;
|
|
1435
2333
|
exports.fillRunText = fillRunText;
|
|
1436
2334
|
exports.fillStepInputs = fillStepInputs;
|
|
2335
|
+
exports.fromPlanAssignee = fromPlanAssignee;
|
|
2336
|
+
exports.fromPlanDocumentRef = fromPlanDocumentRef;
|
|
1437
2337
|
exports.fromPlanSteps = fromPlanSteps;
|
|
1438
2338
|
exports.initialRunInputs = initialRunInputs;
|
|
1439
2339
|
exports.inputsFromContext = inputsFromContext;
|
|
1440
2340
|
exports.isEmptyWorkflowScope = isEmptyWorkflowScope;
|
|
1441
2341
|
exports.isIncompleteSignal = isIncompleteSignal;
|
|
2342
|
+
exports.isPersonAction = isPersonAction;
|
|
1442
2343
|
exports.isPersonStep = isPersonStep;
|
|
1443
2344
|
exports.isRunFinished = isRunFinished;
|
|
1444
2345
|
exports.isSteppedWorkflow = isSteppedWorkflow;
|
|
@@ -1449,13 +2350,21 @@ exports.orderSteps = orderSteps;
|
|
|
1449
2350
|
exports.promptFieldName = promptFieldName;
|
|
1450
2351
|
exports.reviewInstructions = reviewInstructions;
|
|
1451
2352
|
exports.runFields = runFields;
|
|
2353
|
+
exports.runFieldsOf = runFieldsOf;
|
|
1452
2354
|
exports.runThreadTitle = runThreadTitle;
|
|
2355
|
+
exports.sendBackTargets = sendBackTargets;
|
|
1453
2356
|
exports.skillToWorkflow = skillToWorkflow;
|
|
2357
|
+
exports.splitDocRef = splitDocRef;
|
|
2358
|
+
exports.stepConfigProblems = stepConfigProblems;
|
|
1454
2359
|
exports.stepDependencies = stepDependencies;
|
|
2360
|
+
exports.stepFields = stepFields;
|
|
1455
2361
|
exports.stepLevels = stepLevels;
|
|
1456
2362
|
exports.stepPhase = stepPhase;
|
|
1457
2363
|
exports.stepStatesFromActivity = stepStatesFromActivity;
|
|
2364
|
+
exports.toPlanAssignee = toPlanAssignee;
|
|
2365
|
+
exports.toPlanDocumentRef = toPlanDocumentRef;
|
|
1458
2366
|
exports.toPlanSteps = toPlanSteps;
|
|
2367
|
+
exports.upstreamSteps = upstreamSteps;
|
|
1459
2368
|
exports.useWorkflowView = useWorkflowView;
|
|
1460
2369
|
exports.validateInputs = validateInputs;
|
|
1461
2370
|
exports.validateStep = validateStep;
|
|
@@ -1465,5 +2374,5 @@ exports.workflowFromFrontmatter = workflowFromFrontmatter;
|
|
|
1465
2374
|
exports.workflowSteps = workflowSteps;
|
|
1466
2375
|
exports.workflowsAccepting = workflowsAccepting;
|
|
1467
2376
|
exports.workflowsForHost = workflowsForHost;
|
|
1468
|
-
//# sourceMappingURL=chunk-
|
|
1469
|
-
//# sourceMappingURL=chunk-
|
|
2377
|
+
//# sourceMappingURL=chunk-3XR3IEGU.cjs.map
|
|
2378
|
+
//# sourceMappingURL=chunk-3XR3IEGU.cjs.map
|