@sanity/workflow-studio-plugin 0.23.0 → 0.24.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.
@@ -10,7 +10,7 @@ import { createContext, useContext, useEffect, useSyncExternalStore, useCallback
10
10
 
11
11
  import { usePaneRouter } from "sanity/structure";
12
12
 
13
- import { tryParseGdr, resourceFromParsed, latestDeployedDefinitions, isStartableDefinition, isSubjectEntry, isInputSourced, acceptsDocumentType, missingRequiredInputs, initialFieldIssues, gdrRef, releaseRef, refKindAcceptsTypes, rejectedRefTypes, ActionDisabledError, MutationGuardDeniedError, errorMessage, findOpenStageEntry, actionRendering, terminalState, isTodoListEntry, isTodoListItem, isTerminalActivityStatus, describeCondition, sentenceCase, checklistLines, findCurrentActivityEntry, ENGINE_API_VERSION, WORKFLOW_INSTANCE_TYPE, WORKFLOW_DEFINITION_TYPE, GUARD_DOC_TYPE, scalarValidationIssues, classifyPrincipalId, 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, 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, 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";
14
14
 
15
15
  import { CheckmarkIcon } from "@sanity/icons/Checkmark";
16
16
 
@@ -26,7 +26,7 @@ import { defineEvent } from "@sanity/telemetry";
26
26
 
27
27
  import { useStudioProjectUsers, useStudioObserver, useWorkflowEngine, useWorkflowInstances, useWorkflowSession } from "@sanity/workflow-studio";
28
28
 
29
- import { useCurrentUser, SanityDefaultPreview, Preview, useValuePreview, useClient, useSchema, useWorkspace, TextWithTone, usePerspective, useIsReleaseActive, useDocumentPreviewStore, useActiveReleases, useTemplates, useInitialValueResolverContext, resolveInitialValue, definePlugin, isObjectInputProps } from "sanity";
29
+ import { useCurrentUser, Preview, SanityDefaultPreview, useValuePreview, useClient, useSchema, useWorkspace, TextWithTone, usePerspective, useIsReleaseActive, useDocumentPreviewStore, useActiveReleases, useTemplates, useInitialValueResolverContext, resolveInitialValue, definePlugin, isObjectInputProps } from "sanity";
30
30
 
31
31
  import { CalendarIcon } from "@sanity/icons/Calendar";
32
32
 
@@ -78,6 +78,18 @@ import { switchMap, distinctUntilChanged } from "rxjs/operators";
78
78
 
79
79
  import { TransferIcon } from "@sanity/icons/Transfer";
80
80
 
81
+ const WORKFLOW_SYSTEM_TYPES = [ WORKFLOW_INSTANCE_TYPE, WORKFLOW_DEFINITION_TYPE, GUARD_DOC_TYPE ];
82
+
83
+ function contentDocumentTypes(schema) {
84
+ return schema.getTypeNames().filter(name => schema.get(name)?.type?.name === "document" && !WORKFLOW_SYSTEM_TYPES.includes(name));
85
+ }
86
+
87
+ const SYSTEM_TYPE_PREFIX = "sanity.";
88
+
89
+ function isSystemDocumentType(name) {
90
+ return name.startsWith(SYSTEM_TYPE_PREFIX) || WORKFLOW_SYSTEM_TYPES.includes(name);
91
+ }
92
+
81
93
  function isLocalContentResource(resource, contentResource) {
82
94
  return resource?.type === "dataset" && resource.id === contentResource.id;
83
95
  }
@@ -102,14 +114,14 @@ function assertUniqueWorkflowMappings(mappings) {
102
114
 
103
115
  function discoverWorkflowMappings(args) {
104
116
  assertUniqueWorkflowMappings(args.overrides ?? []);
105
- const discovered = latestDeployedDefinitions(args.definitions).flatMap(definition => {
117
+ const bindable = [ ...args.schemaContentTypes ].filter(name => !isSystemDocumentType(name)), discovered = latestDeployedDefinitions(args.definitions).flatMap(definition => {
106
118
  if (!isStartableDefinition(definition)) return [];
107
119
  const subject = (definition.fields ?? []).find(isSubjectEntry);
108
120
  if (subject === void 0 || !isInputSourced(subject)) return [];
109
121
  const source = {
110
122
  fields: [ ...definition.fields ?? [] ]
111
123
  };
112
- return [ ...args.schemaContentTypes ].filter(docType => acceptsDocumentType(source, docType)).map(docType => ({
124
+ return bindable.filter(docType => acceptsDocumentType(source, docType)).map(docType => ({
113
125
  docType: docType,
114
126
  definition: definition.name,
115
127
  label: definition.title ?? definition.name
@@ -240,14 +252,11 @@ function rowProblems(args) {
240
252
  mapping: args.mapping,
241
253
  contentResource: args.contentResource,
242
254
  declared: declared
243
- }), missing = missingRequiredInputs({
244
- entryDefs: declared,
245
- initialFields: seeded
246
- }), consumptionProblems = initialFieldIssues({
255
+ });
256
+ return [ ...initialFieldIssues({
247
257
  workflowFields: declared,
248
258
  initialFields: seeded
249
- }).flatMap(issue => seedConsumptionProblem(issue) ?? []);
250
- return [ ...missing.map(m => `its start would not provide the required entry "${m.name}" (${m.type})`), ...consumptionProblems, ...seeded.flatMap(seed => seedReferenceProblems({
259
+ }).flatMap(issue => seedConsumptionProblem(issue) ?? []), ...seeded.flatMap(seed => seedReferenceProblems({
251
260
  seed: seed,
252
261
  declared: declared
253
262
  })), ...seeded.flatMap(seed => seededSchemaProblems({
@@ -257,12 +266,24 @@ function rowProblems(args) {
257
266
  })) ];
258
267
  }
259
268
 
269
+ const NOT_DEPLOYED = "the definition is not deployed — deploy it or fix the mapping row";
270
+
271
+ function namesNoDeployedDefinition(issue) {
272
+ return issue.version === void 0;
273
+ }
274
+
260
275
  function mappingIssues(args) {
261
276
  const latestByName = new Map(latestDeployedDefinitions(args.definitions).map(d => [ d.name, d ])), issues = /* @__PURE__ */ new Map;
262
277
  for (const mapping of args.mappings) {
263
- const definition = latestByName.get(mapping.definition);
278
+ const identity = {
279
+ docType: mapping.docType,
280
+ definition: mapping.definition
281
+ }, definition = latestByName.get(mapping.definition);
264
282
  if (definition === void 0) {
265
- issues.set(mappingKey(mapping), `Workflow mapping for document type "${mapping.docType}" points at definition "${mapping.definition}", which is not deployed — deploy it or fix the mapping row.`);
283
+ issues.set(mappingKey(mapping), {
284
+ ...identity,
285
+ problems: [ NOT_DEPLOYED ]
286
+ });
266
287
  continue;
267
288
  }
268
289
  const problems = rowProblems({
@@ -271,11 +292,31 @@ function mappingIssues(args) {
271
292
  contentResource: args.contentResource,
272
293
  schemaContentTypes: args.schemaContentTypes
273
294
  });
274
- problems.length > 0 && issues.set(mappingKey(mapping), `Workflow mapping for document type "${mapping.docType}" points at definition "${mapping.definition}" (v${definition.version}), but ${problems.join("; ")}.`);
295
+ problems.length > 0 && issues.set(mappingKey(mapping), {
296
+ ...identity,
297
+ version: definition.version,
298
+ problems: problems
299
+ });
275
300
  }
276
301
  return issues;
277
302
  }
278
303
 
304
+ function sameMappingIssue(left, right) {
305
+ return left.docType === right.docType && left.definition === right.definition && left.version === right.version && left.problems.length === right.problems.length && left.problems.every((problem, index) => problem === right.problems[index]);
306
+ }
307
+
308
+ function mappingIssueDetail(issue) {
309
+ return issue.problems.join("; ");
310
+ }
311
+
312
+ function versionSuffix(issue) {
313
+ return issue.version === void 0 ? "" : ` (v${issue.version})`;
314
+ }
315
+
316
+ function mappingIssueLogLines(issues) {
317
+ return [ ...issues.values() ].map(issue => `The "${issue.docType}" → "${issue.definition}" mapping row${versionSuffix(issue)} is disabled: ${mappingIssueDetail(issue)}.`);
318
+ }
319
+
279
320
  const WORKFLOWS_VIEW_ID = "workflows", WORKFLOWS_TAB_PARAM = "workflowsTab";
280
321
 
281
322
  function withoutWorkflowsTab(params) {
@@ -318,10 +359,16 @@ function landingDefaultOpen(landing, instanceId) {
318
359
  if (!(landing === void 0 || !landing.instanceIds.includes(instanceId))) return instanceId === landing.focusedId;
319
360
  }
320
361
 
321
- const WORKFLOWS_TOOL_NAME = "workflows", WORKFLOW_INTENT = "workflow";
362
+ const WORKFLOWS_TOOL_NAME = "workflows";
363
+
364
+ function workflowsToolAvailable(tools) {
365
+ return tools.some(tool => tool.name === WORKFLOWS_TOOL_NAME);
366
+ }
367
+
368
+ const WORKFLOW_INTENT = "workflow";
322
369
 
323
370
  function pathSegmentTab(args) {
324
- return args.tabs.find(tab => tab === args.segment) ?? args.fallback;
371
+ return args.segment === void 0 ? args.fallback : args.tabs.find(tab => tab === args.segment);
325
372
  }
326
373
 
327
374
  function handlesWorkflowIntent(intent, params) {
@@ -335,11 +382,19 @@ function workflowIntentState(intent, params) {
335
382
  } : null;
336
383
  }
337
384
 
338
- const pad2 = n => String(n).padStart(2, "0");
385
+ const pad2 = n => String(n).padStart(2, "0"), DATE_FIELD_KINDS = [ "date", "dueDate", "datetime", "dueDatetime" ], DATE_FIELD_KIND_SET = new Set(DATE_FIELD_KINDS);
386
+
387
+ function isDateFieldKind(kind) {
388
+ return DATE_FIELD_KIND_SET.has(kind);
389
+ }
390
+
391
+ function hasTimeOfDay(kind) {
392
+ return kind === "datetime" || kind === "dueDatetime";
393
+ }
339
394
 
340
395
  function parseDateFieldValue(value, kind) {
341
396
  if (typeof value != "string" || value === "") return;
342
- const parsed2 = kind === "date" ? parseLocalDate(value) : new Date(value);
397
+ const parsed2 = hasTimeOfDay(kind) ? new Date(value) : parseLocalDate(value);
343
398
  return Number.isNaN(parsed2.getTime()) ? void 0 : parsed2;
344
399
  }
345
400
 
@@ -355,16 +410,24 @@ function parseStoredDateValue(value) {
355
410
  }
356
411
 
357
412
  function serializeDateFieldValue(date, kind) {
358
- return kind === "datetime" ? date.toISOString() : `${date.getFullYear()}-${pad2(date.getMonth() + 1)}-${pad2(date.getDate())}`;
413
+ return hasTimeOfDay(kind) ? date.toISOString() : `${date.getFullYear()}-${pad2(date.getMonth() + 1)}-${pad2(date.getDate())}`;
414
+ }
415
+
416
+ class EffectsIncompleteError extends Error {
417
+ reason;
418
+ constructor(reason, options) {
419
+ super(`The change was committed, but running its effects failed: ${reason}`, options),
420
+ this.name = "EffectsIncompleteError", this.reason = reason;
421
+ }
359
422
  }
360
423
 
361
424
  const editDisabledSentence = {
362
425
  "edit-window-closed": () => "Can only be edited while its activity is active",
363
- "editor-not-permitted": () => "You don't have permission to edit this",
426
+ "editor-not-permitted": () => "You dont have permission to edit this",
364
427
  "instance-aborted": () => "This workflow was aborted",
365
428
  "instance-completed": () => "This workflow is already complete",
366
429
  "mutation-guard-denied": () => "An earlier step is holding this document",
367
- "not-editable": () => "This isn't editable here"
430
+ "not-editable": () => "This isnt editable here"
368
431
  };
369
432
 
370
433
  function describeEditDisabledReason(reason) {
@@ -437,24 +500,43 @@ const activityNotActiveSentence = {
437
500
  }, disabledSentence = {
438
501
  "activity-not-active": r => activityNotActiveSentence[r.status],
439
502
  "cascade-fired": () => "This happens automatically — the workflow runs it when its condition is met.",
440
- "filter-failed": () => "Not available to you yet — you may not have the required role, it may be assigned to someone else, or a needed value isn't set.",
503
+ "filter-failed": () => "Not available to you yet — you may not have the required role, it may be assigned to someone else, or a needed value isnt set.",
441
504
  "instance-aborted": () => "This workflow was aborted.",
442
505
  "instance-completed": () => "This workflow is already complete.",
443
506
  "mutation-guard-denied": () => "An earlier step is holding this document.",
444
- "requirements-unmet": () => "This step isn't ready yet — a required condition hasn't been met.",
507
+ "requirements-unmet": () => "This step isnt ready yet — a required condition hasnt been met.",
445
508
  "stage-terminal": () => "This stage is finished.",
446
- "subject-permission-denied": () => "You don't have permission to change the document this step works on."
509
+ "subject-permission-denied": () => "You dont have permission to change the document this step works on."
447
510
  };
448
511
 
449
512
  function describeDisabledReason(reason) {
450
513
  return disabledSentence[reason.kind](reason);
451
514
  }
452
515
 
516
+ function readRejection(err) {
517
+ return err instanceof ActionDisabledError ? {
518
+ kind: "refusal",
519
+ message: describeDisabledReason(err.reason)
520
+ } : err instanceof MutationGuardDeniedError ? {
521
+ kind: "refusal",
522
+ message: describeDisabledReason({
523
+ kind: "mutation-guard-denied",
524
+ denied: err.denied
525
+ })
526
+ } : err instanceof EditFieldDeniedError ? {
527
+ kind: "refusal",
528
+ message: describeEditDisabledReason(err.reason)
529
+ } : err instanceof EffectsIncompleteError ? {
530
+ kind: "committed-incomplete",
531
+ message: err.reason
532
+ } : {
533
+ kind: "failure",
534
+ message: errorMessage(err)
535
+ };
536
+ }
537
+
453
538
  function describeError(err) {
454
- return err instanceof ActionDisabledError ? describeDisabledReason(err.reason) : err instanceof MutationGuardDeniedError ? describeDisabledReason({
455
- kind: "mutation-guard-denied",
456
- denied: err.denied
457
- }) : errorMessage(err);
539
+ return readRejection(err).message;
458
540
  }
459
541
 
460
542
  function hrefIfHttp(value) {
@@ -510,6 +592,28 @@ function isTodoOverdue(item, today = /* @__PURE__ */ new Date) {
510
592
  return !item.dueDate || isTodoDone(item) ? !1 : item.dueDate < serializeDateFieldValue(today, "date");
511
593
  }
512
594
 
595
+ function todoEditKind(patch) {
596
+ return "assignee" in patch ? "assignee" : "due-date";
597
+ }
598
+
599
+ function assertNamesOneRow(items, key) {
600
+ const matches = items.filter(row => row._key === key).length;
601
+ if (matches !== 1) throw new Error(matches === 0 ? "This to-do is no longer in the stored list. Reload and try again." : `${matches} to-dos in this list share one id, so they cannot be told apart. The stored list has to be repaired before it can be edited.`);
602
+ }
603
+
604
+ function todoItemsPatched(args) {
605
+ const {items: items, key: key, patch: patch} = args;
606
+ return assertNamesOneRow(items, key), items.map(row => row._key === key ? {
607
+ ...row,
608
+ ...patch
609
+ } : row);
610
+ }
611
+
612
+ function todoItemsWithout(args) {
613
+ const {items: items, key: key} = args;
614
+ return assertNamesOneRow(items, key), items.filter(row => row._key !== key);
615
+ }
616
+
513
617
  function tickOpsOf(action) {
514
618
  return (action.ops ?? []).flatMap(o => o.type === "field.updateWhere" ? [ o ] : []);
515
619
  }
@@ -950,7 +1054,7 @@ function rowAssignControlState(args) {
950
1054
 
951
1055
  function rowDateControlState(args) {
952
1056
  return rowControlState({
953
- kinds: [ "date", "datetime" ],
1057
+ kinds: DATE_FIELD_KINDS,
954
1058
  ...args
955
1059
  });
956
1060
  }
@@ -990,7 +1094,7 @@ function activityRowProps(args) {
990
1094
  }
991
1095
 
992
1096
  function dateControlKind(state) {
993
- if (state.kind === "editable" && (state.field.type === "date" || state.field.type === "datetime")) return state.field.type;
1097
+ if (state.kind === "editable" && isDateFieldKind(state.field.type)) return state.field.type;
994
1098
  }
995
1099
 
996
1100
  function dateControlValue(args) {
@@ -1020,7 +1124,7 @@ function deriveActivityDetail(args) {
1020
1124
  };
1021
1125
  }
1022
1126
 
1023
- const WORKFLOW_API_VERSION = ENGINE_API_VERSION, WORKFLOW_SYSTEM_TYPES = [ WORKFLOW_INSTANCE_TYPE, WORKFLOW_DEFINITION_TYPE, GUARD_DOC_TYPE ], EMPTY_ENTRIES = [], WorkflowContext = createContext(null);
1127
+ const WORKFLOW_API_VERSION = ENGINE_API_VERSION, EMPTY_ENTRIES = [], WorkflowContext = createContext(null);
1024
1128
 
1025
1129
  function useWorkflowContext() {
1026
1130
  const value = useContext(WorkflowContext);
@@ -1072,10 +1176,27 @@ const WorkflowToolOpened = defineEvent({
1072
1176
  name: "Editorial Workflows Studio Plugin Instance Detail Viewed",
1073
1177
  version: 1,
1074
1178
  description: "The Workflows tool's per-instance detail view was opened"
1179
+ });
1180
+
1181
+ function definitionFingerprint(definition) {
1182
+ const hash = definition?.contentHash;
1183
+ return hash === void 0 ? {} : {
1184
+ definitionContentHash: hash
1185
+ };
1186
+ }
1187
+
1188
+ const WorkflowDefinitionDetailViewed = defineEvent({
1189
+ name: "Editorial Workflows Studio Plugin Definition Detail Viewed",
1190
+ version: 1,
1191
+ description: "The Workflows tool's per-definition detail view was opened"
1075
1192
  }), WorkflowFormStripClicked = defineEvent({
1076
1193
  name: "Editorial Workflows Studio Plugin Form Strip Clicked",
1077
1194
  version: 1,
1078
1195
  description: "The form strip's instance line was clicked, opening the document view"
1196
+ }), WorkflowDocumentLinkClicked = defineEvent({
1197
+ name: "Editorial Workflows Studio Plugin Document Link Clicked",
1198
+ version: 1,
1199
+ description: "A document link was clicked, opening the referenced document's editor"
1079
1200
  }), WorkflowStartDialogOpened = defineEvent({
1080
1201
  name: "Editorial Workflows Studio Plugin Start Dialog Opened",
1081
1202
  version: 1,
@@ -1090,8 +1211,12 @@ const WorkflowToolOpened = defineEvent({
1090
1211
  description: "A fresh document's auto-start ran — one start request per configured workflow"
1091
1212
  }), WorkflowActionControlUsed = defineEvent({
1092
1213
  name: "Editorial Workflows Studio Plugin Action Control Used",
1093
- version: 1,
1214
+ version: 2,
1094
1215
  description: "An action-firing control was used, attributed to its UI surface"
1216
+ }), WorkflowFieldControlUsed = defineEvent({
1217
+ name: "Editorial Workflows Studio Plugin Field Control Used",
1218
+ version: 1,
1219
+ description: "A field-editing control committed an edit, attributed to its UI surface"
1095
1220
  }), WorkflowActivityDialogOpened = defineEvent({
1096
1221
  name: "Editorial Workflows Studio Plugin Activity Dialog Opened",
1097
1222
  version: 1,
@@ -1100,10 +1225,26 @@ const WorkflowToolOpened = defineEvent({
1100
1225
  name: "Editorial Workflows Studio Plugin Task Filters Applied",
1101
1226
  version: 1,
1102
1227
  description: "The tool's task-filter menu closed with a changed selection"
1228
+ }), WorkflowBoardWorkflowSelected = defineEvent({
1229
+ name: "Editorial Workflows Studio Plugin Board Workflow Selected",
1230
+ version: 1,
1231
+ description: "The Documents board settled on a workflow to show"
1232
+ }), WorkflowBoardLayoutChanged = defineEvent({
1233
+ name: "Editorial Workflows Studio Plugin Board Layout Changed",
1234
+ version: 1,
1235
+ description: "The Documents board's layout was switched"
1236
+ }), WorkflowTitleSeedDrifted = defineEvent({
1237
+ name: "Editorial Workflows Studio Plugin Title Seed Drifted",
1238
+ version: 1,
1239
+ description: "A cold-start seeded preview title diverged from the live preview pipeline"
1103
1240
  }), WorkflowTodoToggled = defineEvent({
1104
1241
  name: "Editorial Workflows Studio Plugin Todo Toggled",
1105
1242
  version: 1,
1106
1243
  description: "A todo checkbox was toggled, attributed to its UI surface and write seam"
1244
+ }), WorkflowTodoEdited = defineEvent({
1245
+ name: "Editorial Workflows Studio Plugin Todo Edited",
1246
+ version: 1,
1247
+ description: "A non-toggle todo-list write, attributed to its UI surface and gesture"
1107
1248
  });
1108
1249
 
1109
1250
  function useLogEventOnMount(event, data) {
@@ -1193,20 +1334,32 @@ function useUserDisplay(id) {
1193
1334
  };
1194
1335
  }
1195
1336
 
1196
- const warnedNotMember = /* @__PURE__ */ new Set;
1337
+ const warnedSelfUnavailable = /* @__PURE__ */ new Set;
1338
+
1339
+ function warnSelfUnavailableOnce(key, message) {
1340
+ warnedSelfUnavailable.has(key) || (warnedSelfUnavailable.add(key), console.warn(message));
1341
+ }
1342
+
1343
+ function bridgedSelfId(users, meId) {
1344
+ const classified = classifyPrincipalId(meId);
1345
+ return users.find(user => user.membership.id === meId)?.profile?.sanityUserId ?? classified.globalId ?? (classified.namespace === "project" ? void 0 : meId);
1346
+ }
1197
1347
 
1198
1348
  function useBridgedSelf() {
1199
- const me = useCurrentUser(), {users: users, loading: loading} = useStudioProjectUsers();
1200
- if (!me || loading) return;
1201
- const classified = classifyPrincipalId(me.id), id = users.find(user => user.membership.id === me.id)?.profile?.sanityUserId ?? classified.globalId ?? (classified.namespace === "project" ? void 0 : me.id);
1202
- if (id === void 0) {
1203
- warnedNotMember.has(me.id) || (warnedNotMember.add(me.id), console.warn(`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.`));
1204
- return;
1205
- }
1206
- return {
1349
+ const me = useCurrentUser(), {users: users, loading: loading, error: error} = useStudioProjectUsers();
1350
+ if (!me) return;
1351
+ const id = bridgedSelfId(users, me.id);
1352
+ if (id !== void 0) return {
1207
1353
  id: id,
1208
1354
  roles: me.roles ?? []
1209
1355
  };
1356
+ if (!loading) {
1357
+ if (error !== void 0) {
1358
+ 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.`);
1359
+ return;
1360
+ }
1361
+ 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.`);
1362
+ }
1210
1363
  }
1211
1364
 
1212
1365
  function useSelfActor() {
@@ -1347,8 +1500,11 @@ function HoverHint(props) {
1347
1500
  children: /* @__PURE__ */ jsx(Box, {
1348
1501
  "data-testid": props["data-testid"],
1349
1502
  style: {
1350
- display: "inline-flex",
1351
- maxWidth: "100%"
1503
+ display: props.fill ? "flex" : "inline-flex",
1504
+ maxWidth: "100%",
1505
+ ...props.fill ? {
1506
+ width: "100%"
1507
+ } : {}
1352
1508
  },
1353
1509
  children: children
1354
1510
  })
@@ -1436,7 +1592,7 @@ function DismissablePopover({children: children, content: content, onDismiss: on
1436
1592
  function DateFieldInput({kind: kind, value: value, onChange: onChange, readOnly: readOnly = !1}) {
1437
1593
  const [open, setOpen] = useState(!1), parsed2 = parseDateFieldValue(value, kind), close = () => setOpen(!1), toggle = () => {
1438
1594
  readOnly || setOpen(v => !v);
1439
- };
1595
+ }, pickHint = hasTimeOfDay(kind) ? "Pick a date and time…" : "Pick a date…";
1440
1596
  /* @__PURE__ */
1441
1597
  return jsx(DismissablePopover, {
1442
1598
  content: /* @__PURE__ */ jsx(ClearableDatePicker, {
@@ -1447,7 +1603,7 @@ function DateFieldInput({kind: kind, value: value, onChange: onChange, readOnly:
1447
1603
  onPick: next => {
1448
1604
  close(), onChange(serializeDateFieldValue(next, kind));
1449
1605
  },
1450
- selectTime: kind === "datetime",
1606
+ selectTime: hasTimeOfDay(kind),
1451
1607
  value: parsed2
1452
1608
  }),
1453
1609
  onDismiss: close,
@@ -1460,7 +1616,7 @@ function DateFieldInput({kind: kind, value: value, onChange: onChange, readOnly:
1460
1616
  children: /* @__PURE__ */ jsx(TextInput, {
1461
1617
  fontSize: 1,
1462
1618
  onClick: toggle,
1463
- placeholder: readOnly ? "" : kind === "datetime" ? "Pick a date and time…" : "Pick a date…",
1619
+ placeholder: readOnly ? "" : pickHint,
1464
1620
  readOnly: !0,
1465
1621
  value: parsed2 ? formatDate(String(value)) : ""
1466
1622
  })
@@ -1504,7 +1660,7 @@ function ChoiceSelect({options: options, value: value, onChange: onChange, readO
1504
1660
  });
1505
1661
  }
1506
1662
 
1507
- const SCALAR_INPUT_KINDS = [ "string", "text", "url", "number", "progress", "date", "dateTime", "datetime", "boolean" ], SCALAR_INPUT_KIND_SET = new Set(SCALAR_INPUT_KINDS);
1663
+ const SCALAR_INPUT_KINDS = [ "string", "text", "url", "number", "progress", ...DATE_FIELD_KINDS, "dateTime", "boolean" ], SCALAR_INPUT_KIND_SET = new Set(SCALAR_INPUT_KINDS);
1508
1664
 
1509
1665
  function isScalarInputKind(kind) {
1510
1666
  return SCALAR_INPUT_KIND_SET.has(kind);
@@ -1522,8 +1678,8 @@ function ScalarInput({kind: kind, value: value, onChange: onChange, options: opt
1522
1678
  }) : kind === "boolean" ? /* @__PURE__ */ jsx(Checkbox, {
1523
1679
  checked: value === !0,
1524
1680
  onChange: e => onChange(e.currentTarget.checked)
1525
- }) : kind === "date" || kind === "dateTime" || kind === "datetime" ? /* @__PURE__ */ jsx(DateFieldInput, {
1526
- kind: kind === "date" ? "date" : "datetime",
1681
+ }) : isDateFieldKind(kind) || kind === "dateTime" ? /* @__PURE__ */ jsx(DateFieldInput, {
1682
+ kind: kind === "dateTime" ? "datetime" : kind,
1527
1683
  onChange: next => onChange(next ?? ""),
1528
1684
  value: value
1529
1685
  }) : /* @__PURE__ */ jsx(TextInput, {
@@ -1629,11 +1785,16 @@ function useStubValuePreview(id, schemaType) {
1629
1785
  };
1630
1786
  }
1631
1787
 
1788
+ function PreviewPlaceholder() {
1789
+ /* @__PURE__ */
1790
+ return jsx(SanityDefaultPreview, {
1791
+ isPlaceholder: !0
1792
+ });
1793
+ }
1794
+
1632
1795
  function StubPreview({id: id, schemaType: schemaType}) {
1633
1796
  const {value: value, preview: preview} = useStubValuePreview(id, schemaType);
1634
- return preview.isLoading ? /* @__PURE__ */ jsx(SanityDefaultPreview, {
1635
- isPlaceholder: !0
1636
- }) : /* @__PURE__ */ jsx(Preview, {
1797
+ return preview.isLoading ? /* @__PURE__ */ jsx(PreviewPlaceholder, {}) : /* @__PURE__ */ jsx(Preview, {
1637
1798
  layout: "default",
1638
1799
  schemaType: schemaType,
1639
1800
  skipVisibilityCheck: !0,
@@ -1866,14 +2027,87 @@ function ParamsForm({decls: decls, values: values, onChange: onChange}) {
1866
2027
  });
1867
2028
  }
1868
2029
 
1869
- function useClosableToast() {
2030
+ const TOAST_ID = {
2031
+ abort: "workflow-abort",
2032
+ detailsCopy: "workflow-details-copy",
2033
+ documentCreate: "workflow-document-create",
2034
+ documentSave: "workflow-document-save",
2035
+ effectResolve: "workflow-effect-resolve",
2036
+ effectsDrain: "workflow-effects-drain",
2037
+ effectsIncomplete: "workflow-effects-incomplete",
2038
+ orphanSettle: "workflow-orphan-settle",
2039
+ start: "workflow-start"
2040
+ };
2041
+
2042
+ function instanceToastId(gesture, instanceId) {
2043
+ return `workflow-${gesture}:${instanceId}`;
2044
+ }
2045
+
2046
+ function actionFireToastId(args) {
2047
+ return `workflow-action-fire:${args.instanceId}:${args.activity}:${args.action}`;
2048
+ }
2049
+
2050
+ const REASON_TOAST_DURATION = 2e4, DISMISS_SENTINEL_DURATION = .01;
2051
+
2052
+ function carriesReason(params) {
2053
+ return params.description !== void 0 && params.status !== "info";
2054
+ }
2055
+
2056
+ function withConvention(params) {
2057
+ return {
2058
+ ...params,
2059
+ closable: !0,
2060
+ ...carriesReason(params) ? {
2061
+ duration: REASON_TOAST_DURATION
2062
+ } : {}
2063
+ };
2064
+ }
2065
+
2066
+ function useWorkflowToast() {
1870
2067
  const toast = useToast();
1871
2068
  return useMemo(() => ({
1872
- ...toast,
1873
- push: params => toast.push({
1874
- ...params,
1875
- closable: !0
1876
- })
2069
+ push: params => {
2070
+ toast.push(withConvention(params));
2071
+ },
2072
+ dismiss: id => {
2073
+ toast.push({
2074
+ id: id,
2075
+ duration: DISMISS_SENTINEL_DURATION
2076
+ });
2077
+ }
2078
+ }), [ toast ]);
2079
+ }
2080
+
2081
+ const COMMITTED_INCOMPLETE_TITLE = "Saved, but its follow-up didn’t run";
2082
+
2083
+ function rejectionToast(reading, titles) {
2084
+ return reading.kind === "committed-incomplete" ? {
2085
+ id: TOAST_ID.effectsIncomplete,
2086
+ status: "warning",
2087
+ title: COMMITTED_INCOMPLETE_TITLE,
2088
+ description: reading.message
2089
+ } : reading.kind === "refusal" ? {
2090
+ id: titles.id,
2091
+ status: "warning",
2092
+ title: titles.refused,
2093
+ description: reading.message
2094
+ } : {
2095
+ id: titles.id,
2096
+ status: "error",
2097
+ title: titles.failed,
2098
+ description: reading.message
2099
+ };
2100
+ }
2101
+
2102
+ function useRejectionReport() {
2103
+ const toast = useWorkflowToast();
2104
+ return useMemo(() => ({
2105
+ rejected: args => {
2106
+ const reading = readRejection(args.err);
2107
+ reading.kind !== "refusal" && console.error(`[workflow-studio-plugin] ${args.context} rejected:`, args.err),
2108
+ toast.push(rejectionToast(reading, args));
2109
+ },
2110
+ dismiss: toast.dismiss
1877
2111
  }), [ toast ]);
1878
2112
  }
1879
2113
 
@@ -1896,10 +2130,21 @@ function useActionClusterPending() {
1896
2130
  }
1897
2131
 
1898
2132
  function useFireAction(args) {
1899
- const {instanceId: instanceId, activity: activity, action: action, label: label, surface: surface, viaMenu: viaMenu} = args, {fireActionFor: fireActionFor} = useWorkflowContext(), telemetry = useWorkflowTelemetry(), toast = useClosableToast(), cluster = useActionClusterLock(), [localPending, setLocalPending] = useState(!1), pending = localPending || cluster?.pending === !0;
2133
+ const {instanceId: instanceId, activity: activity, action: action, label: label, surface: surface, placement: placement, viaMenu: viaMenu} = args, {fireActionFor: fireActionFor} = useWorkflowContext(), telemetry = useWorkflowTelemetry(), report = useRejectionReport(), cluster = useActionClusterLock(), [localPending, setLocalPending] = useState(!1), pending = localPending || cluster?.pending === !0, toastId = actionFireToastId({
2134
+ instanceId: instanceId,
2135
+ activity: activity,
2136
+ action: action
2137
+ });
1900
2138
  return {
1901
2139
  fire: useCallback(async params => {
1902
2140
  if (pending) return !1;
2141
+ const log = success => telemetry.log(WorkflowActionControlUsed, {
2142
+ instanceId: instanceId,
2143
+ surface: surface,
2144
+ placement: placement,
2145
+ viaMenu: viaMenu,
2146
+ success: success
2147
+ });
1903
2148
  setLocalPending(!0), cluster?.onFireChange(!0);
1904
2149
  try {
1905
2150
  return await fireActionFor(instanceId, {
@@ -1908,31 +2153,19 @@ function useFireAction(args) {
1908
2153
  ...params && Object.keys(params).length > 0 ? {
1909
2154
  params: params
1910
2155
  } : {}
1911
- }), toast.push({
1912
- status: "success",
1913
- title: `${label} done`
1914
- }), telemetry.log(WorkflowActionControlUsed, {
1915
- instanceId: instanceId,
1916
- surface: surface,
1917
- viaMenu: viaMenu,
1918
- success: !0
1919
- }), !0;
2156
+ }), report.dismiss(toastId), log(!0), !0;
1920
2157
  } catch (err) {
1921
- return console.error(`[workflow-studio-plugin] firing "${action}" on "${activity}" failed:`, err),
1922
- toast.push({
1923
- status: "error",
1924
- title: `${label} failed`,
1925
- description: describeError(err)
1926
- }), telemetry.log(WorkflowActionControlUsed, {
1927
- instanceId: instanceId,
1928
- surface: surface,
1929
- viaMenu: viaMenu,
1930
- success: !1
1931
- }), !1;
2158
+ return report.rejected({
2159
+ err: err,
2160
+ context: `firing "${action}" on "${activity}"`,
2161
+ id: toastId,
2162
+ refused: `“${label}” isn’t available right now`,
2163
+ failed: `Failed to complete “${label}”`
2164
+ }), log(!1), !1;
1932
2165
  } finally {
1933
2166
  setLocalPending(!1), cluster?.onFireChange(!1);
1934
2167
  }
1935
- }, [ fireActionFor, instanceId, activity, action, label, pending, toast, cluster, telemetry, surface, viaMenu ]),
2168
+ }, [ fireActionFor, instanceId, activity, action, label, pending, report, toastId, cluster, telemetry, surface, placement, viaMenu ]),
1936
2169
  pending: pending
1937
2170
  };
1938
2171
  }
@@ -1973,13 +2206,14 @@ function RowClickShield({active: active, children: children}) {
1973
2206
  });
1974
2207
  }
1975
2208
 
1976
- function FireButton({instanceId: instanceId, activity: activity, action: action, label: label, surface: surface, mode: mode = "default", chrome: chrome, tone: tone = "default", icon: icon}) {
2209
+ function FireButton({instanceId: instanceId, activity: activity, action: action, label: label, surface: surface, placement: placement, mode: mode = "default", chrome: chrome, tone: tone = "default", icon: icon}) {
1977
2210
  const {fire: fire, pending: pending} = useFireAction({
1978
2211
  instanceId: instanceId,
1979
2212
  activity: activity,
1980
2213
  action: action,
1981
2214
  label: label,
1982
2215
  surface: surface,
2216
+ placement: placement,
1983
2217
  viaMenu: !1
1984
2218
  }), handleClick = e => {
1985
2219
  chrome?.inButtonCard === !0 && e.stopPropagation(), !pending && fire();
@@ -2001,7 +2235,7 @@ function FireButton({instanceId: instanceId, activity: activity, action: action,
2001
2235
  });
2002
2236
  }
2003
2237
 
2004
- function ActivityActionRow({actionEval: actionEval, instanceId: instanceId, activity: activity, surface: surface, chrome: chrome}) {
2238
+ function ActivityActionRow({actionEval: actionEval, instanceId: instanceId, activity: activity, surface: surface, placement: placement, chrome: chrome}) {
2005
2239
  const rowKind = actionRowKind(actionEval);
2006
2240
  return rowKind.kind === "disabled" ? /* @__PURE__ */ jsx(DisabledActionButton, {
2007
2241
  actionEval: actionEval,
@@ -2012,12 +2246,14 @@ function ActivityActionRow({actionEval: actionEval, instanceId: instanceId, acti
2012
2246
  instanceId: instanceId,
2013
2247
  activity: activity,
2014
2248
  chrome: chrome,
2249
+ placement: placement,
2015
2250
  surface: surface
2016
2251
  }) : /* @__PURE__ */ jsx(ParamsActionButton, {
2017
2252
  actionEval: actionEval,
2018
2253
  instanceId: instanceId,
2019
2254
  activity: activity,
2020
2255
  chrome: chrome,
2256
+ placement: placement,
2021
2257
  surface: surface
2022
2258
  });
2023
2259
  }
@@ -2043,7 +2279,7 @@ function DisabledActionButton({actionEval: actionEval, activity: activity, chrom
2043
2279
  }) : button;
2044
2280
  }
2045
2281
 
2046
- function PlainActionButton({actionEval: actionEval, instanceId: instanceId, activity: activity, surface: surface, chrome: chrome}) {
2282
+ function PlainActionButton({actionEval: actionEval, instanceId: instanceId, activity: activity, surface: surface, placement: placement, chrome: chrome}) {
2047
2283
  const {action: action} = actionEval, label = actionLabel(action), btn = actionButtonFace({
2048
2284
  actionEval: actionEval,
2049
2285
  activityName: activity
@@ -2055,6 +2291,7 @@ function PlainActionButton({actionEval: actionEval, instanceId: instanceId, acti
2055
2291
  mode: btn.mode,
2056
2292
  activity: activity,
2057
2293
  chrome: chrome,
2294
+ placement: placement,
2058
2295
  surface: surface,
2059
2296
  tone: btn.tone
2060
2297
  });
@@ -2064,13 +2301,14 @@ function PlainActionButton({actionEval: actionEval, instanceId: instanceId, acti
2064
2301
  }) : button;
2065
2302
  }
2066
2303
 
2067
- function ParamsActionDialog({actionEval: actionEval, instanceId: instanceId, activity: activity, surface: surface, viaMenu: viaMenu, onClose: onClose}) {
2304
+ function ParamsActionDialog({actionEval: actionEval, instanceId: instanceId, activity: activity, surface: surface, placement: placement, viaMenu: viaMenu, onClose: onClose}) {
2068
2305
  const {action: action} = actionEval, label = actionLabel(action), decls = action.params ?? [], [values, setValues] = useState({}), {fire: fire, pending: pending} = useFireAction({
2069
2306
  instanceId: instanceId,
2070
2307
  activity: activity,
2071
2308
  action: action.name,
2072
2309
  label: label,
2073
2310
  surface: surface,
2311
+ placement: placement,
2074
2312
  viaMenu: viaMenu
2075
2313
  }), built = buildParams(decls, values), confirm = async () => {
2076
2314
  await fire(built.params) && onClose();
@@ -2126,7 +2364,7 @@ function ParamsActionDialog({actionEval: actionEval, instanceId: instanceId, act
2126
2364
  });
2127
2365
  }
2128
2366
 
2129
- function ParamsActionButton({actionEval: actionEval, instanceId: instanceId, activity: activity, surface: surface, chrome: chrome}) {
2367
+ function ParamsActionButton({actionEval: actionEval, instanceId: instanceId, activity: activity, surface: surface, placement: placement, chrome: chrome}) {
2130
2368
  const [open, setOpen] = useState(!1), btn = actionButtonFace({
2131
2369
  actionEval: actionEval,
2132
2370
  activityName: activity
@@ -2152,6 +2390,7 @@ function ParamsActionButton({actionEval: actionEval, instanceId: instanceId, act
2152
2390
  activity: activity,
2153
2391
  instanceId: instanceId,
2154
2392
  onClose: () => setOpen(!1),
2393
+ placement: placement,
2155
2394
  surface: surface,
2156
2395
  viaMenu: !1
2157
2396
  })
@@ -2325,7 +2564,9 @@ function FieldInput$1({kind: kind, value: value, onChange: onChange, onEnter: on
2325
2564
  });
2326
2565
 
2327
2566
  case "date":
2567
+ case "dueDate":
2328
2568
  case "datetime":
2569
+ case "dueDatetime":
2329
2570
  /* @__PURE__ */
2330
2571
  return jsx(DateFieldInput, {
2331
2572
  kind: kind,
@@ -2371,22 +2612,76 @@ function FieldInput$1({kind: kind, value: value, onChange: onChange, onEnter: on
2371
2612
  }
2372
2613
  }
2373
2614
 
2374
- function LinkChip({hint: hint, children: children, as: as = "a", ...anchorProps}) {
2615
+ function useDelayedFlag(active, delayMs) {
2616
+ const [held, setHeld] = useState(!1);
2617
+ return useEffect(() => {
2618
+ if (!active) {
2619
+ setHeld(!1);
2620
+ return;
2621
+ }
2622
+ const timer = setTimeout(() => setHeld(!0), delayMs);
2623
+ return () => clearTimeout(timer);
2624
+ }, [ active, delayMs ]), held && active;
2625
+ }
2626
+
2627
+ function isCompact(layout) {
2628
+ return layout === "inline" || layout === "row";
2629
+ }
2630
+
2631
+ function docFaceChrome(args) {
2632
+ const {layout: layout, state: state} = args, compact = isCompact(layout);
2633
+ switch (state.kind) {
2634
+ case "linked":
2635
+ return {
2636
+ bareId: state.bareId,
2637
+ selfInset: !compact
2638
+ };
2639
+
2640
+ case "foreign":
2641
+ return {};
2642
+
2643
+ case "missing":
2644
+ return {
2645
+ tone: "caution"
2646
+ };
2647
+
2648
+ case "unopenable":
2649
+ return {};
2650
+
2651
+ case "pending":
2652
+ return compact ? {} : {
2653
+ selfInset: !0
2654
+ };
2655
+
2656
+ case "unresolvable":
2657
+ return {};
2658
+ }
2659
+ }
2660
+
2661
+ function chipPadding(fill) {
2662
+ return fill ? 3 : 2;
2663
+ }
2664
+
2665
+ function LinkChip({hint: hint, children: children, as: as = "a", fill: fill = !1, ...anchorProps}) {
2375
2666
  /* @__PURE__ */
2376
2667
  return jsx(HoverHint, {
2668
+ fill: fill,
2377
2669
  text: hint,
2378
2670
  children: /* @__PURE__ */ jsx(Card, {
2379
2671
  __unstable_focusRing: !0,
2380
2672
  as: as,
2381
2673
  "data-as": "a",
2382
- padding: 2,
2674
+ padding: chipPadding(fill),
2383
2675
  radius: 3,
2384
2676
  style: {
2385
2677
  alignItems: "center",
2386
2678
  color: "inherit",
2387
2679
  display: "flex",
2388
2680
  minWidth: 0,
2389
- textDecoration: "none"
2681
+ textDecoration: "none",
2682
+ ...fill ? {
2683
+ width: "100%"
2684
+ } : {}
2390
2685
  },
2391
2686
  tone: "inherit",
2392
2687
  ...anchorProps,
@@ -2505,7 +2800,7 @@ function DocRefFace({gdr: gdr}) {
2505
2800
  });
2506
2801
  }
2507
2802
 
2508
- function ForeignRefNotice({bareId: bareId, resource: resource}) {
2803
+ function foreignNotice(bareId, resource) {
2509
2804
  const location = resource.type === "dataset" ? `another dataset (${resource.id})` : `${resource.type} (${resource.id})`;
2510
2805
  /* @__PURE__ */
2511
2806
  return jsxs(Text, {
@@ -2515,44 +2810,22 @@ function ForeignRefNotice({bareId: bareId, resource: resource}) {
2515
2810
  });
2516
2811
  }
2517
2812
 
2518
- function MissingDocNotice({bareId: bareId, layout: layout}) {
2519
- return layout === "inline" ?
2520
- /* @__PURE__ */ jsx(Box, {
2521
- padding: 2,
2522
- children: /* @__PURE__ */ jsxs(Flex, {
2523
- align: "center",
2524
- gap: 2,
2525
- children: [
2526
- /* @__PURE__ */ jsx(Text, {
2527
- muted: !0,
2528
- size: 1,
2529
- children: /* @__PURE__ */ jsx(WarningOutlineIcon, {})
2530
- }),
2531
- /* @__PURE__ */ jsx(Text, {
2532
- muted: !0,
2533
- size: 1,
2534
- children: "Document unavailable"
2535
- }) ]
2536
- })
2537
- }) : /* @__PURE__ */ jsx(Card, {
2538
- border: !0,
2539
- padding: 2,
2540
- radius: 3,
2541
- tone: "caution",
2542
- children: /* @__PURE__ */ jsxs(Flex, {
2543
- align: "center",
2544
- gap: 2,
2545
- children: [
2546
- /* @__PURE__ */ jsx(Text, {
2547
- size: 1,
2548
- children: /* @__PURE__ */ jsx(WarningOutlineIcon, {})
2549
- }),
2550
- /* @__PURE__ */ jsxs(Text, {
2551
- muted: !0,
2552
- size: 1,
2553
- children: [ "Document unavailable — ", bareId ]
2554
- }) ]
2555
- })
2813
+ function missingNotice(bareId, layout) {
2814
+ /* @__PURE__ */
2815
+ return jsxs(Flex, {
2816
+ align: "center",
2817
+ gap: 2,
2818
+ children: [
2819
+ /* @__PURE__ */ jsx(Text, {
2820
+ muted: !0,
2821
+ size: 1,
2822
+ children: /* @__PURE__ */ jsx(WarningOutlineIcon, {})
2823
+ }),
2824
+ /* @__PURE__ */ jsx(Text, {
2825
+ muted: !0,
2826
+ size: 1,
2827
+ children: isCompact(layout) ? "Document unavailable" : `Document unavailable — ${bareId}`
2828
+ }) ]
2556
2829
  });
2557
2830
  }
2558
2831
 
@@ -2569,6 +2842,18 @@ function renderTypeIcon(icon) {
2569
2842
  return typeof icon == "function" ? createElement(icon) : isValidElement(icon) ? icon : /* @__PURE__ */ jsx(DocumentIcon, {});
2570
2843
  }
2571
2844
 
2845
+ function TitleSkeleton() {
2846
+ /* @__PURE__ */
2847
+ return jsx(TextSkeleton, {
2848
+ animated: !0,
2849
+ radius: 1,
2850
+ size: 1,
2851
+ style: {
2852
+ width: 96
2853
+ }
2854
+ });
2855
+ }
2856
+
2572
2857
  function InlineChipFace({bareId: bareId, schemaType: schemaType}) {
2573
2858
  const {preview: preview} = useStubValuePreview(bareId, schemaType);
2574
2859
  /* @__PURE__ */
@@ -2579,14 +2864,7 @@ function InlineChipFace({bareId: bareId, schemaType: schemaType}) {
2579
2864
  /* @__PURE__ */ jsx(Text, {
2580
2865
  size: 1,
2581
2866
  children: renderTypeIcon(schemaType.icon)
2582
- }), preview.isLoading ? /* @__PURE__ */ jsx(TextSkeleton, {
2583
- animated: !0,
2584
- radius: 1,
2585
- size: 1,
2586
- style: {
2587
- width: 96
2588
- }
2589
- }) : /* @__PURE__ */ jsx(Text, {
2867
+ }), preview.isLoading ? /* @__PURE__ */ jsx(TitleSkeleton, {}) : /* @__PURE__ */ jsx(Text, {
2590
2868
  size: 1,
2591
2869
  textOverflow: "ellipsis",
2592
2870
  weight: "medium",
@@ -2597,8 +2875,59 @@ function InlineChipFace({bareId: bareId, schemaType: schemaType}) {
2597
2875
  });
2598
2876
  }
2599
2877
 
2600
- function LinkedDocPreview({bareId: bareId, layout: layout, schemaType: schemaType}) {
2601
- const EditIntentLink = useMemo(() => function(linkProps) {
2878
+ const NOTICE_PADDING = 2;
2879
+
2880
+ function CompactDocRef({face: face, fill: fill, link: link, onClick: onClick}) {
2881
+ return link === void 0 ? /* @__PURE__ */ jsx(Box, {
2882
+ padding: chipPadding(fill),
2883
+ style: fill ? {
2884
+ width: "100%"
2885
+ } : {},
2886
+ children: face.content
2887
+ }) : /* @__PURE__ */ jsx(LinkChip, {
2888
+ as: link,
2889
+ fill: fill,
2890
+ hint: "Open document",
2891
+ onClick: onClick,
2892
+ children: face.content
2893
+ });
2894
+ }
2895
+
2896
+ const PENDING_FACE_MAX_WAIT_MS = 4e3;
2897
+
2898
+ function PendingDocFace({bareId: bareId, layout: layout}) {
2899
+ const expired = useDelayedFlag(!0, PENDING_FACE_MAX_WAIT_MS), compact = isCompact(layout);
2900
+ if (expired) {
2901
+ const id = /* @__PURE__ */ jsx(Text, {
2902
+ muted: !0,
2903
+ size: 1,
2904
+ children: bareId
2905
+ });
2906
+ return compact ? id : /* @__PURE__ */ jsx(Box, {
2907
+ padding: NOTICE_PADDING,
2908
+ children: id
2909
+ });
2910
+ }
2911
+ return compact ?
2912
+ /* @__PURE__ */ jsxs(Flex, {
2913
+ align: "center",
2914
+ gap: 2,
2915
+ children: [
2916
+ /* @__PURE__ */ jsx(Text, {
2917
+ muted: !0,
2918
+ size: 1,
2919
+ children: /* @__PURE__ */ jsx(DocumentIcon, {})
2920
+ }),
2921
+ /* @__PURE__ */ jsx(TitleSkeleton, {}) ]
2922
+ }) : /* @__PURE__ */ jsx(PreviewPlaceholder, {});
2923
+ }
2924
+
2925
+ function DocRefShell({face: face, layout: layout, source: source}) {
2926
+ const telemetry = useWorkflowTelemetry(), {bareId: bareId} = face, handleClick = e => {
2927
+ e.stopPropagation(), telemetry.log(WorkflowDocumentLinkClicked, {
2928
+ source: source
2929
+ });
2930
+ }, EditIntentLink = useMemo(() => bareId === void 0 ? void 0 : function(linkProps) {
2602
2931
  /* @__PURE__ */
2603
2932
  return jsx(IntentLink, {
2604
2933
  ...linkProps,
@@ -2608,58 +2937,52 @@ function LinkedDocPreview({bareId: bareId, layout: layout, schemaType: schemaTyp
2608
2937
  }
2609
2938
  });
2610
2939
  }, [ bareId ]);
2611
- return layout === "inline" ? /* @__PURE__ */ jsx(LinkChip, {
2612
- as: EditIntentLink,
2613
- hint: "Open document",
2614
- onClick: e => e.stopPropagation(),
2615
- children: /* @__PURE__ */ jsx(InlineChipFace, {
2616
- bareId: bareId,
2617
- schemaType: schemaType
2618
- })
2619
- }) : /* @__PURE__ */ jsx(Card, {
2940
+ if (isCompact(layout)) /* @__PURE__ */
2941
+ return jsx(CompactDocRef, {
2942
+ face: face,
2943
+ fill: layout === "row",
2944
+ link: EditIntentLink,
2945
+ onClick: handleClick
2946
+ });
2947
+ const padding = face.selfInset === !0 ? 0 : NOTICE_PADDING;
2948
+ /* @__PURE__ */
2949
+ return jsx(Card, {
2620
2950
  __unstable_focusRing: !0,
2621
- as: EditIntentLink,
2622
- border: !0,
2623
- "data-as": "a",
2624
- onClick: e => e.stopPropagation(),
2625
- padding: 1,
2951
+ border: layout === "default",
2952
+ padding: padding,
2626
2953
  radius: 3,
2627
- style: {
2628
- color: "inherit",
2629
- textDecoration: "none",
2630
- display: "block"
2954
+ tone: face.tone ?? (layout === "bare" ? "inherit" : "default"),
2955
+ ...EditIntentLink === void 0 ? {} : {
2956
+ as: EditIntentLink,
2957
+ "data-as": "a",
2958
+ onClick: handleClick,
2959
+ style: {
2960
+ color: "inherit",
2961
+ textDecoration: "none",
2962
+ display: "block"
2963
+ }
2631
2964
  },
2632
- children: /* @__PURE__ */ jsx(StubPreview, {
2633
- id: bareId,
2634
- schemaType: schemaType
2635
- })
2965
+ children: face.content
2636
2966
  });
2637
2967
  }
2638
2968
 
2639
- function DocPreviewLink({gdr: gdr, layout: layout = "default"}) {
2640
- const state = useDocLink(gdr);
2969
+ function faceContent(args) {
2970
+ const {gdr: gdr, layout: layout, state: state} = args, compact = isCompact(layout);
2641
2971
  switch (state.kind) {
2642
2972
  case "linked":
2643
- /* @__PURE__ */
2644
- return jsx(LinkedDocPreview, {
2973
+ return compact ? /* @__PURE__ */ jsx(InlineChipFace, {
2645
2974
  bareId: state.bareId,
2646
- layout: layout,
2975
+ schemaType: state.schemaType
2976
+ }) : /* @__PURE__ */ jsx(StubPreview, {
2977
+ id: state.bareId,
2647
2978
  schemaType: state.schemaType
2648
2979
  });
2649
2980
 
2650
2981
  case "foreign":
2651
- /* @__PURE__ */
2652
- return jsx(ForeignRefNotice, {
2653
- bareId: state.bareId,
2654
- resource: state.resource
2655
- });
2982
+ return foreignNotice(state.bareId, state.resource);
2656
2983
 
2657
2984
  case "missing":
2658
- /* @__PURE__ */
2659
- return jsx(MissingDocNotice, {
2660
- bareId: state.bareId,
2661
- layout: layout
2662
- });
2985
+ return missingNotice(state.bareId, layout);
2663
2986
 
2664
2987
  case "unopenable":
2665
2988
  /* @__PURE__ */
@@ -2670,10 +2993,9 @@ function DocPreviewLink({gdr: gdr, layout: layout = "default"}) {
2670
2993
 
2671
2994
  case "pending":
2672
2995
  /* @__PURE__ */
2673
- return jsx(Text, {
2674
- muted: !0,
2675
- size: 1,
2676
- children: state.bareId
2996
+ return jsx(PendingDocFace, {
2997
+ bareId: state.bareId,
2998
+ layout: layout
2677
2999
  });
2678
3000
 
2679
3001
  case "unresolvable":
@@ -2686,6 +3008,27 @@ function DocPreviewLink({gdr: gdr, layout: layout = "default"}) {
2686
3008
  }
2687
3009
  }
2688
3010
 
3011
+ function docFace(args) {
3012
+ return {
3013
+ ...docFaceChrome(args),
3014
+ content: faceContent(args)
3015
+ };
3016
+ }
3017
+
3018
+ function DocPreviewLink({gdr: gdr, layout: layout = "default", source: source}) {
3019
+ const state = useDocLink(gdr);
3020
+ /* @__PURE__ */
3021
+ return jsx(DocRefShell, {
3022
+ face: docFace({
3023
+ gdr: gdr,
3024
+ layout: layout,
3025
+ state: state
3026
+ }),
3027
+ layout: layout,
3028
+ source: source
3029
+ });
3030
+ }
3031
+
2689
3032
  function ReleaseLink({releaseName: releaseName, label: label}) {
2690
3033
  const {basePath: basePath} = useWorkspace(), href = `${basePath === "/" ? "" : basePath}/releases/${releaseName}`;
2691
3034
  /* @__PURE__ */
@@ -2744,7 +3087,8 @@ function renderTextValue(field) {
2744
3087
 
2745
3088
  function renderSingleDocRef(field) {
2746
3089
  return field.value ? /* @__PURE__ */ jsx(DocPreviewLink, {
2747
- gdr: field.value
3090
+ gdr: field.value,
3091
+ source: "field-value"
2748
3092
  }) : /* @__PURE__ */ jsx(Empty, {});
2749
3093
  }
2750
3094
 
@@ -2766,12 +3110,15 @@ const fieldValueRenderer = {
2766
3110
  children: formatBoolean(field.value)
2767
3111
  }),
2768
3112
  date: renderTextValue,
3113
+ dueDate: renderTextValue,
2769
3114
  datetime: renderTextValue,
3115
+ dueDatetime: renderTextValue,
2770
3116
  "doc.ref": renderSingleDocRef,
2771
3117
  "doc.refs": field => field.value.length > 0 ? /* @__PURE__ */ jsx(Stack, {
2772
3118
  gap: 2,
2773
3119
  children: field.value.map(ref => /* @__PURE__ */ jsx(DocPreviewLink, {
2774
- gdr: ref
3120
+ gdr: ref,
3121
+ source: "field-value"
2775
3122
  }, ref.id))
2776
3123
  }) : /* @__PURE__ */ jsx(Empty, {}),
2777
3124
  number: renderTextValue,
@@ -2993,6 +3340,27 @@ function ReadOnlyField({entry: entry}) {
2993
3340
  });
2994
3341
  }
2995
3342
 
3343
+ function useEditField(surface) {
3344
+ const {editFieldFor: editFieldFor} = useWorkflowContext(), telemetry = useWorkflowTelemetry();
3345
+ return useCallback(async ({instanceId: instanceId, field: field, ...change}) => {
3346
+ const log = success => telemetry.log(WorkflowFieldControlUsed, {
3347
+ instanceId: instanceId,
3348
+ surface: surface,
3349
+ fieldKind: field.type,
3350
+ success: success
3351
+ });
3352
+ try {
3353
+ await editFieldFor(instanceId, {
3354
+ ...change,
3355
+ target: editFieldTarget(field)
3356
+ });
3357
+ } catch (err) {
3358
+ throw log(!1), err;
3359
+ }
3360
+ log(!0);
3361
+ }, [ editFieldFor, surface, telemetry ]);
3362
+ }
3363
+
2996
3364
  function sameValue(a, b) {
2997
3365
  return (a ?? void 0) === (b ?? void 0);
2998
3366
  }
@@ -3029,11 +3397,12 @@ function useFieldDraft(args) {
3029
3397
  };
3030
3398
  }
3031
3399
 
3032
- function EditableFieldControl({instanceId: instanceId, field: field}) {
3033
- const {editFieldFor: editFieldFor, previewFieldFor: previewFieldFor, discardFieldPreviewFor: discardFieldPreviewFor} = useWorkflowContext(), selfActor = useSelfActor(), held = useHeldWorkflowEntry(instanceId), entry = held ? resolveFieldEntry(held.instance, field) : void 0, evaluation = held?.evaluation, target = editFieldTarget(field), consequence = fieldConsequence(evaluation, field.name), advanceTo = advanceTargetTitle(evaluation, field.name);
3400
+ function EditableFieldControl({instanceId: instanceId, field: field, surface: surface}) {
3401
+ const {previewFieldFor: previewFieldFor, discardFieldPreviewFor: discardFieldPreviewFor} = useWorkflowContext(), editField = useEditField(surface), selfActor = useSelfActor(), held = useHeldWorkflowEntry(instanceId), entry = held ? resolveFieldEntry(held.instance, field) : void 0, evaluation = held?.evaluation, target = editFieldTarget(field), consequence = fieldConsequence(evaluation, field.name), advanceTo = advanceTargetTitle(evaluation, field.name);
3034
3402
  /* @__PURE__ */
3035
3403
  return jsx(EditableField, {
3036
3404
  field: field,
3405
+ instanceId: instanceId,
3037
3406
  ...entry === void 0 ? {} : {
3038
3407
  entry: entry
3039
3408
  },
@@ -3046,30 +3415,33 @@ function EditableFieldControl({instanceId: instanceId, field: field}) {
3046
3415
  ...advanceTo === void 0 ? {} : {
3047
3416
  advanceTo: advanceTo
3048
3417
  },
3049
- onSave: value => editFieldFor(instanceId, {
3050
- target: target,
3418
+ onSave: value => editField({
3419
+ instanceId: instanceId,
3420
+ field: field,
3051
3421
  mode: "set",
3052
3422
  value: value
3053
- }).then(() => {}),
3423
+ }),
3054
3424
  onPreview: value => previewFieldFor(instanceId, {
3055
3425
  target: target,
3056
3426
  mode: "set",
3057
3427
  value: value
3058
3428
  }),
3059
3429
  onDiscardPreview: () => discardFieldPreviewFor(instanceId, target),
3060
- onUnset: () => editFieldFor(instanceId, {
3061
- target: target,
3430
+ onUnset: () => editField({
3431
+ instanceId: instanceId,
3432
+ field: field,
3062
3433
  mode: "unset"
3063
- }).then(() => {}),
3064
- onAppend: body => editFieldFor(instanceId, {
3065
- target: target,
3434
+ }),
3435
+ onAppend: body => editField({
3436
+ instanceId: instanceId,
3437
+ field: field,
3066
3438
  mode: "append",
3067
3439
  value: noteRow({
3068
3440
  body: body,
3069
3441
  actor: selfActor,
3070
3442
  at: /* @__PURE__ */ (new Date).toISOString()
3071
3443
  })
3072
- }).then(() => {})
3444
+ })
3073
3445
  });
3074
3446
  }
3075
3447
 
@@ -3097,28 +3469,34 @@ function EditableValueButton({children: children, hint: hint, hintDisabled: hint
3097
3469
  });
3098
3470
  }
3099
3471
 
3100
- function useSaveFailureToast() {
3101
- const toast = useClosableToast();
3102
- return err => {
3103
- console.error("[workflow-studio-plugin] field save failed:", err), toast.push({
3104
- status: "error",
3105
- title: "Saving failed",
3106
- description: describeError(err)
3107
- });
3108
- };
3472
+ function useFieldSaveReport(instanceId) {
3473
+ const report = useRejectionReport();
3474
+ return useMemo(() => {
3475
+ const id = instanceToastId("field-save", instanceId);
3476
+ return {
3477
+ rejected: err => report.rejected({
3478
+ err: err,
3479
+ context: "field save",
3480
+ id: id,
3481
+ refused: "This field can’t be edited right now",
3482
+ failed: "Failed to save the field"
3483
+ }),
3484
+ dismiss: () => report.dismiss(id)
3485
+ };
3486
+ }, [ report, instanceId ]);
3109
3487
  }
3110
3488
 
3111
- function useSaveField(args = {}) {
3112
- const reportFailure = useSaveFailureToast(), [saving, setSaving] = useState(!1);
3489
+ function useSaveField(args) {
3490
+ const report = useFieldSaveReport(args.instanceId), [saving, setSaving] = useState(!1);
3113
3491
  return {
3114
3492
  saving: saving,
3115
3493
  save: async commit => {
3116
3494
  if (!saving) {
3117
3495
  setSaving(!0);
3118
3496
  try {
3119
- await commit(), args.onSaved?.();
3497
+ await commit(), report.dismiss(), args.onSaved?.();
3120
3498
  } catch (err) {
3121
- reportFailure(err);
3499
+ report.rejected(err);
3122
3500
  } finally {
3123
3501
  setSaving(!1);
3124
3502
  }
@@ -3128,7 +3506,9 @@ function useSaveField(args = {}) {
3128
3506
  }
3129
3507
 
3130
3508
  function useActorPick(args) {
3131
- const {current: current, onSave: onSave, onUnset: onUnset} = args, {saving: saving, save: save} = useSaveField();
3509
+ const {current: current, onSave: onSave, onUnset: onUnset} = args, {saving: saving, save: save} = useSaveField({
3510
+ instanceId: args.instanceId
3511
+ });
3132
3512
  return {
3133
3513
  saving: saving,
3134
3514
  pick: member => {
@@ -3137,9 +3517,10 @@ function useActorPick(args) {
3137
3517
  };
3138
3518
  }
3139
3519
 
3140
- function ActorField({field: field, onSave: onSave, onUnset: onUnset}) {
3520
+ function ActorField({field: field, instanceId: instanceId, onSave: onSave, onUnset: onUnset}) {
3141
3521
  const [open, setOpen] = useState(!1), cur = isActorShape(field.value) ? field.value : null, {pick: pick} = useActorPick({
3142
3522
  current: cur,
3523
+ instanceId: instanceId,
3143
3524
  onSave: onSave,
3144
3525
  onUnset: onUnset
3145
3526
  }), pickAndClose = member => {
@@ -3174,7 +3555,9 @@ function ActorField({field: field, onSave: onSave, onUnset: onUnset}) {
3174
3555
  }
3175
3556
 
3176
3557
  function useAssigneePick(args) {
3177
- const {current: current, onSave: onSave, onUnset: onUnset} = args, {saving: saving, save: save} = useSaveField();
3558
+ const {current: current, onSave: onSave, onUnset: onUnset} = args, {saving: saving, save: save} = useSaveField({
3559
+ instanceId: args.instanceId
3560
+ });
3178
3561
  return {
3179
3562
  saving: saving,
3180
3563
  pick: assignee => {
@@ -3189,9 +3572,10 @@ function useAssigneePick(args) {
3189
3572
  };
3190
3573
  }
3191
3574
 
3192
- function AssigneeField({field: field, onSave: onSave, onUnset: onUnset}) {
3575
+ function AssigneeField({field: field, instanceId: instanceId, onSave: onSave, onUnset: onUnset}) {
3193
3576
  const [open, setOpen] = useState(!1), cur = isAssigneeShape(field.value) ? field.value : null, {pick: pick} = useAssigneePick({
3194
3577
  current: cur,
3578
+ instanceId: instanceId,
3195
3579
  onSave: onSave,
3196
3580
  onUnset: onUnset
3197
3581
  }), pickAndClose = assignee => {
@@ -3231,8 +3615,10 @@ function arrayRowsOf(value) {
3231
3615
  return Array.isArray(value) ? value.filter(row => typeof row == "object" && row !== null) : [];
3232
3616
  }
3233
3617
 
3234
- function NotesField({field: field, onAppend: onAppend}) {
3235
- const [body, setBody] = useState(""), {saving: saving, save: save} = useSaveField(), rows = arrayRowsOf(field.value), trimmed = body.trim(), add = () => {
3618
+ function NotesField({field: field, instanceId: instanceId, onAppend: onAppend}) {
3619
+ const [body, setBody] = useState(""), {saving: saving, save: save} = useSaveField({
3620
+ instanceId: instanceId
3621
+ }), rows = arrayRowsOf(field.value), trimmed = body.trim(), add = () => {
3236
3622
  saving || trimmed === "" || (setBody(""), save(async () => {
3237
3623
  try {
3238
3624
  await onAppend(trimmed);
@@ -3273,11 +3659,13 @@ function NotesField({field: field, onAppend: onAppend}) {
3273
3659
  });
3274
3660
  }
3275
3661
 
3276
- function DateField({field: field, onSave: onSave, onUnset: onUnset}) {
3277
- const {save: save} = useSaveField();
3662
+ function DateField({field: field, kind: kind, instanceId: instanceId, onSave: onSave, onUnset: onUnset}) {
3663
+ const {save: save} = useSaveField({
3664
+ instanceId: instanceId
3665
+ });
3278
3666
  /* @__PURE__ */
3279
3667
  return jsx(DateFieldInput, {
3280
- kind: field.type === "datetime" ? "datetime" : "date",
3668
+ kind: kind,
3281
3669
  onChange: next => {
3282
3670
  save(() => next === null && onUnset !== void 0 ? onUnset() : onSave(next));
3283
3671
  },
@@ -3285,8 +3673,10 @@ function DateField({field: field, onSave: onSave, onUnset: onUnset}) {
3285
3673
  });
3286
3674
  }
3287
3675
 
3288
- function DocRefField({field: field, entry: entry, onSave: onSave, onUnset: onUnset}) {
3289
- const {save: save} = useSaveField(), value = isGdr(field.value) ? field.value : null, types = entry !== void 0 && isSingleDocRefEntry(entry) ? entry.types : void 0;
3676
+ function DocRefField({field: field, entry: entry, instanceId: instanceId, onSave: onSave, onUnset: onUnset}) {
3677
+ const {save: save} = useSaveField({
3678
+ instanceId: instanceId
3679
+ }), value = isGdr(field.value) ? field.value : null, types = entry !== void 0 && isSingleDocRefEntry(entry) ? entry.types : void 0;
3290
3680
  return field.editable ? /* @__PURE__ */ jsx(DocPicker, {
3291
3681
  onChange: ref => {
3292
3682
  save(() => ref === null && onUnset !== void 0 ? onUnset() : onSave(ref));
@@ -3301,8 +3691,10 @@ function DocRefField({field: field, entry: entry, onSave: onSave, onUnset: onUns
3301
3691
  });
3302
3692
  }
3303
3693
 
3304
- function BooleanSwitchField({field: field, onSave: onSave}) {
3305
- const {save: save} = useSaveField(), committed = field.value === !0;
3694
+ function BooleanSwitchField({field: field, instanceId: instanceId, onSave: onSave}) {
3695
+ const {save: save} = useSaveField({
3696
+ instanceId: instanceId
3697
+ }), committed = field.value === !0;
3306
3698
  /* @__PURE__ */
3307
3699
  return jsx(Flex, {
3308
3700
  align: "center",
@@ -3315,8 +3707,10 @@ function BooleanSwitchField({field: field, onSave: onSave}) {
3315
3707
  });
3316
3708
  }
3317
3709
 
3318
- function ChoiceField({field: field, options: options, onSave: onSave, onUnset: onUnset}) {
3319
- const {save: save} = useSaveField();
3710
+ function ChoiceField({field: field, instanceId: instanceId, options: options, onSave: onSave, onUnset: onUnset}) {
3711
+ const {save: save} = useSaveField({
3712
+ instanceId: instanceId
3713
+ });
3320
3714
  /* @__PURE__ */
3321
3715
  return jsx(ChoiceSelect, {
3322
3716
  onChange: value => {
@@ -3390,8 +3784,8 @@ function FieldEditRow({field: field, onSave: onSave, onCancel: onCancel, saving:
3390
3784
  });
3391
3785
  }
3392
3786
 
3393
- function GenericField({field: field, onSave: onSave, onPreview: onPreview, onDiscardPreview: onDiscardPreview}) {
3394
- const reportFailure = useSaveFailureToast(), canSave = value => scalarValidationIssue({
3787
+ function GenericField({field: field, onSave: onSave, instanceId: instanceId, onPreview: onPreview, onDiscardPreview: onDiscardPreview}) {
3788
+ const report = useFieldSaveReport(instanceId), canSave = value => scalarValidationIssue({
3395
3789
  kind: field.type,
3396
3790
  label: field.title ?? field.name,
3397
3791
  validation: field.validation,
@@ -3402,7 +3796,7 @@ function GenericField({field: field, onSave: onSave, onPreview: onPreview, onDis
3402
3796
  onPreview: onPreview,
3403
3797
  onDiscardPreview: onDiscardPreview,
3404
3798
  canSave: canSave,
3405
- onSaveFailure: reportFailure
3799
+ onSaveFailure: report.rejected
3406
3800
  }), validationIssue = scalarValidationIssue({
3407
3801
  kind: field.type,
3408
3802
  label: field.title ?? field.name,
@@ -3448,9 +3842,10 @@ function AdvanceHint({stageTitle: stageTitle2}) {
3448
3842
  });
3449
3843
  }
3450
3844
 
3451
- function arrayArm({field: field, entry: entry, onAppend: onAppend}) {
3845
+ function arrayArm({field: field, entry: entry, instanceId: instanceId, onAppend: onAppend}) {
3452
3846
  return field.editable && onAppend !== void 0 && entry !== void 0 && isNotesEntry(entry) ? /* @__PURE__ */ jsx(NotesField, {
3453
3847
  field: field,
3848
+ instanceId: instanceId,
3454
3849
  onAppend: onAppend
3455
3850
  }) : /* @__PURE__ */ jsx(ArrayValueRows, {
3456
3851
  rows: arrayRowsOf(field.value)
@@ -3458,7 +3853,7 @@ function arrayArm({field: field, entry: entry, onAppend: onAppend}) {
3458
3853
  }
3459
3854
 
3460
3855
  function fieldArm({arm: arm, entry: entry, onUnset: onUnset, onAppend: onAppend, onPreview: onPreview, onDiscardPreview: onDiscardPreview}) {
3461
- const {field: field} = arm;
3856
+ const {field: field, instanceId: instanceId} = arm;
3462
3857
  return field.type === "actor" ? /* @__PURE__ */ jsx(ActorField, {
3463
3858
  ...arm,
3464
3859
  onUnset: onUnset
@@ -3471,11 +3866,13 @@ function fieldArm({arm: arm, entry: entry, onUnset: onUnset, onAppend: onAppend,
3471
3866
  }) : field.type === "array" ? arrayArm({
3472
3867
  field: field,
3473
3868
  entry: entry,
3869
+ instanceId: instanceId,
3474
3870
  onAppend: onAppend
3475
3871
  }) : field.type === "boolean" && field.editable ? /* @__PURE__ */ jsx(BooleanSwitchField, {
3476
3872
  ...arm
3477
- }) : (field.type === "date" || field.type === "datetime") && field.editable ? /* @__PURE__ */ jsx(DateField, {
3873
+ }) : isDateFieldKind(field.type) && field.editable ? /* @__PURE__ */ jsx(DateField, {
3478
3874
  ...arm,
3875
+ kind: field.type,
3479
3876
  onUnset: onUnset
3480
3877
  }) : isSingleDocRefKind(field.type) ? /* @__PURE__ */ jsx(DocRefField, {
3481
3878
  ...arm,
@@ -3488,9 +3885,10 @@ function fieldArm({arm: arm, entry: entry, onUnset: onUnset, onAppend: onAppend,
3488
3885
  });
3489
3886
  }
3490
3887
 
3491
- function EditableField({field: field, entry: entry, description: description, onSave: onSave, onUnset: onUnset, onAppend: onAppend, onPreview: onPreview, onDiscardPreview: onDiscardPreview, consequence: consequence, advanceTo: advanceTo}) {
3888
+ function EditableField({field: field, entry: entry, description: description, instanceId: instanceId, onSave: onSave, onUnset: onUnset, onAppend: onAppend, onPreview: onPreview, onDiscardPreview: onDiscardPreview, consequence: consequence, advanceTo: advanceTo}) {
3492
3889
  const label = field.title ?? field.name, arm = {
3493
3890
  field: field,
3891
+ instanceId: instanceId,
3494
3892
  onSave: onSave
3495
3893
  }, content = entry?.options === void 0 ? fieldArm({
3496
3894
  arm: arm,
@@ -3522,11 +3920,15 @@ function EditableField({field: field, entry: entry, description: description, on
3522
3920
  });
3523
3921
  }
3524
3922
 
3525
- function MetaRow({label: label, children: children}) {
3923
+ function MetaRow({children: children, fillHeight: fillHeight, label: label}) {
3526
3924
  /* @__PURE__ */
3527
3925
  return jsxs(Flex, {
3528
- align: "flex-start",
3529
3926
  gap: 4,
3927
+ ...fillHeight ? {
3928
+ flex: 1
3929
+ } : {
3930
+ align: "flex-start"
3931
+ },
3530
3932
  children: [
3531
3933
  /* @__PURE__ */ jsx(Box, {
3532
3934
  style: {
@@ -3626,6 +4028,12 @@ function useSpaceToken(index) {
3626
4028
  return value;
3627
4029
  }
3628
4030
 
4031
+ function useRadiusToken(index) {
4032
+ const value = useTheme_v2().radius[index];
4033
+ if (value === void 0) throw new Error(`theme is missing radius token ${index}`);
4034
+ return value;
4035
+ }
4036
+
3629
4037
  function useContainerToken(index) {
3630
4038
  const value = useTheme_v2().container[index];
3631
4039
  if (value === void 0) throw new Error(`theme is missing container token ${index}`);
@@ -3746,8 +4154,8 @@ function UserAvatarGroup({ids: ids, hint: hint}) {
3746
4154
  });
3747
4155
  }
3748
4156
 
3749
- function AssignActivityControl({instanceId: instanceId, state: state, assigneeIds: assigneeIds = []}) {
3750
- const {editFieldFor: editFieldFor} = useWorkflowContext(), toast = useClosableToast(), [open, setOpen] = useState(!1), [busy, setBusy] = useState(!1);
4157
+ function AssignActivityControl({instanceId: instanceId, state: state, surface: surface, assigneeIds: assigneeIds = []}) {
4158
+ const editField = useEditField(surface), report = useRejectionReport(), [open, setOpen] = useState(!1), [busy, setBusy] = useState(!1);
3751
4159
  if (state.kind === "none") return assigneeIds.length === 0 ? null : /* @__PURE__ */ jsx(AvatarDisplay, {
3752
4160
  "aria-label": "Assignees",
3753
4161
  avatar: /* @__PURE__ */ jsx(UserAvatarGroup, {
@@ -3768,23 +4176,27 @@ function AssignActivityControl({instanceId: instanceId, state: state, assigneeId
3768
4176
  if (!(busy || field === void 0)) {
3769
4177
  setBusy(!0);
3770
4178
  try {
3771
- selectedIds.has(memberId) ? await editFieldFor(instanceId, {
3772
- target: editFieldTarget(field),
4179
+ selectedIds.has(memberId) ? await editField({
4180
+ instanceId: instanceId,
4181
+ field: field,
3773
4182
  mode: "set",
3774
4183
  value: members.filter(m => !(m.type === "user" && m.id === memberId))
3775
- }) : await editFieldFor(instanceId, {
3776
- target: editFieldTarget(field),
4184
+ }) : await editField({
4185
+ instanceId: instanceId,
4186
+ field: field,
3777
4187
  mode: "append",
3778
4188
  value: {
3779
4189
  type: "user",
3780
4190
  id: memberId
3781
4191
  }
3782
- });
4192
+ }), report.dismiss(instanceToastId("assign", instanceId));
3783
4193
  } catch (err) {
3784
- toast.push({
3785
- status: "error",
3786
- title: "Assigning failed",
3787
- description: describeError(err)
4194
+ report.rejected({
4195
+ err: err,
4196
+ context: "assignment",
4197
+ id: instanceToastId("assign", instanceId),
4198
+ refused: "Assignees can’t be changed right now",
4199
+ failed: "Failed to update assignees"
3788
4200
  });
3789
4201
  } finally {
3790
4202
  setBusy(!1);
@@ -3851,6 +4263,11 @@ function appendTargetFor(targets, filter) {
3851
4263
  if (filter?.kind !== "mine") return filter?.kind === "activity" ? targets.find(t => t.activity === filter.activity) : filter?.kind === "field" ? targets.find(t => t.scope === filter.scope && t.field === filter.field && (filter.scope !== "activity" || t.activity === filter.activity)) : targets[0];
3852
4264
  }
3853
4265
 
4266
+ function canRemoveRow(args) {
4267
+ const {editTarget: editTarget, appendTarget: appendTarget} = args;
4268
+ return editTarget === void 0 || appendTarget === void 0 ? !1 : editTarget.scope === appendTarget.scope && editTarget.field === appendTarget.field && editTarget.activity === appendTarget.activity;
4269
+ }
4270
+
3854
4271
  function looksLikeDefinition(value) {
3855
4272
  return typeof value == "object" && value !== null && Array.isArray(value.stages);
3856
4273
  }
@@ -4092,6 +4509,21 @@ function AddItemControl({onAdd: onAdd, button: button, busy: busy}) {
4092
4509
  });
4093
4510
  }
4094
4511
 
4512
+ function RemoveItemButton({onClick: onClick}) {
4513
+ /* @__PURE__ */
4514
+ return jsx(HoverHint, {
4515
+ text: "Remove item",
4516
+ children: /* @__PURE__ */ jsx(Button, {
4517
+ "aria-label": "Remove item",
4518
+ fontSize: 1,
4519
+ icon: CloseIcon,
4520
+ mode: "bleed",
4521
+ onClick: onClick,
4522
+ padding: 2
4523
+ })
4524
+ });
4525
+ }
4526
+
4095
4527
  function BreadcrumbTail({segments: segments, style: style}) {
4096
4528
  /* @__PURE__ */
4097
4529
  return jsx(Text, {
@@ -4158,7 +4590,7 @@ function WorkRow({lead: lead, children: children, end: end, onOpen: onOpen}) {
4158
4590
  });
4159
4591
  }
4160
4592
 
4161
- function TodoItemRowView({breadcrumb: breadcrumb, row: row, onToggle: onToggle, onPatch: onPatch}) {
4593
+ function TodoItemRowView({breadcrumb: breadcrumb, row: row, onToggle: onToggle, onPatch: onPatch, onRemove: onRemove}) {
4162
4594
  const {canClick: canClick, hint: hint} = rowInteractivity(row), editable = row.editTarget !== void 0, checkbox = /* @__PURE__ */ jsx(TodoCheckbox, {
4163
4595
  canClick: canClick,
4164
4596
  checked: isTodoDone(row.item),
@@ -4177,6 +4609,8 @@ function TodoItemRowView({breadcrumb: breadcrumb, row: row, onToggle: onToggle,
4177
4609
  editable: editable,
4178
4610
  item: row.item,
4179
4611
  onPatch: onPatch
4612
+ }), onRemove === void 0 ? null : /* @__PURE__ */ jsx(RemoveItemButton, {
4613
+ onClick: onRemove
4180
4614
  }) ]
4181
4615
  }),
4182
4616
  lead:
@@ -4203,37 +4637,41 @@ function TodoItemRowView({breadcrumb: breadcrumb, row: row, onToggle: onToggle,
4203
4637
  }
4204
4638
 
4205
4639
  function TodoItemsList({breadcrumb: breadcrumb, entry: entry, filter: filter, surface: surface}) {
4206
- const {instance: instance} = entry, definition = useDefinition(entry), {editFieldFor: editFieldFor, fireActionFor: fireActionFor} = useWorkflowContext(), telemetry = useWorkflowTelemetry(), toast = useClosableToast(), [busy, setBusy] = useState(!1), derivation = deriveTodoItems(entry), rows = derivation.rows.filter(row => rowMatches(row, filter)), appendTarget = appendTargetFor(derivation.appendTargets, filter), run = async op => {
4640
+ const {instance: instance} = entry, definition = useDefinition(entry), {editFieldFor: editFieldFor, fireActionFor: fireActionFor} = useWorkflowContext(), telemetry = useWorkflowTelemetry(), report = useRejectionReport(), [busy, setBusy] = useState(!1), derivation = deriveTodoItems(entry), rows = derivation.rows.filter(row => rowMatches(row, filter)), appendTarget = appendTargetFor(derivation.appendTargets, filter), run = async op => {
4207
4641
  if (busy) return !1;
4208
4642
  setBusy(!0);
4209
4643
  try {
4210
- return await op(), !0;
4644
+ return await op(), report.dismiss(instanceToastId("todo-write", instance._id)),
4645
+ !0;
4211
4646
  } catch (err) {
4212
- return toast.push({
4213
- status: "error",
4214
- title: "Updating to-dos failed",
4215
- description: describeError(err)
4647
+ return report.rejected({
4648
+ err: err,
4649
+ context: "to-do write",
4650
+ id: instanceToastId("todo-write", instance._id),
4651
+ refused: "To-dos can’t be changed right now",
4652
+ failed: "Failed to update to-dos"
4216
4653
  }), !1;
4217
4654
  } finally {
4218
4655
  setBusy(!1);
4219
4656
  }
4220
- }, patchItem = (row, patch) => {
4221
- if (!row.editTarget) return Promise.resolve();
4222
- const target = row.editTarget, next = row.items.map(it => it._key === row.item._key ? {
4223
- ...it,
4224
- ...patch
4225
- } : it);
4657
+ }, writeItems = (row, nextItems) => {
4658
+ if (!row.editTarget) return Promise.resolve(!1);
4659
+ const target = row.editTarget;
4226
4660
  return run(() => editFieldFor(instance._id, {
4227
4661
  target: target,
4228
4662
  mode: "set",
4229
- value: next
4663
+ value: nextItems()
4230
4664
  }));
4231
- }, toggleRow = async row => {
4665
+ }, patchItem = (row, patch) => writeItems(row, () => todoItemsPatched({
4666
+ items: row.items,
4667
+ key: row.item._key,
4668
+ patch: patch
4669
+ })), toggleRow = async row => {
4232
4670
  if (busy) return;
4233
4671
  if (row.editTarget) {
4234
4672
  const done = !isTodoDone(row.item), success = await patchItem(row, {
4235
4673
  status: toggledTodoStatus(row.item)
4236
- }) === !0;
4674
+ });
4237
4675
  telemetry.log(WorkflowTodoToggled, {
4238
4676
  instanceId: instance._id,
4239
4677
  surface: surface,
@@ -4257,14 +4695,44 @@ function TodoItemsList({breadcrumb: breadcrumb, entry: entry, filter: filter, su
4257
4695
  success: success
4258
4696
  });
4259
4697
  }
4260
- }, addItem = label => appendTarget ? run(() => editFieldFor(instance._id, {
4261
- target: appendTarget,
4262
- mode: "append",
4263
- value: {
4264
- label: label,
4265
- status: "open"
4266
- }
4267
- })) : Promise.resolve(!1);
4698
+ }, addItem = async label => {
4699
+ if (busy || !appendTarget) return !1;
4700
+ const success = await run(() => editFieldFor(instance._id, {
4701
+ target: appendTarget,
4702
+ mode: "append",
4703
+ value: {
4704
+ label: label,
4705
+ status: "open"
4706
+ }
4707
+ }));
4708
+ return telemetry.log(WorkflowTodoEdited, {
4709
+ instanceId: instance._id,
4710
+ surface: surface,
4711
+ kind: "add",
4712
+ success: success
4713
+ }), success;
4714
+ }, editRow = async (row, patch) => {
4715
+ if (busy || row.editTarget === void 0) return;
4716
+ const success = await patchItem(row, patch);
4717
+ telemetry.log(WorkflowTodoEdited, {
4718
+ instanceId: instance._id,
4719
+ surface: surface,
4720
+ kind: todoEditKind(patch),
4721
+ success: success
4722
+ });
4723
+ }, removeRow = async row => {
4724
+ if (busy || row.editTarget === void 0) return;
4725
+ const success = await writeItems(row, () => todoItemsWithout({
4726
+ items: row.items,
4727
+ key: row.item._key
4728
+ }));
4729
+ telemetry.log(WorkflowTodoEdited, {
4730
+ instanceId: instance._id,
4731
+ surface: surface,
4732
+ kind: "remove",
4733
+ success: success
4734
+ });
4735
+ };
4268
4736
  if (rows.length === 0 && !appendTarget) return null;
4269
4737
  const rowKey = row => `${row.scope}:${row.activityName ?? ""}:${row.fieldName}:${row.item._key}`, rowBreadcrumb = row => {
4270
4738
  if (breadcrumb === void 0 || row.activityName === void 0) return breadcrumb;
@@ -4284,8 +4752,16 @@ function TodoItemsList({breadcrumb: breadcrumb, entry: entry, filter: filter, su
4284
4752
  children: rows.map(row => /* @__PURE__ */ jsx(TodoItemRowView, {
4285
4753
  breadcrumb: rowBreadcrumb(row),
4286
4754
  onPatch: patch => {
4287
- patchItem(row, patch);
4755
+ editRow(row, patch);
4288
4756
  },
4757
+ ...canRemoveRow({
4758
+ editTarget: row.editTarget,
4759
+ appendTarget: appendTarget
4760
+ }) ? {
4761
+ onRemove: () => {
4762
+ removeRow(row);
4763
+ }
4764
+ } : {},
4289
4765
  onToggle: () => {
4290
4766
  toggleRow(row);
4291
4767
  },
@@ -4373,7 +4849,7 @@ const ACTIONS_MENU_TRIGGER = {
4373
4849
  padding: 2
4374
4850
  };
4375
4851
 
4376
- function ActionMenuItem({actionEval: actionEval, instanceId: instanceId, activity: activity, surface: surface, onCollectParams: onCollectParams}) {
4852
+ function ActionMenuItem({actionEval: actionEval, instanceId: instanceId, activity: activity, surface: surface, placement: placement, onCollectParams: onCollectParams}) {
4377
4853
  const rowKind = actionRowKind(actionEval), label = actionTriggerLabel(actionEval), {tone: tone, icon: icon} = actionButtonFace({
4378
4854
  actionEval: actionEval,
4379
4855
  activityName: activity
@@ -4385,6 +4861,7 @@ function ActionMenuItem({actionEval: actionEval, instanceId: instanceId, activit
4385
4861
  action: actionEval.action.name,
4386
4862
  label: label,
4387
4863
  surface: surface,
4864
+ placement: placement,
4388
4865
  viaMenu: !0
4389
4866
  });
4390
4867
  return rowKind.kind === "disabled" ? /* @__PURE__ */ jsx(MenuItem, {
@@ -4421,7 +4898,7 @@ function rowShield(menuButton) {
4421
4898
  });
4422
4899
  }
4423
4900
 
4424
- function ActionsMenuButton({actions: actions, instanceId: instanceId, activity: activity, label: label, surface: surface, mode: mode = "ghost", inButtonCard: inButtonCard = !1}) {
4901
+ function ActionsMenuButton({actions: actions, instanceId: instanceId, activity: activity, label: label, surface: surface, placement: placement, mode: mode = "ghost", inButtonCard: inButtonCard = !1}) {
4425
4902
  const [paramsAction, setParamsAction] = useState(void 0), clusterPending = useActionClusterPending(), menuId = useId(), menuButton = /* @__PURE__ */ jsx(MenuButton, {
4426
4903
  button: /* @__PURE__ */ jsx(Button, {
4427
4904
  ...ACTIONS_MENU_TRIGGER,
@@ -4441,6 +4918,7 @@ function ActionsMenuButton({actions: actions, instanceId: instanceId, activity:
4441
4918
  activity: activity,
4442
4919
  instanceId: instanceId,
4443
4920
  onCollectParams: () => setParamsAction(a),
4921
+ placement: placement,
4444
4922
  surface: surface
4445
4923
  }, a.action.name))
4446
4924
  }),
@@ -4458,6 +4936,7 @@ function ActionsMenuButton({actions: actions, instanceId: instanceId, activity:
4458
4936
  activity: activity,
4459
4937
  instanceId: instanceId,
4460
4938
  onClose: () => setParamsAction(void 0),
4939
+ placement: placement,
4461
4940
  surface: surface,
4462
4941
  viaMenu: !0
4463
4942
  })
@@ -4476,7 +4955,8 @@ function TerminalFooter({actions: actions, activity: activity, instanceId: insta
4476
4955
  actionEval: only,
4477
4956
  activity: activity,
4478
4957
  instanceId: instanceId,
4479
- surface: "terminal-footer"
4958
+ placement: "terminal-footer",
4959
+ surface: "activity-dialog"
4480
4960
  })
4481
4961
  }) : /* @__PURE__ */ jsx(FittedActions, {
4482
4962
  actions: actions,
@@ -4531,14 +5011,16 @@ function FittedActions({actions: actions, activity: activity, instanceId: instan
4531
5011
  actionEval: a,
4532
5012
  activity: activity,
4533
5013
  instanceId: instanceId,
4534
- surface: "terminal-footer"
5014
+ placement: "terminal-footer",
5015
+ surface: "activity-dialog"
4535
5016
  }, a.action.name)), overflow.length > 0 ? /* @__PURE__ */ jsx(ActionsMenuButton, {
4536
5017
  actions: overflow,
4537
5018
  activity: activity,
4538
5019
  instanceId: instanceId,
4539
5020
  label: MORE_ACTIONS_LABEL,
4540
5021
  mode: "default",
4541
- surface: "terminal-footer"
5022
+ placement: "terminal-footer",
5023
+ surface: "activity-dialog"
4542
5024
  }) : null ]
4543
5025
  }) ]
4544
5026
  });
@@ -4673,7 +5155,8 @@ function MetaBlock({detail: detail, definition: definition, document: document,
4673
5155
  children: /* @__PURE__ */ jsx(Flex, {
4674
5156
  children: /* @__PURE__ */ jsx(DocPreviewLink, {
4675
5157
  gdr: document,
4676
- layout: "inline"
5158
+ layout: "inline",
5159
+ source: "dialog-subject"
4677
5160
  })
4678
5161
  })
4679
5162
  }) : null,
@@ -4697,7 +5180,8 @@ function TopActions({detail: detail, definition: definition, instanceId: instanc
4697
5180
  actionEval: a,
4698
5181
  activity: activityName,
4699
5182
  instanceId: instanceId,
4700
- surface: "dialog-strip"
5183
+ placement: "dialog-strip",
5184
+ surface: "activity-dialog"
4701
5185
  }, a.action.name)), p.manualTarget ? /* @__PURE__ */ jsx(Button, {
4702
5186
  as: "a",
4703
5187
  fontSize: 1,
@@ -4755,7 +5239,8 @@ function FieldRow({field: field, detail: detail, entry: entry, activityName: act
4755
5239
  state: {
4756
5240
  kind: "editable",
4757
5241
  field: assignField
4758
- }
5242
+ },
5243
+ surface: "activity-dialog"
4759
5244
  }) : null ]
4760
5245
  }) ]
4761
5246
  });
@@ -4763,7 +5248,8 @@ function FieldRow({field: field, detail: detail, entry: entry, activityName: act
4763
5248
  const editable = detail.editableByName.get(field.name);
4764
5249
  return editable ? /* @__PURE__ */ jsx(EditableFieldControl, {
4765
5250
  field: editable,
4766
- instanceId: instanceId
5251
+ instanceId: instanceId,
5252
+ surface: "activity-dialog"
4767
5253
  }) : /* @__PURE__ */ jsxs(Stack, {
4768
5254
  gap: 2,
4769
5255
  children: [ head,
@@ -4932,7 +5418,7 @@ function ActivityRowTitle({dimmed: dimmed, children: children}) {
4932
5418
  });
4933
5419
  }
4934
5420
 
4935
- function RowTerminalActions({actions: actions, activity: activity, instanceId: instanceId}) {
5421
+ function RowTerminalActions({actions: actions, activity: activity, instanceId: instanceId, surface: surface}) {
4936
5422
  const lock = useActionClusterState(), [only, ...rest] = actions;
4937
5423
  return only ? /* @__PURE__ */ jsx(ActionClusterProvider, {
4938
5424
  value: lock,
@@ -4944,14 +5430,16 @@ function RowTerminalActions({actions: actions, activity: activity, instanceId: i
4944
5430
  inButtonCard: !0
4945
5431
  },
4946
5432
  instanceId: instanceId,
4947
- surface: "inline-row"
5433
+ placement: "inline-row",
5434
+ surface: surface
4948
5435
  }) : /* @__PURE__ */ jsx(ActionsMenuButton, {
4949
5436
  actions: actions,
4950
5437
  activity: activity,
4951
5438
  inButtonCard: !0,
4952
5439
  instanceId: instanceId,
4953
5440
  label: "Select action",
4954
- surface: "inline-row"
5441
+ placement: "inline-row",
5442
+ surface: surface
4955
5443
  })
4956
5444
  }) : null;
4957
5445
  }
@@ -4972,7 +5460,7 @@ function TitleTag({hint: hint, tone: tone, children: children}) {
4972
5460
  });
4973
5461
  }
4974
5462
 
4975
- function ActivityRow({face: face, breadcrumb: breadcrumb, assigneeIds: assigneeIds, assignState: assignState, dateControl: dateControl, instanceId: instanceId, onOpen: onOpen, terminalActions: terminalActions = []}) {
5463
+ function ActivityRow({face: face, breadcrumb: breadcrumb, assigneeIds: assigneeIds, assignState: assignState, dateControl: dateControl, instanceId: instanceId, onOpen: onOpen, surface: surface, terminalActions: terminalActions = []}) {
4976
5464
  const settled = isTerminalActivityStatus(face.status), dimmed = settledDim(settled);
4977
5465
  /* @__PURE__ */
4978
5466
  return jsxs(WorkRow, {
@@ -4980,12 +5468,14 @@ function ActivityRow({face: face, breadcrumb: breadcrumb, assigneeIds: assigneeI
4980
5468
  children: [ settled || terminalActions.length === 0 ? null : /* @__PURE__ */ jsx(RowTerminalActions, {
4981
5469
  actions: terminalActions,
4982
5470
  activity: face.activityName,
4983
- instanceId: instanceId
5471
+ instanceId: instanceId,
5472
+ surface: surface
4984
5473
  }), dateControl,
4985
5474
  /* @__PURE__ */ jsx(AssignActivityControl, {
4986
5475
  assigneeIds: assigneeIds,
4987
5476
  instanceId: instanceId,
4988
- state: assignState
5477
+ state: assignState,
5478
+ surface: surface
4989
5479
  }) ]
4990
5480
  }),
4991
5481
  lead: /* @__PURE__ */ jsx(ActivityStatusLead, {
@@ -5010,7 +5500,7 @@ function ActivityRow({face: face, breadcrumb: breadcrumb, assigneeIds: assigneeI
5010
5500
  });
5011
5501
  }
5012
5502
 
5013
- function ActivitiesList({entry: entry, onOpenActivity: onOpenActivity}) {
5503
+ function ActivitiesList({entry: entry, onOpenActivity: onOpenActivity, surface: surface}) {
5014
5504
  const activities = (entry.evaluation?.currentStage.activities ?? []).filter(t => !t.scopedOut), activityState = stateByActivity(entry.instance);
5015
5505
  return activities.length === 0 ?
5016
5506
  /* @__PURE__ */ jsx(Box, {
@@ -5030,7 +5520,8 @@ function ActivitiesList({entry: entry, onOpenActivity: onOpenActivity}) {
5030
5520
  editableFields: entry.evaluation?.editableFields
5031
5521
  }),
5032
5522
  instanceId: entry.instance._id,
5033
- onOpen: () => onOpenActivity(t.activity.name)
5523
+ onOpen: () => onOpenActivity(t.activity.name),
5524
+ surface: surface
5034
5525
  }, t.activity.name))
5035
5526
  });
5036
5527
  }
@@ -5094,7 +5585,9 @@ const EDITOR_BY_KIND = {
5094
5585
  assignees: "assignees",
5095
5586
  boolean: "scalar",
5096
5587
  date: "scalar",
5588
+ dueDate: "scalar",
5097
5589
  datetime: "scalar",
5590
+ dueDatetime: "scalar",
5098
5591
  number: "scalar",
5099
5592
  progress: "scalar",
5100
5593
  string: "scalar",
@@ -5104,7 +5597,9 @@ const EDITOR_BY_KIND = {
5104
5597
  array: e => e.value.length > 0 ? pluralize("item", e.value.length, !0) : void 0,
5105
5598
  boolean: e => e.value === null ? void 0 : formatBoolean(e.value),
5106
5599
  date: e => e.value === null ? void 0 : formatDate(e.value),
5600
+ dueDate: e => e.value === null ? void 0 : formatDate(e.value),
5107
5601
  datetime: e => e.value === null ? void 0 : formatDateTime(e.value),
5602
+ dueDatetime: e => e.value === null ? void 0 : formatDateTime(e.value),
5108
5603
  "doc.refs": e => e.value.length > 0 ? pluralize("document", e.value.length, !0) : void 0,
5109
5604
  object: e => e.value === null ? void 0 : "Set",
5110
5605
  "release.ref": e => e.value === null ? void 0 : e.value.releaseName
@@ -5228,7 +5723,7 @@ function TodoFieldDialog({entry: entry, scope: scope, field: field, title: title
5228
5723
 
5229
5724
  const MAX_VISIBLE_PILLS = 4;
5230
5725
 
5231
- function FieldPills({entry: entry, scope: scope, definition: definition}) {
5726
+ function FieldPills({entry: entry, scope: scope, definition: definition, surface: surface}) {
5232
5727
  const [expanded, setExpanded] = useState(!1), pills = deriveFieldPills({
5233
5728
  scope: scope,
5234
5729
  definition: definition,
@@ -5246,7 +5741,8 @@ function FieldPills({entry: entry, scope: scope, definition: definition}) {
5246
5741
  children: [ visible.map(pill => /* @__PURE__ */ jsx(FieldPill, {
5247
5742
  entry: entry,
5248
5743
  pill: pill,
5249
- scope: scope
5744
+ scope: scope,
5745
+ surface: surface
5250
5746
  }, pill.name)), overflow > 0 ?
5251
5747
  /* @__PURE__ */ jsx(Button, {
5252
5748
  mode: "bleed",
@@ -5280,7 +5776,9 @@ function isEmptyFace(face) {
5280
5776
 
5281
5777
  const KIND_ICON = {
5282
5778
  date: CalendarIcon,
5779
+ dueDate: CalendarIcon,
5283
5780
  datetime: CalendarIcon,
5781
+ dueDatetime: CalendarIcon,
5284
5782
  "doc.ref": DocumentIcon,
5285
5783
  "doc.refs": DocumentIcon,
5286
5784
  subject: DocumentIcon
@@ -5432,18 +5930,20 @@ function PillButton({children: children, pill: pill, hintDisabled: hintDisabled
5432
5930
  });
5433
5931
  }
5434
5932
 
5435
- function useFieldCommit({entry: entry, editability: editability}) {
5436
- const {editFieldFor: editFieldFor} = useWorkflowContext(), target = editFieldTarget(editability);
5933
+ function useFieldCommit({entry: entry, editability: editability, surface: surface}) {
5934
+ const editField = useEditField(surface), instanceId = entry.instance._id;
5437
5935
  return {
5438
- set: value => editFieldFor(entry.instance._id, {
5439
- target: target,
5936
+ set: value => editField({
5937
+ instanceId: instanceId,
5938
+ field: editability,
5440
5939
  mode: "set",
5441
5940
  value: value
5442
- }).then(() => {}),
5443
- unset: () => editFieldFor(entry.instance._id, {
5444
- target: target,
5941
+ }),
5942
+ unset: () => editField({
5943
+ instanceId: instanceId,
5944
+ field: editability,
5445
5945
  mode: "unset"
5446
- }).then(() => {})
5946
+ })
5447
5947
  };
5448
5948
  }
5449
5949
 
@@ -5513,11 +6013,28 @@ function ReadOnlyPill({pill: pill}) {
5513
6013
  });
5514
6014
  }
5515
6015
 
5516
- function ScalarPill({entry: entry, pill: pill, editability: editability}) {
5517
- const [open, setOpen] = useState(!1), {set: set} = useFieldCommit({
6016
+ function usePillWrite(args) {
6017
+ const {entry: entry, editability: editability, surface: surface, onSaved: onSaved} = args, commit = useFieldCommit({
6018
+ entry: entry,
6019
+ editability: editability,
6020
+ surface: surface
6021
+ }), saver = useSaveField({
6022
+ instanceId: entry.instance._id,
6023
+ ...onSaved === void 0 ? {} : {
6024
+ onSaved: onSaved
6025
+ }
6026
+ });
6027
+ return {
6028
+ ...commit,
6029
+ ...saver
6030
+ };
6031
+ }
6032
+
6033
+ function ScalarPill({entry: entry, pill: pill, editability: editability, surface: surface}) {
6034
+ const [open, setOpen] = useState(!1), {set: set, saving: saving, save: save} = usePillWrite({
5518
6035
  entry: entry,
5519
- editability: editability
5520
- }), {saving: saving, save: save} = useSaveField({
6036
+ editability: editability,
6037
+ surface: surface,
5521
6038
  onSaved: () => setOpen(!1)
5522
6039
  });
5523
6040
  /* @__PURE__ */
@@ -5543,18 +6060,21 @@ function ScalarPill({entry: entry, pill: pill, editability: editability}) {
5543
6060
  });
5544
6061
  }
5545
6062
 
5546
- function DatePill({entry: entry, pill: pill, editability: editability, kind: kind}) {
6063
+ function DatePill({entry: entry, pill: pill, editability: editability, surface: surface, kind: kind}) {
5547
6064
  const [open, setOpen] = useState(!1), {set: set} = useFieldCommit({
5548
6065
  entry: entry,
5549
- editability: editability
5550
- }), {save: save} = useSaveField();
6066
+ editability: editability,
6067
+ surface: surface
6068
+ }), {save: save} = useSaveField({
6069
+ instanceId: entry.instance._id
6070
+ });
5551
6071
  /* @__PURE__ */
5552
6072
  return jsx(PillPopover, {
5553
6073
  content: /* @__PURE__ */ jsx(DatePicker, {
5554
6074
  onSelect: next => {
5555
- kind === "date" && setOpen(!1), save(() => set(serializeDateFieldValue(next, kind)));
6075
+ hasTimeOfDay(kind) || setOpen(!1), save(() => set(serializeDateFieldValue(next, kind)));
5556
6076
  },
5557
- selectTime: kind === "datetime",
6077
+ selectTime: hasTimeOfDay(kind),
5558
6078
  value: parseDateFieldValue(pill.entry?.value, kind)
5559
6079
  }),
5560
6080
  onDismiss: () => setOpen(!1),
@@ -5564,11 +6084,12 @@ function DatePill({entry: entry, pill: pill, editability: editability, kind: kin
5564
6084
  });
5565
6085
  }
5566
6086
 
5567
- function BooleanPill({entry: entry, pill: pill, editability: editability}) {
5568
- const {set: set} = useFieldCommit({
6087
+ function BooleanPill({entry: entry, pill: pill, editability: editability, surface: surface}) {
6088
+ const {set: set, save: save} = usePillWrite({
5569
6089
  entry: entry,
5570
- editability: editability
5571
- }), {save: save} = useSaveField(), chrome = usePillChrome(), current = pill.entry?._type === "boolean" ? pill.entry.value : null, menuId = useId();
6090
+ editability: editability,
6091
+ surface: surface
6092
+ }), chrome = usePillChrome(), current = pill.entry?._type === "boolean" ? pill.entry.value : null, menuId = useId();
5572
6093
  /* @__PURE__ */
5573
6094
  return jsx(PillHint, {
5574
6095
  pill: pill,
@@ -5612,12 +6133,14 @@ function BooleanPill({entry: entry, pill: pill, editability: editability}) {
5612
6133
  });
5613
6134
  }
5614
6135
 
5615
- function ActorPill({entry: entry, pill: pill, editability: editability}) {
6136
+ function ActorPill({entry: entry, pill: pill, editability: editability, surface: surface}) {
5616
6137
  const [open, setOpen] = useState(!1), {set: set, unset: unset} = useFieldCommit({
5617
6138
  entry: entry,
5618
- editability: editability
6139
+ editability: editability,
6140
+ surface: surface
5619
6141
  }), current = isActorShape(pill.entry?.value) ? pill.entry.value : null, {pick: pick} = useActorPick({
5620
6142
  current: current,
6143
+ instanceId: entry.instance._id,
5621
6144
  onSave: set,
5622
6145
  onUnset: unset
5623
6146
  });
@@ -5637,12 +6160,14 @@ function ActorPill({entry: entry, pill: pill, editability: editability}) {
5637
6160
  });
5638
6161
  }
5639
6162
 
5640
- function AssigneePill({entry: entry, pill: pill, editability: editability}) {
6163
+ function AssigneePill({entry: entry, pill: pill, editability: editability, surface: surface}) {
5641
6164
  const [open, setOpen] = useState(!1), {set: set, unset: unset} = useFieldCommit({
5642
6165
  entry: entry,
5643
- editability: editability
6166
+ editability: editability,
6167
+ surface: surface
5644
6168
  }), current = pill.entry?._type === "assignee" ? pill.entry.value : null, {pick: pick} = useAssigneePick({
5645
6169
  current: current,
6170
+ instanceId: entry.instance._id,
5646
6171
  onSave: set,
5647
6172
  onUnset: unset
5648
6173
  });
@@ -5662,11 +6187,12 @@ function AssigneePill({entry: entry, pill: pill, editability: editability}) {
5662
6187
  });
5663
6188
  }
5664
6189
 
5665
- function AssigneesPill({entry: entry, pill: pill, editability: editability}) {
5666
- const [open, setOpen] = useState(!1), {set: set} = useFieldCommit({
6190
+ function AssigneesPill({entry: entry, pill: pill, editability: editability, surface: surface}) {
6191
+ const [open, setOpen] = useState(!1), {set: set, saving: saving, save: save} = usePillWrite({
5667
6192
  entry: entry,
5668
- editability: editability
5669
- }), {saving: saving, save: save} = useSaveField(), current = pill.face.kind === "assignees" ? pill.face.assignees : [];
6193
+ editability: editability,
6194
+ surface: surface
6195
+ }), current = pill.face.kind === "assignees" ? pill.face.assignees : [];
5670
6196
  /* @__PURE__ */
5671
6197
  return jsx(PillPopover, {
5672
6198
  content: /* @__PURE__ */ jsx(AssigneePicker, {
@@ -5709,46 +6235,53 @@ function TodoPill({entry: entry, pill: pill, scope: scope}) {
5709
6235
  });
5710
6236
  }
5711
6237
 
5712
- function ScalarEditorPill({entry: entry, pill: pill, editability: editability}) {
6238
+ function ScalarEditorPill({entry: entry, pill: pill, editability: editability, surface: surface}) {
5713
6239
  return editability.type === "boolean" ? /* @__PURE__ */ jsx(BooleanPill, {
5714
6240
  editability: editability,
5715
6241
  entry: entry,
5716
- pill: pill
5717
- }) : editability.type === "date" || editability.type === "datetime" ? /* @__PURE__ */ jsx(DatePill, {
6242
+ pill: pill,
6243
+ surface: surface
6244
+ }) : isDateFieldKind(editability.type) ? /* @__PURE__ */ jsx(DatePill, {
5718
6245
  editability: editability,
5719
6246
  entry: entry,
5720
6247
  kind: editability.type,
5721
- pill: pill
6248
+ pill: pill,
6249
+ surface: surface
5722
6250
  }) : /* @__PURE__ */ jsx(ScalarPill, {
5723
6251
  editability: editability,
5724
6252
  entry: entry,
5725
- pill: pill
6253
+ pill: pill,
6254
+ surface: surface
5726
6255
  });
5727
6256
  }
5728
6257
 
5729
- function EditorPill({entry: entry, pill: pill, editability: editability}) {
6258
+ function EditorPill({entry: entry, pill: pill, editability: editability, surface: surface}) {
5730
6259
  return pill.editor === "scalar" ? /* @__PURE__ */ jsx(ScalarEditorPill, {
5731
6260
  editability: editability,
5732
6261
  entry: entry,
5733
- pill: pill
6262
+ pill: pill,
6263
+ surface: surface
5734
6264
  }) : pill.editor === "actor" ? /* @__PURE__ */ jsx(ActorPill, {
5735
6265
  editability: editability,
5736
6266
  entry: entry,
5737
- pill: pill
6267
+ pill: pill,
6268
+ surface: surface
5738
6269
  }) : pill.editor === "assignee" ? /* @__PURE__ */ jsx(AssigneePill, {
5739
6270
  editability: editability,
5740
6271
  entry: entry,
5741
- pill: pill
6272
+ pill: pill,
6273
+ surface: surface
5742
6274
  }) : pill.editor === "assignees" ? /* @__PURE__ */ jsx(AssigneesPill, {
5743
6275
  editability: editability,
5744
6276
  entry: entry,
5745
- pill: pill
6277
+ pill: pill,
6278
+ surface: surface
5746
6279
  }) : /* @__PURE__ */ jsx(ReadOnlyPill, {
5747
6280
  pill: pill
5748
6281
  });
5749
6282
  }
5750
6283
 
5751
- function FieldPill({entry: entry, pill: pill, scope: scope}) {
6284
+ function FieldPill({entry: entry, pill: pill, scope: scope, surface: surface}) {
5752
6285
  if (pill.editor === "todoList" && pill.entry !== void 0) /* @__PURE__ */
5753
6286
  return jsx(TodoPill, {
5754
6287
  entry: entry,
@@ -5761,7 +6294,8 @@ function FieldPill({entry: entry, pill: pill, scope: scope}) {
5761
6294
  }) : /* @__PURE__ */ jsx(EditorPill, {
5762
6295
  editability: editability,
5763
6296
  entry: entry,
5764
- pill: pill
6297
+ pill: pill,
6298
+ surface: surface
5765
6299
  });
5766
6300
  }
5767
6301
 
@@ -5892,7 +6426,7 @@ function InstanceToolLink({entry: entry}) {
5892
6426
  }
5893
6427
  });
5894
6428
  }, [ instanceId ]);
5895
- return tools.some(tool => tool.name === WORKFLOWS_TOOL_NAME) ? /* @__PURE__ */ jsx(Flex, {
6429
+ return workflowsToolAvailable(tools) ? /* @__PURE__ */ jsx(Flex, {
5896
6430
  children: /* @__PURE__ */ jsx(Button, {
5897
6431
  as: WorkflowIntentLink,
5898
6432
  fontSize: 1,
@@ -6095,6 +6629,7 @@ function StageGlyph(props) {
6095
6629
  }
6096
6630
 
6097
6631
  function StageFace({completed: completed = !1, detail: detail, title: title}) {
6632
+ const tone = completed ? "default" : "primary";
6098
6633
  /* @__PURE__ */
6099
6634
  return jsxs(Flex, {
6100
6635
  align: "center",
@@ -6103,8 +6638,8 @@ function StageFace({completed: completed = !1, detail: detail, title: title}) {
6103
6638
  children: [
6104
6639
  /* @__PURE__ */ jsx(TextWithTone, {
6105
6640
  size: 1,
6106
- tone: "primary",
6107
- children: completed ? /* @__PURE__ */ jsx(CheckmarkCircleIcon, {
6641
+ tone: tone,
6642
+ children: completed ? /* @__PURE__ */ jsx(CheckmarkCircleFilledIcon, {
6108
6643
  style: {
6109
6644
  color: "inherit"
6110
6645
  }
@@ -6116,7 +6651,7 @@ function StageFace({completed: completed = !1, detail: detail, title: title}) {
6116
6651
  }),
6117
6652
  /* @__PURE__ */ jsx(TextWithTone, {
6118
6653
  size: 1,
6119
- tone: "primary",
6654
+ tone: tone,
6120
6655
  weight: "medium",
6121
6656
  children: title
6122
6657
  }), detail === void 0 ? null : /* @__PURE__ */ jsx(Text, {
@@ -6134,10 +6669,10 @@ function StageChip({completed: completed = !1, detail: detail, interactive: inte
6134
6669
  padding: 3,
6135
6670
  radius: 4,
6136
6671
  style: {
6137
- boxShadow: `inset 0 0 0 1px ${color.focusRing}`,
6672
+ boxShadow: `inset 0 0 0 1px ${completed ? color.badge.default.fg : color.focusRing}`,
6138
6673
  cursor: interactive ? "help" : "default"
6139
6674
  },
6140
- tone: "primary",
6675
+ tone: completed ? "default" : "primary",
6141
6676
  ...interactive ? {
6142
6677
  tabIndex: 0
6143
6678
  } : {},
@@ -6365,7 +6900,8 @@ function WorkflowInstanceSection({defaultOpen: defaultOpen, entry: entry, onOpen
6365
6900
  children: [
6366
6901
  /* @__PURE__ */ jsx(InstanceSnapshotBody, {
6367
6902
  entry: entry,
6368
- onOpenActivity: onOpenActivity
6903
+ onOpenActivity: onOpenActivity,
6904
+ surface: "document-view"
6369
6905
  }),
6370
6906
  /* @__PURE__ */ jsx(InstanceToolLink, {
6371
6907
  entry: entry
@@ -6374,7 +6910,7 @@ function WorkflowInstanceSection({defaultOpen: defaultOpen, entry: entry, onOpen
6374
6910
  });
6375
6911
  }
6376
6912
 
6377
- function InstanceSnapshotBody({entry: entry, onOpenActivity: onOpenActivity}) {
6913
+ function InstanceSnapshotBody({entry: entry, onOpenActivity: onOpenActivity, surface: surface}) {
6378
6914
  const definition = useDefinition(entry), {instance: instance} = entry;
6379
6915
  /* @__PURE__ */
6380
6916
  return jsxs(Stack, {
@@ -6385,7 +6921,8 @@ function InstanceSnapshotBody({entry: entry, onOpenActivity: onOpenActivity}) {
6385
6921
  /* @__PURE__ */ jsx(FieldPills, {
6386
6922
  definition: definition,
6387
6923
  entry: entry,
6388
- scope: "workflow"
6924
+ scope: "workflow",
6925
+ surface: surface
6389
6926
  }),
6390
6927
  /* @__PURE__ */ jsxs(Card, {
6391
6928
  border: !0,
@@ -6410,14 +6947,15 @@ function InstanceSnapshotBody({entry: entry, onOpenActivity: onOpenActivity}) {
6410
6947
  padding: 2,
6411
6948
  children: /* @__PURE__ */ jsx(StageSection, {
6412
6949
  entry: entry,
6413
- onOpenActivity: onOpenActivity
6950
+ onOpenActivity: onOpenActivity,
6951
+ surface: surface
6414
6952
  })
6415
6953
  }) ]
6416
6954
  }) ]
6417
6955
  });
6418
6956
  }
6419
6957
 
6420
- function StageSection({entry: entry, onOpenActivity: onOpenActivity}) {
6958
+ function StageSection({entry: entry, onOpenActivity: onOpenActivity, surface: surface}) {
6421
6959
  const definition = useDefinition(entry), notice = instanceNotice(entry);
6422
6960
  return notice !== null ? notice : /* @__PURE__ */ jsx(StaleLock, {
6423
6961
  stale: isEvaluationStale(entry),
@@ -6427,11 +6965,13 @@ function StageSection({entry: entry, onOpenActivity: onOpenActivity}) {
6427
6965
  /* @__PURE__ */ jsx(FieldPills, {
6428
6966
  definition: definition,
6429
6967
  entry: entry,
6430
- scope: "stage"
6968
+ scope: "stage",
6969
+ surface: surface
6431
6970
  }),
6432
6971
  /* @__PURE__ */ jsx(ActivitiesList, {
6433
6972
  entry: entry,
6434
- onOpenActivity: onOpenActivity
6973
+ onOpenActivity: onOpenActivity,
6974
+ surface: surface
6435
6975
  }) ]
6436
6976
  })
6437
6977
  });
@@ -6440,8 +6980,9 @@ function StageSection({entry: entry, onOpenActivity: onOpenActivity}) {
6440
6980
  function CautionNote({action: action, label: label}) {
6441
6981
  /* @__PURE__ */
6442
6982
  return jsxs(Card, {
6443
- padding: 2,
6444
6983
  paddingLeft: 3,
6984
+ paddingRight: 2,
6985
+ paddingY: 3,
6445
6986
  radius: 3,
6446
6987
  style: {
6447
6988
  alignItems: "center",
@@ -6469,18 +7010,20 @@ function CautionNote({action: action, label: label}) {
6469
7010
  }
6470
7011
 
6471
7012
  function CopyDetailsButton({unreadable: unreadable}) {
6472
- const toast = useClosableToast();
7013
+ const toast = useWorkflowToast();
6473
7014
  /* @__PURE__ */
6474
7015
  return jsx(Button, {
6475
7016
  fontSize: 1,
6476
7017
  mode: "ghost",
6477
7018
  onClick: () => {
6478
7019
  navigator.clipboard.writeText(unreadableDocsReport(unreadable)).then(() => toast.push({
6479
- status: "success",
6480
- title: "Details copied"
7020
+ id: TOAST_ID.detailsCopy,
7021
+ status: "info",
7022
+ title: "Details copied to clipboard"
6481
7023
  }), () => toast.push({
7024
+ id: TOAST_ID.detailsCopy,
6482
7025
  status: "error",
6483
- title: "Could not copy the details"
7026
+ title: "Failed to copy the details"
6484
7027
  }));
6485
7028
  },
6486
7029
  padding: 2,
@@ -6506,7 +7049,7 @@ const HEADLINES = {
6506
7049
  };
6507
7050
 
6508
7051
  function remediation(invalid) {
6509
- return invalid.reason === "model-ahead" ? `"${invalid.documentId}" was created by a newer version of the workflow engine than this Studio can read. It needs a plugin update that supports the newer data model — share the details with your Studio maintainers.` : `This version of the Studio can't read "${invalid.documentId}" — it was likely created by a newer or different version of the workflow tooling. Share the details with your Studio maintainers.`;
7052
+ return invalid.reason === "model-ahead" ? `"${invalid.documentId}" was created by a newer version of the workflow engine than this Studio can read. It needs a plugin update that supports the newer data model — share the details with your Studio maintainers.` : `This version of the Studio cant read "${invalid.documentId}" — it was likely created by a newer or different version of the workflow tooling. Share the details with your Studio maintainers.`;
6510
7053
  }
6511
7054
 
6512
7055
  function InvalidDocNotice({invalid: invalid}) {
@@ -6557,18 +7100,6 @@ function TabSwitch({ariaControls: ariaControls, idPrefix: idPrefix, options: opt
6557
7100
  });
6558
7101
  }
6559
7102
 
6560
- function useDelayedFlag(active, delayMs) {
6561
- const [held, setHeld] = useState(!1);
6562
- return useEffect(() => {
6563
- if (!active) {
6564
- setHeld(!1);
6565
- return;
6566
- }
6567
- const timer = setTimeout(() => setHeld(!0), delayMs);
6568
- return () => clearTimeout(timer);
6569
- }, [ active, delayMs ]), held && active;
6570
- }
6571
-
6572
7103
  function openActivityGone(args) {
6573
7104
  const {entry: entry, target: target} = args;
6574
7105
  if (entry === void 0 || entry.instance.currentStage !== target.stage) return !0;
@@ -6701,7 +7232,9 @@ const asInitial = candidate => candidate, scalarInitialValue = (entry, value) =>
6701
7232
  value: value === !0
6702
7233
  }),
6703
7234
  date: scalarInitialValue,
7235
+ dueDate: scalarInitialValue,
6704
7236
  datetime: scalarInitialValue,
7237
+ dueDatetime: scalarInitialValue,
6705
7238
  "doc.ref": singleRefInitialValue,
6706
7239
  "doc.refs": (entry, value) => asInitial({
6707
7240
  type: entry.type,
@@ -6852,15 +7385,36 @@ function classifyStartError(err) {
6852
7385
  };
6853
7386
  }
6854
7387
 
7388
+ function startOutcomeToast(outcome, label) {
7389
+ return outcome.kind === "started-not-settled" ? {
7390
+ id: TOAST_ID.start,
7391
+ status: "warning",
7392
+ title: `“${label}” started but didn’t finish`,
7393
+ description: outcome.description
7394
+ } : outcome.kind === "not-allowed" ? {
7395
+ id: TOAST_ID.start,
7396
+ status: "warning",
7397
+ title: `“${label}” can’t be started right now`,
7398
+ description: outcome.description
7399
+ } : {
7400
+ id: TOAST_ID.start,
7401
+ status: "error",
7402
+ title: `Failed to start “${label}”`,
7403
+ description: outcome.description
7404
+ };
7405
+ }
7406
+
6855
7407
  function boundReleaseId(mapping, selectedReleaseId) {
6856
7408
  return mapping?.perspectiveField !== void 0 && selectedReleaseId !== void 0 ? selectedReleaseId : void 0;
6857
7409
  }
6858
7410
 
7411
+ const MAPPING_BROKEN_HINT = docTypeLabel => `Unavailable — this workflow isn’t set up correctly for ${docTypeLabel} documents`;
7412
+
6859
7413
  function startGate(args) {
6860
7414
  const {mapping: mapping, mappingIssue: mappingIssue, selectedReleaseId: selectedReleaseId, releaseActive: releaseActive} = args;
6861
7415
  if (mappingIssue !== void 0) return {
6862
7416
  blocked: !0,
6863
- tooltip: mappingIssue
7417
+ tooltip: MAPPING_BROKEN_HINT(args.docTypeLabel)
6864
7418
  };
6865
7419
  if (mapping.perspectiveField?.required === !0 && selectedReleaseId === void 0) return {
6866
7420
  blocked: !0,
@@ -6872,7 +7426,7 @@ function startGate(args) {
6872
7426
  };
6873
7427
  if (args.startFilterFailed === !0) return {
6874
7428
  blocked: !0,
6875
- tooltip: `${mapping.label} can't start for this document right now — the workflow's start condition isn't met`
7429
+ tooltip: `${mapping.label} cant start for this document right now — the workflows start condition isnt met`
6876
7430
  };
6877
7431
  if (args.unmetRequirement !== void 0) {
6878
7432
  const requirement = args.unmetRequirement;
@@ -7134,7 +7688,7 @@ function showRowOnError(key, mapping) {
7134
7688
  }
7135
7689
 
7136
7690
  function useStartWorkflow(args) {
7137
- const {mapping: mapping, docId: docId, initialValue: initialValue, source: source} = args, toast = useClosableToast(), {engine: engine, openStartDialog: openStartDialog, mappingIssues: mappingIssues2, mappingStarts: mappingStarts} = useWorkflowContext(), observer = useStudioObserver({
7691
+ const {mapping: mapping, docId: docId, initialValue: initialValue, source: source} = args, toast = useWorkflowToast(), schema = useSchema(), {engine: engine, openStartDialog: openStartDialog, mappingIssues: mappingIssues2, mappingStarts: mappingStarts} = useWorkflowContext(), observer = useStudioObserver({
7138
7692
  engine: engine
7139
7693
  }), [starting, setStarting] = useState(!1), {selectedReleaseId: selectedReleaseId} = usePerspective(), releaseActive = useIsReleaseActive(), startBlock = mappingStarts.get(mappingKey(mapping)), hidden = startKindOf({
7140
7694
  start: startBlock
@@ -7154,6 +7708,7 @@ function useStartWorkflow(args) {
7154
7708
  }), {blocked: blocked, tooltip: tooltip} = startGate({
7155
7709
  mapping: mapping,
7156
7710
  mappingIssue: mappingIssues2.get(mappingKey(mapping)),
7711
+ docTypeLabel: schema.get(mapping.docType)?.title ?? mapping.docType,
7157
7712
  selectedReleaseId: selectedReleaseId,
7158
7713
  releaseActive: releaseActive,
7159
7714
  startFilterFailed: filterFailed,
@@ -7177,8 +7732,9 @@ function useStartWorkflow(args) {
7177
7732
  selectedReleaseId: selectedReleaseId,
7178
7733
  ensureDocumentExists: observer.ensureDocumentExists,
7179
7734
  onPersistFailure: err => toast.push({
7735
+ id: TOAST_ID.documentSave,
7180
7736
  status: "error",
7181
- title: "Could not persist the document before starting",
7737
+ title: "Failed to save the document",
7182
7738
  description: describeError(err)
7183
7739
  }),
7184
7740
  openStartDialog: request => openStartDialog({
@@ -7319,7 +7875,8 @@ function ForMeList({entry: entry, work: work, identity: identity, onOpenActivity
7319
7875
  }),
7320
7876
  breadcrumb: breadcrumb,
7321
7877
  instanceId: instance._id,
7322
- onOpen: () => onOpenActivity(activityEval.activity.name)
7878
+ onOpen: () => onOpenActivity(activityEval.activity.name),
7879
+ surface: "document-view"
7323
7880
  }, activityEval.activity.name)), itemCount > 0 ? /* @__PURE__ */ jsx(TodoItemsList, {
7324
7881
  breadcrumb: breadcrumb,
7325
7882
  entry: entry,
@@ -7667,6 +8224,23 @@ function workflowIssue(args) {
7667
8224
  if (!isInputSourced(subject)) return `autoStart: "${docType}" → workflow "${name}" has a self-filling subject (not caller-provided), so the document can't be its subject — skipped.`;
7668
8225
  }
7669
8226
 
8227
+ function createSubscribers() {
8228
+ const listeners = /* @__PURE__ */ new Set;
8229
+ return {
8230
+ subscribe(listener) {
8231
+ return listeners.add(listener), () => {
8232
+ listeners.delete(listener);
8233
+ };
8234
+ },
8235
+ notify() {
8236
+ for (const listener of [ ...listeners ]) listener();
8237
+ },
8238
+ clear() {
8239
+ listeners.clear();
8240
+ }
8241
+ };
8242
+ }
8243
+
7670
8244
  function actualType$(previews, bareId) {
7671
8245
  return previews.unstable_observeDocumentPairAvailability(bareId).pipe(switchMap(({draft: draft, published: published}) => draft.available ? previews.observeDocumentTypeFromId(getDraftId(bareId)) : published.available ? previews.observeDocumentTypeFromId(bareId) : draft.reason === "PERMISSION_DENIED" || published.reason === "PERMISSION_DENIED" ? of(void 0) : previews.unstable_observeVersionDocumentIds(bareId).pipe(switchMap(([firstVersionId]) => firstVersionId === void 0 ? of(null) : previews.observeDocumentTypeFromId(firstVersionId)))), distinctUntilChanged());
7672
8246
  }
@@ -7674,12 +8248,10 @@ function actualType$(previews, bareId) {
7674
8248
  const REBUILD_DELAY_MS = 5e3;
7675
8249
 
7676
8250
  function createActualTypeProbeStore(previews) {
7677
- const verdicts = /* @__PURE__ */ new Map, live = /* @__PURE__ */ new Map, listeners = /* @__PURE__ */ new Set, notify = () => {
7678
- for (const listener of [ ...listeners ]) listener();
7679
- }, start = (bareId, entry) => actualType$(previews, bareId).subscribe({
8251
+ const verdicts = /* @__PURE__ */ new Map, live = /* @__PURE__ */ new Map, subscribers = createSubscribers(), start = (bareId, entry) => actualType$(previews, bareId).subscribe({
7680
8252
  next: value => {
7681
8253
  verdicts.has(bareId) && verdicts.get(bareId) === value || (verdicts.set(bareId, value),
7682
- notify());
8254
+ subscribers.notify());
7683
8255
  },
7684
8256
  error: err => {
7685
8257
  console.error(`[workflow-studio-plugin] actual-type probe for "${bareId}" failed:`, err),
@@ -7689,12 +8261,14 @@ function createActualTypeProbeStore(previews) {
7689
8261
  }
7690
8262
  });
7691
8263
  return {
7692
- subscribe(listener) {
7693
- return listeners.add(listener), () => {
7694
- listeners.delete(listener);
7695
- };
7696
- },
8264
+ subscribe: subscribers.subscribe,
7697
8265
  read: bareId => verdicts.get(bareId),
8266
+ seed(types) {
8267
+ let changed = !1;
8268
+ for (const [bareId, actualType] of types) verdicts.has(bareId) || (verdicts.set(bareId, actualType),
8269
+ changed = !0);
8270
+ changed && subscribers.notify();
8271
+ },
7698
8272
  track(bareId) {
7699
8273
  let entry = live.get(bareId);
7700
8274
  if (entry === void 0) {
@@ -7715,10 +8289,6 @@ function createActualTypeProbeStore(previews) {
7715
8289
  };
7716
8290
  }
7717
8291
 
7718
- function contentDocumentTypes(schema) {
7719
- return schema.getTypeNames().filter(name => schema.get(name)?.type?.name === "document" && !WORKFLOW_SYSTEM_TYPES.includes(name));
7720
- }
7721
-
7722
8292
  async function readDeployedDefinitions(engine) {
7723
8293
  return (await engine.query({
7724
8294
  groq: latestDefinitionsGroq()
@@ -7893,7 +8463,7 @@ const REPORT_FLUSH_MS = 50, EMPTY_COMMITTED = {
7893
8463
 
7894
8464
  function createEntriesStore() {
7895
8465
  let committed = EMPTY_COMMITTED, reports = /* @__PURE__ */ new Map, byInstance = /* @__PURE__ */ new Map, byDocument = /* @__PURE__ */ new Map;
7896
- const listeners = /* @__PURE__ */ new Set;
8466
+ const subscribers = createSubscribers();
7897
8467
  let flushTimer;
7898
8468
  const recompute = () => {
7899
8469
  flushTimer !== void 0 && (clearTimeout(flushTimer), flushTimer = void 0);
@@ -7906,10 +8476,8 @@ function createEntriesStore() {
7906
8476
  byInstance: nextByInstance,
7907
8477
  previous: byDocument
7908
8478
  });
7909
- if (!(nextByInstance === byInstance && nextByDocument === byDocument)) {
7910
- byInstance = nextByInstance, byDocument = nextByDocument;
7911
- for (const listener of [ ...listeners ]) listener();
7912
- }
8479
+ nextByInstance === byInstance && nextByDocument === byDocument || (byInstance = nextByInstance,
8480
+ byDocument = nextByDocument, subscribers.notify());
7913
8481
  };
7914
8482
  return {
7915
8483
  setCommitted(inputs) {
@@ -7925,13 +8493,9 @@ function createEntriesStore() {
7925
8493
  getReport: instanceId => reports.get(instanceId),
7926
8494
  getInstance: instanceId => byInstance.get(instanceId),
7927
8495
  getDocument: docId => byDocument.get(docId) ?? EMPTY_ENTRIES,
7928
- subscribe(listener) {
7929
- return listeners.add(listener), () => {
7930
- listeners.delete(listener);
7931
- };
7932
- },
8496
+ subscribe: subscribers.subscribe,
7933
8497
  dispose() {
7934
- flushTimer !== void 0 && clearTimeout(flushTimer), flushTimer = void 0, listeners.clear();
8498
+ flushTimer !== void 0 && clearTimeout(flushTimer), flushTimer = void 0, subscribers.clear();
7935
8499
  }
7936
8500
  };
7937
8501
  }
@@ -8061,7 +8625,7 @@ function WorkflowProvider(props) {
8061
8625
  try {
8062
8626
  await (drainRef.current?.(instanceId));
8063
8627
  } catch (err) {
8064
- throw new Error(`The change was committed, but running its effects failed: ${describeError(err)}`, {
8628
+ throw new EffectsIncompleteError(describeError(err), {
8065
8629
  cause: err
8066
8630
  });
8067
8631
  }
@@ -8192,12 +8756,19 @@ function WorkflowProvider(props) {
8192
8756
  });
8193
8757
  }
8194
8758
 
8195
- function sameEntries(a, b) {
8196
- if (a.size !== b.size) return !1;
8197
- for (const [key, value] of b) if (a.get(key) !== value) return !1;
8198
- return !0;
8759
+ function entriesSameBy(equal) {
8760
+ return (a, b) => {
8761
+ if (a.size !== b.size) return !1;
8762
+ for (const [key, value] of b) {
8763
+ const previous = a.get(key);
8764
+ if (previous === void 0 || !equal(previous, value)) return !1;
8765
+ }
8766
+ return !0;
8767
+ };
8199
8768
  }
8200
8769
 
8770
+ const sameIssues = entriesSameBy(sameMappingIssue), sameVersions = entriesSameBy(Object.is);
8771
+
8201
8772
  function sameMappings(a, b) {
8202
8773
  return a.length === b.length && a.every((mapping, index) => {
8203
8774
  const other = b[index];
@@ -8221,10 +8792,7 @@ function useDeployedDefinitions(args) {
8221
8792
  contentResource: contentResource,
8222
8793
  schemaContentTypes: schemaContentTypes
8223
8794
  });
8224
- for (const [rowKey, message] of found) {
8225
- const signature = `${rowKey}|${message}`;
8226
- logged.current.has(signature) || (logged.current.add(signature), console.error(`[workflow-studio-plugin] ${message}`));
8227
- }
8795
+ logOnce(mappingIssueLogLines(found), logged.current);
8228
8796
  const resolvedAutoStart = resolveAutoStart({
8229
8797
  autoStart: mappingAutoStartMap(effectiveMappings),
8230
8798
  knownDocTypes: new Set(schema.getTypeNames()),
@@ -8232,7 +8800,7 @@ function useDeployedDefinitions(args) {
8232
8800
  });
8233
8801
  if (logOnce(resolvedAutoStart.warnings, logged.current), cancelled) return;
8234
8802
  setMappings(prev => sameMappings(prev, effectiveMappings) ? prev : effectiveMappings),
8235
- setIssues(prev => sameEntries(prev, found) ? prev : found), setStarts(mappingStartBlocks({
8803
+ setIssues(prev => sameIssues(prev, found) ? prev : found), setStarts(mappingStartBlocks({
8236
8804
  mappings: effectiveMappings,
8237
8805
  definitions: definitions
8238
8806
  })), setFields(mappingDeclaredFields({
@@ -8240,7 +8808,7 @@ function useDeployedDefinitions(args) {
8240
8808
  definitions: definitions
8241
8809
  }));
8242
8810
  const versions = new Map(latestDeployedDefinitions(definitions).map(d => [ d.name, d.version ]));
8243
- setLatestVersions(prev => sameEntries(prev, versions) ? prev : versions), setAutoStartByType(resolvedAutoStart.byType),
8811
+ setLatestVersions(prev => sameVersions(prev, versions) ? prev : versions), setAutoStartByType(resolvedAutoStart.byType),
8244
8812
  setAutoStartDefinitions(resolvedAutoStart.definitions);
8245
8813
  })().catch(err => {
8246
8814
  console.error("[workflow-studio-plugin] mapping discovery failed — keeping the last resolved workflow state:", err);
@@ -8384,16 +8952,8 @@ function ChecklistInput({value: value, onChange: onChange}) {
8384
8952
  value: it.label
8385
8953
  })
8386
8954
  }),
8387
- /* @__PURE__ */ jsx(HoverHint, {
8388
- text: "Remove item",
8389
- children: /* @__PURE__ */ jsx(Button, {
8390
- "aria-label": "Remove item",
8391
- fontSize: 1,
8392
- icon: CloseIcon,
8393
- mode: "bleed",
8394
- onClick: () => remove(i),
8395
- padding: 2
8396
- })
8955
+ /* @__PURE__ */ jsx(RemoveItemButton, {
8956
+ onClick: () => remove(i)
8397
8957
  }) ]
8398
8958
  }, it._key)),
8399
8959
  /* @__PURE__ */ jsx(Flex, {
@@ -8497,7 +9057,7 @@ function useLatestDefinition(definitionName) {
8497
9057
  function useCreateDoc(args) {
8498
9058
  const {releaseId: releaseId, onCreated: onCreated} = args, {engine: engine, binding: binding} = useWorkflowContext(), observer = useStudioObserver({
8499
9059
  engine: engine
8500
- }), schema = useSchema(), templates = useTemplates(), resolverContext = useInitialValueResolverContext(), toast = useClosableToast(), [creating, setCreating] = useState(!1);
9060
+ }), schema = useSchema(), templates = useTemplates(), resolverContext = useInitialValueResolverContext(), toast = useWorkflowToast(), [creating, setCreating] = useState(!1);
8501
9061
  return {
8502
9062
  creating: creating,
8503
9063
  createDoc: async type => {
@@ -8522,8 +9082,9 @@ function useCreateDoc(args) {
8522
9082
  }));
8523
9083
  } catch (err) {
8524
9084
  toast.push({
9085
+ id: TOAST_ID.documentCreate,
8525
9086
  status: "error",
8526
- title: "Could not create document",
9087
+ title: "Failed to create the document",
8527
9088
  description: describeError(err)
8528
9089
  });
8529
9090
  } finally {
@@ -8840,31 +9401,12 @@ function ResumeNote({onStartNew: onStartNew}) {
8840
9401
 
8841
9402
  function handleStartError(args) {
8842
9403
  const {label: label, toast: toast, seedInstance: seedInstance, onClose: onClose} = args, outcome = classifyStartError(args.err);
8843
- if (outcome.kind === "started-not-settled") {
8844
- toast.push({
8845
- status: "warning",
8846
- title: `${label} started, but didn’t finish auto-advancing`,
8847
- description: outcome.description
8848
- }), outcome.instance !== void 0 && seedInstance(outcome.instance), onClose();
8849
- return;
8850
- }
8851
- if (outcome.kind === "not-allowed") {
8852
- toast.push({
8853
- status: "warning",
8854
- title: `${label} can't be started right now`,
8855
- description: outcome.description
8856
- });
8857
- return;
8858
- }
8859
- toast.push({
8860
- status: "error",
8861
- title: `Failed to start ${label}`,
8862
- description: outcome.description
8863
- });
9404
+ toast.push(startOutcomeToast(outcome, label)), outcome.kind === "started-not-settled" && (outcome.instance !== void 0 && seedInstance(outcome.instance),
9405
+ onClose());
8864
9406
  }
8865
9407
 
8866
9408
  function StartWorkflowForm({request: request, onClose: onClose}) {
8867
- const {definition: definitionName, label: label, mapping: mapping, subjectDocId: subjectDocId} = request, {engine: engine, binding: binding, seedInstance: seedInstance} = useWorkflowContext(), telemetry = useWorkflowTelemetry(), toast = useClosableToast(), {def: definition, error: definitionError} = useLatestDefinition(definitionName), {selectedReleaseId: selectedReleaseId} = usePerspective(), releaseId = boundReleaseId(mapping, selectedReleaseId), [values, setValues] = useState({}), [attempt, setAttempt] = useState(void 0), starting = attempt !== void 0, [heldInstanceId, setHeldInstanceId] = useState(void 0), [startNew, setStartNew] = useState(!1), {entries: entries} = useWorkflowsForDocument(subjectDocId), resumeEntry = presentedResumeEntry({
9409
+ const {definition: definitionName, label: label, mapping: mapping, subjectDocId: subjectDocId} = request, {engine: engine, binding: binding, seedInstance: seedInstance} = useWorkflowContext(), telemetry = useWorkflowTelemetry(), toast = useWorkflowToast(), {def: definition, error: definitionError} = useLatestDefinition(definitionName), {selectedReleaseId: selectedReleaseId} = usePerspective(), releaseId = boundReleaseId(mapping, selectedReleaseId), [values, setValues] = useState({}), [attempt, setAttempt] = useState(void 0), starting = attempt !== void 0, [heldInstanceId, setHeldInstanceId] = useState(void 0), [startNew, setStartNew] = useState(!1), {entries: entries} = useWorkflowsForDocument(subjectDocId), resumeEntry = presentedResumeEntry({
8868
9410
  entries: entries,
8869
9411
  definitionName: definitionName,
8870
9412
  heldInstanceId: heldInstanceId,
@@ -8904,8 +9446,9 @@ function StartWorkflowForm({request: request, onClose: onClose}) {
8904
9446
  values: values
8905
9447
  }));
8906
9448
  toast.push({
8907
- status: "success",
8908
- title: `${definition?.title ?? label} started`,
9449
+ id: TOAST_ID.start,
9450
+ status: "info",
9451
+ title: `“${definition?.title ?? label}” started`,
8909
9452
  description: `Stage: ${stageTitle(definition ?? void 0, result.instance.currentStage)}`
8910
9453
  }), seedInstance(result.instance), onClose();
8911
9454
  } catch (err) {
@@ -9407,6 +9950,22 @@ function finishedLinesOf(entries) {
9407
9950
  return [ ...latestByType.values() ].sort((a, b) => b.at - a.at).map(({entry: entry}) => entry);
9408
9951
  }
9409
9952
 
9953
+ function openStageTaskCount(evaluation) {
9954
+ if (evaluation !== void 0) return evaluation.currentStage.activities.filter(activity => isOpenActivityStatus(activity.status)).length;
9955
+ }
9956
+
9957
+ const OPEN_VIEW = "Open the Workflows view";
9958
+
9959
+ function unassignedLineHint(args) {
9960
+ return !args.identityKnown || args.openTaskCount === void 0 ? {
9961
+ text: OPEN_VIEW
9962
+ } : args.openTaskCount === 0 ? {
9963
+ text: "No open tasks in this stage"
9964
+ } : {
9965
+ text: `${pluralize("open task", args.openTaskCount, !0)}, none assigned to you`
9966
+ };
9967
+ }
9968
+
9410
9969
  function WorkflowFormStrip(props) {
9411
9970
  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 => {
9412
9971
  telemetry.log(WorkflowFormStripClicked), setParams(focusedViewParams(params, focusId));
@@ -9451,18 +10010,17 @@ function StripLines({active: active, docId: docId, finished: finished, initialVa
9451
10010
  });
9452
10011
  }
9453
10012
 
9454
- function lineHint(identity, forMe) {
10013
+ function lineHint(entry, identity) {
10014
+ const forMe = forMeWorkOf([ entry ], identity);
9455
10015
  return forMe.work.some(({shown: shown}) => hasOpenAssignedWork(shown)) ? {
9456
10016
  content: /* @__PURE__ */ jsx(AssignedTasksHint, {
9457
10017
  work: forMe.work
9458
10018
  }),
9459
10019
  wide: !0
9460
- } : identity !== void 0 ? {
9461
- text: "Open the Workflows view",
9462
- description: "Nothing here is assigned to you"
9463
- } : {
9464
- text: "Open the Workflows view"
9465
- };
10020
+ } : unassignedLineHint({
10021
+ identityKnown: identity !== void 0,
10022
+ openTaskCount: openStageTaskCount(entry.evaluation)
10023
+ });
9466
10024
  }
9467
10025
 
9468
10026
  function StripLine({aside: aside, children: children, hint: hint, onOpen: onOpen}) {
@@ -9495,7 +10053,7 @@ function InstanceLine({entry: entry, onOpen: onOpen}) {
9495
10053
  aside: unprimed ? void 0 : /* @__PURE__ */ jsx(TaskCountSpinner, {
9496
10054
  entry: entry
9497
10055
  }),
9498
- hint: lineHint(identity, forMeWorkOf([ entry ], identity)),
10056
+ hint: lineHint(entry, identity),
9499
10057
  onOpen: onOpen,
9500
10058
  children: [
9501
10059
  /* @__PURE__ */ jsx(Flex, {
@@ -9615,7 +10173,7 @@ const workflowsTool = {
9615
10173
  title: "Workflows",
9616
10174
  icon: TransferIcon,
9617
10175
  component: LazyWorkflowsTool,
9618
- router: route.create("/", [ route.create("/instance/:instanceId"), route.create("/definition/:definitionName"), route.create("/:workflowsTab") ]),
10176
+ router: route.create("/", [ route.create("/instance/:instanceId"), route.create("/definition/:definitionName"), route.create("/documents/:boardDefinition"), route.create("/:workflowsTab") ]),
9619
10177
  canHandleIntent: (intent, params) => handlesWorkflowIntent(intent, params),
9620
10178
  getIntentState: (intent, params) => workflowIntentState(intent, params)
9621
10179
  }, LOCKABLE_ACTIONS = /* @__PURE__ */ new Map([ [ "delete", "delete" ], [ "publish", "publish" ], [ "unpublish", "unpublish" ] ]);
@@ -9709,4 +10267,4 @@ function WorkflowRootInput(props) {
9709
10267
  });
9710
10268
  }
9711
10269
 
9712
- export { ActivityDetailDialog, ActivityRow, BreadcrumbTail, CautionNote, CollapsibleBand, DismissablePopover, DocPreviewLink, DocRefFace, ForMeEmptyState, HintedMenuButton, HoverHint, InstanceSnapshotBody, InvalidDocNotice, LinkChip, LoadingRow, MetaRow, SpinnerSlot, StageFace, StaleLock, TabSwitch, TrailingHairline, UnreadableDocsNote, UserAvatar, WORKFLOW_API_VERSION, WorkflowInstanceDetailViewed, WorkflowTaskFiltersApplied, WorkflowToolOpened, activityRowProps, assigneeUserIdsOf, committedRowFace, dateControlKind, dateControlValue, definitionSnapshotOf, describeError, findActivity, findActivityNode, formatDate, formatDateTime, formatShortAgo, gdrLocality, instanceBreadcrumb, instanceTitle, isActivityAssignedTo, isEvaluationStale, isOpenActivityStatus, openActivityGone, openableSchemaType, parseDateFieldValue, parseStoredDateValue, pathSegmentTab, readDeployedDefinitions, rowAssignControlState, rowDateControlState, serializeDateFieldValue, stageTitle, stateByActivity, stopRowClick, stopRowMouseDown, useAssignmentIdentity, useAvatarSize, useBadgeCapTrim, useClosableToast, useContainerToken, useDefinition, useLogEventOnMount, useProjectMembers, useSaveField, useSpaceToken, useUserDisplay, useUserDisplays, useWorkflowContext, useWorkflowInstanceEntry, workflowDefaultDocumentNode, workflowStudioPlugin, workflowsView };
10270
+ export { ActivityDetailDialog, ActivityRow, BreadcrumbTail, CautionNote, CollapsibleBand, CountedLabel, DismissablePopover, DocPreviewLink, DocRefFace, EmptyState, ForMeEmptyState, HintedMenuButton, HoverHint, InstanceSnapshotBody, InvalidDocNotice, LinkChip, LoadingRow, LogEventOnMount, MetaRow, NOTICE_PADDING, SpinnerSlot, StageFace, StaleLock, TOAST_ID, TabSwitch, TrailingHairline, UnreadableDocsNote, UserAvatar, WORKFLOW_API_VERSION, WorkflowBoardLayoutChanged, WorkflowBoardWorkflowSelected, WorkflowDefinitionDetailViewed, WorkflowInstanceDetailViewed, WorkflowTaskFiltersApplied, WorkflowTitleSeedDrifted, WorkflowToolOpened, activityRowProps, assigneeUserIdsOf, chipPadding, committedRowFace, createSubscribers, dateControlKind, dateControlValue, definitionFingerprint, definitionSnapshotOf, describeError, findActivity, findActivityNode, formatDate, formatDateTime, formatShortAgo, formatShortDateTime, formatTimeAgo, gdrLocality, hasTimeOfDay, instanceBreadcrumb, instanceTitle, isActivityAssignedTo, isDateFieldKind, isEvaluationStale, isLiveEntry, isOpenActivityStatus, mappingIssueDetail, namesNoDeployedDefinition, openActivityGone, openableSchemaType, parseDateFieldValue, parseStoredDateValue, pathSegmentTab, readDeployedDefinitions, rowAssignControlState, rowDateControlState, serializeDateFieldValue, stageTitle, stateByActivity, stopRowClick, stopRowMouseDown, useAssignmentIdentity, useAvatarSize, useBadgeCapTrim, useContainerToken, useDefinition, useDelayedFlag, useEditField, useLogEventOnMount, useProjectMembers, useRadiusToken, useSaveField, useSpaceToken, useUserDisplay, useUserDisplays, useWorkflowContext, useWorkflowInstanceEntry, useWorkflowToast, workflowDefaultDocumentNode, workflowStudioPlugin, workflowsView };