@sanity/workflow-studio-plugin 0.28.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 +295 -0
- package/dist/_chunks-cjs/index.cjs +563 -193
- package/dist/_chunks-cjs/workflows-tool-root.cjs +698 -257
- package/dist/_chunks-es/index.js +549 -189
- package/dist/_chunks-es/workflows-tool-root.js +712 -261
- 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, isRevisionConflict, 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";
|
|
@@ -78,8 +80,6 @@ import { CogIcon } from "@sanity/icons/Cog";
|
|
|
78
80
|
|
|
79
81
|
import { ArrowUpIcon } from "@sanity/icons/ArrowUp";
|
|
80
82
|
|
|
81
|
-
import { ErrorOutlineIcon } from "@sanity/icons/ErrorOutline";
|
|
82
|
-
|
|
83
83
|
import { of } from "rxjs";
|
|
84
84
|
|
|
85
85
|
import { switchMap, distinctUntilChanged } from "rxjs/operators";
|
|
@@ -409,16 +409,25 @@ function parseLocalDate(value) {
|
|
|
409
409
|
return parsed2.getFullYear() === year && parsed2.getMonth() === (month ?? NaN) - 1 && parsed2.getDate() === day ? parsed2 : /* @__PURE__ */ new Date(NaN);
|
|
410
410
|
}
|
|
411
411
|
|
|
412
|
+
function storedDateKind(value) {
|
|
413
|
+
return /^\d{4}-\d{2}-\d{2}$/.test(value) ? "date" : "datetime";
|
|
414
|
+
}
|
|
415
|
+
|
|
412
416
|
function parseStoredDateValue(value) {
|
|
413
|
-
if (typeof value
|
|
414
|
-
const kind = /^\d{4}-\d{2}-\d{2}$/.test(value) ? "date" : "datetime";
|
|
415
|
-
return parseDateFieldValue(value, kind);
|
|
417
|
+
if (typeof value == "string") return parseDateFieldValue(value, storedDateKind(value));
|
|
416
418
|
}
|
|
417
419
|
|
|
418
420
|
function serializeDateFieldValue(date, kind) {
|
|
419
421
|
return hasTimeOfDay(kind) ? date.toISOString() : `${date.getFullYear()}-${pad2(date.getMonth() + 1)}-${pad2(date.getDate())}`;
|
|
420
422
|
}
|
|
421
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
|
+
|
|
422
431
|
class EffectsIncompleteError extends Error {
|
|
423
432
|
reason;
|
|
424
433
|
constructor(reason, options) {
|
|
@@ -599,7 +608,7 @@ function isLiveEntry(entry) {
|
|
|
599
608
|
const isTodoDone = item => item.status === "done", toggledTodoStatus = item => isTodoDone(item) ? "open" : "done";
|
|
600
609
|
|
|
601
610
|
function isTodoOverdue(item, today = /* @__PURE__ */ new Date) {
|
|
602
|
-
return !item.dueDate || isTodoDone(item) ? !1 : item.dueDate
|
|
611
|
+
return !item.dueDate || isTodoDone(item) ? !1 : isDueDatePast(item.dueDate, today);
|
|
603
612
|
}
|
|
604
613
|
|
|
605
614
|
function todoEditKind(patch) {
|
|
@@ -920,7 +929,7 @@ function concludesHere(actionEval, activityName) {
|
|
|
920
929
|
return changesOwnStatus(actionEval.action, activityName) || actionEval.firing?.exitsStage === !0;
|
|
921
930
|
}
|
|
922
931
|
|
|
923
|
-
const
|
|
932
|
+
const DECISION_SEMANTIC_FACE = {
|
|
924
933
|
"decision.accept": {
|
|
925
934
|
tone: "positive",
|
|
926
935
|
icon: CheckmarkIcon
|
|
@@ -931,6 +940,15 @@ const SEMANTIC_FACE = {
|
|
|
931
940
|
}
|
|
932
941
|
};
|
|
933
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
|
+
|
|
934
952
|
function actionButtonFace(args) {
|
|
935
953
|
const mode = concludesHere(args.actionEval, args.activityName) ? "default" : "ghost";
|
|
936
954
|
if (actionAdvanceStatus(args.actionEval.action, args.activityName) === "failed") return {
|
|
@@ -938,7 +956,7 @@ function actionButtonFace(args) {
|
|
|
938
956
|
tone: "critical",
|
|
939
957
|
icon: void 0
|
|
940
958
|
};
|
|
941
|
-
const
|
|
959
|
+
const face = decisionSemanticFace(args.actionEval.semantics ?? []);
|
|
942
960
|
return {
|
|
943
961
|
mode: mode,
|
|
944
962
|
tone: face?.tone ?? "default",
|
|
@@ -1405,21 +1423,32 @@ function bridgedSelfId(users, meId) {
|
|
|
1405
1423
|
return users.find(user => user.membership.id === meId)?.profile?.sanityUserId ?? classified.globalId ?? (classified.namespace === "project" ? void 0 : meId);
|
|
1406
1424
|
}
|
|
1407
1425
|
|
|
1408
|
-
function
|
|
1426
|
+
function useSelfState() {
|
|
1409
1427
|
const me = useCurrentUser(), {users: users, loading: loading, error: error} = useStudioProjectUsers();
|
|
1410
|
-
if (!me) return
|
|
1411
|
-
|
|
1412
|
-
if (id !== void 0) return {
|
|
1413
|
-
id: id,
|
|
1414
|
-
roles: me.roles ?? []
|
|
1428
|
+
if (!me) return {
|
|
1429
|
+
kind: "unavailable"
|
|
1415
1430
|
};
|
|
1416
|
-
|
|
1417
|
-
|
|
1418
|
-
|
|
1419
|
-
|
|
1431
|
+
const id = bridgedSelfId(users, me.id);
|
|
1432
|
+
return id !== void 0 ? {
|
|
1433
|
+
kind: "resolved",
|
|
1434
|
+
self: {
|
|
1435
|
+
id: id,
|
|
1436
|
+
roles: me.roles ?? []
|
|
1420
1437
|
}
|
|
1421
|
-
|
|
1422
|
-
|
|
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;
|
|
1423
1452
|
}
|
|
1424
1453
|
|
|
1425
1454
|
function useSelfActor() {
|
|
@@ -1428,13 +1457,22 @@ function useSelfActor() {
|
|
|
1428
1457
|
}
|
|
1429
1458
|
|
|
1430
1459
|
function useAssignmentIdentity() {
|
|
1431
|
-
const
|
|
1432
|
-
if (
|
|
1433
|
-
|
|
1434
|
-
|
|
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
|
+
}
|
|
1435
1469
|
};
|
|
1436
1470
|
}
|
|
1437
1471
|
|
|
1472
|
+
function identityOf(state) {
|
|
1473
|
+
return state.kind === "resolved" ? state.identity : void 0;
|
|
1474
|
+
}
|
|
1475
|
+
|
|
1438
1476
|
const projectMembersByUsers = /* @__PURE__ */ new WeakMap;
|
|
1439
1477
|
|
|
1440
1478
|
function projectMembersFrom(users) {
|
|
@@ -1542,6 +1580,8 @@ function buildParams(decls, values) {
|
|
|
1542
1580
|
};
|
|
1543
1581
|
}
|
|
1544
1582
|
|
|
1583
|
+
const LOADING_CUE_DELAY_MS = 400;
|
|
1584
|
+
|
|
1545
1585
|
function useDelayedFlag(active, delayMs) {
|
|
1546
1586
|
const [held, setHeld] = useState(!1);
|
|
1547
1587
|
return useEffect(() => {
|
|
@@ -2549,11 +2589,10 @@ function Separator() {
|
|
|
2549
2589
|
}
|
|
2550
2590
|
|
|
2551
2591
|
function stageTitle(definition, stageName) {
|
|
2552
|
-
return
|
|
2553
|
-
|
|
2554
|
-
|
|
2555
|
-
|
|
2556
|
-
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;
|
|
2557
2596
|
}
|
|
2558
2597
|
|
|
2559
2598
|
function findActivity(args) {
|
|
@@ -4021,6 +4060,267 @@ function EditableField({field: field, entry: entry, description: description, in
|
|
|
4021
4060
|
});
|
|
4022
4061
|
}
|
|
4023
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
|
+
|
|
4024
4324
|
function MetaRow({children: children, fillHeight: fillHeight, label: label}) {
|
|
4025
4325
|
/* @__PURE__ */
|
|
4026
4326
|
return jsxs(Flex, {
|
|
@@ -4149,7 +4449,7 @@ function useBadgeCapTrim() {
|
|
|
4149
4449
|
}
|
|
4150
4450
|
|
|
4151
4451
|
function SpinnerSlot({busy: busy}) {
|
|
4152
|
-
const size = useTextIconSize(), trim = useCapTrimFor(size);
|
|
4452
|
+
const size = useTextIconSize(), trim = useCapTrimFor(size), spinning = useDelayedFlag(busy, LOADING_CUE_DELAY_MS);
|
|
4153
4453
|
/* @__PURE__ */
|
|
4154
4454
|
return jsx(Flex, {
|
|
4155
4455
|
align: "center",
|
|
@@ -4161,7 +4461,7 @@ function SpinnerSlot({busy: busy}) {
|
|
|
4161
4461
|
marginTop: trim,
|
|
4162
4462
|
width: size
|
|
4163
4463
|
},
|
|
4164
|
-
children:
|
|
4464
|
+
children: spinning ? /* @__PURE__ */ jsx(Spinner, {
|
|
4165
4465
|
muted: !0,
|
|
4166
4466
|
size: 1
|
|
4167
4467
|
}) : null
|
|
@@ -4169,6 +4469,7 @@ function SpinnerSlot({busy: busy}) {
|
|
|
4169
4469
|
}
|
|
4170
4470
|
|
|
4171
4471
|
function LoadingRow({label: label, padding: padding}) {
|
|
4472
|
+
const announced = useDelayedFlag(!0, LOADING_CUE_DELAY_MS);
|
|
4172
4473
|
/* @__PURE__ */
|
|
4173
4474
|
return jsxs(Flex, {
|
|
4174
4475
|
align: "center",
|
|
@@ -4179,12 +4480,11 @@ function LoadingRow({label: label, padding: padding}) {
|
|
|
4179
4480
|
children: [
|
|
4180
4481
|
/* @__PURE__ */ jsx(SpinnerSlot, {
|
|
4181
4482
|
busy: !0
|
|
4182
|
-
}),
|
|
4183
|
-
/* @__PURE__ */ jsx(Text, {
|
|
4483
|
+
}), announced ? /* @__PURE__ */ jsx(Text, {
|
|
4184
4484
|
muted: !0,
|
|
4185
4485
|
size: 1,
|
|
4186
4486
|
children: label
|
|
4187
|
-
}) ]
|
|
4487
|
+
}) : null ]
|
|
4188
4488
|
});
|
|
4189
4489
|
}
|
|
4190
4490
|
|
|
@@ -4451,49 +4751,40 @@ function ForMeEmptyState() {
|
|
|
4451
4751
|
});
|
|
4452
4752
|
}
|
|
4453
4753
|
|
|
4454
|
-
|
|
4455
|
-
return typeof value == "object" && value !== null && Array.isArray(value.stages);
|
|
4456
|
-
}
|
|
4457
|
-
|
|
4458
|
-
const parsed = /* @__PURE__ */ new WeakMap;
|
|
4754
|
+
const OVERDUE_HINT = "Now overdue";
|
|
4459
4755
|
|
|
4460
|
-
function
|
|
4461
|
-
|
|
4462
|
-
|
|
4463
|
-
|
|
4464
|
-
|
|
4465
|
-
|
|
4466
|
-
|
|
4467
|
-
|
|
4468
|
-
|
|
4469
|
-
}
|
|
4470
|
-
return parsed.set(instance, definition), definition;
|
|
4471
|
-
}
|
|
4472
|
-
|
|
4473
|
-
function useDefinition(entry) {
|
|
4474
|
-
return useMemo(() => {
|
|
4475
|
-
if (entry) return entry.evaluation ? entry.evaluation.definition : definitionSnapshotOf(entry.instance);
|
|
4476
|
-
}, [ entry ]);
|
|
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
|
+
};
|
|
4477
4765
|
}
|
|
4478
4766
|
|
|
4479
|
-
function
|
|
4480
|
-
|
|
4481
|
-
|
|
4482
|
-
|
|
4483
|
-
|
|
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)
|
|
4484
4780
|
});
|
|
4485
|
-
|
|
4486
|
-
|
|
4487
|
-
|
|
4488
|
-
|
|
4489
|
-
|
|
4490
|
-
|
|
4491
|
-
|
|
4492
|
-
textWeight: "medium",
|
|
4493
|
-
children: /* @__PURE__ */ jsx(Badge, {
|
|
4494
|
-
fontSize: 1,
|
|
4495
|
-
tone: "caution",
|
|
4496
|
-
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
|
|
4497
4788
|
})
|
|
4498
4789
|
});
|
|
4499
4790
|
}
|
|
@@ -4533,18 +4824,6 @@ function CheckboxSlot({children: children}) {
|
|
|
4533
4824
|
});
|
|
4534
4825
|
}
|
|
4535
4826
|
|
|
4536
|
-
function DueDateText({dueDate: dueDate, overdue: overdue}) {
|
|
4537
|
-
return overdue ? /* @__PURE__ */ jsx(TextWithTone, {
|
|
4538
|
-
size: 1,
|
|
4539
|
-
tone: "caution",
|
|
4540
|
-
children: formatDate(dueDate)
|
|
4541
|
-
}) : /* @__PURE__ */ jsx(Text, {
|
|
4542
|
-
muted: !0,
|
|
4543
|
-
size: 1,
|
|
4544
|
-
children: formatDate(dueDate)
|
|
4545
|
-
});
|
|
4546
|
-
}
|
|
4547
|
-
|
|
4548
4827
|
function DueDateEditor({dueDate: dueDate, onDone: onDone, onPatch: onPatch}) {
|
|
4549
4828
|
/* @__PURE__ */
|
|
4550
4829
|
return jsx(ClearableDatePicker, {
|
|
@@ -4564,8 +4843,9 @@ function DueDateEditor({dueDate: dueDate, onDone: onDone, onPatch: onPatch}) {
|
|
|
4564
4843
|
}
|
|
4565
4844
|
|
|
4566
4845
|
function DueDateControl({item: item, editable: editable, onPatch: onPatch}) {
|
|
4567
|
-
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, {
|
|
4568
4847
|
dueDate: item.dueDate,
|
|
4848
|
+
hintDisabled: open,
|
|
4569
4849
|
overdue: overdue
|
|
4570
4850
|
}) : null;
|
|
4571
4851
|
return editable ? /* @__PURE__ */ jsx(DismissablePopover, {
|
|
@@ -4576,18 +4856,14 @@ function DueDateControl({item: item, editable: editable, onPatch: onPatch}) {
|
|
|
4576
4856
|
}),
|
|
4577
4857
|
onDismiss: () => setOpen(!1),
|
|
4578
4858
|
open: open,
|
|
4579
|
-
children: display ? /* @__PURE__ */ jsx(
|
|
4580
|
-
|
|
4581
|
-
|
|
4582
|
-
|
|
4583
|
-
|
|
4584
|
-
|
|
4585
|
-
|
|
4586
|
-
|
|
4587
|
-
padding: 2,
|
|
4588
|
-
tone: overdue ? "caution" : "default",
|
|
4589
|
-
children: display
|
|
4590
|
-
})
|
|
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
|
|
4591
4867
|
}) : /* @__PURE__ */ jsx(HoverHint, {
|
|
4592
4868
|
disabled: open,
|
|
4593
4869
|
text: "Set due date",
|
|
@@ -4601,9 +4877,6 @@ function DueDateControl({item: item, editable: editable, onPatch: onPatch}) {
|
|
|
4601
4877
|
radius: 2
|
|
4602
4878
|
})
|
|
4603
4879
|
})
|
|
4604
|
-
}) : display && overdue ? /* @__PURE__ */ jsx(HoverHint, {
|
|
4605
|
-
text: "Now overdue",
|
|
4606
|
-
children: display
|
|
4607
4880
|
}) : display;
|
|
4608
4881
|
}
|
|
4609
4882
|
|
|
@@ -5256,9 +5529,15 @@ function ActivityDetailDialog({entry: entry, activityName: activityName, breadcr
|
|
|
5256
5529
|
const detail = deriveActivityDetail({
|
|
5257
5530
|
entry: entry,
|
|
5258
5531
|
activityName: activityName
|
|
5259
|
-
});
|
|
5532
|
+
}), faultingActivity2 = useInstanceFault(entry)?.activity;
|
|
5260
5533
|
if (!detail) return null;
|
|
5261
|
-
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;
|
|
5262
5541
|
/* @__PURE__ */
|
|
5263
5542
|
return jsxs(Dialog, {
|
|
5264
5543
|
footer: detail.presentation.terminalActions.length > 0 ? /* @__PURE__ */ jsx(TerminalFooter, {
|
|
@@ -5299,7 +5578,7 @@ function ActivityDetailDialog({entry: entry, activityName: activityName, breadcr
|
|
|
5299
5578
|
padding: 4,
|
|
5300
5579
|
children: /* @__PURE__ */ jsxs(Stack, {
|
|
5301
5580
|
gap: 5,
|
|
5302
|
-
children: [ detail.state.map(field => /* @__PURE__ */ jsx(FieldRow, {
|
|
5581
|
+
children: [ fault, detail.state.map(field => /* @__PURE__ */ jsx(FieldRow, {
|
|
5303
5582
|
activityName: activityName,
|
|
5304
5583
|
detail: detail,
|
|
5305
5584
|
entry: entry,
|
|
@@ -5480,6 +5759,18 @@ function CountedLabel({count: count, label: label}) {
|
|
|
5480
5759
|
});
|
|
5481
5760
|
}
|
|
5482
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
|
+
|
|
5483
5774
|
function GroupHeading({busy: busy, count: count, title: title, end: end}) {
|
|
5484
5775
|
/* @__PURE__ */
|
|
5485
5776
|
return jsxs(Flex, {
|
|
@@ -5488,13 +5779,9 @@ function GroupHeading({busy: busy, count: count, title: title, end: end}) {
|
|
|
5488
5779
|
paddingLeft: 2,
|
|
5489
5780
|
paddingY: end === void 0 ? 3 : 1,
|
|
5490
5781
|
children: [
|
|
5491
|
-
/* @__PURE__ */ jsx(
|
|
5782
|
+
/* @__PURE__ */ jsx(CountedHeading, {
|
|
5492
5783
|
count: count,
|
|
5493
|
-
|
|
5494
|
-
size: 1,
|
|
5495
|
-
weight: "semibold",
|
|
5496
|
-
children: title
|
|
5497
|
-
})
|
|
5784
|
+
title: title
|
|
5498
5785
|
}), busy === void 0 ? null : /* @__PURE__ */ jsx(SpinnerSlot, {
|
|
5499
5786
|
busy: busy
|
|
5500
5787
|
}), end === void 0 ? null : /* @__PURE__ */ jsxs(Fragment, {
|
|
@@ -5506,21 +5793,81 @@ function GroupHeading({busy: busy, count: count, title: title, end: end}) {
|
|
|
5506
5793
|
});
|
|
5507
5794
|
}
|
|
5508
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
|
+
|
|
5509
5853
|
function ActivityDateControl({instanceId: instanceId, state: state, surface: surface, dueDates: dueDates}) {
|
|
5510
5854
|
const editField = useEditField(surface), {save: save} = useSaveField({
|
|
5511
5855
|
instanceId: instanceId
|
|
5512
5856
|
}), [open, setOpen] = useState(!1), raw = dateControlValue({
|
|
5513
5857
|
state: state,
|
|
5514
5858
|
dueDates: dueDates
|
|
5515
|
-
}),
|
|
5516
|
-
|
|
5517
|
-
|
|
5518
|
-
|
|
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
|
+
}
|
|
5519
5866
|
});
|
|
5520
|
-
if (state.kind === "none") return
|
|
5521
|
-
if (state.kind === "closed")
|
|
5522
|
-
|
|
5523
|
-
|
|
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, {
|
|
5524
5871
|
"aria-label": "Date",
|
|
5525
5872
|
as: "span",
|
|
5526
5873
|
fontSize: 1,
|
|
@@ -5529,8 +5876,8 @@ function ActivityDateControl({instanceId: instanceId, state: state, surface: sur
|
|
|
5529
5876
|
onMouseDown: stopRowMouseDown,
|
|
5530
5877
|
padding: 2,
|
|
5531
5878
|
children: display
|
|
5532
|
-
})
|
|
5533
|
-
}
|
|
5879
|
+
});
|
|
5880
|
+
}
|
|
5534
5881
|
const kind = dateControlKind(state), commit = (mode, value) => {
|
|
5535
5882
|
state.kind === "editable" && save(() => editField({
|
|
5536
5883
|
instanceId: instanceId,
|
|
@@ -5566,7 +5913,7 @@ function ActivityDateControl({instanceId: instanceId, state: state, surface: sur
|
|
|
5566
5913
|
}),
|
|
5567
5914
|
onDismiss: () => setOpen(!1),
|
|
5568
5915
|
open: open,
|
|
5569
|
-
children:
|
|
5916
|
+
children: raw !== void 0 ? /* @__PURE__ */ jsx(Button, {
|
|
5570
5917
|
"aria-label": "Change date",
|
|
5571
5918
|
as: "span",
|
|
5572
5919
|
fontSize: 1,
|
|
@@ -5574,7 +5921,7 @@ function ActivityDateControl({instanceId: instanceId, state: state, surface: sur
|
|
|
5574
5921
|
onClick: handleClick,
|
|
5575
5922
|
onMouseDown: stopRowMouseDown,
|
|
5576
5923
|
padding: 2,
|
|
5577
|
-
children:
|
|
5924
|
+
children: dueDate()
|
|
5578
5925
|
}) : /* @__PURE__ */ jsx(HoverHint, {
|
|
5579
5926
|
disabled: open,
|
|
5580
5927
|
text: "Set date",
|
|
@@ -5664,7 +6011,7 @@ function TitleTag({hint: hint, tone: tone, children: children}) {
|
|
|
5664
6011
|
});
|
|
5665
6012
|
}
|
|
5666
6013
|
|
|
5667
|
-
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 = []}) {
|
|
5668
6015
|
const settled = isTerminalActivityStatus(face.status), dimmed = settledDim(settled);
|
|
5669
6016
|
/* @__PURE__ */
|
|
5670
6017
|
return jsxs(WorkRow, {
|
|
@@ -5697,6 +6044,10 @@ function ActivityRow({face: face, breadcrumb: breadcrumb, assignees: assignees,
|
|
|
5697
6044
|
/* @__PURE__ */ jsx(ActivityRowTitle, {
|
|
5698
6045
|
dimmed: dimmed,
|
|
5699
6046
|
children: face.title
|
|
6047
|
+
}), faultHint === void 0 || face.status === "failed" ? null : /* @__PURE__ */ jsx(AlertGlyph, {
|
|
6048
|
+
Icon: ErrorOutlineIcon,
|
|
6049
|
+
hint: faultHint,
|
|
6050
|
+
tone: "critical"
|
|
5700
6051
|
}), face.automated ? /* @__PURE__ */ jsx(TitleTag, {
|
|
5701
6052
|
hint: "Completes on its own — no user action is needed",
|
|
5702
6053
|
children: "Automated"
|
|
@@ -5712,7 +6063,7 @@ function ActivityRow({face: face, breadcrumb: breadcrumb, assignees: assignees,
|
|
|
5712
6063
|
}
|
|
5713
6064
|
|
|
5714
6065
|
function ActivitiesList({entry: entry, onOpenActivity: onOpenActivity, surface: surface}) {
|
|
5715
|
-
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);
|
|
5716
6067
|
return activities.length === 0 ?
|
|
5717
6068
|
/* @__PURE__ */ jsx(Box, {
|
|
5718
6069
|
paddingX: 1,
|
|
@@ -5730,6 +6081,9 @@ function ActivitiesList({entry: entry, onOpenActivity: onOpenActivity, surface:
|
|
|
5730
6081
|
activityState: activityState,
|
|
5731
6082
|
editableFields: entry.evaluation?.editableFields
|
|
5732
6083
|
}),
|
|
6084
|
+
...fault?.activity === t.activity.name ? {
|
|
6085
|
+
faultHint: fault.summary
|
|
6086
|
+
} : {},
|
|
5733
6087
|
instanceId: entry.instance._id,
|
|
5734
6088
|
onOpen: () => onOpenActivity(t.activity.name),
|
|
5735
6089
|
surface: surface
|
|
@@ -5876,7 +6230,10 @@ function progressFillPercent(face) {
|
|
|
5876
6230
|
}
|
|
5877
6231
|
|
|
5878
6232
|
function deriveFieldPills(args) {
|
|
5879
|
-
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({
|
|
5880
6237
|
committed: committed,
|
|
5881
6238
|
evaluation: evaluation
|
|
5882
6239
|
}) ? editablesByName(evaluation, scope) : /* @__PURE__ */ new Map, declaredNames = new Set(declared.map(d => d.name));
|
|
@@ -7066,6 +7423,27 @@ function HintedMenuButton({hint: hint, ...menuButtonProps}) {
|
|
|
7066
7423
|
});
|
|
7067
7424
|
}
|
|
7068
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
|
+
|
|
7069
7447
|
function historyWindow(args) {
|
|
7070
7448
|
const {entries: entries, expanded: expanded} = args;
|
|
7071
7449
|
return {
|
|
@@ -7075,28 +7453,10 @@ function historyWindow(args) {
|
|
|
7075
7453
|
}
|
|
7076
7454
|
|
|
7077
7455
|
function PendingEffectRows({instance: instance, now: now}) {
|
|
7078
|
-
const {
|
|
7456
|
+
const {completeEffectFor: completeEffectFor, effectHandlers: effectHandlers} = useWorkflowContext(), toast = useWorkflowToast(), drain = useDrainEffects(instance._id), [resolving, setResolving] = useState(!1), pending = instance.pendingEffects ?? [];
|
|
7079
7457
|
if (pending.length === 0) return null;
|
|
7080
|
-
const
|
|
7081
|
-
|
|
7082
|
-
try {
|
|
7083
|
-
await drainEffectsFor(instance._id), toast.push({
|
|
7084
|
-
id: TOAST_ID.effectsDrain,
|
|
7085
|
-
status: "info",
|
|
7086
|
-
title: "Ran the registered handlers"
|
|
7087
|
-
});
|
|
7088
|
-
} catch (err) {
|
|
7089
|
-
toast.push({
|
|
7090
|
-
id: TOAST_ID.effectsDrain,
|
|
7091
|
-
status: "error",
|
|
7092
|
-
title: "Failed to run pending effects",
|
|
7093
|
-
description: describeError(err)
|
|
7094
|
-
});
|
|
7095
|
-
} finally {
|
|
7096
|
-
setBusy(!1);
|
|
7097
|
-
}
|
|
7098
|
-
}, resolve = async (effectKey, status) => {
|
|
7099
|
-
setBusy(!0);
|
|
7458
|
+
const resolve = async (effectKey, status) => {
|
|
7459
|
+
setResolving(!0);
|
|
7100
7460
|
try {
|
|
7101
7461
|
await completeEffectFor(instance._id, {
|
|
7102
7462
|
effectKey: effectKey,
|
|
@@ -7115,18 +7475,20 @@ function PendingEffectRows({instance: instance, now: now}) {
|
|
|
7115
7475
|
description: describeError(err)
|
|
7116
7476
|
});
|
|
7117
7477
|
} finally {
|
|
7118
|
-
|
|
7478
|
+
setResolving(!1);
|
|
7119
7479
|
}
|
|
7120
7480
|
};
|
|
7121
7481
|
/* @__PURE__ */
|
|
7122
7482
|
return jsx(Fragment, {
|
|
7123
7483
|
children: pending.map(fx => /* @__PURE__ */ jsx(PendingEffectRow, {
|
|
7124
|
-
busy: busy,
|
|
7484
|
+
busy: drain.busy || resolving,
|
|
7125
7485
|
effect: fx,
|
|
7126
7486
|
instanceId: instance._id,
|
|
7127
7487
|
now: now,
|
|
7128
7488
|
onResolve: status => resolve(fx._key, status),
|
|
7129
|
-
onRunHandlers:
|
|
7489
|
+
onRunHandlers: () => {
|
|
7490
|
+
drain.run();
|
|
7491
|
+
},
|
|
7130
7492
|
registered: fx.name in effectHandlers
|
|
7131
7493
|
}, fx._key))
|
|
7132
7494
|
});
|
|
@@ -7210,12 +7572,7 @@ function PendingEffectRow({busy: busy, effect: effect, instanceId: instanceId, n
|
|
|
7210
7572
|
}
|
|
7211
7573
|
|
|
7212
7574
|
function ActivityLog({instance: instance, definition: definition, windowed: windowed = !0}) {
|
|
7213
|
-
const titles = useMemo(() => makeTitleResolver(definition), [ definition ]), entries = useMemo(() => instance.history.toReversed(), [ instance.history ]),
|
|
7214
|
-
useEffect(() => {
|
|
7215
|
-
const timer = setInterval(() => setNow(/* @__PURE__ */ new Date), 6e4);
|
|
7216
|
-
return () => clearInterval(timer);
|
|
7217
|
-
}, []);
|
|
7218
|
-
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({
|
|
7219
7576
|
entries: entries,
|
|
7220
7577
|
expanded: expanded || !windowed
|
|
7221
7578
|
});
|
|
@@ -7318,12 +7675,9 @@ function HistoryRow({entry: entry, now: now, titles: titles}) {
|
|
|
7318
7675
|
}
|
|
7319
7676
|
|
|
7320
7677
|
function ActorNameSpan({id: id}) {
|
|
7321
|
-
const {name: name} = useUserDisplay(id)
|
|
7678
|
+
const {name: name} = useUserDisplay(id);
|
|
7322
7679
|
/* @__PURE__ */
|
|
7323
|
-
return jsx(
|
|
7324
|
-
style: {
|
|
7325
|
-
fontWeight: font.text.weights.medium
|
|
7326
|
-
},
|
|
7680
|
+
return jsx(InlineEmphasis, {
|
|
7327
7681
|
children: name
|
|
7328
7682
|
});
|
|
7329
7683
|
}
|
|
@@ -7731,7 +8085,6 @@ function StageOverviewCard({overview: overview}) {
|
|
|
7731
8085
|
}
|
|
7732
8086
|
|
|
7733
8087
|
function AdvanceCard({advance: advance}) {
|
|
7734
|
-
const {font: font} = useTheme_v2();
|
|
7735
8088
|
/* @__PURE__ */
|
|
7736
8089
|
return jsx(Card, {
|
|
7737
8090
|
padding: 3,
|
|
@@ -7743,10 +8096,7 @@ function AdvanceCard({advance: advance}) {
|
|
|
7743
8096
|
/* @__PURE__ */ jsxs(Text, {
|
|
7744
8097
|
size: 1,
|
|
7745
8098
|
children: [ "Advances to ",
|
|
7746
|
-
/* @__PURE__ */ jsx(
|
|
7747
|
-
style: {
|
|
7748
|
-
fontWeight: font.text.weights.medium
|
|
7749
|
-
},
|
|
8099
|
+
/* @__PURE__ */ jsx(InlineEmphasis, {
|
|
7750
8100
|
children: advance.toTitle
|
|
7751
8101
|
}), ADVANCE_TAILS[advance.kind] ]
|
|
7752
8102
|
}), advance.kind !== "conditions" ? null : advance.lines.map((line, index) =>
|
|
@@ -8854,7 +9204,7 @@ function DiscoverySpinner() {
|
|
|
8854
9204
|
});
|
|
8855
9205
|
}
|
|
8856
9206
|
|
|
8857
|
-
const
|
|
9207
|
+
const GROUP_GAP = 2;
|
|
8858
9208
|
|
|
8859
9209
|
function useWorkflowsTab() {
|
|
8860
9210
|
const {params: params, setParams: setParams} = usePaneRouter();
|
|
@@ -8879,7 +9229,7 @@ function useOpenActivity(entries) {
|
|
|
8879
9229
|
}
|
|
8880
9230
|
|
|
8881
9231
|
function WorkflowsPanel({entries: entries, documentId: documentId, docTypeMappings: docTypeMappings, initialValue: initialValue}) {
|
|
8882
|
-
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, {
|
|
8883
9233
|
defaultOpen: landingDefaultOpen(landing, e.instance._id),
|
|
8884
9234
|
entry: e,
|
|
8885
9235
|
onOpenActivity: activityName => setOpenActivity({
|
|
@@ -10822,6 +11172,28 @@ function unassignedLineHint(args) {
|
|
|
10822
11172
|
};
|
|
10823
11173
|
}
|
|
10824
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
|
+
|
|
10825
11197
|
function WorkflowFormStrip(props) {
|
|
10826
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 => {
|
|
10827
11199
|
telemetry.log(WorkflowFormStripClicked), setParams(focusedViewParams(params, focusId));
|
|
@@ -10909,7 +11281,7 @@ function InstanceLine({entry: entry, onOpen: onOpen}) {
|
|
|
10909
11281
|
aside: unprimed ? void 0 : /* @__PURE__ */ jsx(TaskCountSpinner, {
|
|
10910
11282
|
entry: entry
|
|
10911
11283
|
}),
|
|
10912
|
-
hint: lineHint(entry, identity),
|
|
11284
|
+
hint: lineHint(entry, identityOf(identity)),
|
|
10913
11285
|
onOpen: onOpen,
|
|
10914
11286
|
children: [
|
|
10915
11287
|
/* @__PURE__ */ jsx(Flex, {
|
|
@@ -10968,28 +11340,16 @@ function finishedHint(instance) {
|
|
|
10968
11340
|
}
|
|
10969
11341
|
|
|
10970
11342
|
function useTaskCountState(entry) {
|
|
10971
|
-
const identity = useAssignmentIdentity()
|
|
10972
|
-
|
|
10973
|
-
|
|
10974
|
-
|
|
10975
|
-
|
|
10976
|
-
kind: "pending"
|
|
10977
|
-
} : freshness === "stale" ? {
|
|
10978
|
-
kind: "stale"
|
|
10979
|
-
} : {
|
|
10980
|
-
kind: "ready",
|
|
10981
|
-
tasks: assignedTaskCount({
|
|
10982
|
-
instance: entry.instance,
|
|
10983
|
-
committed: entry.committed,
|
|
10984
|
-
evaluation: entry.evaluation,
|
|
10985
|
-
who: identity
|
|
10986
|
-
})
|
|
10987
|
-
};
|
|
11343
|
+
const identity = useAssignmentIdentity();
|
|
11344
|
+
return taskCountState({
|
|
11345
|
+
entry: entry,
|
|
11346
|
+
identity: identity
|
|
11347
|
+
});
|
|
10988
11348
|
}
|
|
10989
11349
|
|
|
10990
11350
|
function TaskCountText({entry: entry}) {
|
|
10991
11351
|
const state = useTaskCountState(entry);
|
|
10992
|
-
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, {
|
|
10993
11353
|
muted: !0,
|
|
10994
11354
|
size: 1,
|
|
10995
11355
|
children: state.kind === "stale" ? "Updating…" : pluralize("assigned task", state.tasks, !0)
|
|
@@ -11220,4 +11580,4 @@ function WorkflowRootInput(props) {
|
|
|
11220
11580
|
});
|
|
11221
11581
|
}
|
|
11222
11582
|
|
|
11223
|
-
export { AbortWorkflowDialog, ActivityDetailDialog, ActivityLog, ActivityRow, BreadcrumbTail, CodeChip,
|
|
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 };
|