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