@sanity/workflow-studio-plugin 0.27.0 → 0.28.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 +132 -0
- package/dist/_chunks-cjs/index.cjs +88 -29
- package/dist/_chunks-cjs/workflows-tool-root.cjs +149 -82
- package/dist/_chunks-es/index.js +85 -28
- package/dist/_chunks-es/workflows-tool-root.js +151 -84
- package/package.json +12 -12
package/dist/_chunks-es/index.js
CHANGED
|
@@ -10,7 +10,7 @@ import { createContext, useContext, useEffect, useSyncExternalStore, useCallback
|
|
|
10
10
|
|
|
11
11
|
import { usePaneRouter } from "sanity/structure";
|
|
12
12
|
|
|
13
|
-
import { WORKFLOW_INSTANCE_TYPE, WORKFLOW_DEFINITION_TYPE, GUARD_DOC_TYPE, tryParseGdr, resourceFromParsed, latestDeployedDefinitions, isStartableDefinition, isSubjectEntry, isInputSourced, acceptsDocumentType, initialFieldIssues, gdrRef, releaseRef, refKindAcceptsTypes, rejectedRefTypes, ActionDisabledError, MutationGuardDeniedError, EditFieldDeniedError, errorMessage, terminalState, findOpenStageEntry, actionRendering, isTodoListEntry, isTodoListItem, isTerminalActivityStatus, describeCondition, sentenceCase, checklistLines, findCurrentActivityEntry, ENGINE_API_VERSION, scalarValidationIssues, classifyPrincipalId, userLoginProvider, toBareId, isSingleDocRefEntry, isGdr, resolveFieldEntry, isSingleDocRefKind, isNotesEntry, parseDefinitionSnapshot, isUnprimed, isTerminalStage, DEFAULT_TRANSITION_WHEN, instancesQuery, assertReadableModel, projectStartSliceRow, StartNotSettledError, StartNotAllowedError, humanize, unboundRequirementReads, explainStartRequirement, singleSubjectRequirementRefused, evaluateStartFilter, startKindOf, hasSingleSubjectRequirement, readsRootDocument, latestDefinitionsGroq, gdrFromResource, subscriptionDocumentsForInstance, aclPathForResource, definitionLookupGroq, instanceDocId, missingRequiredInputs, documentActionDenials } from "@sanity/workflow-engine";
|
|
13
|
+
import { WORKFLOW_INSTANCE_TYPE, WORKFLOW_DEFINITION_TYPE, GUARD_DOC_TYPE, tryParseGdr, resourceFromParsed, latestDeployedDefinitions, isStartableDefinition, isSubjectEntry, isInputSourced, acceptsDocumentType, initialFieldIssues, gdrRef, releaseRef, refKindAcceptsTypes, rejectedRefTypes, ActionDisabledError, MutationGuardDeniedError, EditFieldDeniedError, errorMessage, terminalState, findOpenStageEntry, actionRendering, isTodoListEntry, isTodoListItem, isTerminalActivityStatus, describeCondition, sentenceCase, checklistLines, findCurrentActivityEntry, ENGINE_API_VERSION, scalarValidationIssues, classifyPrincipalId, userLoginProvider, toBareId, 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";
|
|
14
14
|
|
|
15
15
|
import { CheckmarkIcon } from "@sanity/icons/Checkmark";
|
|
16
16
|
|
|
@@ -78,6 +78,8 @@ import { CogIcon } from "@sanity/icons/Cog";
|
|
|
78
78
|
|
|
79
79
|
import { ArrowUpIcon } from "@sanity/icons/ArrowUp";
|
|
80
80
|
|
|
81
|
+
import { ErrorOutlineIcon } from "@sanity/icons/ErrorOutline";
|
|
82
|
+
|
|
81
83
|
import { of } from "rxjs";
|
|
82
84
|
|
|
83
85
|
import { switchMap, distinctUntilChanged } from "rxjs/operators";
|
|
@@ -796,13 +798,25 @@ function isItemAssignedTo(item, who) {
|
|
|
796
798
|
return item.assignee != null && assigneeMatches(item.assignee, who);
|
|
797
799
|
}
|
|
798
800
|
|
|
801
|
+
function matchingAssignees(state, who) {
|
|
802
|
+
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 ] : []);
|
|
803
|
+
}
|
|
804
|
+
|
|
799
805
|
function isActivityAssignedTo(args) {
|
|
800
|
-
return args.state
|
|
806
|
+
return matchingAssignees(args.state, args.who).length > 0;
|
|
807
|
+
}
|
|
808
|
+
|
|
809
|
+
function isRoleAssignedTo(args) {
|
|
810
|
+
return matchingAssignees(args.state, args.who).some(member => member.type === "role");
|
|
811
|
+
}
|
|
812
|
+
|
|
813
|
+
function isItemRoleAssignedTo(item, who) {
|
|
814
|
+
return isItemAssignedTo(item, who) && item.assignee?.type === "role";
|
|
801
815
|
}
|
|
802
816
|
|
|
803
817
|
function assignedWork(args) {
|
|
804
|
-
const {instance: instance, committed: committed, who: who} = args, evaluation = args.staleEvaluation === "keep" || isEvaluationCurrent(args) ? args.evaluation : void 0, byActivity = stateByActivity(instance), activities = (evaluation?.currentStage.activities ?? []).filter(t => isActivityAssignedTo({
|
|
805
|
-
state:
|
|
818
|
+
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({
|
|
819
|
+
state: stateOf(t),
|
|
806
820
|
who: who
|
|
807
821
|
})), items = deriveTodoItems({
|
|
808
822
|
instance: instance,
|
|
@@ -812,7 +826,11 @@ function assignedWork(args) {
|
|
|
812
826
|
return {
|
|
813
827
|
activities: activities,
|
|
814
828
|
openItems: items.filter(row => !isTodoDone(row.item)),
|
|
815
|
-
doneItems: items.filter(row => isTodoDone(row.item))
|
|
829
|
+
doneItems: items.filter(row => isTodoDone(row.item)),
|
|
830
|
+
roleMatched: activities.some(t => isRoleAssignedTo({
|
|
831
|
+
state: stateOf(t),
|
|
832
|
+
who: who
|
|
833
|
+
})) || items.some(row => isItemRoleAssignedTo(row.item, who))
|
|
816
834
|
};
|
|
817
835
|
}
|
|
818
836
|
|
|
@@ -861,7 +879,8 @@ function forMeWorkOf(entries, identity) {
|
|
|
861
879
|
return {
|
|
862
880
|
work: work,
|
|
863
881
|
count: work.reduce((n, {count: count}) => n + count, 0),
|
|
864
|
-
hasRows: work.some(({shown: shown}) => hasAssignedRows(shown))
|
|
882
|
+
hasRows: work.some(({shown: shown}) => hasAssignedRows(shown)),
|
|
883
|
+
hasRoleMatched: work.some(({shown: shown}) => shown.roleMatched)
|
|
865
884
|
};
|
|
866
885
|
}
|
|
867
886
|
|
|
@@ -1435,9 +1454,10 @@ function projectMembersFrom(users) {
|
|
|
1435
1454
|
}
|
|
1436
1455
|
|
|
1437
1456
|
function useProjectMembers() {
|
|
1438
|
-
const {users: users, loading: loading, error: error} = useStudioProjectUsers();
|
|
1457
|
+
const {users: users, roles: roles, loading: loading, error: error} = useStudioProjectUsers();
|
|
1439
1458
|
return {
|
|
1440
1459
|
members: useMemo(() => projectMembersFrom(users), [ users ]),
|
|
1460
|
+
roles: roles,
|
|
1441
1461
|
loading: loading,
|
|
1442
1462
|
error: error === void 0 ? void 0 : errorMessage(error)
|
|
1443
1463
|
};
|
|
@@ -1791,10 +1811,12 @@ function PickedValueRow({children: children, onRequestChange: onRequestChange})
|
|
|
1791
1811
|
}
|
|
1792
1812
|
|
|
1793
1813
|
function MemberPicker({selectedIds: selectedIds, onSelect: onSelect, unassignRow: unassignRow = !1}) {
|
|
1794
|
-
const
|
|
1814
|
+
const {error: error, loading: loading, members: members} = useProjectMembers();
|
|
1795
1815
|
/* @__PURE__ */
|
|
1796
1816
|
return jsx(MemberPicker$1, {
|
|
1797
|
-
|
|
1817
|
+
error: error,
|
|
1818
|
+
loading: loading,
|
|
1819
|
+
members: members,
|
|
1798
1820
|
onSelect: onSelect,
|
|
1799
1821
|
selectedIds: selectedIds,
|
|
1800
1822
|
unassignRow: unassignRow
|
|
@@ -2578,20 +2600,20 @@ function noteRow(args) {
|
|
|
2578
2600
|
}
|
|
2579
2601
|
|
|
2580
2602
|
function AssigneeBadge({assignee: assignee}) {
|
|
2581
|
-
const
|
|
2603
|
+
const vocabulary = useProjectMembers();
|
|
2582
2604
|
/* @__PURE__ */
|
|
2583
2605
|
return jsx(AssigneeBadge$1, {
|
|
2584
2606
|
assignee: assignee,
|
|
2585
|
-
|
|
2607
|
+
vocabulary: vocabulary
|
|
2586
2608
|
});
|
|
2587
2609
|
}
|
|
2588
2610
|
|
|
2589
2611
|
function AssigneeBadges({assignees: assignees}) {
|
|
2590
|
-
const
|
|
2612
|
+
const vocabulary = useProjectMembers();
|
|
2591
2613
|
/* @__PURE__ */
|
|
2592
2614
|
return jsx(AssigneeBadges$1, {
|
|
2593
2615
|
assignees: assignees,
|
|
2594
|
-
|
|
2616
|
+
vocabulary: vocabulary
|
|
2595
2617
|
});
|
|
2596
2618
|
}
|
|
2597
2619
|
|
|
@@ -4218,7 +4240,7 @@ function AvatarButton({avatar: avatar, onClick: onClick, onMouseDown: onMouseDow
|
|
|
4218
4240
|
}
|
|
4219
4241
|
|
|
4220
4242
|
function RowAssignees({assignees: assignees, hint: hint}) {
|
|
4221
|
-
const ids = assignees.flatMap(item => item.type === "user" ? [ item.id ] : []),
|
|
4243
|
+
const ids = assignees.flatMap(item => item.type === "user" ? [ item.id ] : []), vocabulary = useProjectMembers(), roles = assignees.flatMap(item => item.type === "role" ? [ memberRoleFor(vocabulary, item.role) ] : []), displays = useUserDisplays(ids);
|
|
4222
4244
|
if (ids.length === 0 && roles.length === 0) return null;
|
|
4223
4245
|
const bothKinds = roles.length > 0 && displays.length > 0;
|
|
4224
4246
|
/* @__PURE__ */
|
|
@@ -6088,7 +6110,7 @@ function AvatarCapAligned({children: children}) {
|
|
|
6088
6110
|
}
|
|
6089
6111
|
|
|
6090
6112
|
function AssigneesFace({assignees: assignees}) {
|
|
6091
|
-
const
|
|
6113
|
+
const vocabulary = useProjectMembers(), userIds = assignees.flatMap(a => a.type === "user" ? [ a.id ] : []), roles = assignees.flatMap(a => a.type === "role" ? [ roleLabelFor(vocabulary, a.role) ] : []);
|
|
6092
6114
|
/* @__PURE__ */
|
|
6093
6115
|
return jsxs(Fragment, {
|
|
6094
6116
|
children: [ userIds.length > 0 ? /* @__PURE__ */ jsx(AvatarCapAligned, {
|
|
@@ -7848,18 +7870,23 @@ function StageSection({entry: entry, onOpenActivity: onOpenActivity, surface: su
|
|
|
7848
7870
|
});
|
|
7849
7871
|
}
|
|
7850
7872
|
|
|
7851
|
-
|
|
7873
|
+
const BANNER_PADDING = 3, ICONS = {
|
|
7874
|
+
caution: /* @__PURE__ */ jsx(WarningOutlineIcon, {}),
|
|
7875
|
+
critical: /* @__PURE__ */ jsx(ErrorOutlineIcon, {})
|
|
7876
|
+
};
|
|
7877
|
+
|
|
7878
|
+
function NoteBanner({action: action, label: label, tone: tone = "caution"}) {
|
|
7852
7879
|
/* @__PURE__ */
|
|
7853
7880
|
return jsxs(Card, {
|
|
7854
7881
|
paddingLeft: 3,
|
|
7855
7882
|
paddingRight: 2,
|
|
7856
|
-
paddingY:
|
|
7883
|
+
paddingY: BANNER_PADDING,
|
|
7857
7884
|
radius: 3,
|
|
7858
7885
|
style: {
|
|
7859
7886
|
alignItems: "center",
|
|
7860
7887
|
display: "flex"
|
|
7861
7888
|
},
|
|
7862
|
-
tone:
|
|
7889
|
+
tone: tone,
|
|
7863
7890
|
children: [
|
|
7864
7891
|
/* @__PURE__ */ jsxs(Flex, {
|
|
7865
7892
|
align: "center",
|
|
@@ -7869,7 +7896,7 @@ function CautionNote({action: action, label: label}) {
|
|
|
7869
7896
|
/* @__PURE__ */ jsx(Text, {
|
|
7870
7897
|
muted: !0,
|
|
7871
7898
|
size: 1,
|
|
7872
|
-
children:
|
|
7899
|
+
children: ICONS[tone]
|
|
7873
7900
|
}),
|
|
7874
7901
|
/* @__PURE__ */ jsx(Text, {
|
|
7875
7902
|
muted: !0,
|
|
@@ -7906,7 +7933,7 @@ function UnreadableDocsNote({unreadable: unreadable}) {
|
|
|
7906
7933
|
if (unreadable.length === 0) return null;
|
|
7907
7934
|
const label = unreadable.length === 1 ? "1 workflow document isn’t listed — this Studio can’t read it. Share the details with your Studio maintainers." : `${unreadable.length} workflow documents aren’t listed — this Studio can’t read them. Share the details with your Studio maintainers.`;
|
|
7908
7935
|
/* @__PURE__ */
|
|
7909
|
-
return jsx(
|
|
7936
|
+
return jsx(NoteBanner, {
|
|
7910
7937
|
action: /* @__PURE__ */ jsx(CopyDetailsButton, {
|
|
7911
7938
|
unreadable: unreadable
|
|
7912
7939
|
}),
|
|
@@ -7952,6 +7979,21 @@ function InvalidDocNotice({invalid: invalid}) {
|
|
|
7952
7979
|
});
|
|
7953
7980
|
}
|
|
7954
7981
|
|
|
7982
|
+
function RoleAssignedNotice() {
|
|
7983
|
+
/* @__PURE__ */
|
|
7984
|
+
return jsx(Box, {
|
|
7985
|
+
padding: 2,
|
|
7986
|
+
children: /* @__PURE__ */ jsx(Text, {
|
|
7987
|
+
muted: !0,
|
|
7988
|
+
size: 1,
|
|
7989
|
+
style: {
|
|
7990
|
+
fontStyle: "italic"
|
|
7991
|
+
},
|
|
7992
|
+
children: "Including tasks assigned to your role"
|
|
7993
|
+
})
|
|
7994
|
+
});
|
|
7995
|
+
}
|
|
7996
|
+
|
|
7955
7997
|
function TabSwitch({ariaControls: ariaControls, idPrefix: idPrefix, options: options, selected: selected, onSelect: onSelect}) {
|
|
7956
7998
|
/* @__PURE__ */
|
|
7957
7999
|
return jsx(TabList, {
|
|
@@ -8216,8 +8258,15 @@ function presentedResumeEntry(args) {
|
|
|
8216
8258
|
if (!args.startNew) return findResumeEntry(args);
|
|
8217
8259
|
}
|
|
8218
8260
|
|
|
8261
|
+
function settledByAnotherWriter(cause, instance) {
|
|
8262
|
+
return isRevisionConflict(cause) && terminalState(instance) === "completed";
|
|
8263
|
+
}
|
|
8264
|
+
|
|
8219
8265
|
function classifyStartError(err) {
|
|
8220
|
-
return err instanceof StartNotSettledError ? {
|
|
8266
|
+
return err instanceof StartNotSettledError ? err.instance !== void 0 && settledByAnotherWriter(err.cause, err.instance) ? {
|
|
8267
|
+
kind: "started-settled-elsewhere",
|
|
8268
|
+
instance: err.instance
|
|
8269
|
+
} : {
|
|
8221
8270
|
kind: "started-not-settled",
|
|
8222
8271
|
instance: err.instance,
|
|
8223
8272
|
description: describeError(err.cause)
|
|
@@ -8230,8 +8279,16 @@ function classifyStartError(err) {
|
|
|
8230
8279
|
};
|
|
8231
8280
|
}
|
|
8232
8281
|
|
|
8282
|
+
function startProducedRun(outcome) {
|
|
8283
|
+
return outcome.kind === "started-not-settled" || outcome.kind === "started-settled-elsewhere";
|
|
8284
|
+
}
|
|
8285
|
+
|
|
8233
8286
|
function startOutcomeToast(outcome, label) {
|
|
8234
|
-
return outcome.kind === "started-
|
|
8287
|
+
return outcome.kind === "started-settled-elsewhere" ? {
|
|
8288
|
+
id: TOAST_ID.start,
|
|
8289
|
+
status: "info",
|
|
8290
|
+
title: `“${label}” started and finished`
|
|
8291
|
+
} : outcome.kind === "started-not-settled" ? {
|
|
8235
8292
|
id: TOAST_ID.start,
|
|
8236
8293
|
status: "warning",
|
|
8237
8294
|
title: `“${label}” started but didn’t finish`,
|
|
@@ -8962,10 +9019,10 @@ function OverviewEmptyState({mappings: mappings, docId: docId, initialValue: ini
|
|
|
8962
9019
|
}
|
|
8963
9020
|
|
|
8964
9021
|
function ForMeTab({forMe: forMe, assignedWorkUnknown: assignedWorkUnknown, onOpenActivity: onOpenActivity}) {
|
|
8965
|
-
return forMe.hasRows ? /* @__PURE__ */
|
|
9022
|
+
return forMe.hasRows ? /* @__PURE__ */ jsxs(Stack, {
|
|
8966
9023
|
gap: GROUP_GAP,
|
|
8967
9024
|
paddingBottom: 4,
|
|
8968
|
-
children: forMe.work.map(({entry: entry, who: who, shown: shown}) => /* @__PURE__ */ jsx(ForMeList, {
|
|
9025
|
+
children: [ forMe.hasRoleMatched ? /* @__PURE__ */ jsx(RoleAssignedNotice, {}) : null, forMe.work.map(({entry: entry, who: who, shown: shown}) => /* @__PURE__ */ jsx(ForMeList, {
|
|
8969
9026
|
entry: entry,
|
|
8970
9027
|
identity: who,
|
|
8971
9028
|
work: shown,
|
|
@@ -8974,7 +9031,7 @@ function ForMeTab({forMe: forMe, assignedWorkUnknown: assignedWorkUnknown, onOpe
|
|
|
8974
9031
|
activityName: activityName,
|
|
8975
9032
|
stage: entry.instance.currentStage
|
|
8976
9033
|
})
|
|
8977
|
-
}, entry.instance._id))
|
|
9034
|
+
}, entry.instance._id)) ]
|
|
8978
9035
|
}) : assignedWorkUnknown ? null : /* @__PURE__ */ jsx(ForMeEmptyState, {});
|
|
8979
9036
|
}
|
|
8980
9037
|
|
|
@@ -10211,7 +10268,7 @@ function ResumeNote({onStartNew: onStartNew}) {
|
|
|
10211
10268
|
|
|
10212
10269
|
function handleStartError(args) {
|
|
10213
10270
|
const {label: label, toast: toast, seedInstance: seedInstance, onClose: onClose} = args, outcome = classifyStartError(args.err);
|
|
10214
|
-
toast.push(startOutcomeToast(outcome, label)), outcome
|
|
10271
|
+
toast.push(startOutcomeToast(outcome, label)), startProducedRun(outcome) && (outcome.instance !== void 0 && seedInstance(outcome.instance),
|
|
10215
10272
|
onClose());
|
|
10216
10273
|
}
|
|
10217
10274
|
|
|
@@ -10564,7 +10621,7 @@ async function startRequest(engine, request) {
|
|
|
10564
10621
|
};
|
|
10565
10622
|
} catch (err) {
|
|
10566
10623
|
const outcome = classifyStartError(err);
|
|
10567
|
-
return outcome
|
|
10624
|
+
return startProducedRun(outcome) ? outcome.instance ? {
|
|
10568
10625
|
instance: outcome.instance
|
|
10569
10626
|
} : {} : outcome.kind === "not-allowed" ? {} : {
|
|
10570
10627
|
failure: outcome.description
|
|
@@ -11163,4 +11220,4 @@ function WorkflowRootInput(props) {
|
|
|
11163
11220
|
});
|
|
11164
11221
|
}
|
|
11165
11222
|
|
|
11166
|
-
export { AbortWorkflowDialog, ActivityDetailDialog, ActivityLog, ActivityRow, BreadcrumbTail,
|
|
11223
|
+
export { AbortWorkflowDialog, ActivityDetailDialog, ActivityLog, ActivityRow, BreadcrumbTail, CodeChip, CountedLabel, DismissablePopover, DocPreviewLink, DocRefFace, EmptyState, ForMeEmptyState, Hairline, HoverHint, InstanceSnapshotBody, InvalidDocNotice, LinkChip, LoadingRow, LogEventOnMount, MetaRow, 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, findActivityNode, formatDate, formatShortDateTime, formatTimeAgo, gdrLocality, instanceBreadcrumb, instanceState, instanceTitle, isActivityAssignedTo, isEvaluationStale, isLiveEntry, isOpenActivityStatus, isRoleAssignedTo, landingState, mappingIssueDetail, namesNoDeployedDefinition, openActivityGone, openableSchemaType, parseStoredDateValue, readDeployedDefinitions, rowAssignControlState, rowDateControlState, stageTitle, stateByActivity, tabSelectionNavigates, toolRoute, toolTabState, useAssignmentIdentity, useBadgeCapTrim, useContainerToken, useDefinition, useDelayedFlag, useLogEventOnMount, useProjectMembers, useSpaceToken, useUserDisplays, useWorkflowContext, useWorkflowInstanceEntry, useWorkflowToast, workflowDefaultDocumentNode, workflowPageState, workflowState, workflowStudioPlugin, workflowsView };
|