@sanity/workflow-studio-plugin 0.27.0 → 0.29.0
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/CHANGELOG.md +427 -0
- package/dist/_chunks-cjs/index.cjs +650 -221
- package/dist/_chunks-cjs/workflows-tool-root.cjs +820 -312
- package/dist/_chunks-es/index.js +630 -213
- package/dist/_chunks-es/workflows-tool-root.js +834 -316
- package/package.json +12 -12
package/dist/_chunks-es/index.js
CHANGED
|
@@ -2,7 +2,7 @@ import { jsx, jsxs, Fragment } from "react/jsx-runtime";
|
|
|
2
2
|
|
|
3
3
|
import { TimelineIcon } from "@sanity/icons/Timeline";
|
|
4
4
|
|
|
5
|
-
import { Popover, Tooltip, Box, Stack, Text, useClickOutsideEvent, Flex, TextInput, Button, Select, Checkbox, Autocomplete, Card, TextArea, useToast, Dialog, Switch, TextSkeleton, Code, useTheme_v2, Spinner,
|
|
5
|
+
import { Popover, Tooltip, Box, Stack, Text, useClickOutsideEvent, Flex, TextInput, Button, Select, Checkbox, Autocomplete, Card, TextArea, useToast, Dialog, Switch, TextSkeleton, Code, Badge, useTheme_v2, Spinner, MenuButton, Menu, MenuItem, useElementSize, MenuDivider, TabList, Tab, TabPanel } from "@sanity/ui";
|
|
6
6
|
|
|
7
7
|
import { editFieldTarget, useWorkflowTelemetry, useRefcountedIds } from "@sanity/workflow-react";
|
|
8
8
|
|
|
@@ -10,7 +10,7 @@ import { createContext, useContext, useEffect, useSyncExternalStore, useCallback
|
|
|
10
10
|
|
|
11
11
|
import { usePaneRouter } from "sanity/structure";
|
|
12
12
|
|
|
13
|
-
import { WORKFLOW_INSTANCE_TYPE, WORKFLOW_DEFINITION_TYPE, GUARD_DOC_TYPE, tryParseGdr, resourceFromParsed, latestDeployedDefinitions, isStartableDefinition, isSubjectEntry, isInputSourced, acceptsDocumentType, initialFieldIssues, gdrRef, releaseRef, refKindAcceptsTypes, rejectedRefTypes, ActionDisabledError, MutationGuardDeniedError, EditFieldDeniedError, errorMessage, terminalState, findOpenStageEntry, actionRendering, isTodoListEntry, isTodoListItem, isTerminalActivityStatus, describeCondition, sentenceCase, checklistLines, findCurrentActivityEntry, ENGINE_API_VERSION, scalarValidationIssues, classifyPrincipalId, userLoginProvider, toBareId, isSingleDocRefEntry, isGdr, resolveFieldEntry, isSingleDocRefKind, isNotesEntry, parseDefinitionSnapshot, isUnprimed, isTerminalStage, DEFAULT_TRANSITION_WHEN, instancesQuery, assertReadableModel, projectStartSliceRow, StartNotSettledError, StartNotAllowedError, humanize, unboundRequirementReads, explainStartRequirement, singleSubjectRequirementRefused, evaluateStartFilter, startKindOf, hasSingleSubjectRequirement, readsRootDocument, latestDefinitionsGroq, gdrFromResource, subscriptionDocumentsForInstance, aclPathForResource, definitionLookupGroq, instanceDocId, missingRequiredInputs, documentActionDenials } from "@sanity/workflow-engine";
|
|
13
|
+
import { WORKFLOW_INSTANCE_TYPE, WORKFLOW_DEFINITION_TYPE, GUARD_DOC_TYPE, tryParseGdr, resourceFromParsed, latestDeployedDefinitions, isStartableDefinition, isSubjectEntry, isInputSourced, acceptsDocumentType, initialFieldIssues, gdrRef, releaseRef, refKindAcceptsTypes, rejectedRefTypes, ActionDisabledError, MutationGuardDeniedError, EditFieldDeniedError, errorMessage, terminalState, findOpenStageEntry, actionRendering, isTodoListEntry, isTodoListItem, isTerminalActivityStatus, describeCondition, sentenceCase, checklistLines, findCurrentActivityEntry, ENGINE_API_VERSION, scalarValidationIssues, classifyPrincipalId, userLoginProvider, toBareId, findStageNode, findActivityNode, isSingleDocRefEntry, isGdr, resolveFieldEntry, isSingleDocRefKind, isNotesEntry, remediationsFor, diagnoseInstance, diagnoseInputFromEvaluation, documentStuckCause, parseDefinitionSnapshot, isUnprimed, isTerminalStage, DEFAULT_TRANSITION_WHEN, instancesQuery, assertReadableModel, projectStartSliceRow, StartNotSettledError, StartNotAllowedError, isRevisionConflict, humanize, unboundRequirementReads, explainStartRequirement, singleSubjectRequirementRefused, evaluateStartFilter, startKindOf, hasSingleSubjectRequirement, readsRootDocument, latestDefinitionsGroq, gdrFromResource, subscriptionDocumentsForInstance, aclPathForResource, definitionLookupGroq, instanceDocId, missingRequiredInputs, documentActionDenials } from "@sanity/workflow-engine";
|
|
14
14
|
|
|
15
15
|
import { CheckmarkIcon } from "@sanity/icons/Checkmark";
|
|
16
16
|
|
|
@@ -52,6 +52,8 @@ import { isDocumentSchemaType } from "@sanity/types";
|
|
|
52
52
|
|
|
53
53
|
import { LaunchIcon } from "@sanity/icons/Launch";
|
|
54
54
|
|
|
55
|
+
import { ErrorOutlineIcon } from "@sanity/icons/ErrorOutline";
|
|
56
|
+
|
|
55
57
|
import { EmptyIcon } from "@sanity/icons/Empty";
|
|
56
58
|
|
|
57
59
|
import { ErrorFilledIcon } from "@sanity/icons/ErrorFilled";
|
|
@@ -407,16 +409,25 @@ function parseLocalDate(value) {
|
|
|
407
409
|
return parsed2.getFullYear() === year && parsed2.getMonth() === (month ?? NaN) - 1 && parsed2.getDate() === day ? parsed2 : /* @__PURE__ */ new Date(NaN);
|
|
408
410
|
}
|
|
409
411
|
|
|
412
|
+
function storedDateKind(value) {
|
|
413
|
+
return /^\d{4}-\d{2}-\d{2}$/.test(value) ? "date" : "datetime";
|
|
414
|
+
}
|
|
415
|
+
|
|
410
416
|
function parseStoredDateValue(value) {
|
|
411
|
-
if (typeof value
|
|
412
|
-
const kind = /^\d{4}-\d{2}-\d{2}$/.test(value) ? "date" : "datetime";
|
|
413
|
-
return parseDateFieldValue(value, kind);
|
|
417
|
+
if (typeof value == "string") return parseDateFieldValue(value, storedDateKind(value));
|
|
414
418
|
}
|
|
415
419
|
|
|
416
420
|
function serializeDateFieldValue(date, kind) {
|
|
417
421
|
return hasTimeOfDay(kind) ? date.toISOString() : `${date.getFullYear()}-${pad2(date.getMonth() + 1)}-${pad2(date.getDate())}`;
|
|
418
422
|
}
|
|
419
423
|
|
|
424
|
+
function isDueDatePast(value, now) {
|
|
425
|
+
const kind = storedDateKind(value);
|
|
426
|
+
if (!hasTimeOfDay(kind)) return value < serializeDateFieldValue(now, kind);
|
|
427
|
+
const due = parseDateFieldValue(value, kind);
|
|
428
|
+
return due !== void 0 && due.getTime() < now.getTime();
|
|
429
|
+
}
|
|
430
|
+
|
|
420
431
|
class EffectsIncompleteError extends Error {
|
|
421
432
|
reason;
|
|
422
433
|
constructor(reason, options) {
|
|
@@ -597,7 +608,7 @@ function isLiveEntry(entry) {
|
|
|
597
608
|
const isTodoDone = item => item.status === "done", toggledTodoStatus = item => isTodoDone(item) ? "open" : "done";
|
|
598
609
|
|
|
599
610
|
function isTodoOverdue(item, today = /* @__PURE__ */ new Date) {
|
|
600
|
-
return !item.dueDate || isTodoDone(item) ? !1 : item.dueDate
|
|
611
|
+
return !item.dueDate || isTodoDone(item) ? !1 : isDueDatePast(item.dueDate, today);
|
|
601
612
|
}
|
|
602
613
|
|
|
603
614
|
function todoEditKind(patch) {
|
|
@@ -796,13 +807,25 @@ function isItemAssignedTo(item, who) {
|
|
|
796
807
|
return item.assignee != null && assigneeMatches(item.assignee, who);
|
|
797
808
|
}
|
|
798
809
|
|
|
810
|
+
function matchingAssignees(state, who) {
|
|
811
|
+
return state.flatMap(entry => entry._type === "assignees" ? entry.value.filter(a => assigneeMatches(a, who)) : entry._type === "assignee" && entry.value !== null && assigneeMatches(entry.value, who) ? [ entry.value ] : []);
|
|
812
|
+
}
|
|
813
|
+
|
|
799
814
|
function isActivityAssignedTo(args) {
|
|
800
|
-
return args.state
|
|
815
|
+
return matchingAssignees(args.state, args.who).length > 0;
|
|
816
|
+
}
|
|
817
|
+
|
|
818
|
+
function isRoleAssignedTo(args) {
|
|
819
|
+
return matchingAssignees(args.state, args.who).some(member => member.type === "role");
|
|
820
|
+
}
|
|
821
|
+
|
|
822
|
+
function isItemRoleAssignedTo(item, who) {
|
|
823
|
+
return isItemAssignedTo(item, who) && item.assignee?.type === "role";
|
|
801
824
|
}
|
|
802
825
|
|
|
803
826
|
function assignedWork(args) {
|
|
804
|
-
const {instance: instance, committed: committed, who: who} = args, evaluation = args.staleEvaluation === "keep" || isEvaluationCurrent(args) ? args.evaluation : void 0, byActivity = stateByActivity(instance), activities = (evaluation?.currentStage.activities ?? []).filter(t => isActivityAssignedTo({
|
|
805
|
-
state:
|
|
827
|
+
const {instance: instance, committed: committed, who: who} = args, evaluation = args.staleEvaluation === "keep" || isEvaluationCurrent(args) ? args.evaluation : void 0, byActivity = stateByActivity(instance), stateOf = t => byActivity.get(t.activity.name) ?? [], activities = (evaluation?.currentStage.activities ?? []).filter(t => isActivityAssignedTo({
|
|
828
|
+
state: stateOf(t),
|
|
806
829
|
who: who
|
|
807
830
|
})), items = deriveTodoItems({
|
|
808
831
|
instance: instance,
|
|
@@ -812,7 +835,11 @@ function assignedWork(args) {
|
|
|
812
835
|
return {
|
|
813
836
|
activities: activities,
|
|
814
837
|
openItems: items.filter(row => !isTodoDone(row.item)),
|
|
815
|
-
doneItems: items.filter(row => isTodoDone(row.item))
|
|
838
|
+
doneItems: items.filter(row => isTodoDone(row.item)),
|
|
839
|
+
roleMatched: activities.some(t => isRoleAssignedTo({
|
|
840
|
+
state: stateOf(t),
|
|
841
|
+
who: who
|
|
842
|
+
})) || items.some(row => isItemRoleAssignedTo(row.item, who))
|
|
816
843
|
};
|
|
817
844
|
}
|
|
818
845
|
|
|
@@ -861,7 +888,8 @@ function forMeWorkOf(entries, identity) {
|
|
|
861
888
|
return {
|
|
862
889
|
work: work,
|
|
863
890
|
count: work.reduce((n, {count: count}) => n + count, 0),
|
|
864
|
-
hasRows: work.some(({shown: shown}) => hasAssignedRows(shown))
|
|
891
|
+
hasRows: work.some(({shown: shown}) => hasAssignedRows(shown)),
|
|
892
|
+
hasRoleMatched: work.some(({shown: shown}) => shown.roleMatched)
|
|
865
893
|
};
|
|
866
894
|
}
|
|
867
895
|
|
|
@@ -901,7 +929,7 @@ function concludesHere(actionEval, activityName) {
|
|
|
901
929
|
return changesOwnStatus(actionEval.action, activityName) || actionEval.firing?.exitsStage === !0;
|
|
902
930
|
}
|
|
903
931
|
|
|
904
|
-
const
|
|
932
|
+
const DECISION_SEMANTIC_FACE = {
|
|
905
933
|
"decision.accept": {
|
|
906
934
|
tone: "positive",
|
|
907
935
|
icon: CheckmarkIcon
|
|
@@ -912,6 +940,15 @@ const SEMANTIC_FACE = {
|
|
|
912
940
|
}
|
|
913
941
|
};
|
|
914
942
|
|
|
943
|
+
function isDecisionSemantic(value) {
|
|
944
|
+
return Object.hasOwn(DECISION_SEMANTIC_FACE, value);
|
|
945
|
+
}
|
|
946
|
+
|
|
947
|
+
function decisionSemanticFace(semantics) {
|
|
948
|
+
const semantic = semantics.find(isDecisionSemantic);
|
|
949
|
+
return semantic === void 0 ? void 0 : DECISION_SEMANTIC_FACE[semantic];
|
|
950
|
+
}
|
|
951
|
+
|
|
915
952
|
function actionButtonFace(args) {
|
|
916
953
|
const mode = concludesHere(args.actionEval, args.activityName) ? "default" : "ghost";
|
|
917
954
|
if (actionAdvanceStatus(args.actionEval.action, args.activityName) === "failed") return {
|
|
@@ -919,7 +956,7 @@ function actionButtonFace(args) {
|
|
|
919
956
|
tone: "critical",
|
|
920
957
|
icon: void 0
|
|
921
958
|
};
|
|
922
|
-
const
|
|
959
|
+
const face = decisionSemanticFace(args.actionEval.semantics ?? []);
|
|
923
960
|
return {
|
|
924
961
|
mode: mode,
|
|
925
962
|
tone: face?.tone ?? "default",
|
|
@@ -1386,21 +1423,32 @@ function bridgedSelfId(users, meId) {
|
|
|
1386
1423
|
return users.find(user => user.membership.id === meId)?.profile?.sanityUserId ?? classified.globalId ?? (classified.namespace === "project" ? void 0 : meId);
|
|
1387
1424
|
}
|
|
1388
1425
|
|
|
1389
|
-
function
|
|
1426
|
+
function useSelfState() {
|
|
1390
1427
|
const me = useCurrentUser(), {users: users, loading: loading, error: error} = useStudioProjectUsers();
|
|
1391
|
-
if (!me) return
|
|
1392
|
-
|
|
1393
|
-
if (id !== void 0) return {
|
|
1394
|
-
id: id,
|
|
1395
|
-
roles: me.roles ?? []
|
|
1428
|
+
if (!me) return {
|
|
1429
|
+
kind: "unavailable"
|
|
1396
1430
|
};
|
|
1397
|
-
|
|
1398
|
-
|
|
1399
|
-
|
|
1400
|
-
|
|
1431
|
+
const id = bridgedSelfId(users, me.id);
|
|
1432
|
+
return id !== void 0 ? {
|
|
1433
|
+
kind: "resolved",
|
|
1434
|
+
self: {
|
|
1435
|
+
id: id,
|
|
1436
|
+
roles: me.roles ?? []
|
|
1401
1437
|
}
|
|
1402
|
-
|
|
1403
|
-
|
|
1438
|
+
} : loading ? {
|
|
1439
|
+
kind: "pending"
|
|
1440
|
+
} : error !== void 0 ? (warnSelfUnavailableOnce(`load:${me.id}`, `workflow: the project member directory failed to load ("${errorMessage(error)}") — the logged-in user ("${me.id}") is project-scoped, and only that directory maps it to the account-global identity the engine stores, so workflow assignment and authoring controls stay disabled. A mounted view does not retry on its own; the next consumer to ask reloads the directory once its backoff has passed.`),
|
|
1441
|
+
{
|
|
1442
|
+
kind: "unavailable"
|
|
1443
|
+
}) : (warnSelfUnavailableOnce(`unresolved:${me.id}`, `workflow: the project member directory cannot resolve the logged-in user ("${me.id}") to an account-global identity — the engine stores account-global user ids only, so workflow assignment and authoring controls stay disabled. Typically this user is not a member of this project.`),
|
|
1444
|
+
{
|
|
1445
|
+
kind: "unavailable"
|
|
1446
|
+
});
|
|
1447
|
+
}
|
|
1448
|
+
|
|
1449
|
+
function useBridgedSelf() {
|
|
1450
|
+
const state = useSelfState();
|
|
1451
|
+
return state.kind === "resolved" ? state.self : void 0;
|
|
1404
1452
|
}
|
|
1405
1453
|
|
|
1406
1454
|
function useSelfActor() {
|
|
@@ -1409,13 +1457,22 @@ function useSelfActor() {
|
|
|
1409
1457
|
}
|
|
1410
1458
|
|
|
1411
1459
|
function useAssignmentIdentity() {
|
|
1412
|
-
const
|
|
1413
|
-
if (
|
|
1414
|
-
|
|
1415
|
-
|
|
1460
|
+
const state = useSelfState();
|
|
1461
|
+
if (state.kind !== "resolved") return state;
|
|
1462
|
+
const {id: id, roles: roles} = state.self;
|
|
1463
|
+
return {
|
|
1464
|
+
kind: "resolved",
|
|
1465
|
+
identity: {
|
|
1466
|
+
userId: id,
|
|
1467
|
+
roles: roles.map(r => r.name)
|
|
1468
|
+
}
|
|
1416
1469
|
};
|
|
1417
1470
|
}
|
|
1418
1471
|
|
|
1472
|
+
function identityOf(state) {
|
|
1473
|
+
return state.kind === "resolved" ? state.identity : void 0;
|
|
1474
|
+
}
|
|
1475
|
+
|
|
1419
1476
|
const projectMembersByUsers = /* @__PURE__ */ new WeakMap;
|
|
1420
1477
|
|
|
1421
1478
|
function projectMembersFrom(users) {
|
|
@@ -1435,9 +1492,10 @@ function projectMembersFrom(users) {
|
|
|
1435
1492
|
}
|
|
1436
1493
|
|
|
1437
1494
|
function useProjectMembers() {
|
|
1438
|
-
const {users: users, loading: loading, error: error} = useStudioProjectUsers();
|
|
1495
|
+
const {users: users, roles: roles, loading: loading, error: error} = useStudioProjectUsers();
|
|
1439
1496
|
return {
|
|
1440
1497
|
members: useMemo(() => projectMembersFrom(users), [ users ]),
|
|
1498
|
+
roles: roles,
|
|
1441
1499
|
loading: loading,
|
|
1442
1500
|
error: error === void 0 ? void 0 : errorMessage(error)
|
|
1443
1501
|
};
|
|
@@ -1522,6 +1580,8 @@ function buildParams(decls, values) {
|
|
|
1522
1580
|
};
|
|
1523
1581
|
}
|
|
1524
1582
|
|
|
1583
|
+
const LOADING_CUE_DELAY_MS = 400;
|
|
1584
|
+
|
|
1525
1585
|
function useDelayedFlag(active, delayMs) {
|
|
1526
1586
|
const [held, setHeld] = useState(!1);
|
|
1527
1587
|
return useEffect(() => {
|
|
@@ -1791,10 +1851,12 @@ function PickedValueRow({children: children, onRequestChange: onRequestChange})
|
|
|
1791
1851
|
}
|
|
1792
1852
|
|
|
1793
1853
|
function MemberPicker({selectedIds: selectedIds, onSelect: onSelect, unassignRow: unassignRow = !1}) {
|
|
1794
|
-
const
|
|
1854
|
+
const {error: error, loading: loading, members: members} = useProjectMembers();
|
|
1795
1855
|
/* @__PURE__ */
|
|
1796
1856
|
return jsx(MemberPicker$1, {
|
|
1797
|
-
|
|
1857
|
+
error: error,
|
|
1858
|
+
loading: loading,
|
|
1859
|
+
members: members,
|
|
1798
1860
|
onSelect: onSelect,
|
|
1799
1861
|
selectedIds: selectedIds,
|
|
1800
1862
|
unassignRow: unassignRow
|
|
@@ -2527,11 +2589,10 @@ function Separator() {
|
|
|
2527
2589
|
}
|
|
2528
2590
|
|
|
2529
2591
|
function stageTitle(definition, stageName) {
|
|
2530
|
-
return
|
|
2531
|
-
|
|
2532
|
-
|
|
2533
|
-
|
|
2534
|
-
return args.definition?.stages.find(s => s.name === args.stageName)?.activities?.find(a => a.name === args.activityName);
|
|
2592
|
+
return findStageNode({
|
|
2593
|
+
definition: definition,
|
|
2594
|
+
stageName: stageName
|
|
2595
|
+
})?.title ?? stageName;
|
|
2535
2596
|
}
|
|
2536
2597
|
|
|
2537
2598
|
function findActivity(args) {
|
|
@@ -2578,20 +2639,20 @@ function noteRow(args) {
|
|
|
2578
2639
|
}
|
|
2579
2640
|
|
|
2580
2641
|
function AssigneeBadge({assignee: assignee}) {
|
|
2581
|
-
const
|
|
2642
|
+
const vocabulary = useProjectMembers();
|
|
2582
2643
|
/* @__PURE__ */
|
|
2583
2644
|
return jsx(AssigneeBadge$1, {
|
|
2584
2645
|
assignee: assignee,
|
|
2585
|
-
|
|
2646
|
+
vocabulary: vocabulary
|
|
2586
2647
|
});
|
|
2587
2648
|
}
|
|
2588
2649
|
|
|
2589
2650
|
function AssigneeBadges({assignees: assignees}) {
|
|
2590
|
-
const
|
|
2651
|
+
const vocabulary = useProjectMembers();
|
|
2591
2652
|
/* @__PURE__ */
|
|
2592
2653
|
return jsx(AssigneeBadges$1, {
|
|
2593
2654
|
assignees: assignees,
|
|
2594
|
-
|
|
2655
|
+
vocabulary: vocabulary
|
|
2595
2656
|
});
|
|
2596
2657
|
}
|
|
2597
2658
|
|
|
@@ -3999,6 +4060,267 @@ function EditableField({field: field, entry: entry, description: description, in
|
|
|
3999
4060
|
});
|
|
4000
4061
|
}
|
|
4001
4062
|
|
|
4063
|
+
function useDrainEffects(instanceId) {
|
|
4064
|
+
const {drainEffectsFor: drainEffectsFor} = useWorkflowContext(), toast = useWorkflowToast(), [busy, setBusy] = useState(!1);
|
|
4065
|
+
return {
|
|
4066
|
+
busy: busy,
|
|
4067
|
+
run: async () => {
|
|
4068
|
+
setBusy(!0);
|
|
4069
|
+
try {
|
|
4070
|
+
await drainEffectsFor(instanceId), toast.push({
|
|
4071
|
+
id: TOAST_ID.effectsDrain,
|
|
4072
|
+
status: "info",
|
|
4073
|
+
title: "Ran the registered handlers"
|
|
4074
|
+
});
|
|
4075
|
+
} catch (err) {
|
|
4076
|
+
toast.push({
|
|
4077
|
+
id: TOAST_ID.effectsDrain,
|
|
4078
|
+
status: "error",
|
|
4079
|
+
title: "Failed to run pending effects",
|
|
4080
|
+
description: describeError(err)
|
|
4081
|
+
});
|
|
4082
|
+
} finally {
|
|
4083
|
+
setBusy(!1);
|
|
4084
|
+
}
|
|
4085
|
+
}
|
|
4086
|
+
};
|
|
4087
|
+
}
|
|
4088
|
+
|
|
4089
|
+
function isRunnable(verb) {
|
|
4090
|
+
return verb === "drain-effects";
|
|
4091
|
+
}
|
|
4092
|
+
|
|
4093
|
+
function effectLabel(effect) {
|
|
4094
|
+
return effect.title ?? effect.name;
|
|
4095
|
+
}
|
|
4096
|
+
|
|
4097
|
+
const ACTION_LABEL = {
|
|
4098
|
+
"drain-effects": "Run the step again"
|
|
4099
|
+
}, REMEDY_TEXT = {
|
|
4100
|
+
"retry-effect": "The step has to run again before this workflow can continue.",
|
|
4101
|
+
"reset-activity": "Reset the task to try it again, or skip it.",
|
|
4102
|
+
"set-stage": "Move the workflow on to its next stage yourself."
|
|
4103
|
+
};
|
|
4104
|
+
|
|
4105
|
+
function detailOf(cause) {
|
|
4106
|
+
switch (cause.kind) {
|
|
4107
|
+
case "failed-effect":
|
|
4108
|
+
return `The step “${effectLabel(cause.effect)}” failed`;
|
|
4109
|
+
|
|
4110
|
+
case "hung-effect":
|
|
4111
|
+
return `The step “${effectLabel(cause.effect)}” didn’t finish`;
|
|
4112
|
+
|
|
4113
|
+
case "failed-activity":
|
|
4114
|
+
return "This task failed";
|
|
4115
|
+
|
|
4116
|
+
default:
|
|
4117
|
+
return summaryOf(cause);
|
|
4118
|
+
}
|
|
4119
|
+
}
|
|
4120
|
+
|
|
4121
|
+
function summaryOf(cause) {
|
|
4122
|
+
switch (cause.kind) {
|
|
4123
|
+
case "failed-effect":
|
|
4124
|
+
return "An automated step failed";
|
|
4125
|
+
|
|
4126
|
+
case "hung-effect":
|
|
4127
|
+
return "An automated step didn’t finish";
|
|
4128
|
+
|
|
4129
|
+
case "failed-activity":
|
|
4130
|
+
return "A task failed";
|
|
4131
|
+
|
|
4132
|
+
case "no-transition-fires":
|
|
4133
|
+
return "Every task is done, but nothing moves this workflow on";
|
|
4134
|
+
|
|
4135
|
+
case "transition-unevaluable":
|
|
4136
|
+
return "This workflow is waiting on something it can’t read yet, and will move on by itself";
|
|
4137
|
+
}
|
|
4138
|
+
}
|
|
4139
|
+
|
|
4140
|
+
function activityDeclaringEffect(args) {
|
|
4141
|
+
return findStageNode(args)?.activities?.find(activity => (activity.actions ?? []).some(action => (action.effects ?? []).some(effect => effect.name === args.effectName)))?.name;
|
|
4142
|
+
}
|
|
4143
|
+
|
|
4144
|
+
function faultingActivity(args) {
|
|
4145
|
+
const {cause: cause} = args;
|
|
4146
|
+
if (cause.kind === "failed-activity") return cause.activity;
|
|
4147
|
+
if (cause.kind === "failed-effect" || cause.kind === "hung-effect") return activityDeclaringEffect({
|
|
4148
|
+
definition: args.definition,
|
|
4149
|
+
effectName: cause.effect.name,
|
|
4150
|
+
stageName: args.stageName
|
|
4151
|
+
});
|
|
4152
|
+
}
|
|
4153
|
+
|
|
4154
|
+
function isRecoverable(cause) {
|
|
4155
|
+
return cause.kind === "transition-unevaluable";
|
|
4156
|
+
}
|
|
4157
|
+
|
|
4158
|
+
function diagnosisOf(args) {
|
|
4159
|
+
if (args.evaluation !== void 0) return diagnoseInstance(diagnoseInputFromEvaluation(args.evaluation));
|
|
4160
|
+
const cause = documentStuckCause({
|
|
4161
|
+
instance: args.instance,
|
|
4162
|
+
definition: args.definition
|
|
4163
|
+
});
|
|
4164
|
+
return cause === void 0 ? void 0 : {
|
|
4165
|
+
state: "stuck",
|
|
4166
|
+
cause: cause
|
|
4167
|
+
};
|
|
4168
|
+
}
|
|
4169
|
+
|
|
4170
|
+
function instanceFault(args) {
|
|
4171
|
+
const diagnosis = diagnosisOf(args);
|
|
4172
|
+
if (diagnosis === void 0 || diagnosis.state !== "stuck") return;
|
|
4173
|
+
const verbs = remediationsFor(diagnosis).map(remediation2 => remediation2.verb);
|
|
4174
|
+
return {
|
|
4175
|
+
activity: faultingActivity({
|
|
4176
|
+
cause: diagnosis.cause,
|
|
4177
|
+
definition: args.definition,
|
|
4178
|
+
stageName: args.instance.currentStage
|
|
4179
|
+
}),
|
|
4180
|
+
detail: detailOf(diagnosis.cause),
|
|
4181
|
+
summary: summaryOf(diagnosis.cause),
|
|
4182
|
+
remedies: verbs.flatMap(verb => REMEDY_TEXT[verb] ?? []),
|
|
4183
|
+
actions: verbs.flatMap(verb => isRunnable(verb) ? [ {
|
|
4184
|
+
verb: verb,
|
|
4185
|
+
label: ACTION_LABEL[verb]
|
|
4186
|
+
} ] : []),
|
|
4187
|
+
recoverable: isRecoverable(diagnosis.cause)
|
|
4188
|
+
};
|
|
4189
|
+
}
|
|
4190
|
+
|
|
4191
|
+
function looksLikeDefinition(value) {
|
|
4192
|
+
return typeof value == "object" && value !== null && Array.isArray(value.stages);
|
|
4193
|
+
}
|
|
4194
|
+
|
|
4195
|
+
const parsed = /* @__PURE__ */ new WeakMap;
|
|
4196
|
+
|
|
4197
|
+
function definitionSnapshotOf(instance) {
|
|
4198
|
+
if (parsed.has(instance)) return parsed.get(instance);
|
|
4199
|
+
let definition;
|
|
4200
|
+
try {
|
|
4201
|
+
const candidate = parseDefinitionSnapshot(instance);
|
|
4202
|
+
if (!looksLikeDefinition(candidate)) throw new Error(`definitionSnapshot on "${instance._id}" parsed to a non-definition shape`);
|
|
4203
|
+
definition = candidate;
|
|
4204
|
+
} catch (err) {
|
|
4205
|
+
console.error("[workflow-studio-plugin] unreadable definitionSnapshot:", err), definition = void 0;
|
|
4206
|
+
}
|
|
4207
|
+
return parsed.set(instance, definition), definition;
|
|
4208
|
+
}
|
|
4209
|
+
|
|
4210
|
+
function useDefinition(entry) {
|
|
4211
|
+
return useMemo(() => {
|
|
4212
|
+
if (entry) return entry.evaluation ? entry.evaluation.definition : definitionSnapshotOf(entry.instance);
|
|
4213
|
+
}, [ entry ]);
|
|
4214
|
+
}
|
|
4215
|
+
|
|
4216
|
+
function AbortedBadge({instance: instance}) {
|
|
4217
|
+
return terminalState(instance) !== "aborted" ? null : /* @__PURE__ */ jsx(Badge, {
|
|
4218
|
+
fontSize: 1,
|
|
4219
|
+
tone: "critical",
|
|
4220
|
+
children: "Aborted"
|
|
4221
|
+
});
|
|
4222
|
+
}
|
|
4223
|
+
|
|
4224
|
+
function OlderDefinitionBadge({instance: instance}) {
|
|
4225
|
+
const {latestDefinitionVersions: latestDefinitionVersions} = useWorkflowContext(), latest = latestDefinitionVersions.get(instance.definition);
|
|
4226
|
+
return latest === void 0 || latest <= instance.pinnedVersion ? null : /* @__PURE__ */ jsx(HoverHint, {
|
|
4227
|
+
description: "Running workflows keep the version they started on",
|
|
4228
|
+
text: `Started on v${instance.pinnedVersion}, latest is now v${latest}`,
|
|
4229
|
+
textWeight: "medium",
|
|
4230
|
+
children: /* @__PURE__ */ jsx(Badge, {
|
|
4231
|
+
fontSize: 1,
|
|
4232
|
+
tone: "caution",
|
|
4233
|
+
children: "Older version"
|
|
4234
|
+
})
|
|
4235
|
+
});
|
|
4236
|
+
}
|
|
4237
|
+
|
|
4238
|
+
function useInstanceFault(entry) {
|
|
4239
|
+
return instanceFault({
|
|
4240
|
+
definition: useDefinition(entry),
|
|
4241
|
+
evaluation: entry.evaluation,
|
|
4242
|
+
instance: entry.instance
|
|
4243
|
+
});
|
|
4244
|
+
}
|
|
4245
|
+
|
|
4246
|
+
function InstanceFaultNote({entry: entry, scope: scope}) {
|
|
4247
|
+
const fault = useInstanceFault(entry);
|
|
4248
|
+
if (fault === void 0 || scope.kind === "task" && fault.activity !== scope.activityName) return null;
|
|
4249
|
+
const Icon = fault.recoverable ? WarningOutlineIcon : ErrorOutlineIcon;
|
|
4250
|
+
/* @__PURE__ */
|
|
4251
|
+
return jsx(Card, {
|
|
4252
|
+
padding: 3,
|
|
4253
|
+
radius: 3,
|
|
4254
|
+
tone: fault.recoverable ? "caution" : "critical",
|
|
4255
|
+
children: /* @__PURE__ */ jsxs(Flex, {
|
|
4256
|
+
align: "flex-start",
|
|
4257
|
+
gap: 3,
|
|
4258
|
+
children: [
|
|
4259
|
+
/* @__PURE__ */ jsx(Text, {
|
|
4260
|
+
size: 1,
|
|
4261
|
+
children: /* @__PURE__ */ jsx(Icon, {})
|
|
4262
|
+
}),
|
|
4263
|
+
/* @__PURE__ */ jsxs(Stack, {
|
|
4264
|
+
flex: 1,
|
|
4265
|
+
gap: 3,
|
|
4266
|
+
children: [
|
|
4267
|
+
/* @__PURE__ */ jsx(Text, {
|
|
4268
|
+
size: 1,
|
|
4269
|
+
weight: "medium",
|
|
4270
|
+
children: scope.kind === "run" ? fault.summary : fault.detail
|
|
4271
|
+
}), scope.kind === "run" ? /* @__PURE__ */ jsx(RunControl, {
|
|
4272
|
+
activity: fault.activity,
|
|
4273
|
+
onOpenActivity: scope.onOpenActivity
|
|
4274
|
+
}) : /* @__PURE__ */ jsx(TaskControls, {
|
|
4275
|
+
actions: fault.actions,
|
|
4276
|
+
instanceId: entry.instance._id,
|
|
4277
|
+
remedies: fault.remedies
|
|
4278
|
+
}) ]
|
|
4279
|
+
}) ]
|
|
4280
|
+
})
|
|
4281
|
+
});
|
|
4282
|
+
}
|
|
4283
|
+
|
|
4284
|
+
function RunControl({activity: activity, onOpenActivity: onOpenActivity}) {
|
|
4285
|
+
return activity === void 0 ? null : /* @__PURE__ */ jsx(Flex, {
|
|
4286
|
+
children: /* @__PURE__ */ jsx(Button, {
|
|
4287
|
+
fontSize: 1,
|
|
4288
|
+
mode: "ghost",
|
|
4289
|
+
onClick: () => onOpenActivity(activity),
|
|
4290
|
+
padding: 2,
|
|
4291
|
+
text: "View task"
|
|
4292
|
+
})
|
|
4293
|
+
});
|
|
4294
|
+
}
|
|
4295
|
+
|
|
4296
|
+
const RUN_VERB = {
|
|
4297
|
+
"drain-effects": drain => drain.run()
|
|
4298
|
+
};
|
|
4299
|
+
|
|
4300
|
+
function TaskControls({actions: actions, instanceId: instanceId, remedies: remedies}) {
|
|
4301
|
+
const drain = useDrainEffects(instanceId);
|
|
4302
|
+
/* @__PURE__ */
|
|
4303
|
+
return jsxs(Fragment, {
|
|
4304
|
+
children: [ remedies.length === 0 ? null : /* @__PURE__ */ jsx(Text, {
|
|
4305
|
+
muted: !0,
|
|
4306
|
+
size: 1,
|
|
4307
|
+
children: remedies.join(" ")
|
|
4308
|
+
}), actions.length === 0 ? null : /* @__PURE__ */ jsx(Flex, {
|
|
4309
|
+
gap: 2,
|
|
4310
|
+
children: actions.map(action => /* @__PURE__ */ jsx(Button, {
|
|
4311
|
+
disabled: drain.busy,
|
|
4312
|
+
fontSize: 1,
|
|
4313
|
+
mode: "ghost",
|
|
4314
|
+
onClick: () => {
|
|
4315
|
+
RUN_VERB[action.verb](drain);
|
|
4316
|
+
},
|
|
4317
|
+
padding: 2,
|
|
4318
|
+
text: action.label
|
|
4319
|
+
}, action.verb))
|
|
4320
|
+
}) ]
|
|
4321
|
+
});
|
|
4322
|
+
}
|
|
4323
|
+
|
|
4002
4324
|
function MetaRow({children: children, fillHeight: fillHeight, label: label}) {
|
|
4003
4325
|
/* @__PURE__ */
|
|
4004
4326
|
return jsxs(Flex, {
|
|
@@ -4127,7 +4449,7 @@ function useBadgeCapTrim() {
|
|
|
4127
4449
|
}
|
|
4128
4450
|
|
|
4129
4451
|
function SpinnerSlot({busy: busy}) {
|
|
4130
|
-
const size = useTextIconSize(), trim = useCapTrimFor(size);
|
|
4452
|
+
const size = useTextIconSize(), trim = useCapTrimFor(size), spinning = useDelayedFlag(busy, LOADING_CUE_DELAY_MS);
|
|
4131
4453
|
/* @__PURE__ */
|
|
4132
4454
|
return jsx(Flex, {
|
|
4133
4455
|
align: "center",
|
|
@@ -4139,7 +4461,7 @@ function SpinnerSlot({busy: busy}) {
|
|
|
4139
4461
|
marginTop: trim,
|
|
4140
4462
|
width: size
|
|
4141
4463
|
},
|
|
4142
|
-
children:
|
|
4464
|
+
children: spinning ? /* @__PURE__ */ jsx(Spinner, {
|
|
4143
4465
|
muted: !0,
|
|
4144
4466
|
size: 1
|
|
4145
4467
|
}) : null
|
|
@@ -4147,6 +4469,7 @@ function SpinnerSlot({busy: busy}) {
|
|
|
4147
4469
|
}
|
|
4148
4470
|
|
|
4149
4471
|
function LoadingRow({label: label, padding: padding}) {
|
|
4472
|
+
const announced = useDelayedFlag(!0, LOADING_CUE_DELAY_MS);
|
|
4150
4473
|
/* @__PURE__ */
|
|
4151
4474
|
return jsxs(Flex, {
|
|
4152
4475
|
align: "center",
|
|
@@ -4157,12 +4480,11 @@ function LoadingRow({label: label, padding: padding}) {
|
|
|
4157
4480
|
children: [
|
|
4158
4481
|
/* @__PURE__ */ jsx(SpinnerSlot, {
|
|
4159
4482
|
busy: !0
|
|
4160
|
-
}),
|
|
4161
|
-
/* @__PURE__ */ jsx(Text, {
|
|
4483
|
+
}), announced ? /* @__PURE__ */ jsx(Text, {
|
|
4162
4484
|
muted: !0,
|
|
4163
4485
|
size: 1,
|
|
4164
4486
|
children: label
|
|
4165
|
-
}) ]
|
|
4487
|
+
}) : null ]
|
|
4166
4488
|
});
|
|
4167
4489
|
}
|
|
4168
4490
|
|
|
@@ -4218,7 +4540,7 @@ function AvatarButton({avatar: avatar, onClick: onClick, onMouseDown: onMouseDow
|
|
|
4218
4540
|
}
|
|
4219
4541
|
|
|
4220
4542
|
function RowAssignees({assignees: assignees, hint: hint}) {
|
|
4221
|
-
const ids = assignees.flatMap(item => item.type === "user" ? [ item.id ] : []),
|
|
4543
|
+
const ids = assignees.flatMap(item => item.type === "user" ? [ item.id ] : []), vocabulary = useProjectMembers(), roles = assignees.flatMap(item => item.type === "role" ? [ memberRoleFor(vocabulary, item.role) ] : []), displays = useUserDisplays(ids);
|
|
4222
4544
|
if (ids.length === 0 && roles.length === 0) return null;
|
|
4223
4545
|
const bothKinds = roles.length > 0 && displays.length > 0;
|
|
4224
4546
|
/* @__PURE__ */
|
|
@@ -4429,49 +4751,40 @@ function ForMeEmptyState() {
|
|
|
4429
4751
|
});
|
|
4430
4752
|
}
|
|
4431
4753
|
|
|
4432
|
-
|
|
4433
|
-
return typeof value == "object" && value !== null && Array.isArray(value.stages);
|
|
4434
|
-
}
|
|
4435
|
-
|
|
4436
|
-
const parsed = /* @__PURE__ */ new WeakMap;
|
|
4437
|
-
|
|
4438
|
-
function definitionSnapshotOf(instance) {
|
|
4439
|
-
if (parsed.has(instance)) return parsed.get(instance);
|
|
4440
|
-
let definition;
|
|
4441
|
-
try {
|
|
4442
|
-
const candidate = parseDefinitionSnapshot(instance);
|
|
4443
|
-
if (!looksLikeDefinition(candidate)) throw new Error(`definitionSnapshot on "${instance._id}" parsed to a non-definition shape`);
|
|
4444
|
-
definition = candidate;
|
|
4445
|
-
} catch (err) {
|
|
4446
|
-
console.error("[workflow-studio-plugin] unreadable definitionSnapshot:", err), definition = void 0;
|
|
4447
|
-
}
|
|
4448
|
-
return parsed.set(instance, definition), definition;
|
|
4449
|
-
}
|
|
4754
|
+
const OVERDUE_HINT = "Now overdue";
|
|
4450
4755
|
|
|
4451
|
-
function
|
|
4452
|
-
return
|
|
4453
|
-
|
|
4454
|
-
}
|
|
4756
|
+
function hintFace(args) {
|
|
4757
|
+
return args.overdue ? args.reason === void 0 ? {
|
|
4758
|
+
text: OVERDUE_HINT
|
|
4759
|
+
} : {
|
|
4760
|
+
text: OVERDUE_HINT,
|
|
4761
|
+
description: args.reason
|
|
4762
|
+
} : args.reason === void 0 ? void 0 : {
|
|
4763
|
+
text: args.reason
|
|
4764
|
+
};
|
|
4455
4765
|
}
|
|
4456
4766
|
|
|
4457
|
-
function
|
|
4458
|
-
|
|
4459
|
-
|
|
4460
|
-
|
|
4461
|
-
|
|
4767
|
+
function DueDate({dueDate: dueDate, hintDisabled: hintDisabled, overdue: overdue, reason: reason}) {
|
|
4768
|
+
const face = hintFace({
|
|
4769
|
+
overdue: overdue,
|
|
4770
|
+
reason: reason
|
|
4771
|
+
}), text = overdue ?
|
|
4772
|
+
/* @__PURE__ */ jsx(TextWithTone, {
|
|
4773
|
+
size: 1,
|
|
4774
|
+
tone: "caution",
|
|
4775
|
+
children: formatDate(dueDate)
|
|
4776
|
+
}) : /* @__PURE__ */ jsx(Text, {
|
|
4777
|
+
muted: !0,
|
|
4778
|
+
size: 1,
|
|
4779
|
+
children: formatDate(dueDate)
|
|
4462
4780
|
});
|
|
4463
|
-
|
|
4464
|
-
|
|
4465
|
-
|
|
4466
|
-
|
|
4467
|
-
|
|
4468
|
-
|
|
4469
|
-
|
|
4470
|
-
textWeight: "medium",
|
|
4471
|
-
children: /* @__PURE__ */ jsx(Badge, {
|
|
4472
|
-
fontSize: 1,
|
|
4473
|
-
tone: "caution",
|
|
4474
|
-
children: "Older version"
|
|
4781
|
+
return face === void 0 ? text :
|
|
4782
|
+
/* @__PURE__ */ jsx(Flex, {
|
|
4783
|
+
align: "center",
|
|
4784
|
+
children: /* @__PURE__ */ jsx(HoverHint, {
|
|
4785
|
+
...face,
|
|
4786
|
+
disabled: hintDisabled === !0,
|
|
4787
|
+
children: text
|
|
4475
4788
|
})
|
|
4476
4789
|
});
|
|
4477
4790
|
}
|
|
@@ -4511,18 +4824,6 @@ function CheckboxSlot({children: children}) {
|
|
|
4511
4824
|
});
|
|
4512
4825
|
}
|
|
4513
4826
|
|
|
4514
|
-
function DueDateText({dueDate: dueDate, overdue: overdue}) {
|
|
4515
|
-
return overdue ? /* @__PURE__ */ jsx(TextWithTone, {
|
|
4516
|
-
size: 1,
|
|
4517
|
-
tone: "caution",
|
|
4518
|
-
children: formatDate(dueDate)
|
|
4519
|
-
}) : /* @__PURE__ */ jsx(Text, {
|
|
4520
|
-
muted: !0,
|
|
4521
|
-
size: 1,
|
|
4522
|
-
children: formatDate(dueDate)
|
|
4523
|
-
});
|
|
4524
|
-
}
|
|
4525
|
-
|
|
4526
4827
|
function DueDateEditor({dueDate: dueDate, onDone: onDone, onPatch: onPatch}) {
|
|
4527
4828
|
/* @__PURE__ */
|
|
4528
4829
|
return jsx(ClearableDatePicker, {
|
|
@@ -4542,8 +4843,9 @@ function DueDateEditor({dueDate: dueDate, onDone: onDone, onPatch: onPatch}) {
|
|
|
4542
4843
|
}
|
|
4543
4844
|
|
|
4544
4845
|
function DueDateControl({item: item, editable: editable, onPatch: onPatch}) {
|
|
4545
|
-
const [open, setOpen] = useState(!1), overdue = isTodoOverdue(item), display = item.dueDate ? /* @__PURE__ */ jsx(
|
|
4846
|
+
const [open, setOpen] = useState(!1), overdue = isTodoOverdue(item), display = item.dueDate ? /* @__PURE__ */ jsx(DueDate, {
|
|
4546
4847
|
dueDate: item.dueDate,
|
|
4848
|
+
hintDisabled: open,
|
|
4547
4849
|
overdue: overdue
|
|
4548
4850
|
}) : null;
|
|
4549
4851
|
return editable ? /* @__PURE__ */ jsx(DismissablePopover, {
|
|
@@ -4554,18 +4856,14 @@ function DueDateControl({item: item, editable: editable, onPatch: onPatch}) {
|
|
|
4554
4856
|
}),
|
|
4555
4857
|
onDismiss: () => setOpen(!1),
|
|
4556
4858
|
open: open,
|
|
4557
|
-
children: display ? /* @__PURE__ */ jsx(
|
|
4558
|
-
|
|
4559
|
-
|
|
4560
|
-
|
|
4561
|
-
|
|
4562
|
-
|
|
4563
|
-
|
|
4564
|
-
|
|
4565
|
-
padding: 2,
|
|
4566
|
-
tone: overdue ? "caution" : "default",
|
|
4567
|
-
children: display
|
|
4568
|
-
})
|
|
4859
|
+
children: display ? /* @__PURE__ */ jsx(Button, {
|
|
4860
|
+
"aria-label": "Change due date",
|
|
4861
|
+
fontSize: 1,
|
|
4862
|
+
mode: "bleed",
|
|
4863
|
+
onClick: () => setOpen(v => !v),
|
|
4864
|
+
padding: 2,
|
|
4865
|
+
tone: overdue ? "caution" : "default",
|
|
4866
|
+
children: display
|
|
4569
4867
|
}) : /* @__PURE__ */ jsx(HoverHint, {
|
|
4570
4868
|
disabled: open,
|
|
4571
4869
|
text: "Set due date",
|
|
@@ -4579,9 +4877,6 @@ function DueDateControl({item: item, editable: editable, onPatch: onPatch}) {
|
|
|
4579
4877
|
radius: 2
|
|
4580
4878
|
})
|
|
4581
4879
|
})
|
|
4582
|
-
}) : display && overdue ? /* @__PURE__ */ jsx(HoverHint, {
|
|
4583
|
-
text: "Now overdue",
|
|
4584
|
-
children: display
|
|
4585
4880
|
}) : display;
|
|
4586
4881
|
}
|
|
4587
4882
|
|
|
@@ -5234,9 +5529,15 @@ function ActivityDetailDialog({entry: entry, activityName: activityName, breadcr
|
|
|
5234
5529
|
const detail = deriveActivityDetail({
|
|
5235
5530
|
entry: entry,
|
|
5236
5531
|
activityName: activityName
|
|
5237
|
-
});
|
|
5532
|
+
}), faultingActivity2 = useInstanceFault(entry)?.activity;
|
|
5238
5533
|
if (!detail) return null;
|
|
5239
|
-
const instanceId = entry.instance._id, notice = blockedNotice(detail),
|
|
5534
|
+
const instanceId = entry.instance._id, notice = blockedNotice(detail), fault = /* @__PURE__ */ jsx(InstanceFaultNote, {
|
|
5535
|
+
entry: entry,
|
|
5536
|
+
scope: {
|
|
5537
|
+
kind: "task",
|
|
5538
|
+
activityName: activityName
|
|
5539
|
+
}
|
|
5540
|
+
}), faulted = faultingActivity2 === activityName, hasBody = detail.state.length > 0 || notice !== void 0 || faulted;
|
|
5240
5541
|
/* @__PURE__ */
|
|
5241
5542
|
return jsxs(Dialog, {
|
|
5242
5543
|
footer: detail.presentation.terminalActions.length > 0 ? /* @__PURE__ */ jsx(TerminalFooter, {
|
|
@@ -5277,7 +5578,7 @@ function ActivityDetailDialog({entry: entry, activityName: activityName, breadcr
|
|
|
5277
5578
|
padding: 4,
|
|
5278
5579
|
children: /* @__PURE__ */ jsxs(Stack, {
|
|
5279
5580
|
gap: 5,
|
|
5280
|
-
children: [ detail.state.map(field => /* @__PURE__ */ jsx(FieldRow, {
|
|
5581
|
+
children: [ fault, detail.state.map(field => /* @__PURE__ */ jsx(FieldRow, {
|
|
5281
5582
|
activityName: activityName,
|
|
5282
5583
|
detail: detail,
|
|
5283
5584
|
entry: entry,
|
|
@@ -5458,6 +5759,18 @@ function CountedLabel({count: count, label: label}) {
|
|
|
5458
5759
|
});
|
|
5459
5760
|
}
|
|
5460
5761
|
|
|
5762
|
+
function CountedHeading({count: count, title: title}) {
|
|
5763
|
+
/* @__PURE__ */
|
|
5764
|
+
return jsx(CountedLabel, {
|
|
5765
|
+
count: count,
|
|
5766
|
+
label: /* @__PURE__ */ jsx(Text, {
|
|
5767
|
+
size: 1,
|
|
5768
|
+
weight: "semibold",
|
|
5769
|
+
children: title
|
|
5770
|
+
})
|
|
5771
|
+
});
|
|
5772
|
+
}
|
|
5773
|
+
|
|
5461
5774
|
function GroupHeading({busy: busy, count: count, title: title, end: end}) {
|
|
5462
5775
|
/* @__PURE__ */
|
|
5463
5776
|
return jsxs(Flex, {
|
|
@@ -5466,13 +5779,9 @@ function GroupHeading({busy: busy, count: count, title: title, end: end}) {
|
|
|
5466
5779
|
paddingLeft: 2,
|
|
5467
5780
|
paddingY: end === void 0 ? 3 : 1,
|
|
5468
5781
|
children: [
|
|
5469
|
-
/* @__PURE__ */ jsx(
|
|
5782
|
+
/* @__PURE__ */ jsx(CountedHeading, {
|
|
5470
5783
|
count: count,
|
|
5471
|
-
|
|
5472
|
-
size: 1,
|
|
5473
|
-
weight: "semibold",
|
|
5474
|
-
children: title
|
|
5475
|
-
})
|
|
5784
|
+
title: title
|
|
5476
5785
|
}), busy === void 0 ? null : /* @__PURE__ */ jsx(SpinnerSlot, {
|
|
5477
5786
|
busy: busy
|
|
5478
5787
|
}), end === void 0 ? null : /* @__PURE__ */ jsxs(Fragment, {
|
|
@@ -5484,21 +5793,81 @@ function GroupHeading({busy: busy, count: count, title: title, end: end}) {
|
|
|
5484
5793
|
});
|
|
5485
5794
|
}
|
|
5486
5795
|
|
|
5796
|
+
const EMPTY_METRIC_OPACITY = .5;
|
|
5797
|
+
|
|
5798
|
+
function MetricText({children: children, tone: tone}) {
|
|
5799
|
+
return tone === void 0 ? /* @__PURE__ */ jsx(Text, {
|
|
5800
|
+
muted: !0,
|
|
5801
|
+
size: 1,
|
|
5802
|
+
children: children
|
|
5803
|
+
}) : /* @__PURE__ */ jsx(TextWithTone, {
|
|
5804
|
+
size: 1,
|
|
5805
|
+
tone: tone,
|
|
5806
|
+
children: children
|
|
5807
|
+
});
|
|
5808
|
+
}
|
|
5809
|
+
|
|
5810
|
+
function MetricPair({Icon: Icon, empty: empty, face: face, tone: tone, value: value}) {
|
|
5811
|
+
/* @__PURE__ */
|
|
5812
|
+
return jsx(HoverHint, {
|
|
5813
|
+
...face,
|
|
5814
|
+
children: /* @__PURE__ */ jsxs(Flex, {
|
|
5815
|
+
align: "center",
|
|
5816
|
+
gap: 2,
|
|
5817
|
+
style: empty ? {
|
|
5818
|
+
opacity: EMPTY_METRIC_OPACITY
|
|
5819
|
+
} : void 0,
|
|
5820
|
+
children: [
|
|
5821
|
+
/* @__PURE__ */ jsx(MetricText, {
|
|
5822
|
+
tone: tone,
|
|
5823
|
+
children: /* @__PURE__ */ jsx(Icon, {
|
|
5824
|
+
style: {
|
|
5825
|
+
color: "inherit"
|
|
5826
|
+
}
|
|
5827
|
+
})
|
|
5828
|
+
}),
|
|
5829
|
+
/* @__PURE__ */ jsx(MetricText, {
|
|
5830
|
+
tone: tone,
|
|
5831
|
+
children: value
|
|
5832
|
+
}) ]
|
|
5833
|
+
})
|
|
5834
|
+
});
|
|
5835
|
+
}
|
|
5836
|
+
|
|
5837
|
+
function AlertGlyph({Icon: Icon, hint: hint, tone: tone}) {
|
|
5838
|
+
/* @__PURE__ */
|
|
5839
|
+
return jsx(HoverHint, {
|
|
5840
|
+
text: hint,
|
|
5841
|
+
children: /* @__PURE__ */ jsx(TextWithTone, {
|
|
5842
|
+
size: 1,
|
|
5843
|
+
tone: tone,
|
|
5844
|
+
children: /* @__PURE__ */ jsx(Icon, {
|
|
5845
|
+
style: {
|
|
5846
|
+
color: "inherit"
|
|
5847
|
+
}
|
|
5848
|
+
})
|
|
5849
|
+
})
|
|
5850
|
+
});
|
|
5851
|
+
}
|
|
5852
|
+
|
|
5487
5853
|
function ActivityDateControl({instanceId: instanceId, state: state, surface: surface, dueDates: dueDates}) {
|
|
5488
5854
|
const editField = useEditField(surface), {save: save} = useSaveField({
|
|
5489
5855
|
instanceId: instanceId
|
|
5490
5856
|
}), [open, setOpen] = useState(!1), raw = dateControlValue({
|
|
5491
5857
|
state: state,
|
|
5492
5858
|
dueDates: dueDates
|
|
5493
|
-
}),
|
|
5494
|
-
|
|
5495
|
-
|
|
5496
|
-
|
|
5859
|
+
}), overdue = raw !== void 0 && isDueDatePast(raw, /* @__PURE__ */ new Date), dueDate = reason => raw === void 0 ? null : /* @__PURE__ */ jsx(DueDate, {
|
|
5860
|
+
dueDate: raw,
|
|
5861
|
+
hintDisabled: open,
|
|
5862
|
+
overdue: overdue,
|
|
5863
|
+
...reason === void 0 ? {} : {
|
|
5864
|
+
reason: reason
|
|
5865
|
+
}
|
|
5497
5866
|
});
|
|
5498
|
-
if (state.kind === "none") return
|
|
5499
|
-
if (state.kind === "closed")
|
|
5500
|
-
|
|
5501
|
-
|
|
5867
|
+
if (state.kind === "none") return dueDate();
|
|
5868
|
+
if (state.kind === "closed") {
|
|
5869
|
+
const display = dueDate(state.reason);
|
|
5870
|
+
return display === null ? null : /* @__PURE__ */ jsx(Button, {
|
|
5502
5871
|
"aria-label": "Date",
|
|
5503
5872
|
as: "span",
|
|
5504
5873
|
fontSize: 1,
|
|
@@ -5507,8 +5876,8 @@ function ActivityDateControl({instanceId: instanceId, state: state, surface: sur
|
|
|
5507
5876
|
onMouseDown: stopRowMouseDown,
|
|
5508
5877
|
padding: 2,
|
|
5509
5878
|
children: display
|
|
5510
|
-
})
|
|
5511
|
-
}
|
|
5879
|
+
});
|
|
5880
|
+
}
|
|
5512
5881
|
const kind = dateControlKind(state), commit = (mode, value) => {
|
|
5513
5882
|
state.kind === "editable" && save(() => editField({
|
|
5514
5883
|
instanceId: instanceId,
|
|
@@ -5544,7 +5913,7 @@ function ActivityDateControl({instanceId: instanceId, state: state, surface: sur
|
|
|
5544
5913
|
}),
|
|
5545
5914
|
onDismiss: () => setOpen(!1),
|
|
5546
5915
|
open: open,
|
|
5547
|
-
children:
|
|
5916
|
+
children: raw !== void 0 ? /* @__PURE__ */ jsx(Button, {
|
|
5548
5917
|
"aria-label": "Change date",
|
|
5549
5918
|
as: "span",
|
|
5550
5919
|
fontSize: 1,
|
|
@@ -5552,7 +5921,7 @@ function ActivityDateControl({instanceId: instanceId, state: state, surface: sur
|
|
|
5552
5921
|
onClick: handleClick,
|
|
5553
5922
|
onMouseDown: stopRowMouseDown,
|
|
5554
5923
|
padding: 2,
|
|
5555
|
-
children:
|
|
5924
|
+
children: dueDate()
|
|
5556
5925
|
}) : /* @__PURE__ */ jsx(HoverHint, {
|
|
5557
5926
|
disabled: open,
|
|
5558
5927
|
text: "Set date",
|
|
@@ -5642,7 +6011,7 @@ function TitleTag({hint: hint, tone: tone, children: children}) {
|
|
|
5642
6011
|
});
|
|
5643
6012
|
}
|
|
5644
6013
|
|
|
5645
|
-
function ActivityRow({face: face, breadcrumb: breadcrumb, assignees: assignees, assignState: assignState, dateState: dateState, dueDates: dueDates, instanceId: instanceId, onOpen: onOpen, surface: surface, terminalActions: terminalActions = []}) {
|
|
6014
|
+
function ActivityRow({face: face, breadcrumb: breadcrumb, assignees: assignees, assignState: assignState, dateState: dateState, dueDates: dueDates, faultHint: faultHint, instanceId: instanceId, onOpen: onOpen, surface: surface, terminalActions: terminalActions = []}) {
|
|
5646
6015
|
const settled = isTerminalActivityStatus(face.status), dimmed = settledDim(settled);
|
|
5647
6016
|
/* @__PURE__ */
|
|
5648
6017
|
return jsxs(WorkRow, {
|
|
@@ -5675,6 +6044,10 @@ function ActivityRow({face: face, breadcrumb: breadcrumb, assignees: assignees,
|
|
|
5675
6044
|
/* @__PURE__ */ jsx(ActivityRowTitle, {
|
|
5676
6045
|
dimmed: dimmed,
|
|
5677
6046
|
children: face.title
|
|
6047
|
+
}), faultHint === void 0 || face.status === "failed" ? null : /* @__PURE__ */ jsx(AlertGlyph, {
|
|
6048
|
+
Icon: ErrorOutlineIcon,
|
|
6049
|
+
hint: faultHint,
|
|
6050
|
+
tone: "critical"
|
|
5678
6051
|
}), face.automated ? /* @__PURE__ */ jsx(TitleTag, {
|
|
5679
6052
|
hint: "Completes on its own — no user action is needed",
|
|
5680
6053
|
children: "Automated"
|
|
@@ -5690,7 +6063,7 @@ function ActivityRow({face: face, breadcrumb: breadcrumb, assignees: assignees,
|
|
|
5690
6063
|
}
|
|
5691
6064
|
|
|
5692
6065
|
function ActivitiesList({entry: entry, onOpenActivity: onOpenActivity, surface: surface}) {
|
|
5693
|
-
const activities = (entry.evaluation?.currentStage.activities ?? []).filter(t => !t.scopedOut), activityState = stateByActivity(entry.instance);
|
|
6066
|
+
const activities = (entry.evaluation?.currentStage.activities ?? []).filter(t => !t.scopedOut), activityState = stateByActivity(entry.instance), fault = useInstanceFault(entry);
|
|
5694
6067
|
return activities.length === 0 ?
|
|
5695
6068
|
/* @__PURE__ */ jsx(Box, {
|
|
5696
6069
|
paddingX: 1,
|
|
@@ -5708,6 +6081,9 @@ function ActivitiesList({entry: entry, onOpenActivity: onOpenActivity, surface:
|
|
|
5708
6081
|
activityState: activityState,
|
|
5709
6082
|
editableFields: entry.evaluation?.editableFields
|
|
5710
6083
|
}),
|
|
6084
|
+
...fault?.activity === t.activity.name ? {
|
|
6085
|
+
faultHint: fault.summary
|
|
6086
|
+
} : {},
|
|
5711
6087
|
instanceId: entry.instance._id,
|
|
5712
6088
|
onOpen: () => onOpenActivity(t.activity.name),
|
|
5713
6089
|
surface: surface
|
|
@@ -5854,7 +6230,10 @@ function progressFillPercent(face) {
|
|
|
5854
6230
|
}
|
|
5855
6231
|
|
|
5856
6232
|
function deriveFieldPills(args) {
|
|
5857
|
-
const {scope: scope, definition: definition, instance: instance, committed: committed, evaluation: evaluation} = args, declared = scope === "workflow" ? definition?.fields ?? [] :
|
|
6233
|
+
const {scope: scope, definition: definition, instance: instance, committed: committed, evaluation: evaluation} = args, declared = scope === "workflow" ? definition?.fields ?? [] : findStageNode({
|
|
6234
|
+
definition: definition,
|
|
6235
|
+
stageName: instance.currentStage
|
|
6236
|
+
})?.fields ?? [], entries = scope === "workflow" ? instance.fields : findOpenStageEntry(instance)?.fields ?? [], entriesByName = new Map(entries.map(entry => [ entry.name, entry ])), editables = isEvaluationCurrent({
|
|
5858
6237
|
committed: committed,
|
|
5859
6238
|
evaluation: evaluation
|
|
5860
6239
|
}) ? editablesByName(evaluation, scope) : /* @__PURE__ */ new Map, declaredNames = new Set(declared.map(d => d.name));
|
|
@@ -6088,7 +6467,7 @@ function AvatarCapAligned({children: children}) {
|
|
|
6088
6467
|
}
|
|
6089
6468
|
|
|
6090
6469
|
function AssigneesFace({assignees: assignees}) {
|
|
6091
|
-
const
|
|
6470
|
+
const vocabulary = useProjectMembers(), userIds = assignees.flatMap(a => a.type === "user" ? [ a.id ] : []), roles = assignees.flatMap(a => a.type === "role" ? [ roleLabelFor(vocabulary, a.role) ] : []);
|
|
6092
6471
|
/* @__PURE__ */
|
|
6093
6472
|
return jsxs(Fragment, {
|
|
6094
6473
|
children: [ userIds.length > 0 ? /* @__PURE__ */ jsx(AvatarCapAligned, {
|
|
@@ -7044,6 +7423,27 @@ function HintedMenuButton({hint: hint, ...menuButtonProps}) {
|
|
|
7044
7423
|
});
|
|
7045
7424
|
}
|
|
7046
7425
|
|
|
7426
|
+
function InlineEmphasis({children: children}) {
|
|
7427
|
+
const {font: font} = useTheme_v2();
|
|
7428
|
+
/* @__PURE__ */
|
|
7429
|
+
return jsx("span", {
|
|
7430
|
+
style: {
|
|
7431
|
+
fontWeight: font.text.weights.medium
|
|
7432
|
+
},
|
|
7433
|
+
children: children
|
|
7434
|
+
});
|
|
7435
|
+
}
|
|
7436
|
+
|
|
7437
|
+
const MINUTE_MS = 6e4;
|
|
7438
|
+
|
|
7439
|
+
function useMinuteClock() {
|
|
7440
|
+
const [now, setNow] = useState(() => /* @__PURE__ */ new Date);
|
|
7441
|
+
return useEffect(() => {
|
|
7442
|
+
const timer = setInterval(() => setNow(/* @__PURE__ */ new Date), MINUTE_MS);
|
|
7443
|
+
return () => clearInterval(timer);
|
|
7444
|
+
}, []), now;
|
|
7445
|
+
}
|
|
7446
|
+
|
|
7047
7447
|
function historyWindow(args) {
|
|
7048
7448
|
const {entries: entries, expanded: expanded} = args;
|
|
7049
7449
|
return {
|
|
@@ -7053,28 +7453,10 @@ function historyWindow(args) {
|
|
|
7053
7453
|
}
|
|
7054
7454
|
|
|
7055
7455
|
function PendingEffectRows({instance: instance, now: now}) {
|
|
7056
|
-
const {
|
|
7456
|
+
const {completeEffectFor: completeEffectFor, effectHandlers: effectHandlers} = useWorkflowContext(), toast = useWorkflowToast(), drain = useDrainEffects(instance._id), [resolving, setResolving] = useState(!1), pending = instance.pendingEffects ?? [];
|
|
7057
7457
|
if (pending.length === 0) return null;
|
|
7058
|
-
const
|
|
7059
|
-
|
|
7060
|
-
try {
|
|
7061
|
-
await drainEffectsFor(instance._id), toast.push({
|
|
7062
|
-
id: TOAST_ID.effectsDrain,
|
|
7063
|
-
status: "info",
|
|
7064
|
-
title: "Ran the registered handlers"
|
|
7065
|
-
});
|
|
7066
|
-
} catch (err) {
|
|
7067
|
-
toast.push({
|
|
7068
|
-
id: TOAST_ID.effectsDrain,
|
|
7069
|
-
status: "error",
|
|
7070
|
-
title: "Failed to run pending effects",
|
|
7071
|
-
description: describeError(err)
|
|
7072
|
-
});
|
|
7073
|
-
} finally {
|
|
7074
|
-
setBusy(!1);
|
|
7075
|
-
}
|
|
7076
|
-
}, resolve = async (effectKey, status) => {
|
|
7077
|
-
setBusy(!0);
|
|
7458
|
+
const resolve = async (effectKey, status) => {
|
|
7459
|
+
setResolving(!0);
|
|
7078
7460
|
try {
|
|
7079
7461
|
await completeEffectFor(instance._id, {
|
|
7080
7462
|
effectKey: effectKey,
|
|
@@ -7093,18 +7475,20 @@ function PendingEffectRows({instance: instance, now: now}) {
|
|
|
7093
7475
|
description: describeError(err)
|
|
7094
7476
|
});
|
|
7095
7477
|
} finally {
|
|
7096
|
-
|
|
7478
|
+
setResolving(!1);
|
|
7097
7479
|
}
|
|
7098
7480
|
};
|
|
7099
7481
|
/* @__PURE__ */
|
|
7100
7482
|
return jsx(Fragment, {
|
|
7101
7483
|
children: pending.map(fx => /* @__PURE__ */ jsx(PendingEffectRow, {
|
|
7102
|
-
busy: busy,
|
|
7484
|
+
busy: drain.busy || resolving,
|
|
7103
7485
|
effect: fx,
|
|
7104
7486
|
instanceId: instance._id,
|
|
7105
7487
|
now: now,
|
|
7106
7488
|
onResolve: status => resolve(fx._key, status),
|
|
7107
|
-
onRunHandlers:
|
|
7489
|
+
onRunHandlers: () => {
|
|
7490
|
+
drain.run();
|
|
7491
|
+
},
|
|
7108
7492
|
registered: fx.name in effectHandlers
|
|
7109
7493
|
}, fx._key))
|
|
7110
7494
|
});
|
|
@@ -7188,12 +7572,7 @@ function PendingEffectRow({busy: busy, effect: effect, instanceId: instanceId, n
|
|
|
7188
7572
|
}
|
|
7189
7573
|
|
|
7190
7574
|
function ActivityLog({instance: instance, definition: definition, windowed: windowed = !0}) {
|
|
7191
|
-
const titles = useMemo(() => makeTitleResolver(definition), [ definition ]), entries = useMemo(() => instance.history.toReversed(), [ instance.history ]),
|
|
7192
|
-
useEffect(() => {
|
|
7193
|
-
const timer = setInterval(() => setNow(/* @__PURE__ */ new Date), 6e4);
|
|
7194
|
-
return () => clearInterval(timer);
|
|
7195
|
-
}, []);
|
|
7196
|
-
const history = historyWindow({
|
|
7575
|
+
const titles = useMemo(() => makeTitleResolver(definition), [ definition ]), entries = useMemo(() => instance.history.toReversed(), [ instance.history ]), now = useMinuteClock(), [expanded, setExpanded] = useState(!1), history = historyWindow({
|
|
7197
7576
|
entries: entries,
|
|
7198
7577
|
expanded: expanded || !windowed
|
|
7199
7578
|
});
|
|
@@ -7296,12 +7675,9 @@ function HistoryRow({entry: entry, now: now, titles: titles}) {
|
|
|
7296
7675
|
}
|
|
7297
7676
|
|
|
7298
7677
|
function ActorNameSpan({id: id}) {
|
|
7299
|
-
const {name: name} = useUserDisplay(id)
|
|
7678
|
+
const {name: name} = useUserDisplay(id);
|
|
7300
7679
|
/* @__PURE__ */
|
|
7301
|
-
return jsx(
|
|
7302
|
-
style: {
|
|
7303
|
-
fontWeight: font.text.weights.medium
|
|
7304
|
-
},
|
|
7680
|
+
return jsx(InlineEmphasis, {
|
|
7305
7681
|
children: name
|
|
7306
7682
|
});
|
|
7307
7683
|
}
|
|
@@ -7709,7 +8085,6 @@ function StageOverviewCard({overview: overview}) {
|
|
|
7709
8085
|
}
|
|
7710
8086
|
|
|
7711
8087
|
function AdvanceCard({advance: advance}) {
|
|
7712
|
-
const {font: font} = useTheme_v2();
|
|
7713
8088
|
/* @__PURE__ */
|
|
7714
8089
|
return jsx(Card, {
|
|
7715
8090
|
padding: 3,
|
|
@@ -7721,10 +8096,7 @@ function AdvanceCard({advance: advance}) {
|
|
|
7721
8096
|
/* @__PURE__ */ jsxs(Text, {
|
|
7722
8097
|
size: 1,
|
|
7723
8098
|
children: [ "Advances to ",
|
|
7724
|
-
/* @__PURE__ */ jsx(
|
|
7725
|
-
style: {
|
|
7726
|
-
fontWeight: font.text.weights.medium
|
|
7727
|
-
},
|
|
8099
|
+
/* @__PURE__ */ jsx(InlineEmphasis, {
|
|
7728
8100
|
children: advance.toTitle
|
|
7729
8101
|
}), ADVANCE_TAILS[advance.kind] ]
|
|
7730
8102
|
}), advance.kind !== "conditions" ? null : advance.lines.map((line, index) =>
|
|
@@ -7848,18 +8220,23 @@ function StageSection({entry: entry, onOpenActivity: onOpenActivity, surface: su
|
|
|
7848
8220
|
});
|
|
7849
8221
|
}
|
|
7850
8222
|
|
|
7851
|
-
|
|
8223
|
+
const BANNER_PADDING = 3, ICONS = {
|
|
8224
|
+
caution: /* @__PURE__ */ jsx(WarningOutlineIcon, {}),
|
|
8225
|
+
critical: /* @__PURE__ */ jsx(ErrorOutlineIcon, {})
|
|
8226
|
+
};
|
|
8227
|
+
|
|
8228
|
+
function NoteBanner({action: action, label: label, tone: tone = "caution"}) {
|
|
7852
8229
|
/* @__PURE__ */
|
|
7853
8230
|
return jsxs(Card, {
|
|
7854
8231
|
paddingLeft: 3,
|
|
7855
8232
|
paddingRight: 2,
|
|
7856
|
-
paddingY:
|
|
8233
|
+
paddingY: BANNER_PADDING,
|
|
7857
8234
|
radius: 3,
|
|
7858
8235
|
style: {
|
|
7859
8236
|
alignItems: "center",
|
|
7860
8237
|
display: "flex"
|
|
7861
8238
|
},
|
|
7862
|
-
tone:
|
|
8239
|
+
tone: tone,
|
|
7863
8240
|
children: [
|
|
7864
8241
|
/* @__PURE__ */ jsxs(Flex, {
|
|
7865
8242
|
align: "center",
|
|
@@ -7869,7 +8246,7 @@ function CautionNote({action: action, label: label}) {
|
|
|
7869
8246
|
/* @__PURE__ */ jsx(Text, {
|
|
7870
8247
|
muted: !0,
|
|
7871
8248
|
size: 1,
|
|
7872
|
-
children:
|
|
8249
|
+
children: ICONS[tone]
|
|
7873
8250
|
}),
|
|
7874
8251
|
/* @__PURE__ */ jsx(Text, {
|
|
7875
8252
|
muted: !0,
|
|
@@ -7906,7 +8283,7 @@ function UnreadableDocsNote({unreadable: unreadable}) {
|
|
|
7906
8283
|
if (unreadable.length === 0) return null;
|
|
7907
8284
|
const label = unreadable.length === 1 ? "1 workflow document isn’t listed — this Studio can’t read it. Share the details with your Studio maintainers." : `${unreadable.length} workflow documents aren’t listed — this Studio can’t read them. Share the details with your Studio maintainers.`;
|
|
7908
8285
|
/* @__PURE__ */
|
|
7909
|
-
return jsx(
|
|
8286
|
+
return jsx(NoteBanner, {
|
|
7910
8287
|
action: /* @__PURE__ */ jsx(CopyDetailsButton, {
|
|
7911
8288
|
unreadable: unreadable
|
|
7912
8289
|
}),
|
|
@@ -7952,6 +8329,21 @@ function InvalidDocNotice({invalid: invalid}) {
|
|
|
7952
8329
|
});
|
|
7953
8330
|
}
|
|
7954
8331
|
|
|
8332
|
+
function RoleAssignedNotice() {
|
|
8333
|
+
/* @__PURE__ */
|
|
8334
|
+
return jsx(Box, {
|
|
8335
|
+
padding: 2,
|
|
8336
|
+
children: /* @__PURE__ */ jsx(Text, {
|
|
8337
|
+
muted: !0,
|
|
8338
|
+
size: 1,
|
|
8339
|
+
style: {
|
|
8340
|
+
fontStyle: "italic"
|
|
8341
|
+
},
|
|
8342
|
+
children: "Including tasks assigned to your role"
|
|
8343
|
+
})
|
|
8344
|
+
});
|
|
8345
|
+
}
|
|
8346
|
+
|
|
7955
8347
|
function TabSwitch({ariaControls: ariaControls, idPrefix: idPrefix, options: options, selected: selected, onSelect: onSelect}) {
|
|
7956
8348
|
/* @__PURE__ */
|
|
7957
8349
|
return jsx(TabList, {
|
|
@@ -8216,8 +8608,15 @@ function presentedResumeEntry(args) {
|
|
|
8216
8608
|
if (!args.startNew) return findResumeEntry(args);
|
|
8217
8609
|
}
|
|
8218
8610
|
|
|
8611
|
+
function settledByAnotherWriter(cause, instance) {
|
|
8612
|
+
return isRevisionConflict(cause) && terminalState(instance) === "completed";
|
|
8613
|
+
}
|
|
8614
|
+
|
|
8219
8615
|
function classifyStartError(err) {
|
|
8220
|
-
return err instanceof StartNotSettledError ? {
|
|
8616
|
+
return err instanceof StartNotSettledError ? err.instance !== void 0 && settledByAnotherWriter(err.cause, err.instance) ? {
|
|
8617
|
+
kind: "started-settled-elsewhere",
|
|
8618
|
+
instance: err.instance
|
|
8619
|
+
} : {
|
|
8221
8620
|
kind: "started-not-settled",
|
|
8222
8621
|
instance: err.instance,
|
|
8223
8622
|
description: describeError(err.cause)
|
|
@@ -8230,8 +8629,16 @@ function classifyStartError(err) {
|
|
|
8230
8629
|
};
|
|
8231
8630
|
}
|
|
8232
8631
|
|
|
8632
|
+
function startProducedRun(outcome) {
|
|
8633
|
+
return outcome.kind === "started-not-settled" || outcome.kind === "started-settled-elsewhere";
|
|
8634
|
+
}
|
|
8635
|
+
|
|
8233
8636
|
function startOutcomeToast(outcome, label) {
|
|
8234
|
-
return outcome.kind === "started-
|
|
8637
|
+
return outcome.kind === "started-settled-elsewhere" ? {
|
|
8638
|
+
id: TOAST_ID.start,
|
|
8639
|
+
status: "info",
|
|
8640
|
+
title: `“${label}” started and finished`
|
|
8641
|
+
} : outcome.kind === "started-not-settled" ? {
|
|
8235
8642
|
id: TOAST_ID.start,
|
|
8236
8643
|
status: "warning",
|
|
8237
8644
|
title: `“${label}” started but didn’t finish`,
|
|
@@ -8797,7 +9204,7 @@ function DiscoverySpinner() {
|
|
|
8797
9204
|
});
|
|
8798
9205
|
}
|
|
8799
9206
|
|
|
8800
|
-
const
|
|
9207
|
+
const GROUP_GAP = 2;
|
|
8801
9208
|
|
|
8802
9209
|
function useWorkflowsTab() {
|
|
8803
9210
|
const {params: params, setParams: setParams} = usePaneRouter();
|
|
@@ -8822,7 +9229,7 @@ function useOpenActivity(entries) {
|
|
|
8822
9229
|
}
|
|
8823
9230
|
|
|
8824
9231
|
function WorkflowsPanel({entries: entries, documentId: documentId, docTypeMappings: docTypeMappings, initialValue: initialValue}) {
|
|
8825
|
-
const identity = useAssignmentIdentity(), panelId = useId(), {params: params} = usePaneRouter(), {view: view, setView: setView} = useWorkflowsTab(), telemetry = useWorkflowTelemetry(), {openActivity: openActivity, setOpenActivity: setOpenActivity, dialogEntry: dialogEntry} = useOpenActivity(entries), active = entries.filter(isLiveEntry), finished = entries.filter(e => !isLiveEntry(e)), forMe = forMeWorkOf(active, identity), [landing] = useState(() => focusedLanding(params?.[WORKFLOWS_FOCUS_PARAM], entries.map(e => e.instance._id))), assignedWorkUnknown = active.some(e => e.invalid !== void 0), booting =
|
|
9232
|
+
const identity = useAssignmentIdentity(), panelId = useId(), {params: params} = usePaneRouter(), {view: view, setView: setView} = useWorkflowsTab(), telemetry = useWorkflowTelemetry(), {openActivity: openActivity, setOpenActivity: setOpenActivity, dialogEntry: dialogEntry} = useOpenActivity(entries), active = entries.filter(isLiveEntry), finished = entries.filter(e => !isLiveEntry(e)), forMe = forMeWorkOf(active, identityOf(identity)), [landing] = useState(() => focusedLanding(params?.[WORKFLOWS_FOCUS_PARAM], entries.map(e => e.instance._id))), assignedWorkUnknown = active.some(e => e.invalid !== void 0), booting = active.some(e => !e.ready && e.invalid === void 0), sectionFor = e => /* @__PURE__ */ jsx(WorkflowInstanceSection, {
|
|
8826
9233
|
defaultOpen: landingDefaultOpen(landing, e.instance._id),
|
|
8827
9234
|
entry: e,
|
|
8828
9235
|
onOpenActivity: activityName => setOpenActivity({
|
|
@@ -8962,10 +9369,10 @@ function OverviewEmptyState({mappings: mappings, docId: docId, initialValue: ini
|
|
|
8962
9369
|
}
|
|
8963
9370
|
|
|
8964
9371
|
function ForMeTab({forMe: forMe, assignedWorkUnknown: assignedWorkUnknown, onOpenActivity: onOpenActivity}) {
|
|
8965
|
-
return forMe.hasRows ? /* @__PURE__ */
|
|
9372
|
+
return forMe.hasRows ? /* @__PURE__ */ jsxs(Stack, {
|
|
8966
9373
|
gap: GROUP_GAP,
|
|
8967
9374
|
paddingBottom: 4,
|
|
8968
|
-
children: forMe.work.map(({entry: entry, who: who, shown: shown}) => /* @__PURE__ */ jsx(ForMeList, {
|
|
9375
|
+
children: [ forMe.hasRoleMatched ? /* @__PURE__ */ jsx(RoleAssignedNotice, {}) : null, forMe.work.map(({entry: entry, who: who, shown: shown}) => /* @__PURE__ */ jsx(ForMeList, {
|
|
8969
9376
|
entry: entry,
|
|
8970
9377
|
identity: who,
|
|
8971
9378
|
work: shown,
|
|
@@ -8974,7 +9381,7 @@ function ForMeTab({forMe: forMe, assignedWorkUnknown: assignedWorkUnknown, onOpe
|
|
|
8974
9381
|
activityName: activityName,
|
|
8975
9382
|
stage: entry.instance.currentStage
|
|
8976
9383
|
})
|
|
8977
|
-
}, entry.instance._id))
|
|
9384
|
+
}, entry.instance._id)) ]
|
|
8978
9385
|
}) : assignedWorkUnknown ? null : /* @__PURE__ */ jsx(ForMeEmptyState, {});
|
|
8979
9386
|
}
|
|
8980
9387
|
|
|
@@ -10211,7 +10618,7 @@ function ResumeNote({onStartNew: onStartNew}) {
|
|
|
10211
10618
|
|
|
10212
10619
|
function handleStartError(args) {
|
|
10213
10620
|
const {label: label, toast: toast, seedInstance: seedInstance, onClose: onClose} = args, outcome = classifyStartError(args.err);
|
|
10214
|
-
toast.push(startOutcomeToast(outcome, label)), outcome
|
|
10621
|
+
toast.push(startOutcomeToast(outcome, label)), startProducedRun(outcome) && (outcome.instance !== void 0 && seedInstance(outcome.instance),
|
|
10215
10622
|
onClose());
|
|
10216
10623
|
}
|
|
10217
10624
|
|
|
@@ -10564,7 +10971,7 @@ async function startRequest(engine, request) {
|
|
|
10564
10971
|
};
|
|
10565
10972
|
} catch (err) {
|
|
10566
10973
|
const outcome = classifyStartError(err);
|
|
10567
|
-
return outcome
|
|
10974
|
+
return startProducedRun(outcome) ? outcome.instance ? {
|
|
10568
10975
|
instance: outcome.instance
|
|
10569
10976
|
} : {} : outcome.kind === "not-allowed" ? {} : {
|
|
10570
10977
|
failure: outcome.description
|
|
@@ -10765,6 +11172,28 @@ function unassignedLineHint(args) {
|
|
|
10765
11172
|
};
|
|
10766
11173
|
}
|
|
10767
11174
|
|
|
11175
|
+
function taskCountState(args) {
|
|
11176
|
+
const {entry: entry, identity: identity} = args, freshness = entry.invalid === void 0 ? evaluationFreshness({
|
|
11177
|
+
committed: entry.committed,
|
|
11178
|
+
evaluation: entry.evaluation
|
|
11179
|
+
}) : void 0;
|
|
11180
|
+
return identity.kind === "unavailable" ? {
|
|
11181
|
+
kind: "unknowable"
|
|
11182
|
+
} : identity.kind === "pending" || freshness === "pending" ? {
|
|
11183
|
+
kind: "pending"
|
|
11184
|
+
} : freshness === "stale" ? {
|
|
11185
|
+
kind: "stale"
|
|
11186
|
+
} : {
|
|
11187
|
+
kind: "ready",
|
|
11188
|
+
tasks: assignedTaskCount({
|
|
11189
|
+
instance: entry.instance,
|
|
11190
|
+
committed: entry.committed,
|
|
11191
|
+
evaluation: entry.evaluation,
|
|
11192
|
+
who: identity.identity
|
|
11193
|
+
})
|
|
11194
|
+
};
|
|
11195
|
+
}
|
|
11196
|
+
|
|
10768
11197
|
function WorkflowFormStrip(props) {
|
|
10769
11198
|
const {mappings: mappings} = props, {isDocResolved: isDocResolved, discoveryInvalid: discoveryInvalid} = useWorkflowContext(), {docId: docId, entries: entries} = useWorkflowsForDocument(props.value?._id ?? null), {params: params, setParams: setParams} = usePaneRouter(), telemetry = useWorkflowTelemetry(), openWorkflowsView = focusId => {
|
|
10770
11199
|
telemetry.log(WorkflowFormStripClicked), setParams(focusedViewParams(params, focusId));
|
|
@@ -10852,7 +11281,7 @@ function InstanceLine({entry: entry, onOpen: onOpen}) {
|
|
|
10852
11281
|
aside: unprimed ? void 0 : /* @__PURE__ */ jsx(TaskCountSpinner, {
|
|
10853
11282
|
entry: entry
|
|
10854
11283
|
}),
|
|
10855
|
-
hint: lineHint(entry, identity),
|
|
11284
|
+
hint: lineHint(entry, identityOf(identity)),
|
|
10856
11285
|
onOpen: onOpen,
|
|
10857
11286
|
children: [
|
|
10858
11287
|
/* @__PURE__ */ jsx(Flex, {
|
|
@@ -10911,28 +11340,16 @@ function finishedHint(instance) {
|
|
|
10911
11340
|
}
|
|
10912
11341
|
|
|
10913
11342
|
function useTaskCountState(entry) {
|
|
10914
|
-
const identity = useAssignmentIdentity()
|
|
10915
|
-
|
|
10916
|
-
|
|
10917
|
-
|
|
10918
|
-
|
|
10919
|
-
kind: "pending"
|
|
10920
|
-
} : freshness === "stale" ? {
|
|
10921
|
-
kind: "stale"
|
|
10922
|
-
} : {
|
|
10923
|
-
kind: "ready",
|
|
10924
|
-
tasks: assignedTaskCount({
|
|
10925
|
-
instance: entry.instance,
|
|
10926
|
-
committed: entry.committed,
|
|
10927
|
-
evaluation: entry.evaluation,
|
|
10928
|
-
who: identity
|
|
10929
|
-
})
|
|
10930
|
-
};
|
|
11343
|
+
const identity = useAssignmentIdentity();
|
|
11344
|
+
return taskCountState({
|
|
11345
|
+
entry: entry,
|
|
11346
|
+
identity: identity
|
|
11347
|
+
});
|
|
10931
11348
|
}
|
|
10932
11349
|
|
|
10933
11350
|
function TaskCountText({entry: entry}) {
|
|
10934
11351
|
const state = useTaskCountState(entry);
|
|
10935
|
-
return state.kind === "pending" || state.kind === "ready" && state.tasks === 0 ? null : /* @__PURE__ */ jsx(Text, {
|
|
11352
|
+
return state.kind === "pending" || state.kind === "unknowable" || state.kind === "ready" && state.tasks === 0 ? null : /* @__PURE__ */ jsx(Text, {
|
|
10936
11353
|
muted: !0,
|
|
10937
11354
|
size: 1,
|
|
10938
11355
|
children: state.kind === "stale" ? "Updating…" : pluralize("assigned task", state.tasks, !0)
|
|
@@ -11163,4 +11580,4 @@ function WorkflowRootInput(props) {
|
|
|
11163
11580
|
});
|
|
11164
11581
|
}
|
|
11165
11582
|
|
|
11166
|
-
export { AbortWorkflowDialog, ActivityDetailDialog, ActivityLog, ActivityRow,
|
|
11583
|
+
export { AbortWorkflowDialog, ActivityDetailDialog, ActivityLog, ActivityRow, AlertGlyph, BreadcrumbTail, CodeChip, CountedHeading, DismissablePopover, DocPreviewLink, DocRefFace, EmptyState, ForMeEmptyState, Hairline, HoverHint, InlineEmphasis, InstanceFaultNote, InstanceSnapshotBody, InvalidDocNotice, LinkChip, LoadingRow, LogEventOnMount, MetaRow, MetricPair, NoteBanner, RoleAssignedNotice, SpinnerSlot, StageFace, StaleLock, TOAST_ID, TOOL_TABS, TabSwitch, UnreadableDocsNote, WORKFLOW_API_VERSION, WORKFLOW_PAGE_TABS, WorkflowBoardWorkflowSelected, WorkflowDefinitionDetailViewed, WorkflowInstanceDetailViewed, WorkflowTaskFiltersApplied, WorkflowTitleSeedDrifted, WorkflowToolOpened, activityRowProps, assigneesOf, backToTabLabel, committedRowFace, createSubscribers, datesOf, definitionFingerprint, definitionSnapshotOf, describeError, dueDatesOf, findActivity, formatDate, formatShortAgo, formatShortDateTime, formatTimeAgo, gdrLocality, identityOf, instanceBreadcrumb, instanceState, instanceTitle, isActivityAssignedTo, isDueDatePast, isEvaluationStale, isLiveEntry, isOpenActivityStatus, isRoleAssignedTo, landingState, mappingIssueDetail, namesNoDeployedDefinition, openActivityGone, openableSchemaType, parseStoredDateValue, readDeployedDefinitions, rowAssignControlState, rowDateControlState, stageTitle, stateByActivity, tabSelectionNavigates, toolRoute, toolTabState, useAssignmentIdentity, useContainerToken, useDefinition, useLogEventOnMount, useMinuteClock, useProjectMembers, useSpaceToken, useUserDisplays, useWorkflowContext, useWorkflowInstanceEntry, useWorkflowToast, workflowDefaultDocumentNode, workflowPageState, workflowState, workflowStudioPlugin, workflowsView };
|