@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
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
|
|
3
|
-
var jsxRuntime = require("react/jsx-runtime"), Timeline = require("@sanity/icons/Timeline"), ui = require("@sanity/ui"), workflowReact = require("@sanity/workflow-react"), react = require("react"), structure = require("sanity/structure"), workflowEngine = require("@sanity/workflow-engine"), Checkmark = require("@sanity/icons/Checkmark"), Close = require("@sanity/icons/Close"), formatDistanceToNow = require("date-fns/formatDistanceToNow"), workflowComponents = require("@sanity/workflow-components"), csm = require("@sanity/client/csm"), telemetry = require("@sanity/telemetry"), workflowStudio = require("@sanity/workflow-studio"), sanity = require("sanity"), Calendar = require("@sanity/icons/Calendar"), User = require("@sanity/icons/User"), Search = require("@sanity/icons/Search"), ChevronRight = require("@sanity/icons/ChevronRight"), Edit = require("@sanity/icons/Edit"), content = require("@sanity/util/content"), InfoOutline = require("@sanity/icons/InfoOutline"), Document = require("@sanity/icons/Document"), WarningOutline = require("@sanity/icons/WarningOutline"), router = require("sanity/router"), types = require("@sanity/types"), Launch = require("@sanity/icons/Launch"), Empty$1 = require("@sanity/icons/Empty"), ErrorFilled = require("@sanity/icons/ErrorFilled"), RemoveCircle = require("@sanity/icons/RemoveCircle"), Add = require("@sanity/icons/Add"), Ulist = require("@sanity/icons/Ulist"), CheckmarkCircle = require("@sanity/icons/CheckmarkCircle"), Bolt = require("@sanity/icons/Bolt"), ChevronDown = require("@sanity/icons/ChevronDown"), pluralize = require("pluralize-esm"), EllipsisHorizontal = require("@sanity/icons/EllipsisHorizontal"), Clock = require("@sanity/icons/Clock"), Cog = require("@sanity/icons/Cog"), ArrowUp = require("@sanity/icons/ArrowUp"), rxjs = require("rxjs"), operators = require("rxjs/operators"), Transfer = require("@sanity/icons/Transfer");
|
|
3
|
+
var jsxRuntime = require("react/jsx-runtime"), Timeline = require("@sanity/icons/Timeline"), ui = require("@sanity/ui"), workflowReact = require("@sanity/workflow-react"), react = require("react"), structure = require("sanity/structure"), workflowEngine = require("@sanity/workflow-engine"), Checkmark = require("@sanity/icons/Checkmark"), Close = require("@sanity/icons/Close"), formatDistanceToNow = require("date-fns/formatDistanceToNow"), workflowComponents = require("@sanity/workflow-components"), csm = require("@sanity/client/csm"), telemetry = require("@sanity/telemetry"), workflowStudio = require("@sanity/workflow-studio"), sanity = require("sanity"), Calendar = require("@sanity/icons/Calendar"), User = require("@sanity/icons/User"), Search = require("@sanity/icons/Search"), ChevronRight = require("@sanity/icons/ChevronRight"), Edit = require("@sanity/icons/Edit"), content = require("@sanity/util/content"), InfoOutline = require("@sanity/icons/InfoOutline"), Document = require("@sanity/icons/Document"), WarningOutline = require("@sanity/icons/WarningOutline"), router = require("sanity/router"), types = require("@sanity/types"), Launch = require("@sanity/icons/Launch"), ErrorOutline = require("@sanity/icons/ErrorOutline"), Empty$1 = require("@sanity/icons/Empty"), ErrorFilled = require("@sanity/icons/ErrorFilled"), RemoveCircle = require("@sanity/icons/RemoveCircle"), Add = require("@sanity/icons/Add"), Ulist = require("@sanity/icons/Ulist"), CheckmarkCircle = require("@sanity/icons/CheckmarkCircle"), Bolt = require("@sanity/icons/Bolt"), ChevronDown = require("@sanity/icons/ChevronDown"), pluralize = require("pluralize-esm"), EllipsisHorizontal = require("@sanity/icons/EllipsisHorizontal"), Clock = require("@sanity/icons/Clock"), Cog = require("@sanity/icons/Cog"), ArrowUp = require("@sanity/icons/ArrowUp"), rxjs = require("rxjs"), operators = require("rxjs/operators"), Transfer = require("@sanity/icons/Transfer");
|
|
4
4
|
|
|
5
5
|
function _interopDefaultCompat(e) {
|
|
6
6
|
return e && typeof e == "object" && "default" in e ? e : {
|
|
@@ -333,16 +333,25 @@ function parseLocalDate(value) {
|
|
|
333
333
|
return parsed2.getFullYear() === year && parsed2.getMonth() === (month ?? NaN) - 1 && parsed2.getDate() === day ? parsed2 : /* @__PURE__ */ new Date(NaN);
|
|
334
334
|
}
|
|
335
335
|
|
|
336
|
+
function storedDateKind(value) {
|
|
337
|
+
return /^\d{4}-\d{2}-\d{2}$/.test(value) ? "date" : "datetime";
|
|
338
|
+
}
|
|
339
|
+
|
|
336
340
|
function parseStoredDateValue(value) {
|
|
337
|
-
if (typeof value
|
|
338
|
-
const kind = /^\d{4}-\d{2}-\d{2}$/.test(value) ? "date" : "datetime";
|
|
339
|
-
return parseDateFieldValue(value, kind);
|
|
341
|
+
if (typeof value == "string") return parseDateFieldValue(value, storedDateKind(value));
|
|
340
342
|
}
|
|
341
343
|
|
|
342
344
|
function serializeDateFieldValue(date, kind) {
|
|
343
345
|
return hasTimeOfDay(kind) ? date.toISOString() : `${date.getFullYear()}-${pad2(date.getMonth() + 1)}-${pad2(date.getDate())}`;
|
|
344
346
|
}
|
|
345
347
|
|
|
348
|
+
function isDueDatePast(value, now) {
|
|
349
|
+
const kind = storedDateKind(value);
|
|
350
|
+
if (!hasTimeOfDay(kind)) return value < serializeDateFieldValue(now, kind);
|
|
351
|
+
const due = parseDateFieldValue(value, kind);
|
|
352
|
+
return due !== void 0 && due.getTime() < now.getTime();
|
|
353
|
+
}
|
|
354
|
+
|
|
346
355
|
class EffectsIncompleteError extends Error {
|
|
347
356
|
reason;
|
|
348
357
|
constructor(reason, options) {
|
|
@@ -523,7 +532,7 @@ function isLiveEntry(entry) {
|
|
|
523
532
|
const isTodoDone = item => item.status === "done", toggledTodoStatus = item => isTodoDone(item) ? "open" : "done";
|
|
524
533
|
|
|
525
534
|
function isTodoOverdue(item, today = /* @__PURE__ */ new Date) {
|
|
526
|
-
return !item.dueDate || isTodoDone(item) ? !1 : item.dueDate
|
|
535
|
+
return !item.dueDate || isTodoDone(item) ? !1 : isDueDatePast(item.dueDate, today);
|
|
527
536
|
}
|
|
528
537
|
|
|
529
538
|
function todoEditKind(patch) {
|
|
@@ -722,13 +731,25 @@ function isItemAssignedTo(item, who) {
|
|
|
722
731
|
return item.assignee != null && assigneeMatches(item.assignee, who);
|
|
723
732
|
}
|
|
724
733
|
|
|
734
|
+
function matchingAssignees(state, who) {
|
|
735
|
+
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 ] : []);
|
|
736
|
+
}
|
|
737
|
+
|
|
725
738
|
function isActivityAssignedTo(args) {
|
|
726
|
-
return args.state
|
|
739
|
+
return matchingAssignees(args.state, args.who).length > 0;
|
|
740
|
+
}
|
|
741
|
+
|
|
742
|
+
function isRoleAssignedTo(args) {
|
|
743
|
+
return matchingAssignees(args.state, args.who).some(member => member.type === "role");
|
|
744
|
+
}
|
|
745
|
+
|
|
746
|
+
function isItemRoleAssignedTo(item, who) {
|
|
747
|
+
return isItemAssignedTo(item, who) && item.assignee?.type === "role";
|
|
727
748
|
}
|
|
728
749
|
|
|
729
750
|
function assignedWork(args) {
|
|
730
|
-
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({
|
|
731
|
-
state:
|
|
751
|
+
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({
|
|
752
|
+
state: stateOf(t),
|
|
732
753
|
who: who
|
|
733
754
|
})), items = deriveTodoItems({
|
|
734
755
|
instance: instance,
|
|
@@ -738,7 +759,11 @@ function assignedWork(args) {
|
|
|
738
759
|
return {
|
|
739
760
|
activities: activities,
|
|
740
761
|
openItems: items.filter(row => !isTodoDone(row.item)),
|
|
741
|
-
doneItems: items.filter(row => isTodoDone(row.item))
|
|
762
|
+
doneItems: items.filter(row => isTodoDone(row.item)),
|
|
763
|
+
roleMatched: activities.some(t => isRoleAssignedTo({
|
|
764
|
+
state: stateOf(t),
|
|
765
|
+
who: who
|
|
766
|
+
})) || items.some(row => isItemRoleAssignedTo(row.item, who))
|
|
742
767
|
};
|
|
743
768
|
}
|
|
744
769
|
|
|
@@ -787,7 +812,8 @@ function forMeWorkOf(entries, identity) {
|
|
|
787
812
|
return {
|
|
788
813
|
work: work,
|
|
789
814
|
count: work.reduce((n, {count: count}) => n + count, 0),
|
|
790
|
-
hasRows: work.some(({shown: shown}) => hasAssignedRows(shown))
|
|
815
|
+
hasRows: work.some(({shown: shown}) => hasAssignedRows(shown)),
|
|
816
|
+
hasRoleMatched: work.some(({shown: shown}) => shown.roleMatched)
|
|
791
817
|
};
|
|
792
818
|
}
|
|
793
819
|
|
|
@@ -827,7 +853,7 @@ function concludesHere(actionEval, activityName) {
|
|
|
827
853
|
return changesOwnStatus(actionEval.action, activityName) || actionEval.firing?.exitsStage === !0;
|
|
828
854
|
}
|
|
829
855
|
|
|
830
|
-
const
|
|
856
|
+
const DECISION_SEMANTIC_FACE = {
|
|
831
857
|
"decision.accept": {
|
|
832
858
|
tone: "positive",
|
|
833
859
|
icon: Checkmark.CheckmarkIcon
|
|
@@ -838,6 +864,15 @@ const SEMANTIC_FACE = {
|
|
|
838
864
|
}
|
|
839
865
|
};
|
|
840
866
|
|
|
867
|
+
function isDecisionSemantic(value) {
|
|
868
|
+
return Object.hasOwn(DECISION_SEMANTIC_FACE, value);
|
|
869
|
+
}
|
|
870
|
+
|
|
871
|
+
function decisionSemanticFace(semantics) {
|
|
872
|
+
const semantic = semantics.find(isDecisionSemantic);
|
|
873
|
+
return semantic === void 0 ? void 0 : DECISION_SEMANTIC_FACE[semantic];
|
|
874
|
+
}
|
|
875
|
+
|
|
841
876
|
function actionButtonFace(args) {
|
|
842
877
|
const mode = concludesHere(args.actionEval, args.activityName) ? "default" : "ghost";
|
|
843
878
|
if (actionAdvanceStatus(args.actionEval.action, args.activityName) === "failed") return {
|
|
@@ -845,7 +880,7 @@ function actionButtonFace(args) {
|
|
|
845
880
|
tone: "critical",
|
|
846
881
|
icon: void 0
|
|
847
882
|
};
|
|
848
|
-
const
|
|
883
|
+
const face = decisionSemanticFace(args.actionEval.semantics ?? []);
|
|
849
884
|
return {
|
|
850
885
|
mode: mode,
|
|
851
886
|
tone: face?.tone ?? "default",
|
|
@@ -1312,21 +1347,32 @@ function bridgedSelfId(users, meId) {
|
|
|
1312
1347
|
return users.find(user => user.membership.id === meId)?.profile?.sanityUserId ?? classified.globalId ?? (classified.namespace === "project" ? void 0 : meId);
|
|
1313
1348
|
}
|
|
1314
1349
|
|
|
1315
|
-
function
|
|
1350
|
+
function useSelfState() {
|
|
1316
1351
|
const me = sanity.useCurrentUser(), {users: users, loading: loading, error: error} = workflowStudio.useStudioProjectUsers();
|
|
1317
|
-
if (!me) return
|
|
1318
|
-
|
|
1319
|
-
if (id !== void 0) return {
|
|
1320
|
-
id: id,
|
|
1321
|
-
roles: me.roles ?? []
|
|
1352
|
+
if (!me) return {
|
|
1353
|
+
kind: "unavailable"
|
|
1322
1354
|
};
|
|
1323
|
-
|
|
1324
|
-
|
|
1325
|
-
|
|
1326
|
-
|
|
1355
|
+
const id = bridgedSelfId(users, me.id);
|
|
1356
|
+
return id !== void 0 ? {
|
|
1357
|
+
kind: "resolved",
|
|
1358
|
+
self: {
|
|
1359
|
+
id: id,
|
|
1360
|
+
roles: me.roles ?? []
|
|
1327
1361
|
}
|
|
1328
|
-
|
|
1329
|
-
|
|
1362
|
+
} : loading ? {
|
|
1363
|
+
kind: "pending"
|
|
1364
|
+
} : error !== void 0 ? (warnSelfUnavailableOnce(`load:${me.id}`, `workflow: the project member directory failed to load ("${workflowEngine.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.`),
|
|
1365
|
+
{
|
|
1366
|
+
kind: "unavailable"
|
|
1367
|
+
}) : (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.`),
|
|
1368
|
+
{
|
|
1369
|
+
kind: "unavailable"
|
|
1370
|
+
});
|
|
1371
|
+
}
|
|
1372
|
+
|
|
1373
|
+
function useBridgedSelf() {
|
|
1374
|
+
const state = useSelfState();
|
|
1375
|
+
return state.kind === "resolved" ? state.self : void 0;
|
|
1330
1376
|
}
|
|
1331
1377
|
|
|
1332
1378
|
function useSelfActor() {
|
|
@@ -1335,13 +1381,22 @@ function useSelfActor() {
|
|
|
1335
1381
|
}
|
|
1336
1382
|
|
|
1337
1383
|
function useAssignmentIdentity() {
|
|
1338
|
-
const
|
|
1339
|
-
if (
|
|
1340
|
-
|
|
1341
|
-
|
|
1384
|
+
const state = useSelfState();
|
|
1385
|
+
if (state.kind !== "resolved") return state;
|
|
1386
|
+
const {id: id, roles: roles} = state.self;
|
|
1387
|
+
return {
|
|
1388
|
+
kind: "resolved",
|
|
1389
|
+
identity: {
|
|
1390
|
+
userId: id,
|
|
1391
|
+
roles: roles.map(r => r.name)
|
|
1392
|
+
}
|
|
1342
1393
|
};
|
|
1343
1394
|
}
|
|
1344
1395
|
|
|
1396
|
+
function identityOf(state) {
|
|
1397
|
+
return state.kind === "resolved" ? state.identity : void 0;
|
|
1398
|
+
}
|
|
1399
|
+
|
|
1345
1400
|
const projectMembersByUsers = /* @__PURE__ */ new WeakMap;
|
|
1346
1401
|
|
|
1347
1402
|
function projectMembersFrom(users) {
|
|
@@ -1361,9 +1416,10 @@ function projectMembersFrom(users) {
|
|
|
1361
1416
|
}
|
|
1362
1417
|
|
|
1363
1418
|
function useProjectMembers() {
|
|
1364
|
-
const {users: users, loading: loading, error: error} = workflowStudio.useStudioProjectUsers();
|
|
1419
|
+
const {users: users, roles: roles, loading: loading, error: error} = workflowStudio.useStudioProjectUsers();
|
|
1365
1420
|
return {
|
|
1366
1421
|
members: react.useMemo(() => projectMembersFrom(users), [ users ]),
|
|
1422
|
+
roles: roles,
|
|
1367
1423
|
loading: loading,
|
|
1368
1424
|
error: error === void 0 ? void 0 : workflowEngine.errorMessage(error)
|
|
1369
1425
|
};
|
|
@@ -1448,6 +1504,8 @@ function buildParams(decls, values) {
|
|
|
1448
1504
|
};
|
|
1449
1505
|
}
|
|
1450
1506
|
|
|
1507
|
+
const LOADING_CUE_DELAY_MS = 400;
|
|
1508
|
+
|
|
1451
1509
|
function useDelayedFlag(active, delayMs) {
|
|
1452
1510
|
const [held, setHeld] = react.useState(!1);
|
|
1453
1511
|
return react.useEffect(() => {
|
|
@@ -1717,10 +1775,12 @@ function PickedValueRow({children: children, onRequestChange: onRequestChange})
|
|
|
1717
1775
|
}
|
|
1718
1776
|
|
|
1719
1777
|
function MemberPicker({selectedIds: selectedIds, onSelect: onSelect, unassignRow: unassignRow = !1}) {
|
|
1720
|
-
const
|
|
1778
|
+
const {error: error, loading: loading, members: members} = useProjectMembers();
|
|
1721
1779
|
/* @__PURE__ */
|
|
1722
1780
|
return jsxRuntime.jsx(workflowComponents.MemberPicker, {
|
|
1723
|
-
|
|
1781
|
+
error: error,
|
|
1782
|
+
loading: loading,
|
|
1783
|
+
members: members,
|
|
1724
1784
|
onSelect: onSelect,
|
|
1725
1785
|
selectedIds: selectedIds,
|
|
1726
1786
|
unassignRow: unassignRow
|
|
@@ -2453,15 +2513,14 @@ function Separator() {
|
|
|
2453
2513
|
}
|
|
2454
2514
|
|
|
2455
2515
|
function stageTitle(definition, stageName) {
|
|
2456
|
-
return
|
|
2457
|
-
|
|
2458
|
-
|
|
2459
|
-
|
|
2460
|
-
return args.definition?.stages.find(s => s.name === args.stageName)?.activities?.find(a => a.name === args.activityName);
|
|
2516
|
+
return workflowEngine.findStageNode({
|
|
2517
|
+
definition: definition,
|
|
2518
|
+
stageName: stageName
|
|
2519
|
+
})?.title ?? stageName;
|
|
2461
2520
|
}
|
|
2462
2521
|
|
|
2463
2522
|
function findActivity(args) {
|
|
2464
|
-
const activity = findActivityNode(args);
|
|
2523
|
+
const activity = workflowEngine.findActivityNode(args);
|
|
2465
2524
|
return {
|
|
2466
2525
|
title: activity?.title ?? args.activityName,
|
|
2467
2526
|
description: activity?.description
|
|
@@ -2504,20 +2563,20 @@ function noteRow(args) {
|
|
|
2504
2563
|
}
|
|
2505
2564
|
|
|
2506
2565
|
function AssigneeBadge({assignee: assignee}) {
|
|
2507
|
-
const
|
|
2566
|
+
const vocabulary = useProjectMembers();
|
|
2508
2567
|
/* @__PURE__ */
|
|
2509
2568
|
return jsxRuntime.jsx(workflowComponents.AssigneeBadge, {
|
|
2510
2569
|
assignee: assignee,
|
|
2511
|
-
|
|
2570
|
+
vocabulary: vocabulary
|
|
2512
2571
|
});
|
|
2513
2572
|
}
|
|
2514
2573
|
|
|
2515
2574
|
function AssigneeBadges({assignees: assignees}) {
|
|
2516
|
-
const
|
|
2575
|
+
const vocabulary = useProjectMembers();
|
|
2517
2576
|
/* @__PURE__ */
|
|
2518
2577
|
return jsxRuntime.jsx(workflowComponents.AssigneeBadges, {
|
|
2519
2578
|
assignees: assignees,
|
|
2520
|
-
|
|
2579
|
+
vocabulary: vocabulary
|
|
2521
2580
|
});
|
|
2522
2581
|
}
|
|
2523
2582
|
|
|
@@ -3925,6 +3984,267 @@ function EditableField({field: field, entry: entry, description: description, in
|
|
|
3925
3984
|
});
|
|
3926
3985
|
}
|
|
3927
3986
|
|
|
3987
|
+
function useDrainEffects(instanceId) {
|
|
3988
|
+
const {drainEffectsFor: drainEffectsFor} = useWorkflowContext(), toast = useWorkflowToast(), [busy, setBusy] = react.useState(!1);
|
|
3989
|
+
return {
|
|
3990
|
+
busy: busy,
|
|
3991
|
+
run: async () => {
|
|
3992
|
+
setBusy(!0);
|
|
3993
|
+
try {
|
|
3994
|
+
await drainEffectsFor(instanceId), toast.push({
|
|
3995
|
+
id: TOAST_ID.effectsDrain,
|
|
3996
|
+
status: "info",
|
|
3997
|
+
title: "Ran the registered handlers"
|
|
3998
|
+
});
|
|
3999
|
+
} catch (err) {
|
|
4000
|
+
toast.push({
|
|
4001
|
+
id: TOAST_ID.effectsDrain,
|
|
4002
|
+
status: "error",
|
|
4003
|
+
title: "Failed to run pending effects",
|
|
4004
|
+
description: describeError(err)
|
|
4005
|
+
});
|
|
4006
|
+
} finally {
|
|
4007
|
+
setBusy(!1);
|
|
4008
|
+
}
|
|
4009
|
+
}
|
|
4010
|
+
};
|
|
4011
|
+
}
|
|
4012
|
+
|
|
4013
|
+
function isRunnable(verb) {
|
|
4014
|
+
return verb === "drain-effects";
|
|
4015
|
+
}
|
|
4016
|
+
|
|
4017
|
+
function effectLabel(effect) {
|
|
4018
|
+
return effect.title ?? effect.name;
|
|
4019
|
+
}
|
|
4020
|
+
|
|
4021
|
+
const ACTION_LABEL = {
|
|
4022
|
+
"drain-effects": "Run the step again"
|
|
4023
|
+
}, REMEDY_TEXT = {
|
|
4024
|
+
"retry-effect": "The step has to run again before this workflow can continue.",
|
|
4025
|
+
"reset-activity": "Reset the task to try it again, or skip it.",
|
|
4026
|
+
"set-stage": "Move the workflow on to its next stage yourself."
|
|
4027
|
+
};
|
|
4028
|
+
|
|
4029
|
+
function detailOf(cause) {
|
|
4030
|
+
switch (cause.kind) {
|
|
4031
|
+
case "failed-effect":
|
|
4032
|
+
return `The step “${effectLabel(cause.effect)}” failed`;
|
|
4033
|
+
|
|
4034
|
+
case "hung-effect":
|
|
4035
|
+
return `The step “${effectLabel(cause.effect)}” didn’t finish`;
|
|
4036
|
+
|
|
4037
|
+
case "failed-activity":
|
|
4038
|
+
return "This task failed";
|
|
4039
|
+
|
|
4040
|
+
default:
|
|
4041
|
+
return summaryOf(cause);
|
|
4042
|
+
}
|
|
4043
|
+
}
|
|
4044
|
+
|
|
4045
|
+
function summaryOf(cause) {
|
|
4046
|
+
switch (cause.kind) {
|
|
4047
|
+
case "failed-effect":
|
|
4048
|
+
return "An automated step failed";
|
|
4049
|
+
|
|
4050
|
+
case "hung-effect":
|
|
4051
|
+
return "An automated step didn’t finish";
|
|
4052
|
+
|
|
4053
|
+
case "failed-activity":
|
|
4054
|
+
return "A task failed";
|
|
4055
|
+
|
|
4056
|
+
case "no-transition-fires":
|
|
4057
|
+
return "Every task is done, but nothing moves this workflow on";
|
|
4058
|
+
|
|
4059
|
+
case "transition-unevaluable":
|
|
4060
|
+
return "This workflow is waiting on something it can’t read yet, and will move on by itself";
|
|
4061
|
+
}
|
|
4062
|
+
}
|
|
4063
|
+
|
|
4064
|
+
function activityDeclaringEffect(args) {
|
|
4065
|
+
return workflowEngine.findStageNode(args)?.activities?.find(activity => (activity.actions ?? []).some(action => (action.effects ?? []).some(effect => effect.name === args.effectName)))?.name;
|
|
4066
|
+
}
|
|
4067
|
+
|
|
4068
|
+
function faultingActivity(args) {
|
|
4069
|
+
const {cause: cause} = args;
|
|
4070
|
+
if (cause.kind === "failed-activity") return cause.activity;
|
|
4071
|
+
if (cause.kind === "failed-effect" || cause.kind === "hung-effect") return activityDeclaringEffect({
|
|
4072
|
+
definition: args.definition,
|
|
4073
|
+
effectName: cause.effect.name,
|
|
4074
|
+
stageName: args.stageName
|
|
4075
|
+
});
|
|
4076
|
+
}
|
|
4077
|
+
|
|
4078
|
+
function isRecoverable(cause) {
|
|
4079
|
+
return cause.kind === "transition-unevaluable";
|
|
4080
|
+
}
|
|
4081
|
+
|
|
4082
|
+
function diagnosisOf(args) {
|
|
4083
|
+
if (args.evaluation !== void 0) return workflowEngine.diagnoseInstance(workflowEngine.diagnoseInputFromEvaluation(args.evaluation));
|
|
4084
|
+
const cause = workflowEngine.documentStuckCause({
|
|
4085
|
+
instance: args.instance,
|
|
4086
|
+
definition: args.definition
|
|
4087
|
+
});
|
|
4088
|
+
return cause === void 0 ? void 0 : {
|
|
4089
|
+
state: "stuck",
|
|
4090
|
+
cause: cause
|
|
4091
|
+
};
|
|
4092
|
+
}
|
|
4093
|
+
|
|
4094
|
+
function instanceFault(args) {
|
|
4095
|
+
const diagnosis = diagnosisOf(args);
|
|
4096
|
+
if (diagnosis === void 0 || diagnosis.state !== "stuck") return;
|
|
4097
|
+
const verbs = workflowEngine.remediationsFor(diagnosis).map(remediation2 => remediation2.verb);
|
|
4098
|
+
return {
|
|
4099
|
+
activity: faultingActivity({
|
|
4100
|
+
cause: diagnosis.cause,
|
|
4101
|
+
definition: args.definition,
|
|
4102
|
+
stageName: args.instance.currentStage
|
|
4103
|
+
}),
|
|
4104
|
+
detail: detailOf(diagnosis.cause),
|
|
4105
|
+
summary: summaryOf(diagnosis.cause),
|
|
4106
|
+
remedies: verbs.flatMap(verb => REMEDY_TEXT[verb] ?? []),
|
|
4107
|
+
actions: verbs.flatMap(verb => isRunnable(verb) ? [ {
|
|
4108
|
+
verb: verb,
|
|
4109
|
+
label: ACTION_LABEL[verb]
|
|
4110
|
+
} ] : []),
|
|
4111
|
+
recoverable: isRecoverable(diagnosis.cause)
|
|
4112
|
+
};
|
|
4113
|
+
}
|
|
4114
|
+
|
|
4115
|
+
function looksLikeDefinition(value) {
|
|
4116
|
+
return typeof value == "object" && value !== null && Array.isArray(value.stages);
|
|
4117
|
+
}
|
|
4118
|
+
|
|
4119
|
+
const parsed = /* @__PURE__ */ new WeakMap;
|
|
4120
|
+
|
|
4121
|
+
function definitionSnapshotOf(instance) {
|
|
4122
|
+
if (parsed.has(instance)) return parsed.get(instance);
|
|
4123
|
+
let definition;
|
|
4124
|
+
try {
|
|
4125
|
+
const candidate = workflowEngine.parseDefinitionSnapshot(instance);
|
|
4126
|
+
if (!looksLikeDefinition(candidate)) throw new Error(`definitionSnapshot on "${instance._id}" parsed to a non-definition shape`);
|
|
4127
|
+
definition = candidate;
|
|
4128
|
+
} catch (err) {
|
|
4129
|
+
console.error("[workflow-studio-plugin] unreadable definitionSnapshot:", err), definition = void 0;
|
|
4130
|
+
}
|
|
4131
|
+
return parsed.set(instance, definition), definition;
|
|
4132
|
+
}
|
|
4133
|
+
|
|
4134
|
+
function useDefinition(entry) {
|
|
4135
|
+
return react.useMemo(() => {
|
|
4136
|
+
if (entry) return entry.evaluation ? entry.evaluation.definition : definitionSnapshotOf(entry.instance);
|
|
4137
|
+
}, [ entry ]);
|
|
4138
|
+
}
|
|
4139
|
+
|
|
4140
|
+
function AbortedBadge({instance: instance}) {
|
|
4141
|
+
return workflowEngine.terminalState(instance) !== "aborted" ? null : /* @__PURE__ */ jsxRuntime.jsx(ui.Badge, {
|
|
4142
|
+
fontSize: 1,
|
|
4143
|
+
tone: "critical",
|
|
4144
|
+
children: "Aborted"
|
|
4145
|
+
});
|
|
4146
|
+
}
|
|
4147
|
+
|
|
4148
|
+
function OlderDefinitionBadge({instance: instance}) {
|
|
4149
|
+
const {latestDefinitionVersions: latestDefinitionVersions} = useWorkflowContext(), latest = latestDefinitionVersions.get(instance.definition);
|
|
4150
|
+
return latest === void 0 || latest <= instance.pinnedVersion ? null : /* @__PURE__ */ jsxRuntime.jsx(HoverHint, {
|
|
4151
|
+
description: "Running workflows keep the version they started on",
|
|
4152
|
+
text: `Started on v${instance.pinnedVersion}, latest is now v${latest}`,
|
|
4153
|
+
textWeight: "medium",
|
|
4154
|
+
children: /* @__PURE__ */ jsxRuntime.jsx(ui.Badge, {
|
|
4155
|
+
fontSize: 1,
|
|
4156
|
+
tone: "caution",
|
|
4157
|
+
children: "Older version"
|
|
4158
|
+
})
|
|
4159
|
+
});
|
|
4160
|
+
}
|
|
4161
|
+
|
|
4162
|
+
function useInstanceFault(entry) {
|
|
4163
|
+
return instanceFault({
|
|
4164
|
+
definition: useDefinition(entry),
|
|
4165
|
+
evaluation: entry.evaluation,
|
|
4166
|
+
instance: entry.instance
|
|
4167
|
+
});
|
|
4168
|
+
}
|
|
4169
|
+
|
|
4170
|
+
function InstanceFaultNote({entry: entry, scope: scope}) {
|
|
4171
|
+
const fault = useInstanceFault(entry);
|
|
4172
|
+
if (fault === void 0 || scope.kind === "task" && fault.activity !== scope.activityName) return null;
|
|
4173
|
+
const Icon = fault.recoverable ? WarningOutline.WarningOutlineIcon : ErrorOutline.ErrorOutlineIcon;
|
|
4174
|
+
/* @__PURE__ */
|
|
4175
|
+
return jsxRuntime.jsx(ui.Card, {
|
|
4176
|
+
padding: 3,
|
|
4177
|
+
radius: 3,
|
|
4178
|
+
tone: fault.recoverable ? "caution" : "critical",
|
|
4179
|
+
children: /* @__PURE__ */ jsxRuntime.jsxs(ui.Flex, {
|
|
4180
|
+
align: "flex-start",
|
|
4181
|
+
gap: 3,
|
|
4182
|
+
children: [
|
|
4183
|
+
/* @__PURE__ */ jsxRuntime.jsx(ui.Text, {
|
|
4184
|
+
size: 1,
|
|
4185
|
+
children: /* @__PURE__ */ jsxRuntime.jsx(Icon, {})
|
|
4186
|
+
}),
|
|
4187
|
+
/* @__PURE__ */ jsxRuntime.jsxs(ui.Stack, {
|
|
4188
|
+
flex: 1,
|
|
4189
|
+
gap: 3,
|
|
4190
|
+
children: [
|
|
4191
|
+
/* @__PURE__ */ jsxRuntime.jsx(ui.Text, {
|
|
4192
|
+
size: 1,
|
|
4193
|
+
weight: "medium",
|
|
4194
|
+
children: scope.kind === "run" ? fault.summary : fault.detail
|
|
4195
|
+
}), scope.kind === "run" ? /* @__PURE__ */ jsxRuntime.jsx(RunControl, {
|
|
4196
|
+
activity: fault.activity,
|
|
4197
|
+
onOpenActivity: scope.onOpenActivity
|
|
4198
|
+
}) : /* @__PURE__ */ jsxRuntime.jsx(TaskControls, {
|
|
4199
|
+
actions: fault.actions,
|
|
4200
|
+
instanceId: entry.instance._id,
|
|
4201
|
+
remedies: fault.remedies
|
|
4202
|
+
}) ]
|
|
4203
|
+
}) ]
|
|
4204
|
+
})
|
|
4205
|
+
});
|
|
4206
|
+
}
|
|
4207
|
+
|
|
4208
|
+
function RunControl({activity: activity, onOpenActivity: onOpenActivity}) {
|
|
4209
|
+
return activity === void 0 ? null : /* @__PURE__ */ jsxRuntime.jsx(ui.Flex, {
|
|
4210
|
+
children: /* @__PURE__ */ jsxRuntime.jsx(ui.Button, {
|
|
4211
|
+
fontSize: 1,
|
|
4212
|
+
mode: "ghost",
|
|
4213
|
+
onClick: () => onOpenActivity(activity),
|
|
4214
|
+
padding: 2,
|
|
4215
|
+
text: "View task"
|
|
4216
|
+
})
|
|
4217
|
+
});
|
|
4218
|
+
}
|
|
4219
|
+
|
|
4220
|
+
const RUN_VERB = {
|
|
4221
|
+
"drain-effects": drain => drain.run()
|
|
4222
|
+
};
|
|
4223
|
+
|
|
4224
|
+
function TaskControls({actions: actions, instanceId: instanceId, remedies: remedies}) {
|
|
4225
|
+
const drain = useDrainEffects(instanceId);
|
|
4226
|
+
/* @__PURE__ */
|
|
4227
|
+
return jsxRuntime.jsxs(jsxRuntime.Fragment, {
|
|
4228
|
+
children: [ remedies.length === 0 ? null : /* @__PURE__ */ jsxRuntime.jsx(ui.Text, {
|
|
4229
|
+
muted: !0,
|
|
4230
|
+
size: 1,
|
|
4231
|
+
children: remedies.join(" ")
|
|
4232
|
+
}), actions.length === 0 ? null : /* @__PURE__ */ jsxRuntime.jsx(ui.Flex, {
|
|
4233
|
+
gap: 2,
|
|
4234
|
+
children: actions.map(action => /* @__PURE__ */ jsxRuntime.jsx(ui.Button, {
|
|
4235
|
+
disabled: drain.busy,
|
|
4236
|
+
fontSize: 1,
|
|
4237
|
+
mode: "ghost",
|
|
4238
|
+
onClick: () => {
|
|
4239
|
+
RUN_VERB[action.verb](drain);
|
|
4240
|
+
},
|
|
4241
|
+
padding: 2,
|
|
4242
|
+
text: action.label
|
|
4243
|
+
}, action.verb))
|
|
4244
|
+
}) ]
|
|
4245
|
+
});
|
|
4246
|
+
}
|
|
4247
|
+
|
|
3928
4248
|
function MetaRow({children: children, fillHeight: fillHeight, label: label}) {
|
|
3929
4249
|
/* @__PURE__ */
|
|
3930
4250
|
return jsxRuntime.jsxs(ui.Flex, {
|
|
@@ -4053,7 +4373,7 @@ function useBadgeCapTrim() {
|
|
|
4053
4373
|
}
|
|
4054
4374
|
|
|
4055
4375
|
function SpinnerSlot({busy: busy}) {
|
|
4056
|
-
const size = useTextIconSize(), trim = useCapTrimFor(size);
|
|
4376
|
+
const size = useTextIconSize(), trim = useCapTrimFor(size), spinning = useDelayedFlag(busy, LOADING_CUE_DELAY_MS);
|
|
4057
4377
|
/* @__PURE__ */
|
|
4058
4378
|
return jsxRuntime.jsx(ui.Flex, {
|
|
4059
4379
|
align: "center",
|
|
@@ -4065,7 +4385,7 @@ function SpinnerSlot({busy: busy}) {
|
|
|
4065
4385
|
marginTop: trim,
|
|
4066
4386
|
width: size
|
|
4067
4387
|
},
|
|
4068
|
-
children:
|
|
4388
|
+
children: spinning ? /* @__PURE__ */ jsxRuntime.jsx(ui.Spinner, {
|
|
4069
4389
|
muted: !0,
|
|
4070
4390
|
size: 1
|
|
4071
4391
|
}) : null
|
|
@@ -4073,6 +4393,7 @@ function SpinnerSlot({busy: busy}) {
|
|
|
4073
4393
|
}
|
|
4074
4394
|
|
|
4075
4395
|
function LoadingRow({label: label, padding: padding}) {
|
|
4396
|
+
const announced = useDelayedFlag(!0, LOADING_CUE_DELAY_MS);
|
|
4076
4397
|
/* @__PURE__ */
|
|
4077
4398
|
return jsxRuntime.jsxs(ui.Flex, {
|
|
4078
4399
|
align: "center",
|
|
@@ -4083,12 +4404,11 @@ function LoadingRow({label: label, padding: padding}) {
|
|
|
4083
4404
|
children: [
|
|
4084
4405
|
/* @__PURE__ */ jsxRuntime.jsx(SpinnerSlot, {
|
|
4085
4406
|
busy: !0
|
|
4086
|
-
}),
|
|
4087
|
-
/* @__PURE__ */ jsxRuntime.jsx(ui.Text, {
|
|
4407
|
+
}), announced ? /* @__PURE__ */ jsxRuntime.jsx(ui.Text, {
|
|
4088
4408
|
muted: !0,
|
|
4089
4409
|
size: 1,
|
|
4090
4410
|
children: label
|
|
4091
|
-
}) ]
|
|
4411
|
+
}) : null ]
|
|
4092
4412
|
});
|
|
4093
4413
|
}
|
|
4094
4414
|
|
|
@@ -4144,7 +4464,7 @@ function AvatarButton({avatar: avatar, onClick: onClick, onMouseDown: onMouseDow
|
|
|
4144
4464
|
}
|
|
4145
4465
|
|
|
4146
4466
|
function RowAssignees({assignees: assignees, hint: hint}) {
|
|
4147
|
-
const ids = assignees.flatMap(item => item.type === "user" ? [ item.id ] : []),
|
|
4467
|
+
const ids = assignees.flatMap(item => item.type === "user" ? [ item.id ] : []), vocabulary = useProjectMembers(), roles = assignees.flatMap(item => item.type === "role" ? [ workflowComponents.memberRoleFor(vocabulary, item.role) ] : []), displays = useUserDisplays(ids);
|
|
4148
4468
|
if (ids.length === 0 && roles.length === 0) return null;
|
|
4149
4469
|
const bothKinds = roles.length > 0 && displays.length > 0;
|
|
4150
4470
|
/* @__PURE__ */
|
|
@@ -4355,49 +4675,40 @@ function ForMeEmptyState() {
|
|
|
4355
4675
|
});
|
|
4356
4676
|
}
|
|
4357
4677
|
|
|
4358
|
-
|
|
4359
|
-
return typeof value == "object" && value !== null && Array.isArray(value.stages);
|
|
4360
|
-
}
|
|
4678
|
+
const OVERDUE_HINT = "Now overdue";
|
|
4361
4679
|
|
|
4362
|
-
|
|
4363
|
-
|
|
4364
|
-
|
|
4365
|
-
|
|
4366
|
-
|
|
4367
|
-
|
|
4368
|
-
|
|
4369
|
-
|
|
4370
|
-
|
|
4371
|
-
} catch (err) {
|
|
4372
|
-
console.error("[workflow-studio-plugin] unreadable definitionSnapshot:", err), definition = void 0;
|
|
4373
|
-
}
|
|
4374
|
-
return parsed.set(instance, definition), definition;
|
|
4375
|
-
}
|
|
4376
|
-
|
|
4377
|
-
function useDefinition(entry) {
|
|
4378
|
-
return react.useMemo(() => {
|
|
4379
|
-
if (entry) return entry.evaluation ? entry.evaluation.definition : definitionSnapshotOf(entry.instance);
|
|
4380
|
-
}, [ entry ]);
|
|
4680
|
+
function hintFace(args) {
|
|
4681
|
+
return args.overdue ? args.reason === void 0 ? {
|
|
4682
|
+
text: OVERDUE_HINT
|
|
4683
|
+
} : {
|
|
4684
|
+
text: OVERDUE_HINT,
|
|
4685
|
+
description: args.reason
|
|
4686
|
+
} : args.reason === void 0 ? void 0 : {
|
|
4687
|
+
text: args.reason
|
|
4688
|
+
};
|
|
4381
4689
|
}
|
|
4382
4690
|
|
|
4383
|
-
function
|
|
4384
|
-
|
|
4385
|
-
|
|
4386
|
-
|
|
4387
|
-
|
|
4691
|
+
function DueDate({dueDate: dueDate, hintDisabled: hintDisabled, overdue: overdue, reason: reason}) {
|
|
4692
|
+
const face = hintFace({
|
|
4693
|
+
overdue: overdue,
|
|
4694
|
+
reason: reason
|
|
4695
|
+
}), text = overdue ?
|
|
4696
|
+
/* @__PURE__ */ jsxRuntime.jsx(sanity.TextWithTone, {
|
|
4697
|
+
size: 1,
|
|
4698
|
+
tone: "caution",
|
|
4699
|
+
children: formatDate(dueDate)
|
|
4700
|
+
}) : /* @__PURE__ */ jsxRuntime.jsx(ui.Text, {
|
|
4701
|
+
muted: !0,
|
|
4702
|
+
size: 1,
|
|
4703
|
+
children: formatDate(dueDate)
|
|
4388
4704
|
});
|
|
4389
|
-
|
|
4390
|
-
|
|
4391
|
-
|
|
4392
|
-
|
|
4393
|
-
|
|
4394
|
-
|
|
4395
|
-
|
|
4396
|
-
textWeight: "medium",
|
|
4397
|
-
children: /* @__PURE__ */ jsxRuntime.jsx(ui.Badge, {
|
|
4398
|
-
fontSize: 1,
|
|
4399
|
-
tone: "caution",
|
|
4400
|
-
children: "Older version"
|
|
4705
|
+
return face === void 0 ? text :
|
|
4706
|
+
/* @__PURE__ */ jsxRuntime.jsx(ui.Flex, {
|
|
4707
|
+
align: "center",
|
|
4708
|
+
children: /* @__PURE__ */ jsxRuntime.jsx(HoverHint, {
|
|
4709
|
+
...face,
|
|
4710
|
+
disabled: hintDisabled === !0,
|
|
4711
|
+
children: text
|
|
4401
4712
|
})
|
|
4402
4713
|
});
|
|
4403
4714
|
}
|
|
@@ -4437,18 +4748,6 @@ function CheckboxSlot({children: children}) {
|
|
|
4437
4748
|
});
|
|
4438
4749
|
}
|
|
4439
4750
|
|
|
4440
|
-
function DueDateText({dueDate: dueDate, overdue: overdue}) {
|
|
4441
|
-
return overdue ? /* @__PURE__ */ jsxRuntime.jsx(sanity.TextWithTone, {
|
|
4442
|
-
size: 1,
|
|
4443
|
-
tone: "caution",
|
|
4444
|
-
children: formatDate(dueDate)
|
|
4445
|
-
}) : /* @__PURE__ */ jsxRuntime.jsx(ui.Text, {
|
|
4446
|
-
muted: !0,
|
|
4447
|
-
size: 1,
|
|
4448
|
-
children: formatDate(dueDate)
|
|
4449
|
-
});
|
|
4450
|
-
}
|
|
4451
|
-
|
|
4452
4751
|
function DueDateEditor({dueDate: dueDate, onDone: onDone, onPatch: onPatch}) {
|
|
4453
4752
|
/* @__PURE__ */
|
|
4454
4753
|
return jsxRuntime.jsx(workflowComponents.ClearableDatePicker, {
|
|
@@ -4468,8 +4767,9 @@ function DueDateEditor({dueDate: dueDate, onDone: onDone, onPatch: onPatch}) {
|
|
|
4468
4767
|
}
|
|
4469
4768
|
|
|
4470
4769
|
function DueDateControl({item: item, editable: editable, onPatch: onPatch}) {
|
|
4471
|
-
const [open, setOpen] = react.useState(!1), overdue = isTodoOverdue(item), display = item.dueDate ? /* @__PURE__ */ jsxRuntime.jsx(
|
|
4770
|
+
const [open, setOpen] = react.useState(!1), overdue = isTodoOverdue(item), display = item.dueDate ? /* @__PURE__ */ jsxRuntime.jsx(DueDate, {
|
|
4472
4771
|
dueDate: item.dueDate,
|
|
4772
|
+
hintDisabled: open,
|
|
4473
4773
|
overdue: overdue
|
|
4474
4774
|
}) : null;
|
|
4475
4775
|
return editable ? /* @__PURE__ */ jsxRuntime.jsx(DismissablePopover, {
|
|
@@ -4480,18 +4780,14 @@ function DueDateControl({item: item, editable: editable, onPatch: onPatch}) {
|
|
|
4480
4780
|
}),
|
|
4481
4781
|
onDismiss: () => setOpen(!1),
|
|
4482
4782
|
open: open,
|
|
4483
|
-
children: display ? /* @__PURE__ */ jsxRuntime.jsx(
|
|
4484
|
-
|
|
4485
|
-
|
|
4486
|
-
|
|
4487
|
-
|
|
4488
|
-
|
|
4489
|
-
|
|
4490
|
-
|
|
4491
|
-
padding: 2,
|
|
4492
|
-
tone: overdue ? "caution" : "default",
|
|
4493
|
-
children: display
|
|
4494
|
-
})
|
|
4783
|
+
children: display ? /* @__PURE__ */ jsxRuntime.jsx(ui.Button, {
|
|
4784
|
+
"aria-label": "Change due date",
|
|
4785
|
+
fontSize: 1,
|
|
4786
|
+
mode: "bleed",
|
|
4787
|
+
onClick: () => setOpen(v => !v),
|
|
4788
|
+
padding: 2,
|
|
4789
|
+
tone: overdue ? "caution" : "default",
|
|
4790
|
+
children: display
|
|
4495
4791
|
}) : /* @__PURE__ */ jsxRuntime.jsx(HoverHint, {
|
|
4496
4792
|
disabled: open,
|
|
4497
4793
|
text: "Set due date",
|
|
@@ -4505,9 +4801,6 @@ function DueDateControl({item: item, editable: editable, onPatch: onPatch}) {
|
|
|
4505
4801
|
radius: 2
|
|
4506
4802
|
})
|
|
4507
4803
|
})
|
|
4508
|
-
}) : display && overdue ? /* @__PURE__ */ jsxRuntime.jsx(HoverHint, {
|
|
4509
|
-
text: "Now overdue",
|
|
4510
|
-
children: display
|
|
4511
4804
|
}) : display;
|
|
4512
4805
|
}
|
|
4513
4806
|
|
|
@@ -5160,9 +5453,15 @@ function ActivityDetailDialog({entry: entry, activityName: activityName, breadcr
|
|
|
5160
5453
|
const detail = deriveActivityDetail({
|
|
5161
5454
|
entry: entry,
|
|
5162
5455
|
activityName: activityName
|
|
5163
|
-
});
|
|
5456
|
+
}), faultingActivity2 = useInstanceFault(entry)?.activity;
|
|
5164
5457
|
if (!detail) return null;
|
|
5165
|
-
const instanceId = entry.instance._id, notice = blockedNotice(detail),
|
|
5458
|
+
const instanceId = entry.instance._id, notice = blockedNotice(detail), fault = /* @__PURE__ */ jsxRuntime.jsx(InstanceFaultNote, {
|
|
5459
|
+
entry: entry,
|
|
5460
|
+
scope: {
|
|
5461
|
+
kind: "task",
|
|
5462
|
+
activityName: activityName
|
|
5463
|
+
}
|
|
5464
|
+
}), faulted = faultingActivity2 === activityName, hasBody = detail.state.length > 0 || notice !== void 0 || faulted;
|
|
5166
5465
|
/* @__PURE__ */
|
|
5167
5466
|
return jsxRuntime.jsxs(ui.Dialog, {
|
|
5168
5467
|
footer: detail.presentation.terminalActions.length > 0 ? /* @__PURE__ */ jsxRuntime.jsx(TerminalFooter, {
|
|
@@ -5203,7 +5502,7 @@ function ActivityDetailDialog({entry: entry, activityName: activityName, breadcr
|
|
|
5203
5502
|
padding: 4,
|
|
5204
5503
|
children: /* @__PURE__ */ jsxRuntime.jsxs(ui.Stack, {
|
|
5205
5504
|
gap: 5,
|
|
5206
|
-
children: [ detail.state.map(field => /* @__PURE__ */ jsxRuntime.jsx(FieldRow, {
|
|
5505
|
+
children: [ fault, detail.state.map(field => /* @__PURE__ */ jsxRuntime.jsx(FieldRow, {
|
|
5207
5506
|
activityName: activityName,
|
|
5208
5507
|
detail: detail,
|
|
5209
5508
|
entry: entry,
|
|
@@ -5384,6 +5683,18 @@ function CountedLabel({count: count, label: label}) {
|
|
|
5384
5683
|
});
|
|
5385
5684
|
}
|
|
5386
5685
|
|
|
5686
|
+
function CountedHeading({count: count, title: title}) {
|
|
5687
|
+
/* @__PURE__ */
|
|
5688
|
+
return jsxRuntime.jsx(CountedLabel, {
|
|
5689
|
+
count: count,
|
|
5690
|
+
label: /* @__PURE__ */ jsxRuntime.jsx(ui.Text, {
|
|
5691
|
+
size: 1,
|
|
5692
|
+
weight: "semibold",
|
|
5693
|
+
children: title
|
|
5694
|
+
})
|
|
5695
|
+
});
|
|
5696
|
+
}
|
|
5697
|
+
|
|
5387
5698
|
function GroupHeading({busy: busy, count: count, title: title, end: end}) {
|
|
5388
5699
|
/* @__PURE__ */
|
|
5389
5700
|
return jsxRuntime.jsxs(ui.Flex, {
|
|
@@ -5392,13 +5703,9 @@ function GroupHeading({busy: busy, count: count, title: title, end: end}) {
|
|
|
5392
5703
|
paddingLeft: 2,
|
|
5393
5704
|
paddingY: end === void 0 ? 3 : 1,
|
|
5394
5705
|
children: [
|
|
5395
|
-
/* @__PURE__ */ jsxRuntime.jsx(
|
|
5706
|
+
/* @__PURE__ */ jsxRuntime.jsx(CountedHeading, {
|
|
5396
5707
|
count: count,
|
|
5397
|
-
|
|
5398
|
-
size: 1,
|
|
5399
|
-
weight: "semibold",
|
|
5400
|
-
children: title
|
|
5401
|
-
})
|
|
5708
|
+
title: title
|
|
5402
5709
|
}), busy === void 0 ? null : /* @__PURE__ */ jsxRuntime.jsx(SpinnerSlot, {
|
|
5403
5710
|
busy: busy
|
|
5404
5711
|
}), end === void 0 ? null : /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, {
|
|
@@ -5410,21 +5717,81 @@ function GroupHeading({busy: busy, count: count, title: title, end: end}) {
|
|
|
5410
5717
|
});
|
|
5411
5718
|
}
|
|
5412
5719
|
|
|
5720
|
+
const EMPTY_METRIC_OPACITY = .5;
|
|
5721
|
+
|
|
5722
|
+
function MetricText({children: children, tone: tone}) {
|
|
5723
|
+
return tone === void 0 ? /* @__PURE__ */ jsxRuntime.jsx(ui.Text, {
|
|
5724
|
+
muted: !0,
|
|
5725
|
+
size: 1,
|
|
5726
|
+
children: children
|
|
5727
|
+
}) : /* @__PURE__ */ jsxRuntime.jsx(sanity.TextWithTone, {
|
|
5728
|
+
size: 1,
|
|
5729
|
+
tone: tone,
|
|
5730
|
+
children: children
|
|
5731
|
+
});
|
|
5732
|
+
}
|
|
5733
|
+
|
|
5734
|
+
function MetricPair({Icon: Icon, empty: empty, face: face, tone: tone, value: value}) {
|
|
5735
|
+
/* @__PURE__ */
|
|
5736
|
+
return jsxRuntime.jsx(HoverHint, {
|
|
5737
|
+
...face,
|
|
5738
|
+
children: /* @__PURE__ */ jsxRuntime.jsxs(ui.Flex, {
|
|
5739
|
+
align: "center",
|
|
5740
|
+
gap: 2,
|
|
5741
|
+
style: empty ? {
|
|
5742
|
+
opacity: EMPTY_METRIC_OPACITY
|
|
5743
|
+
} : void 0,
|
|
5744
|
+
children: [
|
|
5745
|
+
/* @__PURE__ */ jsxRuntime.jsx(MetricText, {
|
|
5746
|
+
tone: tone,
|
|
5747
|
+
children: /* @__PURE__ */ jsxRuntime.jsx(Icon, {
|
|
5748
|
+
style: {
|
|
5749
|
+
color: "inherit"
|
|
5750
|
+
}
|
|
5751
|
+
})
|
|
5752
|
+
}),
|
|
5753
|
+
/* @__PURE__ */ jsxRuntime.jsx(MetricText, {
|
|
5754
|
+
tone: tone,
|
|
5755
|
+
children: value
|
|
5756
|
+
}) ]
|
|
5757
|
+
})
|
|
5758
|
+
});
|
|
5759
|
+
}
|
|
5760
|
+
|
|
5761
|
+
function AlertGlyph({Icon: Icon, hint: hint, tone: tone}) {
|
|
5762
|
+
/* @__PURE__ */
|
|
5763
|
+
return jsxRuntime.jsx(HoverHint, {
|
|
5764
|
+
text: hint,
|
|
5765
|
+
children: /* @__PURE__ */ jsxRuntime.jsx(sanity.TextWithTone, {
|
|
5766
|
+
size: 1,
|
|
5767
|
+
tone: tone,
|
|
5768
|
+
children: /* @__PURE__ */ jsxRuntime.jsx(Icon, {
|
|
5769
|
+
style: {
|
|
5770
|
+
color: "inherit"
|
|
5771
|
+
}
|
|
5772
|
+
})
|
|
5773
|
+
})
|
|
5774
|
+
});
|
|
5775
|
+
}
|
|
5776
|
+
|
|
5413
5777
|
function ActivityDateControl({instanceId: instanceId, state: state, surface: surface, dueDates: dueDates}) {
|
|
5414
5778
|
const editField = useEditField(surface), {save: save} = useSaveField({
|
|
5415
5779
|
instanceId: instanceId
|
|
5416
5780
|
}), [open, setOpen] = react.useState(!1), raw = dateControlValue({
|
|
5417
5781
|
state: state,
|
|
5418
5782
|
dueDates: dueDates
|
|
5419
|
-
}),
|
|
5420
|
-
|
|
5421
|
-
|
|
5422
|
-
|
|
5783
|
+
}), overdue = raw !== void 0 && isDueDatePast(raw, /* @__PURE__ */ new Date), dueDate = reason => raw === void 0 ? null : /* @__PURE__ */ jsxRuntime.jsx(DueDate, {
|
|
5784
|
+
dueDate: raw,
|
|
5785
|
+
hintDisabled: open,
|
|
5786
|
+
overdue: overdue,
|
|
5787
|
+
...reason === void 0 ? {} : {
|
|
5788
|
+
reason: reason
|
|
5789
|
+
}
|
|
5423
5790
|
});
|
|
5424
|
-
if (state.kind === "none") return
|
|
5425
|
-
if (state.kind === "closed")
|
|
5426
|
-
|
|
5427
|
-
|
|
5791
|
+
if (state.kind === "none") return dueDate();
|
|
5792
|
+
if (state.kind === "closed") {
|
|
5793
|
+
const display = dueDate(state.reason);
|
|
5794
|
+
return display === null ? null : /* @__PURE__ */ jsxRuntime.jsx(ui.Button, {
|
|
5428
5795
|
"aria-label": "Date",
|
|
5429
5796
|
as: "span",
|
|
5430
5797
|
fontSize: 1,
|
|
@@ -5433,8 +5800,8 @@ function ActivityDateControl({instanceId: instanceId, state: state, surface: sur
|
|
|
5433
5800
|
onMouseDown: stopRowMouseDown,
|
|
5434
5801
|
padding: 2,
|
|
5435
5802
|
children: display
|
|
5436
|
-
})
|
|
5437
|
-
}
|
|
5803
|
+
});
|
|
5804
|
+
}
|
|
5438
5805
|
const kind = dateControlKind(state), commit = (mode, value) => {
|
|
5439
5806
|
state.kind === "editable" && save(() => editField({
|
|
5440
5807
|
instanceId: instanceId,
|
|
@@ -5470,7 +5837,7 @@ function ActivityDateControl({instanceId: instanceId, state: state, surface: sur
|
|
|
5470
5837
|
}),
|
|
5471
5838
|
onDismiss: () => setOpen(!1),
|
|
5472
5839
|
open: open,
|
|
5473
|
-
children:
|
|
5840
|
+
children: raw !== void 0 ? /* @__PURE__ */ jsxRuntime.jsx(ui.Button, {
|
|
5474
5841
|
"aria-label": "Change date",
|
|
5475
5842
|
as: "span",
|
|
5476
5843
|
fontSize: 1,
|
|
@@ -5478,7 +5845,7 @@ function ActivityDateControl({instanceId: instanceId, state: state, surface: sur
|
|
|
5478
5845
|
onClick: handleClick,
|
|
5479
5846
|
onMouseDown: stopRowMouseDown,
|
|
5480
5847
|
padding: 2,
|
|
5481
|
-
children:
|
|
5848
|
+
children: dueDate()
|
|
5482
5849
|
}) : /* @__PURE__ */ jsxRuntime.jsx(HoverHint, {
|
|
5483
5850
|
disabled: open,
|
|
5484
5851
|
text: "Set date",
|
|
@@ -5568,7 +5935,7 @@ function TitleTag({hint: hint, tone: tone, children: children}) {
|
|
|
5568
5935
|
});
|
|
5569
5936
|
}
|
|
5570
5937
|
|
|
5571
|
-
function ActivityRow({face: face, breadcrumb: breadcrumb, assignees: assignees, assignState: assignState, dateState: dateState, dueDates: dueDates, instanceId: instanceId, onOpen: onOpen, surface: surface, terminalActions: terminalActions = []}) {
|
|
5938
|
+
function ActivityRow({face: face, breadcrumb: breadcrumb, assignees: assignees, assignState: assignState, dateState: dateState, dueDates: dueDates, faultHint: faultHint, instanceId: instanceId, onOpen: onOpen, surface: surface, terminalActions: terminalActions = []}) {
|
|
5572
5939
|
const settled = workflowEngine.isTerminalActivityStatus(face.status), dimmed = settledDim(settled);
|
|
5573
5940
|
/* @__PURE__ */
|
|
5574
5941
|
return jsxRuntime.jsxs(WorkRow, {
|
|
@@ -5601,6 +5968,10 @@ function ActivityRow({face: face, breadcrumb: breadcrumb, assignees: assignees,
|
|
|
5601
5968
|
/* @__PURE__ */ jsxRuntime.jsx(ActivityRowTitle, {
|
|
5602
5969
|
dimmed: dimmed,
|
|
5603
5970
|
children: face.title
|
|
5971
|
+
}), faultHint === void 0 || face.status === "failed" ? null : /* @__PURE__ */ jsxRuntime.jsx(AlertGlyph, {
|
|
5972
|
+
Icon: ErrorOutline.ErrorOutlineIcon,
|
|
5973
|
+
hint: faultHint,
|
|
5974
|
+
tone: "critical"
|
|
5604
5975
|
}), face.automated ? /* @__PURE__ */ jsxRuntime.jsx(TitleTag, {
|
|
5605
5976
|
hint: "Completes on its own — no user action is needed",
|
|
5606
5977
|
children: "Automated"
|
|
@@ -5616,7 +5987,7 @@ function ActivityRow({face: face, breadcrumb: breadcrumb, assignees: assignees,
|
|
|
5616
5987
|
}
|
|
5617
5988
|
|
|
5618
5989
|
function ActivitiesList({entry: entry, onOpenActivity: onOpenActivity, surface: surface}) {
|
|
5619
|
-
const activities = (entry.evaluation?.currentStage.activities ?? []).filter(t => !t.scopedOut), activityState = stateByActivity(entry.instance);
|
|
5990
|
+
const activities = (entry.evaluation?.currentStage.activities ?? []).filter(t => !t.scopedOut), activityState = stateByActivity(entry.instance), fault = useInstanceFault(entry);
|
|
5620
5991
|
return activities.length === 0 ?
|
|
5621
5992
|
/* @__PURE__ */ jsxRuntime.jsx(ui.Box, {
|
|
5622
5993
|
paddingX: 1,
|
|
@@ -5634,6 +6005,9 @@ function ActivitiesList({entry: entry, onOpenActivity: onOpenActivity, surface:
|
|
|
5634
6005
|
activityState: activityState,
|
|
5635
6006
|
editableFields: entry.evaluation?.editableFields
|
|
5636
6007
|
}),
|
|
6008
|
+
...fault?.activity === t.activity.name ? {
|
|
6009
|
+
faultHint: fault.summary
|
|
6010
|
+
} : {},
|
|
5637
6011
|
instanceId: entry.instance._id,
|
|
5638
6012
|
onOpen: () => onOpenActivity(t.activity.name),
|
|
5639
6013
|
surface: surface
|
|
@@ -5780,7 +6154,10 @@ function progressFillPercent(face) {
|
|
|
5780
6154
|
}
|
|
5781
6155
|
|
|
5782
6156
|
function deriveFieldPills(args) {
|
|
5783
|
-
const {scope: scope, definition: definition, instance: instance, committed: committed, evaluation: evaluation} = args, declared = scope === "workflow" ? definition?.fields ?? [] :
|
|
6157
|
+
const {scope: scope, definition: definition, instance: instance, committed: committed, evaluation: evaluation} = args, declared = scope === "workflow" ? definition?.fields ?? [] : workflowEngine.findStageNode({
|
|
6158
|
+
definition: definition,
|
|
6159
|
+
stageName: instance.currentStage
|
|
6160
|
+
})?.fields ?? [], entries = scope === "workflow" ? instance.fields : workflowEngine.findOpenStageEntry(instance)?.fields ?? [], entriesByName = new Map(entries.map(entry => [ entry.name, entry ])), editables = isEvaluationCurrent({
|
|
5784
6161
|
committed: committed,
|
|
5785
6162
|
evaluation: evaluation
|
|
5786
6163
|
}) ? editablesByName(evaluation, scope) : /* @__PURE__ */ new Map, declaredNames = new Set(declared.map(d => d.name));
|
|
@@ -6014,7 +6391,7 @@ function AvatarCapAligned({children: children}) {
|
|
|
6014
6391
|
}
|
|
6015
6392
|
|
|
6016
6393
|
function AssigneesFace({assignees: assignees}) {
|
|
6017
|
-
const
|
|
6394
|
+
const vocabulary = useProjectMembers(), userIds = assignees.flatMap(a => a.type === "user" ? [ a.id ] : []), roles = assignees.flatMap(a => a.type === "role" ? [ workflowComponents.roleLabelFor(vocabulary, a.role) ] : []);
|
|
6018
6395
|
/* @__PURE__ */
|
|
6019
6396
|
return jsxRuntime.jsxs(jsxRuntime.Fragment, {
|
|
6020
6397
|
children: [ userIds.length > 0 ? /* @__PURE__ */ jsxRuntime.jsx(AvatarCapAligned, {
|
|
@@ -6970,6 +7347,27 @@ function HintedMenuButton({hint: hint, ...menuButtonProps}) {
|
|
|
6970
7347
|
});
|
|
6971
7348
|
}
|
|
6972
7349
|
|
|
7350
|
+
function InlineEmphasis({children: children}) {
|
|
7351
|
+
const {font: font} = ui.useTheme_v2();
|
|
7352
|
+
/* @__PURE__ */
|
|
7353
|
+
return jsxRuntime.jsx("span", {
|
|
7354
|
+
style: {
|
|
7355
|
+
fontWeight: font.text.weights.medium
|
|
7356
|
+
},
|
|
7357
|
+
children: children
|
|
7358
|
+
});
|
|
7359
|
+
}
|
|
7360
|
+
|
|
7361
|
+
const MINUTE_MS = 6e4;
|
|
7362
|
+
|
|
7363
|
+
function useMinuteClock() {
|
|
7364
|
+
const [now, setNow] = react.useState(() => /* @__PURE__ */ new Date);
|
|
7365
|
+
return react.useEffect(() => {
|
|
7366
|
+
const timer = setInterval(() => setNow(/* @__PURE__ */ new Date), MINUTE_MS);
|
|
7367
|
+
return () => clearInterval(timer);
|
|
7368
|
+
}, []), now;
|
|
7369
|
+
}
|
|
7370
|
+
|
|
6973
7371
|
function historyWindow(args) {
|
|
6974
7372
|
const {entries: entries, expanded: expanded} = args;
|
|
6975
7373
|
return {
|
|
@@ -6979,28 +7377,10 @@ function historyWindow(args) {
|
|
|
6979
7377
|
}
|
|
6980
7378
|
|
|
6981
7379
|
function PendingEffectRows({instance: instance, now: now}) {
|
|
6982
|
-
const {
|
|
7380
|
+
const {completeEffectFor: completeEffectFor, effectHandlers: effectHandlers} = useWorkflowContext(), toast = useWorkflowToast(), drain = useDrainEffects(instance._id), [resolving, setResolving] = react.useState(!1), pending = instance.pendingEffects ?? [];
|
|
6983
7381
|
if (pending.length === 0) return null;
|
|
6984
|
-
const
|
|
6985
|
-
|
|
6986
|
-
try {
|
|
6987
|
-
await drainEffectsFor(instance._id), toast.push({
|
|
6988
|
-
id: TOAST_ID.effectsDrain,
|
|
6989
|
-
status: "info",
|
|
6990
|
-
title: "Ran the registered handlers"
|
|
6991
|
-
});
|
|
6992
|
-
} catch (err) {
|
|
6993
|
-
toast.push({
|
|
6994
|
-
id: TOAST_ID.effectsDrain,
|
|
6995
|
-
status: "error",
|
|
6996
|
-
title: "Failed to run pending effects",
|
|
6997
|
-
description: describeError(err)
|
|
6998
|
-
});
|
|
6999
|
-
} finally {
|
|
7000
|
-
setBusy(!1);
|
|
7001
|
-
}
|
|
7002
|
-
}, resolve = async (effectKey, status) => {
|
|
7003
|
-
setBusy(!0);
|
|
7382
|
+
const resolve = async (effectKey, status) => {
|
|
7383
|
+
setResolving(!0);
|
|
7004
7384
|
try {
|
|
7005
7385
|
await completeEffectFor(instance._id, {
|
|
7006
7386
|
effectKey: effectKey,
|
|
@@ -7019,18 +7399,20 @@ function PendingEffectRows({instance: instance, now: now}) {
|
|
|
7019
7399
|
description: describeError(err)
|
|
7020
7400
|
});
|
|
7021
7401
|
} finally {
|
|
7022
|
-
|
|
7402
|
+
setResolving(!1);
|
|
7023
7403
|
}
|
|
7024
7404
|
};
|
|
7025
7405
|
/* @__PURE__ */
|
|
7026
7406
|
return jsxRuntime.jsx(jsxRuntime.Fragment, {
|
|
7027
7407
|
children: pending.map(fx => /* @__PURE__ */ jsxRuntime.jsx(PendingEffectRow, {
|
|
7028
|
-
busy: busy,
|
|
7408
|
+
busy: drain.busy || resolving,
|
|
7029
7409
|
effect: fx,
|
|
7030
7410
|
instanceId: instance._id,
|
|
7031
7411
|
now: now,
|
|
7032
7412
|
onResolve: status => resolve(fx._key, status),
|
|
7033
|
-
onRunHandlers:
|
|
7413
|
+
onRunHandlers: () => {
|
|
7414
|
+
drain.run();
|
|
7415
|
+
},
|
|
7034
7416
|
registered: fx.name in effectHandlers
|
|
7035
7417
|
}, fx._key))
|
|
7036
7418
|
});
|
|
@@ -7114,12 +7496,7 @@ function PendingEffectRow({busy: busy, effect: effect, instanceId: instanceId, n
|
|
|
7114
7496
|
}
|
|
7115
7497
|
|
|
7116
7498
|
function ActivityLog({instance: instance, definition: definition, windowed: windowed = !0}) {
|
|
7117
|
-
const titles = react.useMemo(() => makeTitleResolver(definition), [ definition ]), entries = react.useMemo(() => instance.history.toReversed(), [ instance.history ]),
|
|
7118
|
-
react.useEffect(() => {
|
|
7119
|
-
const timer = setInterval(() => setNow(/* @__PURE__ */ new Date), 6e4);
|
|
7120
|
-
return () => clearInterval(timer);
|
|
7121
|
-
}, []);
|
|
7122
|
-
const history = historyWindow({
|
|
7499
|
+
const titles = react.useMemo(() => makeTitleResolver(definition), [ definition ]), entries = react.useMemo(() => instance.history.toReversed(), [ instance.history ]), now = useMinuteClock(), [expanded, setExpanded] = react.useState(!1), history = historyWindow({
|
|
7123
7500
|
entries: entries,
|
|
7124
7501
|
expanded: expanded || !windowed
|
|
7125
7502
|
});
|
|
@@ -7222,12 +7599,9 @@ function HistoryRow({entry: entry, now: now, titles: titles}) {
|
|
|
7222
7599
|
}
|
|
7223
7600
|
|
|
7224
7601
|
function ActorNameSpan({id: id}) {
|
|
7225
|
-
const {name: name} = useUserDisplay(id)
|
|
7602
|
+
const {name: name} = useUserDisplay(id);
|
|
7226
7603
|
/* @__PURE__ */
|
|
7227
|
-
return jsxRuntime.jsx(
|
|
7228
|
-
style: {
|
|
7229
|
-
fontWeight: font.text.weights.medium
|
|
7230
|
-
},
|
|
7604
|
+
return jsxRuntime.jsx(InlineEmphasis, {
|
|
7231
7605
|
children: name
|
|
7232
7606
|
});
|
|
7233
7607
|
}
|
|
@@ -7635,7 +8009,6 @@ function StageOverviewCard({overview: overview}) {
|
|
|
7635
8009
|
}
|
|
7636
8010
|
|
|
7637
8011
|
function AdvanceCard({advance: advance}) {
|
|
7638
|
-
const {font: font} = ui.useTheme_v2();
|
|
7639
8012
|
/* @__PURE__ */
|
|
7640
8013
|
return jsxRuntime.jsx(ui.Card, {
|
|
7641
8014
|
padding: 3,
|
|
@@ -7647,10 +8020,7 @@ function AdvanceCard({advance: advance}) {
|
|
|
7647
8020
|
/* @__PURE__ */ jsxRuntime.jsxs(ui.Text, {
|
|
7648
8021
|
size: 1,
|
|
7649
8022
|
children: [ "Advances to ",
|
|
7650
|
-
/* @__PURE__ */ jsxRuntime.jsx(
|
|
7651
|
-
style: {
|
|
7652
|
-
fontWeight: font.text.weights.medium
|
|
7653
|
-
},
|
|
8023
|
+
/* @__PURE__ */ jsxRuntime.jsx(InlineEmphasis, {
|
|
7654
8024
|
children: advance.toTitle
|
|
7655
8025
|
}), ADVANCE_TAILS[advance.kind] ]
|
|
7656
8026
|
}), advance.kind !== "conditions" ? null : advance.lines.map((line, index) =>
|
|
@@ -7774,18 +8144,23 @@ function StageSection({entry: entry, onOpenActivity: onOpenActivity, surface: su
|
|
|
7774
8144
|
});
|
|
7775
8145
|
}
|
|
7776
8146
|
|
|
7777
|
-
|
|
8147
|
+
const BANNER_PADDING = 3, ICONS = {
|
|
8148
|
+
caution: /* @__PURE__ */ jsxRuntime.jsx(WarningOutline.WarningOutlineIcon, {}),
|
|
8149
|
+
critical: /* @__PURE__ */ jsxRuntime.jsx(ErrorOutline.ErrorOutlineIcon, {})
|
|
8150
|
+
};
|
|
8151
|
+
|
|
8152
|
+
function NoteBanner({action: action, label: label, tone: tone = "caution"}) {
|
|
7778
8153
|
/* @__PURE__ */
|
|
7779
8154
|
return jsxRuntime.jsxs(ui.Card, {
|
|
7780
8155
|
paddingLeft: 3,
|
|
7781
8156
|
paddingRight: 2,
|
|
7782
|
-
paddingY:
|
|
8157
|
+
paddingY: BANNER_PADDING,
|
|
7783
8158
|
radius: 3,
|
|
7784
8159
|
style: {
|
|
7785
8160
|
alignItems: "center",
|
|
7786
8161
|
display: "flex"
|
|
7787
8162
|
},
|
|
7788
|
-
tone:
|
|
8163
|
+
tone: tone,
|
|
7789
8164
|
children: [
|
|
7790
8165
|
/* @__PURE__ */ jsxRuntime.jsxs(ui.Flex, {
|
|
7791
8166
|
align: "center",
|
|
@@ -7795,7 +8170,7 @@ function CautionNote({action: action, label: label}) {
|
|
|
7795
8170
|
/* @__PURE__ */ jsxRuntime.jsx(ui.Text, {
|
|
7796
8171
|
muted: !0,
|
|
7797
8172
|
size: 1,
|
|
7798
|
-
children:
|
|
8173
|
+
children: ICONS[tone]
|
|
7799
8174
|
}),
|
|
7800
8175
|
/* @__PURE__ */ jsxRuntime.jsx(ui.Text, {
|
|
7801
8176
|
muted: !0,
|
|
@@ -7832,7 +8207,7 @@ function UnreadableDocsNote({unreadable: unreadable}) {
|
|
|
7832
8207
|
if (unreadable.length === 0) return null;
|
|
7833
8208
|
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.`;
|
|
7834
8209
|
/* @__PURE__ */
|
|
7835
|
-
return jsxRuntime.jsx(
|
|
8210
|
+
return jsxRuntime.jsx(NoteBanner, {
|
|
7836
8211
|
action: /* @__PURE__ */ jsxRuntime.jsx(CopyDetailsButton, {
|
|
7837
8212
|
unreadable: unreadable
|
|
7838
8213
|
}),
|
|
@@ -7878,6 +8253,21 @@ function InvalidDocNotice({invalid: invalid}) {
|
|
|
7878
8253
|
});
|
|
7879
8254
|
}
|
|
7880
8255
|
|
|
8256
|
+
function RoleAssignedNotice() {
|
|
8257
|
+
/* @__PURE__ */
|
|
8258
|
+
return jsxRuntime.jsx(ui.Box, {
|
|
8259
|
+
padding: 2,
|
|
8260
|
+
children: /* @__PURE__ */ jsxRuntime.jsx(ui.Text, {
|
|
8261
|
+
muted: !0,
|
|
8262
|
+
size: 1,
|
|
8263
|
+
style: {
|
|
8264
|
+
fontStyle: "italic"
|
|
8265
|
+
},
|
|
8266
|
+
children: "Including tasks assigned to your role"
|
|
8267
|
+
})
|
|
8268
|
+
});
|
|
8269
|
+
}
|
|
8270
|
+
|
|
7881
8271
|
function TabSwitch({ariaControls: ariaControls, idPrefix: idPrefix, options: options, selected: selected, onSelect: onSelect}) {
|
|
7882
8272
|
/* @__PURE__ */
|
|
7883
8273
|
return jsxRuntime.jsx(ui.TabList, {
|
|
@@ -8142,8 +8532,15 @@ function presentedResumeEntry(args) {
|
|
|
8142
8532
|
if (!args.startNew) return findResumeEntry(args);
|
|
8143
8533
|
}
|
|
8144
8534
|
|
|
8535
|
+
function settledByAnotherWriter(cause, instance) {
|
|
8536
|
+
return workflowEngine.isRevisionConflict(cause) && workflowEngine.terminalState(instance) === "completed";
|
|
8537
|
+
}
|
|
8538
|
+
|
|
8145
8539
|
function classifyStartError(err) {
|
|
8146
|
-
return err instanceof workflowEngine.StartNotSettledError ? {
|
|
8540
|
+
return err instanceof workflowEngine.StartNotSettledError ? err.instance !== void 0 && settledByAnotherWriter(err.cause, err.instance) ? {
|
|
8541
|
+
kind: "started-settled-elsewhere",
|
|
8542
|
+
instance: err.instance
|
|
8543
|
+
} : {
|
|
8147
8544
|
kind: "started-not-settled",
|
|
8148
8545
|
instance: err.instance,
|
|
8149
8546
|
description: describeError(err.cause)
|
|
@@ -8156,8 +8553,16 @@ function classifyStartError(err) {
|
|
|
8156
8553
|
};
|
|
8157
8554
|
}
|
|
8158
8555
|
|
|
8556
|
+
function startProducedRun(outcome) {
|
|
8557
|
+
return outcome.kind === "started-not-settled" || outcome.kind === "started-settled-elsewhere";
|
|
8558
|
+
}
|
|
8559
|
+
|
|
8159
8560
|
function startOutcomeToast(outcome, label) {
|
|
8160
|
-
return outcome.kind === "started-
|
|
8561
|
+
return outcome.kind === "started-settled-elsewhere" ? {
|
|
8562
|
+
id: TOAST_ID.start,
|
|
8563
|
+
status: "info",
|
|
8564
|
+
title: `“${label}” started and finished`
|
|
8565
|
+
} : outcome.kind === "started-not-settled" ? {
|
|
8161
8566
|
id: TOAST_ID.start,
|
|
8162
8567
|
status: "warning",
|
|
8163
8568
|
title: `“${label}” started but didn’t finish`,
|
|
@@ -8723,7 +9128,7 @@ function DiscoverySpinner() {
|
|
|
8723
9128
|
});
|
|
8724
9129
|
}
|
|
8725
9130
|
|
|
8726
|
-
const
|
|
9131
|
+
const GROUP_GAP = 2;
|
|
8727
9132
|
|
|
8728
9133
|
function useWorkflowsTab() {
|
|
8729
9134
|
const {params: params, setParams: setParams} = structure.usePaneRouter();
|
|
@@ -8748,7 +9153,7 @@ function useOpenActivity(entries) {
|
|
|
8748
9153
|
}
|
|
8749
9154
|
|
|
8750
9155
|
function WorkflowsPanel({entries: entries, documentId: documentId, docTypeMappings: docTypeMappings, initialValue: initialValue}) {
|
|
8751
|
-
const identity = useAssignmentIdentity(), panelId = react.useId(), {params: params} = structure.usePaneRouter(), {view: view, setView: setView} = useWorkflowsTab(), telemetry2 = workflowReact.useWorkflowTelemetry(), {openActivity: openActivity, setOpenActivity: setOpenActivity, dialogEntry: dialogEntry} = useOpenActivity(entries), active = entries.filter(isLiveEntry), finished = entries.filter(e => !isLiveEntry(e)), forMe = forMeWorkOf(active, identity), [landing] = react.useState(() => focusedLanding(params?.[WORKFLOWS_FOCUS_PARAM], entries.map(e => e.instance._id))), assignedWorkUnknown = active.some(e => e.invalid !== void 0), booting =
|
|
9156
|
+
const identity = useAssignmentIdentity(), panelId = react.useId(), {params: params} = structure.usePaneRouter(), {view: view, setView: setView} = useWorkflowsTab(), telemetry2 = workflowReact.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] = react.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__ */ jsxRuntime.jsx(WorkflowInstanceSection, {
|
|
8752
9157
|
defaultOpen: landingDefaultOpen(landing, e.instance._id),
|
|
8753
9158
|
entry: e,
|
|
8754
9159
|
onOpenActivity: activityName => setOpenActivity({
|
|
@@ -8888,10 +9293,10 @@ function OverviewEmptyState({mappings: mappings, docId: docId, initialValue: ini
|
|
|
8888
9293
|
}
|
|
8889
9294
|
|
|
8890
9295
|
function ForMeTab({forMe: forMe, assignedWorkUnknown: assignedWorkUnknown, onOpenActivity: onOpenActivity}) {
|
|
8891
|
-
return forMe.hasRows ? /* @__PURE__ */ jsxRuntime.
|
|
9296
|
+
return forMe.hasRows ? /* @__PURE__ */ jsxRuntime.jsxs(ui.Stack, {
|
|
8892
9297
|
gap: GROUP_GAP,
|
|
8893
9298
|
paddingBottom: 4,
|
|
8894
|
-
children: forMe.work.map(({entry: entry, who: who, shown: shown}) => /* @__PURE__ */ jsxRuntime.jsx(ForMeList, {
|
|
9299
|
+
children: [ forMe.hasRoleMatched ? /* @__PURE__ */ jsxRuntime.jsx(RoleAssignedNotice, {}) : null, forMe.work.map(({entry: entry, who: who, shown: shown}) => /* @__PURE__ */ jsxRuntime.jsx(ForMeList, {
|
|
8895
9300
|
entry: entry,
|
|
8896
9301
|
identity: who,
|
|
8897
9302
|
work: shown,
|
|
@@ -8900,7 +9305,7 @@ function ForMeTab({forMe: forMe, assignedWorkUnknown: assignedWorkUnknown, onOpe
|
|
|
8900
9305
|
activityName: activityName,
|
|
8901
9306
|
stage: entry.instance.currentStage
|
|
8902
9307
|
})
|
|
8903
|
-
}, entry.instance._id))
|
|
9308
|
+
}, entry.instance._id)) ]
|
|
8904
9309
|
}) : assignedWorkUnknown ? null : /* @__PURE__ */ jsxRuntime.jsx(ForMeEmptyState, {});
|
|
8905
9310
|
}
|
|
8906
9311
|
|
|
@@ -10138,7 +10543,7 @@ function ResumeNote({onStartNew: onStartNew}) {
|
|
|
10138
10543
|
|
|
10139
10544
|
function handleStartError(args) {
|
|
10140
10545
|
const {label: label, toast: toast, seedInstance: seedInstance, onClose: onClose} = args, outcome = classifyStartError(args.err);
|
|
10141
|
-
toast.push(startOutcomeToast(outcome, label)), outcome
|
|
10546
|
+
toast.push(startOutcomeToast(outcome, label)), startProducedRun(outcome) && (outcome.instance !== void 0 && seedInstance(outcome.instance),
|
|
10142
10547
|
onClose());
|
|
10143
10548
|
}
|
|
10144
10549
|
|
|
@@ -10491,7 +10896,7 @@ async function startRequest(engine, request) {
|
|
|
10491
10896
|
};
|
|
10492
10897
|
} catch (err) {
|
|
10493
10898
|
const outcome = classifyStartError(err);
|
|
10494
|
-
return outcome
|
|
10899
|
+
return startProducedRun(outcome) ? outcome.instance ? {
|
|
10495
10900
|
instance: outcome.instance
|
|
10496
10901
|
} : {} : outcome.kind === "not-allowed" ? {} : {
|
|
10497
10902
|
failure: outcome.description
|
|
@@ -10692,6 +11097,28 @@ function unassignedLineHint(args) {
|
|
|
10692
11097
|
};
|
|
10693
11098
|
}
|
|
10694
11099
|
|
|
11100
|
+
function taskCountState(args) {
|
|
11101
|
+
const {entry: entry, identity: identity} = args, freshness = entry.invalid === void 0 ? evaluationFreshness({
|
|
11102
|
+
committed: entry.committed,
|
|
11103
|
+
evaluation: entry.evaluation
|
|
11104
|
+
}) : void 0;
|
|
11105
|
+
return identity.kind === "unavailable" ? {
|
|
11106
|
+
kind: "unknowable"
|
|
11107
|
+
} : identity.kind === "pending" || freshness === "pending" ? {
|
|
11108
|
+
kind: "pending"
|
|
11109
|
+
} : freshness === "stale" ? {
|
|
11110
|
+
kind: "stale"
|
|
11111
|
+
} : {
|
|
11112
|
+
kind: "ready",
|
|
11113
|
+
tasks: assignedTaskCount({
|
|
11114
|
+
instance: entry.instance,
|
|
11115
|
+
committed: entry.committed,
|
|
11116
|
+
evaluation: entry.evaluation,
|
|
11117
|
+
who: identity.identity
|
|
11118
|
+
})
|
|
11119
|
+
};
|
|
11120
|
+
}
|
|
11121
|
+
|
|
10695
11122
|
function WorkflowFormStrip(props) {
|
|
10696
11123
|
const {mappings: mappings} = props, {isDocResolved: isDocResolved, discoveryInvalid: discoveryInvalid} = useWorkflowContext(), {docId: docId, entries: entries} = useWorkflowsForDocument(props.value?._id ?? null), {params: params, setParams: setParams} = structure.usePaneRouter(), telemetry2 = workflowReact.useWorkflowTelemetry(), openWorkflowsView = focusId => {
|
|
10697
11124
|
telemetry2.log(WorkflowFormStripClicked), setParams(focusedViewParams(params, focusId));
|
|
@@ -10779,7 +11206,7 @@ function InstanceLine({entry: entry, onOpen: onOpen}) {
|
|
|
10779
11206
|
aside: unprimed ? void 0 : /* @__PURE__ */ jsxRuntime.jsx(TaskCountSpinner, {
|
|
10780
11207
|
entry: entry
|
|
10781
11208
|
}),
|
|
10782
|
-
hint: lineHint(entry, identity),
|
|
11209
|
+
hint: lineHint(entry, identityOf(identity)),
|
|
10783
11210
|
onOpen: onOpen,
|
|
10784
11211
|
children: [
|
|
10785
11212
|
/* @__PURE__ */ jsxRuntime.jsx(ui.Flex, {
|
|
@@ -10838,28 +11265,16 @@ function finishedHint(instance) {
|
|
|
10838
11265
|
}
|
|
10839
11266
|
|
|
10840
11267
|
function useTaskCountState(entry) {
|
|
10841
|
-
const identity = useAssignmentIdentity()
|
|
10842
|
-
|
|
10843
|
-
|
|
10844
|
-
|
|
10845
|
-
|
|
10846
|
-
kind: "pending"
|
|
10847
|
-
} : freshness === "stale" ? {
|
|
10848
|
-
kind: "stale"
|
|
10849
|
-
} : {
|
|
10850
|
-
kind: "ready",
|
|
10851
|
-
tasks: assignedTaskCount({
|
|
10852
|
-
instance: entry.instance,
|
|
10853
|
-
committed: entry.committed,
|
|
10854
|
-
evaluation: entry.evaluation,
|
|
10855
|
-
who: identity
|
|
10856
|
-
})
|
|
10857
|
-
};
|
|
11268
|
+
const identity = useAssignmentIdentity();
|
|
11269
|
+
return taskCountState({
|
|
11270
|
+
entry: entry,
|
|
11271
|
+
identity: identity
|
|
11272
|
+
});
|
|
10858
11273
|
}
|
|
10859
11274
|
|
|
10860
11275
|
function TaskCountText({entry: entry}) {
|
|
10861
11276
|
const state = useTaskCountState(entry);
|
|
10862
|
-
return state.kind === "pending" || state.kind === "ready" && state.tasks === 0 ? null : /* @__PURE__ */ jsxRuntime.jsx(ui.Text, {
|
|
11277
|
+
return state.kind === "pending" || state.kind === "unknowable" || state.kind === "ready" && state.tasks === 0 ? null : /* @__PURE__ */ jsxRuntime.jsx(ui.Text, {
|
|
10863
11278
|
muted: !0,
|
|
10864
11279
|
size: 1,
|
|
10865
11280
|
children: state.kind === "stale" ? "Updating…" : pluralize__default.default("assigned task", state.tasks, !0)
|
|
@@ -11100,13 +11515,13 @@ exports.ActivityLog = ActivityLog;
|
|
|
11100
11515
|
|
|
11101
11516
|
exports.ActivityRow = ActivityRow;
|
|
11102
11517
|
|
|
11103
|
-
exports.
|
|
11518
|
+
exports.AlertGlyph = AlertGlyph;
|
|
11104
11519
|
|
|
11105
|
-
exports.
|
|
11520
|
+
exports.BreadcrumbTail = BreadcrumbTail;
|
|
11106
11521
|
|
|
11107
11522
|
exports.CodeChip = CodeChip;
|
|
11108
11523
|
|
|
11109
|
-
exports.
|
|
11524
|
+
exports.CountedHeading = CountedHeading;
|
|
11110
11525
|
|
|
11111
11526
|
exports.DismissablePopover = DismissablePopover;
|
|
11112
11527
|
|
|
@@ -11122,6 +11537,10 @@ exports.Hairline = Hairline;
|
|
|
11122
11537
|
|
|
11123
11538
|
exports.HoverHint = HoverHint;
|
|
11124
11539
|
|
|
11540
|
+
exports.InlineEmphasis = InlineEmphasis;
|
|
11541
|
+
|
|
11542
|
+
exports.InstanceFaultNote = InstanceFaultNote;
|
|
11543
|
+
|
|
11125
11544
|
exports.InstanceSnapshotBody = InstanceSnapshotBody;
|
|
11126
11545
|
|
|
11127
11546
|
exports.InvalidDocNotice = InvalidDocNotice;
|
|
@@ -11134,6 +11553,12 @@ exports.LogEventOnMount = LogEventOnMount;
|
|
|
11134
11553
|
|
|
11135
11554
|
exports.MetaRow = MetaRow;
|
|
11136
11555
|
|
|
11556
|
+
exports.MetricPair = MetricPair;
|
|
11557
|
+
|
|
11558
|
+
exports.NoteBanner = NoteBanner;
|
|
11559
|
+
|
|
11560
|
+
exports.RoleAssignedNotice = RoleAssignedNotice;
|
|
11561
|
+
|
|
11137
11562
|
exports.SpinnerSlot = SpinnerSlot;
|
|
11138
11563
|
|
|
11139
11564
|
exports.StageFace = StageFace;
|
|
@@ -11186,16 +11611,18 @@ exports.dueDatesOf = dueDatesOf;
|
|
|
11186
11611
|
|
|
11187
11612
|
exports.findActivity = findActivity;
|
|
11188
11613
|
|
|
11189
|
-
exports.findActivityNode = findActivityNode;
|
|
11190
|
-
|
|
11191
11614
|
exports.formatDate = formatDate;
|
|
11192
11615
|
|
|
11616
|
+
exports.formatShortAgo = formatShortAgo;
|
|
11617
|
+
|
|
11193
11618
|
exports.formatShortDateTime = formatShortDateTime;
|
|
11194
11619
|
|
|
11195
11620
|
exports.formatTimeAgo = formatTimeAgo;
|
|
11196
11621
|
|
|
11197
11622
|
exports.gdrLocality = gdrLocality;
|
|
11198
11623
|
|
|
11624
|
+
exports.identityOf = identityOf;
|
|
11625
|
+
|
|
11199
11626
|
exports.instanceBreadcrumb = instanceBreadcrumb;
|
|
11200
11627
|
|
|
11201
11628
|
exports.instanceState = instanceState;
|
|
@@ -11204,12 +11631,16 @@ exports.instanceTitle = instanceTitle;
|
|
|
11204
11631
|
|
|
11205
11632
|
exports.isActivityAssignedTo = isActivityAssignedTo;
|
|
11206
11633
|
|
|
11634
|
+
exports.isDueDatePast = isDueDatePast;
|
|
11635
|
+
|
|
11207
11636
|
exports.isEvaluationStale = isEvaluationStale;
|
|
11208
11637
|
|
|
11209
11638
|
exports.isLiveEntry = isLiveEntry;
|
|
11210
11639
|
|
|
11211
11640
|
exports.isOpenActivityStatus = isOpenActivityStatus;
|
|
11212
11641
|
|
|
11642
|
+
exports.isRoleAssignedTo = isRoleAssignedTo;
|
|
11643
|
+
|
|
11213
11644
|
exports.landingState = landingState;
|
|
11214
11645
|
|
|
11215
11646
|
exports.mappingIssueDetail = mappingIssueDetail;
|
|
@@ -11240,16 +11671,14 @@ exports.toolTabState = toolTabState;
|
|
|
11240
11671
|
|
|
11241
11672
|
exports.useAssignmentIdentity = useAssignmentIdentity;
|
|
11242
11673
|
|
|
11243
|
-
exports.useBadgeCapTrim = useBadgeCapTrim;
|
|
11244
|
-
|
|
11245
11674
|
exports.useContainerToken = useContainerToken;
|
|
11246
11675
|
|
|
11247
11676
|
exports.useDefinition = useDefinition;
|
|
11248
11677
|
|
|
11249
|
-
exports.useDelayedFlag = useDelayedFlag;
|
|
11250
|
-
|
|
11251
11678
|
exports.useLogEventOnMount = useLogEventOnMount;
|
|
11252
11679
|
|
|
11680
|
+
exports.useMinuteClock = useMinuteClock;
|
|
11681
|
+
|
|
11253
11682
|
exports.useProjectMembers = useProjectMembers;
|
|
11254
11683
|
|
|
11255
11684
|
exports.useSpaceToken = useSpaceToken;
|