@arbidocs/blocks 0.4.76 → 0.4.77
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/agents/index.cjs +331 -255
- package/dist/agents/index.js +2 -2
- package/dist/agents/tasks/TaskActivityTimeline.d.ts +1 -1
- package/dist/agents/tasks/WorkflowThreadStrip.d.ts +7 -1
- package/dist/agents/workflows/SchemaForm.d.ts +6 -1
- package/dist/agents/workflows/StepParts.d.ts +109 -0
- package/dist/agents/workflows/WorkflowRunner.d.ts +11 -2
- package/dist/agents/workflows/index.d.ts +3 -2
- package/dist/agents/workflows/planSteps.d.ts +8 -1
- package/dist/agents/workflows/run.d.ts +61 -8
- package/dist/agents/workflows/types.d.ts +133 -4
- package/dist/agents/workflows/useWorkflowPreview.d.ts +2 -1
- package/dist/agents/workflows/useWorkflowView.d.ts +19 -0
- package/dist/chat/ChatPage.d.ts +1 -1
- package/dist/chat/WorkflowStepChip.d.ts +24 -0
- package/dist/chat/chat-page-types.d.ts +4 -0
- package/dist/chat/index.cjs +130 -122
- package/dist/chat/index.d.ts +1 -0
- package/dist/chat/index.js +2 -2
- package/dist/{chunk-22P5KNIM.js → chunk-34UW6XUQ.js} +928 -38
- package/dist/chunk-34UW6XUQ.js.map +1 -0
- package/dist/{chunk-VYRKO3XU.cjs → chunk-3XR3IEGU.cjs} +944 -35
- package/dist/chunk-3XR3IEGU.cjs.map +1 -0
- package/dist/{chunk-ZWA7UUZL.cjs → chunk-7YUFMNFW.cjs} +2 -54
- package/dist/chunk-7YUFMNFW.cjs.map +1 -0
- package/dist/chunk-A24C6BNA.js +92 -0
- package/dist/chunk-A24C6BNA.js.map +1 -0
- package/dist/chunk-AINNADMT.cjs +62 -0
- package/dist/chunk-AINNADMT.cjs.map +1 -0
- package/dist/{chunk-7CVF3DK2.cjs → chunk-EKIUMNCN.cjs} +5 -5
- package/dist/{chunk-7CVF3DK2.cjs.map → chunk-EKIUMNCN.cjs.map} +1 -1
- package/dist/chunk-FE4ULGOR.js +151 -0
- package/dist/chunk-FE4ULGOR.js.map +1 -0
- package/dist/chunk-FT5FFXSJ.js +60 -0
- package/dist/chunk-FT5FFXSJ.js.map +1 -0
- package/dist/{chunk-HITAN7JF.cjs → chunk-GTXOV7IJ.cjs} +4 -4
- package/dist/{chunk-HITAN7JF.cjs.map → chunk-GTXOV7IJ.cjs.map} +1 -1
- package/dist/{chunk-TKB7TVMW.js → chunk-HEVVT6IT.js} +78 -14
- package/dist/chunk-HEVVT6IT.js.map +1 -0
- package/dist/{chunk-IPGKTUF7.cjs → chunk-HOD6OM7L.cjs} +68 -3
- package/dist/chunk-HOD6OM7L.cjs.map +1 -0
- package/dist/{chunk-7FKARMA3.cjs → chunk-JFUN4D7D.cjs} +101 -37
- package/dist/chunk-JFUN4D7D.cjs.map +1 -0
- package/dist/{chunk-UIWLDSTF.js → chunk-NIP5BOP7.js} +68 -5
- package/dist/chunk-NIP5BOP7.js.map +1 -0
- package/dist/{chunk-MK6NJQGF.js → chunk-OEM5ARVM.js} +3 -3
- package/dist/{chunk-MK6NJQGF.js.map → chunk-OEM5ARVM.js.map} +1 -1
- package/dist/{chunk-5EBGRG3X.js → chunk-OPA2Y6YZ.js} +3 -54
- package/dist/chunk-OPA2Y6YZ.js.map +1 -0
- package/dist/chunk-TZR36PPP.cjs +95 -0
- package/dist/chunk-TZR36PPP.cjs.map +1 -0
- package/dist/{chunk-WJEKRSPH.js → chunk-UEU23PTW.js} +3 -3
- package/dist/{chunk-WJEKRSPH.js.map → chunk-UEU23PTW.js.map} +1 -1
- package/dist/chunk-ZVBPRMHJ.cjs +153 -0
- package/dist/chunk-ZVBPRMHJ.cjs.map +1 -0
- package/dist/connect/docx.cjs +10 -88
- package/dist/connect/docx.cjs.map +1 -1
- package/dist/connect/docx.js +6 -86
- package/dist/connect/docx.js.map +1 -1
- package/dist/connect/index.cjs +293 -30
- package/dist/connect/index.cjs.map +1 -1
- package/dist/connect/index.js +278 -15
- package/dist/connect/index.js.map +1 -1
- package/dist/connection/ConnectedWorkflowRunner.d.ts +16 -2
- package/dist/connection/WorkflowRunnerDialogs.d.ts +37 -0
- package/dist/connection/useWorkflowThread.d.ts +12 -0
- package/dist/document-tools/index.cjs +7 -143
- package/dist/document-tools/index.cjs.map +1 -1
- package/dist/document-tools/index.js +5 -144
- package/dist/document-tools/index.js.map +1 -1
- package/dist/docx/index.cjs +18 -17
- package/dist/docx/index.cjs.map +1 -1
- package/dist/docx/index.js +3 -2
- package/dist/docx/index.js.map +1 -1
- package/dist/index.cjs +467 -383
- package/dist/index.js +5 -5
- package/dist/studio/index.cjs +3 -3
- package/dist/studio/index.js +2 -2
- package/dist/workflow-canvas/StepActionSettings.d.ts +132 -0
- package/dist/workflow-canvas/StepInspector.d.ts +25 -2
- package/dist/workflow-canvas/WorkflowBuilder.d.ts +11 -3
- package/dist/workflow-canvas/WorkflowCanvas.d.ts +27 -2
- package/dist/workflow-canvas/edit.d.ts +9 -1
- package/dist/workflow-canvas/index.cjs +879 -99
- package/dist/workflow-canvas/index.cjs.map +1 -1
- package/dist/workflow-canvas/index.js +846 -66
- package/dist/workflow-canvas/index.js.map +1 -1
- package/package.json +4 -4
- package/src/workflow-canvas/canvas.css +9 -0
- package/dist/chunk-22P5KNIM.js.map +0 -1
- package/dist/chunk-5EBGRG3X.js.map +0 -1
- package/dist/chunk-7FKARMA3.cjs.map +0 -1
- package/dist/chunk-IPGKTUF7.cjs.map +0 -1
- package/dist/chunk-TKB7TVMW.js.map +0 -1
- package/dist/chunk-UIWLDSTF.js.map +0 -1
- package/dist/chunk-VYRKO3XU.cjs.map +0 -1
- package/dist/chunk-ZWA7UUZL.cjs.map +0 -1
|
@@ -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,
|
|
@@ -740,6 +982,12 @@ function toPlanSteps(workflow, options = {}) {
|
|
|
740
982
|
ui,
|
|
741
983
|
// An unfinished signal (still being typed) is not saved: the server would refuse it.
|
|
742
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) } : {},
|
|
743
991
|
...step.kind === "agent" ? agentStep(workflow, step, options) : { skill: null, inputs: null, prompt: null }
|
|
744
992
|
};
|
|
745
993
|
});
|
|
@@ -772,7 +1020,9 @@ function fromPlanSteps(steps) {
|
|
|
772
1020
|
commit: ui.commit,
|
|
773
1021
|
nextLabel: ui.next_label,
|
|
774
1022
|
...p.after != null ? { after: p.after } : {},
|
|
775
|
-
...p.signals?.length ? { signals: p.signals.map(fromPlanSignal) } : {}
|
|
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 } : {}
|
|
776
1026
|
};
|
|
777
1027
|
switch (p.kind) {
|
|
778
1028
|
case "form":
|
|
@@ -780,7 +1030,15 @@ function fromPlanSteps(steps) {
|
|
|
780
1030
|
case "upload":
|
|
781
1031
|
return { ...base, kind: "upload", required: ui.required, accept: ui.accept, hint: ui.hint };
|
|
782
1032
|
case "review":
|
|
783
|
-
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) };
|
|
784
1042
|
default: {
|
|
785
1043
|
const promptTemplate = ui.prompt_template ?? p.prompt ?? void 0;
|
|
786
1044
|
return {
|
|
@@ -790,7 +1048,8 @@ function fromPlanSteps(steps) {
|
|
|
790
1048
|
with: ui.with ?? p.inputs ?? void 0,
|
|
791
1049
|
run: !ui.workflow && !p.skill && promptTemplate ? { kind: "prompt", promptTemplate } : void 0,
|
|
792
1050
|
output: ui.output,
|
|
793
|
-
branch: p.branch || void 0
|
|
1051
|
+
branch: p.branch || void 0,
|
|
1052
|
+
...fromPlanDocumentRef(p.edit_document) ? { editDocument: fromPlanDocumentRef(p.edit_document) } : {}
|
|
794
1053
|
};
|
|
795
1054
|
}
|
|
796
1055
|
}
|
|
@@ -803,25 +1062,47 @@ function layoutFromPlanSteps(steps) {
|
|
|
803
1062
|
});
|
|
804
1063
|
return entries.length ? Object.fromEntries(entries) : void 0;
|
|
805
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
|
+
}
|
|
806
1087
|
var errorMessage = (e) => e instanceof Error ? e.message : typeof e === "string" ? e : "Something went wrong.";
|
|
807
1088
|
function firstOpen(steps, states) {
|
|
808
1089
|
const open = steps.find((s) => !["done", "skipped"].includes(states[s.id]?.status ?? "pending"));
|
|
809
1090
|
return open?.id ?? (steps.length && isRunFinished(steps, states) ? null : steps[0]?.id ?? null);
|
|
810
1091
|
}
|
|
811
1092
|
function useWorkflowView(options) {
|
|
812
|
-
const { steps, states, inputs, setInput } = options;
|
|
1093
|
+
const { steps, states, inputs, setInput, loaded = true } = options;
|
|
813
1094
|
const [current, setCurrent] = useState(() => firstOpen(steps, states));
|
|
814
1095
|
const [showErrors, setShowErrors] = useState(false);
|
|
815
1096
|
const [busy, setBusy] = useState(false);
|
|
816
1097
|
const [actionError, setActionError] = useState(null);
|
|
817
1098
|
const optionsRef = useRef(options);
|
|
818
1099
|
optionsRef.current = options;
|
|
819
|
-
const placed = useRef(steps.length > 0);
|
|
1100
|
+
const placed = useRef(steps.length > 0 && loaded);
|
|
820
1101
|
useEffect(() => {
|
|
821
|
-
if (placed.current || steps.length === 0) return;
|
|
1102
|
+
if (placed.current || steps.length === 0 || !loaded) return;
|
|
822
1103
|
placed.current = true;
|
|
823
1104
|
setCurrent(firstOpen(steps, states));
|
|
824
|
-
}, [steps, states]);
|
|
1105
|
+
}, [steps, states, loaded]);
|
|
825
1106
|
const step = steps.find((s) => s.id === current);
|
|
826
1107
|
const following = useCallback(
|
|
827
1108
|
(id) => {
|
|
@@ -909,6 +1190,40 @@ function useWorkflowView(options) {
|
|
|
909
1190
|
// eslint-disable-next-line react-hooks/exhaustive-deps
|
|
910
1191
|
[act, !!options.retry]
|
|
911
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
|
+
);
|
|
912
1227
|
const isLocked = useCallback(
|
|
913
1228
|
(stepId) => optionsRef.current.isLocked?.(stepId) ?? false,
|
|
914
1229
|
[]
|
|
@@ -934,6 +1249,19 @@ function useWorkflowView(options) {
|
|
|
934
1249
|
goTo,
|
|
935
1250
|
skip,
|
|
936
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
|
+
},
|
|
937
1265
|
restart: () => {
|
|
938
1266
|
setShowErrors(false);
|
|
939
1267
|
setActionError(null);
|
|
@@ -941,9 +1269,489 @@ function useWorkflowView(options) {
|
|
|
941
1269
|
}
|
|
942
1270
|
};
|
|
943
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
|
+
}
|
|
944
1751
|
function PhaseMark({ phase, icon }) {
|
|
945
1752
|
if (phase === "done") return /* @__PURE__ */ jsx(Check, { className: "size-3.5 shrink-0" });
|
|
946
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" });
|
|
947
1755
|
if (phase === "failed") return /* @__PURE__ */ jsx(AlertTriangle, { className: "size-3.5 shrink-0" });
|
|
948
1756
|
if (phase === "skipped") return /* @__PURE__ */ jsx(MinusCircle, { className: "size-3.5 shrink-0" });
|
|
949
1757
|
return icon ? /* @__PURE__ */ jsx("span", { className: "flex size-3.5 shrink-0 items-center justify-center [&_svg]:size-3.5", children: icon }) : null;
|
|
@@ -976,6 +1784,8 @@ function WorkflowStepBar({
|
|
|
976
1784
|
const pill = (s) => {
|
|
977
1785
|
const phase = run.phaseOf(s.id);
|
|
978
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;
|
|
979
1789
|
return /* @__PURE__ */ jsxs(
|
|
980
1790
|
"button",
|
|
981
1791
|
{
|
|
@@ -985,16 +1795,27 @@ function WorkflowStepBar({
|
|
|
985
1795
|
className: cn(
|
|
986
1796
|
PILL,
|
|
987
1797
|
"transition-colors disabled:cursor-default",
|
|
988
|
-
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"
|
|
989
1799
|
),
|
|
990
1800
|
"aria-current": current ? "step" : void 0,
|
|
991
|
-
"aria-label":
|
|
992
|
-
title
|
|
1801
|
+
"aria-label": title,
|
|
1802
|
+
title,
|
|
993
1803
|
"data-phase": phase,
|
|
994
1804
|
"data-testid": tid(`step-${s.id}`),
|
|
995
1805
|
children: [
|
|
996
1806
|
/* @__PURE__ */ jsx(PhaseMark, { phase, icon: icon(s.icon) }),
|
|
997
|
-
(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
|
+
)
|
|
998
1819
|
]
|
|
999
1820
|
},
|
|
1000
1821
|
s.id
|
|
@@ -1099,7 +1920,8 @@ var DEFAULT_WORKFLOW_RUNNER_LABELS = {
|
|
|
1099
1920
|
fileReading: "Reading\u2026",
|
|
1100
1921
|
fileReady: "Ready",
|
|
1101
1922
|
fileFailed: "Could not be read",
|
|
1102
|
-
readingFiles: "Reading {current} of {count} files\u2026"
|
|
1923
|
+
readingFiles: "Reading {current} of {count} files\u2026",
|
|
1924
|
+
markSent: "Mark as sent"
|
|
1103
1925
|
};
|
|
1104
1926
|
function WorkflowRunner({
|
|
1105
1927
|
workflow,
|
|
@@ -1115,11 +1937,16 @@ function WorkflowRunner({
|
|
|
1115
1937
|
renderScope,
|
|
1116
1938
|
renderDocuments,
|
|
1117
1939
|
renderIcon,
|
|
1940
|
+
people,
|
|
1941
|
+
actions,
|
|
1942
|
+
nameOfDoc,
|
|
1118
1943
|
labels,
|
|
1944
|
+
partsLabels,
|
|
1119
1945
|
testIdPrefix = "workflow-run",
|
|
1120
1946
|
className
|
|
1121
1947
|
}) {
|
|
1122
1948
|
const l = { ...DEFAULT_WORKFLOW_RUNNER_LABELS, ...labels };
|
|
1949
|
+
const pl = { ...DEFAULT_WORKFLOW_STEP_PARTS_LABELS, ...partsLabels };
|
|
1123
1950
|
const { steps, step, isComplete, action } = run;
|
|
1124
1951
|
const completion = workflow.run.kind === "steps" ? workflow.run.completion : void 0;
|
|
1125
1952
|
const tid = (suffix) => `${testIdPrefix}-${suffix}`;
|
|
@@ -1128,7 +1955,7 @@ function WorkflowRunner({
|
|
|
1128
1955
|
const added = step?.kind === "upload" ? (files ?? []).filter((f) => f.addedFor === step.id) : [];
|
|
1129
1956
|
const unread = added.filter((f) => f.status === "processing").length;
|
|
1130
1957
|
const reading = action === "complete" && unread > 0;
|
|
1131
|
-
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;
|
|
1132
1959
|
return /* @__PURE__ */ jsxs("div", { className: cn("space-y-6", className), "data-testid": testIdPrefix, children: [
|
|
1133
1960
|
/* @__PURE__ */ jsx(
|
|
1134
1961
|
WorkflowStepBar,
|
|
@@ -1160,6 +1987,8 @@ function WorkflowRunner({
|
|
|
1160
1987
|
stepDependencies(steps, step.id).map((d) => steps.find((s) => s.id === d)?.title ?? d).join(", ")
|
|
1161
1988
|
) }) }) : step.kind === "form" ? /* @__PURE__ */ jsxs(Card, { className: "max-w-2xl space-y-4 p-6", "data-testid": tid(step.id), children: [
|
|
1162
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) }),
|
|
1163
1992
|
/* @__PURE__ */ jsx("fieldset", { disabled: run.isLocked(step.id), className: "contents", children: /* @__PURE__ */ jsx(
|
|
1164
1993
|
SchemaForm,
|
|
1165
1994
|
{
|
|
@@ -1170,6 +1999,7 @@ function WorkflowRunner({
|
|
|
1170
1999
|
renderScope,
|
|
1171
2000
|
renderDocuments,
|
|
1172
2001
|
renderIcon,
|
|
2002
|
+
people,
|
|
1173
2003
|
onEnterSubmit: () => void run.next(),
|
|
1174
2004
|
testIdPrefix: tid("field")
|
|
1175
2005
|
}
|
|
@@ -1177,6 +2007,8 @@ function WorkflowRunner({
|
|
|
1177
2007
|
run.actionError && /* @__PURE__ */ jsx("p", { className: "text-sm text-destructive", "data-testid": tid("action-error"), children: run.actionError }),
|
|
1178
2008
|
renderStepNote?.(step, run)
|
|
1179
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) }),
|
|
1180
2012
|
renderUpload?.(step) ?? /* @__PURE__ */ jsxs(Fragment, { children: [
|
|
1181
2013
|
/* @__PURE__ */ jsx(
|
|
1182
2014
|
UploadDropzone,
|
|
@@ -1205,9 +2037,52 @@ function WorkflowRunner({
|
|
|
1205
2037
|
renderStepNote?.(step, run)
|
|
1206
2038
|
] }) : step.kind === "review" ? /* @__PURE__ */ jsxs(Card, { className: "max-w-2xl space-y-4 p-6", "data-testid": tid(step.id), children: [
|
|
1207
2039
|
/* @__PURE__ */ jsx(StepHeading, { step, icon: icon(step.icon) }),
|
|
2040
|
+
/* @__PURE__ */ jsx(SentBackNote, { state: run.stateOf(step.id), l: pl, testId: tid(step.id) }),
|
|
1208
2041
|
/* @__PURE__ */ jsx("p", { className: "whitespace-pre-line text-sm text-muted-foreground", children: reviewInstructions(step, run.inputs) }),
|
|
1209
|
-
/* @__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
|
+
),
|
|
1210
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
|
+
),
|
|
1211
2086
|
run.actionError && /* @__PURE__ */ jsx("p", { className: "text-sm text-destructive", children: run.actionError }),
|
|
1212
2087
|
renderStepNote?.(step, run)
|
|
1213
2088
|
] }) : /* @__PURE__ */ jsx(
|
|
@@ -1218,6 +2093,19 @@ function WorkflowRunner({
|
|
|
1218
2093
|
renderAgentOutput,
|
|
1219
2094
|
icon: icon(step.icon),
|
|
1220
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
|
+
] }),
|
|
1221
2109
|
l,
|
|
1222
2110
|
tid
|
|
1223
2111
|
}
|
|
@@ -1348,6 +2236,7 @@ function AgentStepBody({
|
|
|
1348
2236
|
renderAgentOutput,
|
|
1349
2237
|
icon,
|
|
1350
2238
|
renderStepNote,
|
|
2239
|
+
extra,
|
|
1351
2240
|
l,
|
|
1352
2241
|
tid
|
|
1353
2242
|
}) {
|
|
@@ -1390,7 +2279,8 @@ function AgentStepBody({
|
|
|
1390
2279
|
}
|
|
1391
2280
|
),
|
|
1392
2281
|
phase === "failed" && /* @__PURE__ */ jsx("p", { className: "text-sm text-destructive", "data-testid": tid(`${step.id}-failed`), children: state?.error || l.failed }),
|
|
1393
|
-
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
|
|
1394
2284
|
] });
|
|
1395
2285
|
if (step.output === "artifact") {
|
|
1396
2286
|
return /* @__PURE__ */ jsxs(
|
|
@@ -1417,6 +2307,6 @@ function AgentStepBody({
|
|
|
1417
2307
|
] });
|
|
1418
2308
|
}
|
|
1419
2309
|
|
|
1420
|
-
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, isIncompleteSignal, 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 };
|
|
1421
|
-
//# sourceMappingURL=chunk-
|
|
1422
|
-
//# 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
|