@arbidocs/blocks 0.4.75 → 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 +341 -253
- package/dist/agents/index.js +3 -3
- package/dist/agents/tasks/TaskActivityTimeline.d.ts +1 -1
- package/dist/agents/tasks/WorkflowThreadStrip.d.ts +44 -1
- package/dist/agents/tasks/index.d.ts +2 -1
- package/dist/agents/tasks/linkedRuns.d.ts +31 -0
- 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 +10 -1
- package/dist/agents/workflows/run.d.ts +61 -8
- package/dist/agents/workflows/types.d.ts +160 -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-YWYVIQ7T.js → chunk-34UW6XUQ.js} +948 -38
- package/dist/chunk-34UW6XUQ.js.map +1 -0
- package/dist/{chunk-P2RBE3FD.cjs → chunk-3XR3IEGU.cjs} +965 -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-LT2UORRG.js → chunk-HEVVT6IT.js} +205 -38
- 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-F4LUD3YC.cjs → chunk-JFUN4D7D.cjs} +229 -60
- 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 +295 -32
- package/dist/connect/index.cjs.map +1 -1
- package/dist/connect/index.js +280 -17
- 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/facts/index.cjs +1 -1
- package/dist/facts/index.js +1 -1
- package/dist/files/index.cjs +1 -1
- package/dist/files/index.js +1 -1
- package/dist/home/index.cjs +1 -1
- package/dist/home/index.js +1 -1
- package/dist/index.cjs +631 -535
- package/dist/index.js +8 -8
- package/dist/settings/index.cjs +1 -1
- package/dist/settings/index.js +1 -1
- package/dist/shell/index.cjs +1 -1
- package/dist/shell/index.js +1 -1
- package/dist/studio/index.cjs +4 -4
- package/dist/studio/index.js +3 -3
- package/dist/workflow-canvas/SignalsEditor.d.ts +41 -0
- package/dist/workflow-canvas/StepActionSettings.d.ts +132 -0
- package/dist/workflow-canvas/StepInspector.d.ts +28 -2
- package/dist/workflow-canvas/TriggerInspector.d.ts +11 -2
- package/dist/workflow-canvas/WorkflowBuilder.d.ts +17 -4
- package/dist/workflow-canvas/WorkflowCanvas.d.ts +27 -2
- package/dist/workflow-canvas/edit.d.ts +9 -1
- package/dist/workflow-canvas/index.cjs +1282 -208
- package/dist/workflow-canvas/index.cjs.map +1 -1
- package/dist/workflow-canvas/index.d.ts +2 -1
- package/dist/workflow-canvas/index.js +1255 -188
- package/dist/workflow-canvas/index.js.map +1 -1
- package/dist/workflow-canvas/trigger.d.ts +20 -1
- package/package.json +4 -4
- package/src/workflow-canvas/canvas.css +9 -0
- package/dist/chunk-5EBGRG3X.js.map +0 -1
- package/dist/chunk-F4LUD3YC.cjs.map +0 -1
- package/dist/chunk-IPGKTUF7.cjs.map +0 -1
- package/dist/chunk-LT2UORRG.js.map +0 -1
- package/dist/chunk-P2RBE3FD.cjs.map +0 -1
- package/dist/chunk-UIWLDSTF.js.map +0 -1
- package/dist/chunk-YWYVIQ7T.js.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,
|
|
@@ -740,10 +982,35 @@ function toPlanSteps(workflow, options = {}) {
|
|
|
740
982
|
branch: step.kind === "agent" && !!step.branch,
|
|
741
983
|
requires_files: false,
|
|
742
984
|
ui,
|
|
985
|
+
// An unfinished signal (still being typed) is not saved: the server would refuse it.
|
|
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) } : {},
|
|
743
993
|
...step.kind === "agent" ? agentStep(workflow, step, options) : { skill: null, inputs: null, prompt: null }
|
|
744
994
|
};
|
|
745
995
|
});
|
|
746
996
|
}
|
|
997
|
+
function toPlanSignal(signal) {
|
|
998
|
+
return signal.when ? { name: signal.name, when: signal.when } : { name: signal.name };
|
|
999
|
+
}
|
|
1000
|
+
function isIncompleteSignal(signal) {
|
|
1001
|
+
const when = signal.when;
|
|
1002
|
+
if (!signal.name.trim()) return true;
|
|
1003
|
+
if (!when) return false;
|
|
1004
|
+
if ("field" in when) return !when.field || String(when.equals).trim() === "";
|
|
1005
|
+
if ("contains" in when) return !when.contains.trim();
|
|
1006
|
+
if ("matches" in when) return !when.matches.trim();
|
|
1007
|
+
return false;
|
|
1008
|
+
}
|
|
1009
|
+
function fromPlanSignal(signal) {
|
|
1010
|
+
const w = signal.when;
|
|
1011
|
+
const when = w?.field != null && w.equals != null ? { field: w.field, equals: w.equals } : w?.contains != null ? { contains: w.contains } : w?.matches != null ? { matches: w.matches } : w?.approved ? { approved: true } : void 0;
|
|
1012
|
+
return when ? { name: signal.name, when } : { name: signal.name };
|
|
1013
|
+
}
|
|
747
1014
|
function fromPlanSteps(steps) {
|
|
748
1015
|
return (steps ?? []).map((p) => {
|
|
749
1016
|
const ui = p.ui ?? {};
|
|
@@ -754,7 +1021,10 @@ function fromPlanSteps(steps) {
|
|
|
754
1021
|
icon: ui.icon,
|
|
755
1022
|
commit: ui.commit,
|
|
756
1023
|
nextLabel: ui.next_label,
|
|
757
|
-
...p.after != null ? { after: p.after } : {}
|
|
1024
|
+
...p.after != null ? { after: p.after } : {},
|
|
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 } : {}
|
|
758
1028
|
};
|
|
759
1029
|
switch (p.kind) {
|
|
760
1030
|
case "form":
|
|
@@ -762,7 +1032,15 @@ function fromPlanSteps(steps) {
|
|
|
762
1032
|
case "upload":
|
|
763
1033
|
return { ...base, kind: "upload", required: ui.required, accept: ui.accept, hint: ui.hint };
|
|
764
1034
|
case "review":
|
|
765
|
-
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) };
|
|
766
1044
|
default: {
|
|
767
1045
|
const promptTemplate = ui.prompt_template ?? p.prompt ?? void 0;
|
|
768
1046
|
return {
|
|
@@ -772,7 +1050,8 @@ function fromPlanSteps(steps) {
|
|
|
772
1050
|
with: ui.with ?? p.inputs ?? void 0,
|
|
773
1051
|
run: !ui.workflow && !p.skill && promptTemplate ? { kind: "prompt", promptTemplate } : void 0,
|
|
774
1052
|
output: ui.output,
|
|
775
|
-
branch: p.branch || void 0
|
|
1053
|
+
branch: p.branch || void 0,
|
|
1054
|
+
...fromPlanDocumentRef(p.edit_document) ? { editDocument: fromPlanDocumentRef(p.edit_document) } : {}
|
|
776
1055
|
};
|
|
777
1056
|
}
|
|
778
1057
|
}
|
|
@@ -785,25 +1064,47 @@ function layoutFromPlanSteps(steps) {
|
|
|
785
1064
|
});
|
|
786
1065
|
return entries.length ? Object.fromEntries(entries) : void 0;
|
|
787
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
|
+
}
|
|
788
1089
|
var errorMessage = (e) => e instanceof Error ? e.message : typeof e === "string" ? e : "Something went wrong.";
|
|
789
1090
|
function firstOpen(steps, states) {
|
|
790
1091
|
const open = steps.find((s) => !["done", "skipped"].includes(states[s.id]?.status ?? "pending"));
|
|
791
1092
|
return open?.id ?? (steps.length && isRunFinished(steps, states) ? null : steps[0]?.id ?? null);
|
|
792
1093
|
}
|
|
793
1094
|
function useWorkflowView(options) {
|
|
794
|
-
const { steps, states, inputs, setInput } = options;
|
|
1095
|
+
const { steps, states, inputs, setInput, loaded = true } = options;
|
|
795
1096
|
const [current, setCurrent] = react.useState(() => firstOpen(steps, states));
|
|
796
1097
|
const [showErrors, setShowErrors] = react.useState(false);
|
|
797
1098
|
const [busy, setBusy] = react.useState(false);
|
|
798
1099
|
const [actionError, setActionError] = react.useState(null);
|
|
799
1100
|
const optionsRef = react.useRef(options);
|
|
800
1101
|
optionsRef.current = options;
|
|
801
|
-
const placed = react.useRef(steps.length > 0);
|
|
1102
|
+
const placed = react.useRef(steps.length > 0 && loaded);
|
|
802
1103
|
react.useEffect(() => {
|
|
803
|
-
if (placed.current || steps.length === 0) return;
|
|
1104
|
+
if (placed.current || steps.length === 0 || !loaded) return;
|
|
804
1105
|
placed.current = true;
|
|
805
1106
|
setCurrent(firstOpen(steps, states));
|
|
806
|
-
}, [steps, states]);
|
|
1107
|
+
}, [steps, states, loaded]);
|
|
807
1108
|
const step = steps.find((s) => s.id === current);
|
|
808
1109
|
const following = react.useCallback(
|
|
809
1110
|
(id) => {
|
|
@@ -891,6 +1192,40 @@ function useWorkflowView(options) {
|
|
|
891
1192
|
// eslint-disable-next-line react-hooks/exhaustive-deps
|
|
892
1193
|
[act, !!options.retry]
|
|
893
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
|
+
);
|
|
894
1229
|
const isLocked = react.useCallback(
|
|
895
1230
|
(stepId) => optionsRef.current.isLocked?.(stepId) ?? false,
|
|
896
1231
|
[]
|
|
@@ -916,6 +1251,19 @@ function useWorkflowView(options) {
|
|
|
916
1251
|
goTo,
|
|
917
1252
|
skip,
|
|
918
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
|
+
},
|
|
919
1267
|
restart: () => {
|
|
920
1268
|
setShowErrors(false);
|
|
921
1269
|
setActionError(null);
|
|
@@ -923,9 +1271,489 @@ function useWorkflowView(options) {
|
|
|
923
1271
|
}
|
|
924
1272
|
};
|
|
925
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
|
+
}
|
|
926
1753
|
function PhaseMark({ phase, icon }) {
|
|
927
1754
|
if (phase === "done") return /* @__PURE__ */ jsxRuntime.jsx(lucideReact.Check, { className: "size-3.5 shrink-0" });
|
|
928
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" });
|
|
929
1757
|
if (phase === "failed") return /* @__PURE__ */ jsxRuntime.jsx(lucideReact.AlertTriangle, { className: "size-3.5 shrink-0" });
|
|
930
1758
|
if (phase === "skipped") return /* @__PURE__ */ jsxRuntime.jsx(lucideReact.MinusCircle, { className: "size-3.5 shrink-0" });
|
|
931
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;
|
|
@@ -958,6 +1786,8 @@ function WorkflowStepBar({
|
|
|
958
1786
|
const pill = (s) => {
|
|
959
1787
|
const phase = run.phaseOf(s.id);
|
|
960
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;
|
|
961
1791
|
return /* @__PURE__ */ jsxRuntime.jsxs(
|
|
962
1792
|
"button",
|
|
963
1793
|
{
|
|
@@ -967,16 +1797,27 @@ function WorkflowStepBar({
|
|
|
967
1797
|
className: ui.cn(
|
|
968
1798
|
PILL,
|
|
969
1799
|
"transition-colors disabled:cursor-default",
|
|
970
|
-
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"
|
|
971
1801
|
),
|
|
972
1802
|
"aria-current": current ? "step" : void 0,
|
|
973
|
-
"aria-label":
|
|
974
|
-
title
|
|
1803
|
+
"aria-label": title,
|
|
1804
|
+
title,
|
|
975
1805
|
"data-phase": phase,
|
|
976
1806
|
"data-testid": tid(`step-${s.id}`),
|
|
977
1807
|
children: [
|
|
978
1808
|
/* @__PURE__ */ jsxRuntime.jsx(PhaseMark, { phase, icon: icon(s.icon) }),
|
|
979
|
-
(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
|
+
)
|
|
980
1821
|
]
|
|
981
1822
|
},
|
|
982
1823
|
s.id
|
|
@@ -1081,7 +1922,8 @@ var DEFAULT_WORKFLOW_RUNNER_LABELS = {
|
|
|
1081
1922
|
fileReading: "Reading\u2026",
|
|
1082
1923
|
fileReady: "Ready",
|
|
1083
1924
|
fileFailed: "Could not be read",
|
|
1084
|
-
readingFiles: "Reading {current} of {count} files\u2026"
|
|
1925
|
+
readingFiles: "Reading {current} of {count} files\u2026",
|
|
1926
|
+
markSent: "Mark as sent"
|
|
1085
1927
|
};
|
|
1086
1928
|
function WorkflowRunner({
|
|
1087
1929
|
workflow,
|
|
@@ -1097,11 +1939,16 @@ function WorkflowRunner({
|
|
|
1097
1939
|
renderScope,
|
|
1098
1940
|
renderDocuments,
|
|
1099
1941
|
renderIcon,
|
|
1942
|
+
people,
|
|
1943
|
+
actions,
|
|
1944
|
+
nameOfDoc,
|
|
1100
1945
|
labels,
|
|
1946
|
+
partsLabels,
|
|
1101
1947
|
testIdPrefix = "workflow-run",
|
|
1102
1948
|
className
|
|
1103
1949
|
}) {
|
|
1104
1950
|
const l = { ...DEFAULT_WORKFLOW_RUNNER_LABELS, ...labels };
|
|
1951
|
+
const pl = { ...DEFAULT_WORKFLOW_STEP_PARTS_LABELS, ...partsLabels };
|
|
1105
1952
|
const { steps, step, isComplete, action } = run;
|
|
1106
1953
|
const completion = workflow.run.kind === "steps" ? workflow.run.completion : void 0;
|
|
1107
1954
|
const tid = (suffix) => `${testIdPrefix}-${suffix}`;
|
|
@@ -1110,7 +1957,7 @@ function WorkflowRunner({
|
|
|
1110
1957
|
const added = step?.kind === "upload" ? (files ?? []).filter((f) => f.addedFor === step.id) : [];
|
|
1111
1958
|
const unread = added.filter((f) => f.status === "processing").length;
|
|
1112
1959
|
const reading = action === "complete" && unread > 0;
|
|
1113
|
-
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;
|
|
1114
1961
|
return /* @__PURE__ */ jsxRuntime.jsxs("div", { className: ui.cn("space-y-6", className), "data-testid": testIdPrefix, children: [
|
|
1115
1962
|
/* @__PURE__ */ jsxRuntime.jsx(
|
|
1116
1963
|
WorkflowStepBar,
|
|
@@ -1142,6 +1989,8 @@ function WorkflowRunner({
|
|
|
1142
1989
|
stepDependencies(steps, step.id).map((d) => steps.find((s) => s.id === d)?.title ?? d).join(", ")
|
|
1143
1990
|
) }) }) : step.kind === "form" ? /* @__PURE__ */ jsxRuntime.jsxs(ui.Card, { className: "max-w-2xl space-y-4 p-6", "data-testid": tid(step.id), children: [
|
|
1144
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) }),
|
|
1145
1994
|
/* @__PURE__ */ jsxRuntime.jsx("fieldset", { disabled: run.isLocked(step.id), className: "contents", children: /* @__PURE__ */ jsxRuntime.jsx(
|
|
1146
1995
|
SchemaForm,
|
|
1147
1996
|
{
|
|
@@ -1152,6 +2001,7 @@ function WorkflowRunner({
|
|
|
1152
2001
|
renderScope,
|
|
1153
2002
|
renderDocuments,
|
|
1154
2003
|
renderIcon,
|
|
2004
|
+
people,
|
|
1155
2005
|
onEnterSubmit: () => void run.next(),
|
|
1156
2006
|
testIdPrefix: tid("field")
|
|
1157
2007
|
}
|
|
@@ -1159,6 +2009,8 @@ function WorkflowRunner({
|
|
|
1159
2009
|
run.actionError && /* @__PURE__ */ jsxRuntime.jsx("p", { className: "text-sm text-destructive", "data-testid": tid("action-error"), children: run.actionError }),
|
|
1160
2010
|
renderStepNote?.(step, run)
|
|
1161
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) }),
|
|
1162
2014
|
renderUpload?.(step) ?? /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
|
|
1163
2015
|
/* @__PURE__ */ jsxRuntime.jsx(
|
|
1164
2016
|
chunkDETZZBG2_cjs.UploadDropzone,
|
|
@@ -1187,9 +2039,52 @@ function WorkflowRunner({
|
|
|
1187
2039
|
renderStepNote?.(step, run)
|
|
1188
2040
|
] }) : step.kind === "review" ? /* @__PURE__ */ jsxRuntime.jsxs(ui.Card, { className: "max-w-2xl space-y-4 p-6", "data-testid": tid(step.id), children: [
|
|
1189
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) }),
|
|
1190
2043
|
/* @__PURE__ */ jsxRuntime.jsx("p", { className: "whitespace-pre-line text-sm text-muted-foreground", children: reviewInstructions(step, run.inputs) }),
|
|
1191
|
-
/* @__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
|
+
),
|
|
1192
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
|
+
),
|
|
1193
2088
|
run.actionError && /* @__PURE__ */ jsxRuntime.jsx("p", { className: "text-sm text-destructive", children: run.actionError }),
|
|
1194
2089
|
renderStepNote?.(step, run)
|
|
1195
2090
|
] }) : /* @__PURE__ */ jsxRuntime.jsx(
|
|
@@ -1200,6 +2095,19 @@ function WorkflowRunner({
|
|
|
1200
2095
|
renderAgentOutput,
|
|
1201
2096
|
icon: icon(step.icon),
|
|
1202
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
|
+
] }),
|
|
1203
2111
|
l,
|
|
1204
2112
|
tid
|
|
1205
2113
|
}
|
|
@@ -1330,6 +2238,7 @@ function AgentStepBody({
|
|
|
1330
2238
|
renderAgentOutput,
|
|
1331
2239
|
icon,
|
|
1332
2240
|
renderStepNote,
|
|
2241
|
+
extra,
|
|
1333
2242
|
l,
|
|
1334
2243
|
tid
|
|
1335
2244
|
}) {
|
|
@@ -1372,7 +2281,8 @@ function AgentStepBody({
|
|
|
1372
2281
|
}
|
|
1373
2282
|
),
|
|
1374
2283
|
phase === "failed" && /* @__PURE__ */ jsxRuntime.jsx("p", { className: "text-sm text-destructive", "data-testid": tid(`${step.id}-failed`), children: state?.error || l.failed }),
|
|
1375
|
-
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
|
|
1376
2286
|
] });
|
|
1377
2287
|
if (step.output === "artifact") {
|
|
1378
2288
|
return /* @__PURE__ */ jsxRuntime.jsxs(
|
|
@@ -1399,14 +2309,22 @@ function AgentStepBody({
|
|
|
1399
2309
|
] });
|
|
1400
2310
|
}
|
|
1401
2311
|
|
|
2312
|
+
exports.ActionStepBody = ActionStepBody;
|
|
2313
|
+
exports.ApprovalEvidence = ApprovalEvidence;
|
|
2314
|
+
exports.AssigneeLine = AssigneeLine;
|
|
2315
|
+
exports.DEFAULT_ASSIGNEE_WORDING = DEFAULT_ASSIGNEE_WORDING;
|
|
1402
2316
|
exports.DEFAULT_SCHEMA_FORM_LABELS = DEFAULT_SCHEMA_FORM_LABELS;
|
|
1403
2317
|
exports.DEFAULT_WORKFLOW_RUNNER_LABELS = DEFAULT_WORKFLOW_RUNNER_LABELS;
|
|
2318
|
+
exports.DEFAULT_WORKFLOW_STEP_PARTS_LABELS = DEFAULT_WORKFLOW_STEP_PARTS_LABELS;
|
|
1404
2319
|
exports.EMPTY_WORKFLOW_SCOPE = EMPTY_WORKFLOW_SCOPE;
|
|
1405
2320
|
exports.SKILL_PROMPT_FALLBACK_PLACEHOLDER = SKILL_PROMPT_FALLBACK_PLACEHOLDER;
|
|
1406
2321
|
exports.SKILL_PROMPT_LABEL = SKILL_PROMPT_LABEL;
|
|
1407
2322
|
exports.SchemaForm = SchemaForm;
|
|
2323
|
+
exports.SendBackControl = SendBackControl;
|
|
1408
2324
|
exports.WorkflowRunner = WorkflowRunner;
|
|
2325
|
+
exports.assigneeName = assigneeName;
|
|
1409
2326
|
exports.buildLaunch = buildLaunch;
|
|
2327
|
+
exports.canAssign = canAssign;
|
|
1410
2328
|
exports.composeStepPrompt = composeStepPrompt;
|
|
1411
2329
|
exports.composeWorkflowPrompt = composeWorkflowPrompt;
|
|
1412
2330
|
exports.defaultInputs = defaultInputs;
|
|
@@ -1414,10 +2332,14 @@ exports.dependsOn = dependsOn;
|
|
|
1414
2332
|
exports.fieldToFrontmatter = fieldToFrontmatter;
|
|
1415
2333
|
exports.fillRunText = fillRunText;
|
|
1416
2334
|
exports.fillStepInputs = fillStepInputs;
|
|
2335
|
+
exports.fromPlanAssignee = fromPlanAssignee;
|
|
2336
|
+
exports.fromPlanDocumentRef = fromPlanDocumentRef;
|
|
1417
2337
|
exports.fromPlanSteps = fromPlanSteps;
|
|
1418
2338
|
exports.initialRunInputs = initialRunInputs;
|
|
1419
2339
|
exports.inputsFromContext = inputsFromContext;
|
|
1420
2340
|
exports.isEmptyWorkflowScope = isEmptyWorkflowScope;
|
|
2341
|
+
exports.isIncompleteSignal = isIncompleteSignal;
|
|
2342
|
+
exports.isPersonAction = isPersonAction;
|
|
1421
2343
|
exports.isPersonStep = isPersonStep;
|
|
1422
2344
|
exports.isRunFinished = isRunFinished;
|
|
1423
2345
|
exports.isSteppedWorkflow = isSteppedWorkflow;
|
|
@@ -1428,13 +2350,21 @@ exports.orderSteps = orderSteps;
|
|
|
1428
2350
|
exports.promptFieldName = promptFieldName;
|
|
1429
2351
|
exports.reviewInstructions = reviewInstructions;
|
|
1430
2352
|
exports.runFields = runFields;
|
|
2353
|
+
exports.runFieldsOf = runFieldsOf;
|
|
1431
2354
|
exports.runThreadTitle = runThreadTitle;
|
|
2355
|
+
exports.sendBackTargets = sendBackTargets;
|
|
1432
2356
|
exports.skillToWorkflow = skillToWorkflow;
|
|
2357
|
+
exports.splitDocRef = splitDocRef;
|
|
2358
|
+
exports.stepConfigProblems = stepConfigProblems;
|
|
1433
2359
|
exports.stepDependencies = stepDependencies;
|
|
2360
|
+
exports.stepFields = stepFields;
|
|
1434
2361
|
exports.stepLevels = stepLevels;
|
|
1435
2362
|
exports.stepPhase = stepPhase;
|
|
1436
2363
|
exports.stepStatesFromActivity = stepStatesFromActivity;
|
|
2364
|
+
exports.toPlanAssignee = toPlanAssignee;
|
|
2365
|
+
exports.toPlanDocumentRef = toPlanDocumentRef;
|
|
1437
2366
|
exports.toPlanSteps = toPlanSteps;
|
|
2367
|
+
exports.upstreamSteps = upstreamSteps;
|
|
1438
2368
|
exports.useWorkflowView = useWorkflowView;
|
|
1439
2369
|
exports.validateInputs = validateInputs;
|
|
1440
2370
|
exports.validateStep = validateStep;
|
|
@@ -1444,5 +2374,5 @@ exports.workflowFromFrontmatter = workflowFromFrontmatter;
|
|
|
1444
2374
|
exports.workflowSteps = workflowSteps;
|
|
1445
2375
|
exports.workflowsAccepting = workflowsAccepting;
|
|
1446
2376
|
exports.workflowsForHost = workflowsForHost;
|
|
1447
|
-
//# sourceMappingURL=chunk-
|
|
1448
|
-
//# sourceMappingURL=chunk-
|
|
2377
|
+
//# sourceMappingURL=chunk-3XR3IEGU.cjs.map
|
|
2378
|
+
//# sourceMappingURL=chunk-3XR3IEGU.cjs.map
|