@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,6 +10,18 @@ function _interopDefaultCompat(e) {
10
10
 
11
11
  var pluralize__default = /* @__PURE__ */ _interopDefaultCompat(pluralize);
12
12
 
13
+ const WORKFLOW_SYSTEM_TYPES = [ workflowEngine.WORKFLOW_INSTANCE_TYPE, workflowEngine.WORKFLOW_DEFINITION_TYPE, workflowEngine.GUARD_DOC_TYPE ];
14
+
15
+ function contentDocumentTypes(schema) {
16
+ return schema.getTypeNames().filter(name => schema.get(name)?.type?.name === "document" && !WORKFLOW_SYSTEM_TYPES.includes(name));
17
+ }
18
+
19
+ const SYSTEM_TYPE_PREFIX = "sanity.";
20
+
21
+ function isSystemDocumentType(name) {
22
+ return name.startsWith(SYSTEM_TYPE_PREFIX) || WORKFLOW_SYSTEM_TYPES.includes(name);
23
+ }
24
+
13
25
  function isLocalContentResource(resource, contentResource) {
14
26
  return resource?.type === "dataset" && resource.id === contentResource.id;
15
27
  }
@@ -34,14 +46,14 @@ function assertUniqueWorkflowMappings(mappings) {
34
46
 
35
47
  function discoverWorkflowMappings(args) {
36
48
  assertUniqueWorkflowMappings(args.overrides ?? []);
37
- const discovered = workflowEngine.latestDeployedDefinitions(args.definitions).flatMap(definition => {
49
+ const bindable = [ ...args.schemaContentTypes ].filter(name => !isSystemDocumentType(name)), discovered = workflowEngine.latestDeployedDefinitions(args.definitions).flatMap(definition => {
38
50
  if (!workflowEngine.isStartableDefinition(definition)) return [];
39
51
  const subject = (definition.fields ?? []).find(workflowEngine.isSubjectEntry);
40
52
  if (subject === void 0 || !workflowEngine.isInputSourced(subject)) return [];
41
53
  const source = {
42
54
  fields: [ ...definition.fields ?? [] ]
43
55
  };
44
- return [ ...args.schemaContentTypes ].filter(docType => workflowEngine.acceptsDocumentType(source, docType)).map(docType => ({
56
+ return bindable.filter(docType => workflowEngine.acceptsDocumentType(source, docType)).map(docType => ({
45
57
  docType: docType,
46
58
  definition: definition.name,
47
59
  label: definition.title ?? definition.name
@@ -172,14 +184,11 @@ function rowProblems(args) {
172
184
  mapping: args.mapping,
173
185
  contentResource: args.contentResource,
174
186
  declared: declared
175
- }), missing = workflowEngine.missingRequiredInputs({
176
- entryDefs: declared,
177
- initialFields: seeded
178
- }), consumptionProblems = workflowEngine.initialFieldIssues({
187
+ });
188
+ return [ ...workflowEngine.initialFieldIssues({
179
189
  workflowFields: declared,
180
190
  initialFields: seeded
181
- }).flatMap(issue => seedConsumptionProblem(issue) ?? []);
182
- return [ ...missing.map(m => `its start would not provide the required entry "${m.name}" (${m.type})`), ...consumptionProblems, ...seeded.flatMap(seed => seedReferenceProblems({
191
+ }).flatMap(issue => seedConsumptionProblem(issue) ?? []), ...seeded.flatMap(seed => seedReferenceProblems({
183
192
  seed: seed,
184
193
  declared: declared
185
194
  })), ...seeded.flatMap(seed => seededSchemaProblems({
@@ -189,12 +198,24 @@ function rowProblems(args) {
189
198
  })) ];
190
199
  }
191
200
 
201
+ const NOT_DEPLOYED = "the definition is not deployed — deploy it or fix the mapping row";
202
+
203
+ function namesNoDeployedDefinition(issue) {
204
+ return issue.version === void 0;
205
+ }
206
+
192
207
  function mappingIssues(args) {
193
208
  const latestByName = new Map(workflowEngine.latestDeployedDefinitions(args.definitions).map(d => [ d.name, d ])), issues = /* @__PURE__ */ new Map;
194
209
  for (const mapping of args.mappings) {
195
- const definition = latestByName.get(mapping.definition);
210
+ const identity = {
211
+ docType: mapping.docType,
212
+ definition: mapping.definition
213
+ }, definition = latestByName.get(mapping.definition);
196
214
  if (definition === void 0) {
197
- 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.`);
215
+ issues.set(mappingKey(mapping), {
216
+ ...identity,
217
+ problems: [ NOT_DEPLOYED ]
218
+ });
198
219
  continue;
199
220
  }
200
221
  const problems = rowProblems({
@@ -203,11 +224,31 @@ function mappingIssues(args) {
203
224
  contentResource: args.contentResource,
204
225
  schemaContentTypes: args.schemaContentTypes
205
226
  });
206
- 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("; ")}.`);
227
+ problems.length > 0 && issues.set(mappingKey(mapping), {
228
+ ...identity,
229
+ version: definition.version,
230
+ problems: problems
231
+ });
207
232
  }
208
233
  return issues;
209
234
  }
210
235
 
236
+ function sameMappingIssue(left, right) {
237
+ 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]);
238
+ }
239
+
240
+ function mappingIssueDetail(issue) {
241
+ return issue.problems.join("; ");
242
+ }
243
+
244
+ function versionSuffix(issue) {
245
+ return issue.version === void 0 ? "" : ` (v${issue.version})`;
246
+ }
247
+
248
+ function mappingIssueLogLines(issues) {
249
+ return [ ...issues.values() ].map(issue => `The "${issue.docType}" → "${issue.definition}" mapping row${versionSuffix(issue)} is disabled: ${mappingIssueDetail(issue)}.`);
250
+ }
251
+
211
252
  const WORKFLOWS_VIEW_ID = "workflows", WORKFLOWS_TAB_PARAM = "workflowsTab";
212
253
 
213
254
  function withoutWorkflowsTab(params) {
@@ -250,10 +291,16 @@ function landingDefaultOpen(landing, instanceId) {
250
291
  if (!(landing === void 0 || !landing.instanceIds.includes(instanceId))) return instanceId === landing.focusedId;
251
292
  }
252
293
 
253
- const WORKFLOWS_TOOL_NAME = "workflows", WORKFLOW_INTENT = "workflow";
294
+ const WORKFLOWS_TOOL_NAME = "workflows";
295
+
296
+ function workflowsToolAvailable(tools) {
297
+ return tools.some(tool => tool.name === WORKFLOWS_TOOL_NAME);
298
+ }
299
+
300
+ const WORKFLOW_INTENT = "workflow";
254
301
 
255
302
  function pathSegmentTab(args) {
256
- return args.tabs.find(tab => tab === args.segment) ?? args.fallback;
303
+ return args.segment === void 0 ? args.fallback : args.tabs.find(tab => tab === args.segment);
257
304
  }
258
305
 
259
306
  function handlesWorkflowIntent(intent, params) {
@@ -267,11 +314,19 @@ function workflowIntentState(intent, params) {
267
314
  } : null;
268
315
  }
269
316
 
270
- const pad2 = n => String(n).padStart(2, "0");
317
+ const pad2 = n => String(n).padStart(2, "0"), DATE_FIELD_KINDS = [ "date", "dueDate", "datetime", "dueDatetime" ], DATE_FIELD_KIND_SET = new Set(DATE_FIELD_KINDS);
318
+
319
+ function isDateFieldKind(kind) {
320
+ return DATE_FIELD_KIND_SET.has(kind);
321
+ }
322
+
323
+ function hasTimeOfDay(kind) {
324
+ return kind === "datetime" || kind === "dueDatetime";
325
+ }
271
326
 
272
327
  function parseDateFieldValue(value, kind) {
273
328
  if (typeof value != "string" || value === "") return;
274
- const parsed2 = kind === "date" ? parseLocalDate(value) : new Date(value);
329
+ const parsed2 = hasTimeOfDay(kind) ? new Date(value) : parseLocalDate(value);
275
330
  return Number.isNaN(parsed2.getTime()) ? void 0 : parsed2;
276
331
  }
277
332
 
@@ -287,16 +342,24 @@ function parseStoredDateValue(value) {
287
342
  }
288
343
 
289
344
  function serializeDateFieldValue(date, kind) {
290
- return kind === "datetime" ? date.toISOString() : `${date.getFullYear()}-${pad2(date.getMonth() + 1)}-${pad2(date.getDate())}`;
345
+ return hasTimeOfDay(kind) ? date.toISOString() : `${date.getFullYear()}-${pad2(date.getMonth() + 1)}-${pad2(date.getDate())}`;
346
+ }
347
+
348
+ class EffectsIncompleteError extends Error {
349
+ reason;
350
+ constructor(reason, options) {
351
+ super(`The change was committed, but running its effects failed: ${reason}`, options),
352
+ this.name = "EffectsIncompleteError", this.reason = reason;
353
+ }
291
354
  }
292
355
 
293
356
  const editDisabledSentence = {
294
357
  "edit-window-closed": () => "Can only be edited while its activity is active",
295
- "editor-not-permitted": () => "You don't have permission to edit this",
358
+ "editor-not-permitted": () => "You dont have permission to edit this",
296
359
  "instance-aborted": () => "This workflow was aborted",
297
360
  "instance-completed": () => "This workflow is already complete",
298
361
  "mutation-guard-denied": () => "An earlier step is holding this document",
299
- "not-editable": () => "This isn't editable here"
362
+ "not-editable": () => "This isnt editable here"
300
363
  };
301
364
 
302
365
  function describeEditDisabledReason(reason) {
@@ -369,24 +432,43 @@ const activityNotActiveSentence = {
369
432
  }, disabledSentence = {
370
433
  "activity-not-active": r => activityNotActiveSentence[r.status],
371
434
  "cascade-fired": () => "This happens automatically — the workflow runs it when its condition is met.",
372
- "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.",
435
+ "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.",
373
436
  "instance-aborted": () => "This workflow was aborted.",
374
437
  "instance-completed": () => "This workflow is already complete.",
375
438
  "mutation-guard-denied": () => "An earlier step is holding this document.",
376
- "requirements-unmet": () => "This step isn't ready yet — a required condition hasn't been met.",
439
+ "requirements-unmet": () => "This step isnt ready yet — a required condition hasnt been met.",
377
440
  "stage-terminal": () => "This stage is finished.",
378
- "subject-permission-denied": () => "You don't have permission to change the document this step works on."
441
+ "subject-permission-denied": () => "You dont have permission to change the document this step works on."
379
442
  };
380
443
 
381
444
  function describeDisabledReason(reason) {
382
445
  return disabledSentence[reason.kind](reason);
383
446
  }
384
447
 
448
+ function readRejection(err) {
449
+ return err instanceof workflowEngine.ActionDisabledError ? {
450
+ kind: "refusal",
451
+ message: describeDisabledReason(err.reason)
452
+ } : err instanceof workflowEngine.MutationGuardDeniedError ? {
453
+ kind: "refusal",
454
+ message: describeDisabledReason({
455
+ kind: "mutation-guard-denied",
456
+ denied: err.denied
457
+ })
458
+ } : err instanceof workflowEngine.EditFieldDeniedError ? {
459
+ kind: "refusal",
460
+ message: describeEditDisabledReason(err.reason)
461
+ } : err instanceof EffectsIncompleteError ? {
462
+ kind: "committed-incomplete",
463
+ message: err.reason
464
+ } : {
465
+ kind: "failure",
466
+ message: workflowEngine.errorMessage(err)
467
+ };
468
+ }
469
+
385
470
  function describeError(err) {
386
- return err instanceof workflowEngine.ActionDisabledError ? describeDisabledReason(err.reason) : err instanceof workflowEngine.MutationGuardDeniedError ? describeDisabledReason({
387
- kind: "mutation-guard-denied",
388
- denied: err.denied
389
- }) : workflowEngine.errorMessage(err);
471
+ return readRejection(err).message;
390
472
  }
391
473
 
392
474
  function hrefIfHttp(value) {
@@ -442,6 +524,28 @@ function isTodoOverdue(item, today = /* @__PURE__ */ new Date) {
442
524
  return !item.dueDate || isTodoDone(item) ? !1 : item.dueDate < serializeDateFieldValue(today, "date");
443
525
  }
444
526
 
527
+ function todoEditKind(patch) {
528
+ return "assignee" in patch ? "assignee" : "due-date";
529
+ }
530
+
531
+ function assertNamesOneRow(items, key) {
532
+ const matches = items.filter(row => row._key === key).length;
533
+ 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.`);
534
+ }
535
+
536
+ function todoItemsPatched(args) {
537
+ const {items: items, key: key, patch: patch} = args;
538
+ return assertNamesOneRow(items, key), items.map(row => row._key === key ? {
539
+ ...row,
540
+ ...patch
541
+ } : row);
542
+ }
543
+
544
+ function todoItemsWithout(args) {
545
+ const {items: items, key: key} = args;
546
+ return assertNamesOneRow(items, key), items.filter(row => row._key !== key);
547
+ }
548
+
445
549
  function tickOpsOf(action) {
446
550
  return (action.ops ?? []).flatMap(o => o.type === "field.updateWhere" ? [ o ] : []);
447
551
  }
@@ -882,7 +986,7 @@ function rowAssignControlState(args) {
882
986
 
883
987
  function rowDateControlState(args) {
884
988
  return rowControlState({
885
- kinds: [ "date", "datetime" ],
989
+ kinds: DATE_FIELD_KINDS,
886
990
  ...args
887
991
  });
888
992
  }
@@ -922,7 +1026,7 @@ function activityRowProps(args) {
922
1026
  }
923
1027
 
924
1028
  function dateControlKind(state) {
925
- if (state.kind === "editable" && (state.field.type === "date" || state.field.type === "datetime")) return state.field.type;
1029
+ if (state.kind === "editable" && isDateFieldKind(state.field.type)) return state.field.type;
926
1030
  }
927
1031
 
928
1032
  function dateControlValue(args) {
@@ -952,7 +1056,7 @@ function deriveActivityDetail(args) {
952
1056
  };
953
1057
  }
954
1058
 
955
- const WORKFLOW_API_VERSION = workflowEngine.ENGINE_API_VERSION, WORKFLOW_SYSTEM_TYPES = [ workflowEngine.WORKFLOW_INSTANCE_TYPE, workflowEngine.WORKFLOW_DEFINITION_TYPE, workflowEngine.GUARD_DOC_TYPE ], EMPTY_ENTRIES = [], WorkflowContext = react.createContext(null);
1059
+ const WORKFLOW_API_VERSION = workflowEngine.ENGINE_API_VERSION, EMPTY_ENTRIES = [], WorkflowContext = react.createContext(null);
956
1060
 
957
1061
  function useWorkflowContext() {
958
1062
  const value = react.useContext(WorkflowContext);
@@ -1004,10 +1108,27 @@ const WorkflowToolOpened = telemetry.defineEvent({
1004
1108
  name: "Editorial Workflows Studio Plugin Instance Detail Viewed",
1005
1109
  version: 1,
1006
1110
  description: "The Workflows tool's per-instance detail view was opened"
1111
+ });
1112
+
1113
+ function definitionFingerprint(definition) {
1114
+ const hash = definition?.contentHash;
1115
+ return hash === void 0 ? {} : {
1116
+ definitionContentHash: hash
1117
+ };
1118
+ }
1119
+
1120
+ const WorkflowDefinitionDetailViewed = telemetry.defineEvent({
1121
+ name: "Editorial Workflows Studio Plugin Definition Detail Viewed",
1122
+ version: 1,
1123
+ description: "The Workflows tool's per-definition detail view was opened"
1007
1124
  }), WorkflowFormStripClicked = telemetry.defineEvent({
1008
1125
  name: "Editorial Workflows Studio Plugin Form Strip Clicked",
1009
1126
  version: 1,
1010
1127
  description: "The form strip's instance line was clicked, opening the document view"
1128
+ }), WorkflowDocumentLinkClicked = telemetry.defineEvent({
1129
+ name: "Editorial Workflows Studio Plugin Document Link Clicked",
1130
+ version: 1,
1131
+ description: "A document link was clicked, opening the referenced document's editor"
1011
1132
  }), WorkflowStartDialogOpened = telemetry.defineEvent({
1012
1133
  name: "Editorial Workflows Studio Plugin Start Dialog Opened",
1013
1134
  version: 1,
@@ -1022,8 +1143,12 @@ const WorkflowToolOpened = telemetry.defineEvent({
1022
1143
  description: "A fresh document's auto-start ran — one start request per configured workflow"
1023
1144
  }), WorkflowActionControlUsed = telemetry.defineEvent({
1024
1145
  name: "Editorial Workflows Studio Plugin Action Control Used",
1025
- version: 1,
1146
+ version: 2,
1026
1147
  description: "An action-firing control was used, attributed to its UI surface"
1148
+ }), WorkflowFieldControlUsed = telemetry.defineEvent({
1149
+ name: "Editorial Workflows Studio Plugin Field Control Used",
1150
+ version: 1,
1151
+ description: "A field-editing control committed an edit, attributed to its UI surface"
1027
1152
  }), WorkflowActivityDialogOpened = telemetry.defineEvent({
1028
1153
  name: "Editorial Workflows Studio Plugin Activity Dialog Opened",
1029
1154
  version: 1,
@@ -1032,10 +1157,26 @@ const WorkflowToolOpened = telemetry.defineEvent({
1032
1157
  name: "Editorial Workflows Studio Plugin Task Filters Applied",
1033
1158
  version: 1,
1034
1159
  description: "The tool's task-filter menu closed with a changed selection"
1160
+ }), WorkflowBoardWorkflowSelected = telemetry.defineEvent({
1161
+ name: "Editorial Workflows Studio Plugin Board Workflow Selected",
1162
+ version: 1,
1163
+ description: "The Documents board settled on a workflow to show"
1164
+ }), WorkflowBoardLayoutChanged = telemetry.defineEvent({
1165
+ name: "Editorial Workflows Studio Plugin Board Layout Changed",
1166
+ version: 1,
1167
+ description: "The Documents board's layout was switched"
1168
+ }), WorkflowTitleSeedDrifted = telemetry.defineEvent({
1169
+ name: "Editorial Workflows Studio Plugin Title Seed Drifted",
1170
+ version: 1,
1171
+ description: "A cold-start seeded preview title diverged from the live preview pipeline"
1035
1172
  }), WorkflowTodoToggled = telemetry.defineEvent({
1036
1173
  name: "Editorial Workflows Studio Plugin Todo Toggled",
1037
1174
  version: 1,
1038
1175
  description: "A todo checkbox was toggled, attributed to its UI surface and write seam"
1176
+ }), WorkflowTodoEdited = telemetry.defineEvent({
1177
+ name: "Editorial Workflows Studio Plugin Todo Edited",
1178
+ version: 1,
1179
+ description: "A non-toggle todo-list write, attributed to its UI surface and gesture"
1039
1180
  });
1040
1181
 
1041
1182
  function useLogEventOnMount(event, data) {
@@ -1125,20 +1266,32 @@ function useUserDisplay(id) {
1125
1266
  };
1126
1267
  }
1127
1268
 
1128
- const warnedNotMember = /* @__PURE__ */ new Set;
1269
+ const warnedSelfUnavailable = /* @__PURE__ */ new Set;
1270
+
1271
+ function warnSelfUnavailableOnce(key, message) {
1272
+ warnedSelfUnavailable.has(key) || (warnedSelfUnavailable.add(key), console.warn(message));
1273
+ }
1274
+
1275
+ function bridgedSelfId(users, meId) {
1276
+ const classified = workflowEngine.classifyPrincipalId(meId);
1277
+ return users.find(user => user.membership.id === meId)?.profile?.sanityUserId ?? classified.globalId ?? (classified.namespace === "project" ? void 0 : meId);
1278
+ }
1129
1279
 
1130
1280
  function useBridgedSelf() {
1131
- const me = sanity.useCurrentUser(), {users: users, loading: loading} = workflowStudio.useStudioProjectUsers();
1132
- if (!me || loading) return;
1133
- const classified = workflowEngine.classifyPrincipalId(me.id), id = users.find(user => user.membership.id === me.id)?.profile?.sanityUserId ?? classified.globalId ?? (classified.namespace === "project" ? void 0 : me.id);
1134
- if (id === void 0) {
1135
- 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.`));
1136
- return;
1137
- }
1138
- return {
1281
+ const me = sanity.useCurrentUser(), {users: users, loading: loading, error: error} = workflowStudio.useStudioProjectUsers();
1282
+ if (!me) return;
1283
+ const id = bridgedSelfId(users, me.id);
1284
+ if (id !== void 0) return {
1139
1285
  id: id,
1140
1286
  roles: me.roles ?? []
1141
1287
  };
1288
+ if (!loading) {
1289
+ if (error !== void 0) {
1290
+ warnSelfUnavailableOnce(`load:${me.id}`, `workflow: the project member directory failed to load ("${workflowEngine.errorMessage(error)}") — the logged-in user ("${me.id}") is project-scoped, and only that directory maps it to the account-global identity the engine stores, so workflow assignment and authoring controls stay disabled. A mounted view does not retry on its own; the next consumer to ask reloads the directory once its backoff has passed.`);
1291
+ return;
1292
+ }
1293
+ 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.`);
1294
+ }
1142
1295
  }
1143
1296
 
1144
1297
  function useSelfActor() {
@@ -1279,8 +1432,11 @@ function HoverHint(props) {
1279
1432
  children: /* @__PURE__ */ jsxRuntime.jsx(ui.Box, {
1280
1433
  "data-testid": props["data-testid"],
1281
1434
  style: {
1282
- display: "inline-flex",
1283
- maxWidth: "100%"
1435
+ display: props.fill ? "flex" : "inline-flex",
1436
+ maxWidth: "100%",
1437
+ ...props.fill ? {
1438
+ width: "100%"
1439
+ } : {}
1284
1440
  },
1285
1441
  children: children
1286
1442
  })
@@ -1368,7 +1524,7 @@ function DismissablePopover({children: children, content: content2, onDismiss: o
1368
1524
  function DateFieldInput({kind: kind, value: value, onChange: onChange, readOnly: readOnly = !1}) {
1369
1525
  const [open, setOpen] = react.useState(!1), parsed2 = parseDateFieldValue(value, kind), close = () => setOpen(!1), toggle = () => {
1370
1526
  readOnly || setOpen(v => !v);
1371
- };
1527
+ }, pickHint = hasTimeOfDay(kind) ? "Pick a date and time…" : "Pick a date…";
1372
1528
  /* @__PURE__ */
1373
1529
  return jsxRuntime.jsx(DismissablePopover, {
1374
1530
  content: /* @__PURE__ */ jsxRuntime.jsx(workflowComponents.ClearableDatePicker, {
@@ -1379,7 +1535,7 @@ function DateFieldInput({kind: kind, value: value, onChange: onChange, readOnly:
1379
1535
  onPick: next => {
1380
1536
  close(), onChange(serializeDateFieldValue(next, kind));
1381
1537
  },
1382
- selectTime: kind === "datetime",
1538
+ selectTime: hasTimeOfDay(kind),
1383
1539
  value: parsed2
1384
1540
  }),
1385
1541
  onDismiss: close,
@@ -1392,7 +1548,7 @@ function DateFieldInput({kind: kind, value: value, onChange: onChange, readOnly:
1392
1548
  children: /* @__PURE__ */ jsxRuntime.jsx(ui.TextInput, {
1393
1549
  fontSize: 1,
1394
1550
  onClick: toggle,
1395
- placeholder: readOnly ? "" : kind === "datetime" ? "Pick a date and time…" : "Pick a date…",
1551
+ placeholder: readOnly ? "" : pickHint,
1396
1552
  readOnly: !0,
1397
1553
  value: parsed2 ? formatDate(String(value)) : ""
1398
1554
  })
@@ -1436,7 +1592,7 @@ function ChoiceSelect({options: options, value: value, onChange: onChange, readO
1436
1592
  });
1437
1593
  }
1438
1594
 
1439
- const SCALAR_INPUT_KINDS = [ "string", "text", "url", "number", "progress", "date", "dateTime", "datetime", "boolean" ], SCALAR_INPUT_KIND_SET = new Set(SCALAR_INPUT_KINDS);
1595
+ const SCALAR_INPUT_KINDS = [ "string", "text", "url", "number", "progress", ...DATE_FIELD_KINDS, "dateTime", "boolean" ], SCALAR_INPUT_KIND_SET = new Set(SCALAR_INPUT_KINDS);
1440
1596
 
1441
1597
  function isScalarInputKind(kind) {
1442
1598
  return SCALAR_INPUT_KIND_SET.has(kind);
@@ -1454,8 +1610,8 @@ function ScalarInput({kind: kind, value: value, onChange: onChange, options: opt
1454
1610
  }) : kind === "boolean" ? /* @__PURE__ */ jsxRuntime.jsx(ui.Checkbox, {
1455
1611
  checked: value === !0,
1456
1612
  onChange: e => onChange(e.currentTarget.checked)
1457
- }) : kind === "date" || kind === "dateTime" || kind === "datetime" ? /* @__PURE__ */ jsxRuntime.jsx(DateFieldInput, {
1458
- kind: kind === "date" ? "date" : "datetime",
1613
+ }) : isDateFieldKind(kind) || kind === "dateTime" ? /* @__PURE__ */ jsxRuntime.jsx(DateFieldInput, {
1614
+ kind: kind === "dateTime" ? "datetime" : kind,
1459
1615
  onChange: next => onChange(next ?? ""),
1460
1616
  value: value
1461
1617
  }) : /* @__PURE__ */ jsxRuntime.jsx(ui.TextInput, {
@@ -1561,11 +1717,16 @@ function useStubValuePreview(id, schemaType) {
1561
1717
  };
1562
1718
  }
1563
1719
 
1720
+ function PreviewPlaceholder() {
1721
+ /* @__PURE__ */
1722
+ return jsxRuntime.jsx(sanity.SanityDefaultPreview, {
1723
+ isPlaceholder: !0
1724
+ });
1725
+ }
1726
+
1564
1727
  function StubPreview({id: id, schemaType: schemaType}) {
1565
1728
  const {value: value, preview: preview} = useStubValuePreview(id, schemaType);
1566
- return preview.isLoading ? /* @__PURE__ */ jsxRuntime.jsx(sanity.SanityDefaultPreview, {
1567
- isPlaceholder: !0
1568
- }) : /* @__PURE__ */ jsxRuntime.jsx(sanity.Preview, {
1729
+ return preview.isLoading ? /* @__PURE__ */ jsxRuntime.jsx(PreviewPlaceholder, {}) : /* @__PURE__ */ jsxRuntime.jsx(sanity.Preview, {
1569
1730
  layout: "default",
1570
1731
  schemaType: schemaType,
1571
1732
  skipVisibilityCheck: !0,
@@ -1798,14 +1959,87 @@ function ParamsForm({decls: decls, values: values, onChange: onChange}) {
1798
1959
  });
1799
1960
  }
1800
1961
 
1801
- function useClosableToast() {
1962
+ const TOAST_ID = {
1963
+ abort: "workflow-abort",
1964
+ detailsCopy: "workflow-details-copy",
1965
+ documentCreate: "workflow-document-create",
1966
+ documentSave: "workflow-document-save",
1967
+ effectResolve: "workflow-effect-resolve",
1968
+ effectsDrain: "workflow-effects-drain",
1969
+ effectsIncomplete: "workflow-effects-incomplete",
1970
+ orphanSettle: "workflow-orphan-settle",
1971
+ start: "workflow-start"
1972
+ };
1973
+
1974
+ function instanceToastId(gesture, instanceId) {
1975
+ return `workflow-${gesture}:${instanceId}`;
1976
+ }
1977
+
1978
+ function actionFireToastId(args) {
1979
+ return `workflow-action-fire:${args.instanceId}:${args.activity}:${args.action}`;
1980
+ }
1981
+
1982
+ const REASON_TOAST_DURATION = 2e4, DISMISS_SENTINEL_DURATION = .01;
1983
+
1984
+ function carriesReason(params) {
1985
+ return params.description !== void 0 && params.status !== "info";
1986
+ }
1987
+
1988
+ function withConvention(params) {
1989
+ return {
1990
+ ...params,
1991
+ closable: !0,
1992
+ ...carriesReason(params) ? {
1993
+ duration: REASON_TOAST_DURATION
1994
+ } : {}
1995
+ };
1996
+ }
1997
+
1998
+ function useWorkflowToast() {
1802
1999
  const toast = ui.useToast();
1803
2000
  return react.useMemo(() => ({
1804
- ...toast,
1805
- push: params => toast.push({
1806
- ...params,
1807
- closable: !0
1808
- })
2001
+ push: params => {
2002
+ toast.push(withConvention(params));
2003
+ },
2004
+ dismiss: id => {
2005
+ toast.push({
2006
+ id: id,
2007
+ duration: DISMISS_SENTINEL_DURATION
2008
+ });
2009
+ }
2010
+ }), [ toast ]);
2011
+ }
2012
+
2013
+ const COMMITTED_INCOMPLETE_TITLE = "Saved, but its follow-up didn’t run";
2014
+
2015
+ function rejectionToast(reading, titles) {
2016
+ return reading.kind === "committed-incomplete" ? {
2017
+ id: TOAST_ID.effectsIncomplete,
2018
+ status: "warning",
2019
+ title: COMMITTED_INCOMPLETE_TITLE,
2020
+ description: reading.message
2021
+ } : reading.kind === "refusal" ? {
2022
+ id: titles.id,
2023
+ status: "warning",
2024
+ title: titles.refused,
2025
+ description: reading.message
2026
+ } : {
2027
+ id: titles.id,
2028
+ status: "error",
2029
+ title: titles.failed,
2030
+ description: reading.message
2031
+ };
2032
+ }
2033
+
2034
+ function useRejectionReport() {
2035
+ const toast = useWorkflowToast();
2036
+ return react.useMemo(() => ({
2037
+ rejected: args => {
2038
+ const reading = readRejection(args.err);
2039
+ reading.kind !== "refusal" && console.error(`[workflow-studio-plugin] ${args.context} rejected:`, args.err),
2040
+ toast.push(rejectionToast(reading, args));
2041
+ },
2042
+ dismiss: toast.dismiss
1809
2043
  }), [ toast ]);
1810
2044
  }
1811
2045
 
@@ -1828,10 +2062,21 @@ function useActionClusterPending() {
1828
2062
  }
1829
2063
 
1830
2064
  function useFireAction(args) {
1831
- const {instanceId: instanceId, activity: activity, action: action, label: label, surface: surface, viaMenu: viaMenu} = args, {fireActionFor: fireActionFor} = useWorkflowContext(), telemetry2 = workflowReact.useWorkflowTelemetry(), toast = useClosableToast(), cluster = useActionClusterLock(), [localPending, setLocalPending] = react.useState(!1), pending = localPending || cluster?.pending === !0;
2065
+ const {instanceId: instanceId, activity: activity, action: action, label: label, surface: surface, placement: placement, viaMenu: viaMenu} = args, {fireActionFor: fireActionFor} = useWorkflowContext(), telemetry2 = workflowReact.useWorkflowTelemetry(), report = useRejectionReport(), cluster = useActionClusterLock(), [localPending, setLocalPending] = react.useState(!1), pending = localPending || cluster?.pending === !0, toastId = actionFireToastId({
2066
+ instanceId: instanceId,
2067
+ activity: activity,
2068
+ action: action
2069
+ });
1832
2070
  return {
1833
2071
  fire: react.useCallback(async params => {
1834
2072
  if (pending) return !1;
2073
+ const log = success => telemetry2.log(WorkflowActionControlUsed, {
2074
+ instanceId: instanceId,
2075
+ surface: surface,
2076
+ placement: placement,
2077
+ viaMenu: viaMenu,
2078
+ success: success
2079
+ });
1835
2080
  setLocalPending(!0), cluster?.onFireChange(!0);
1836
2081
  try {
1837
2082
  return await fireActionFor(instanceId, {
@@ -1840,31 +2085,19 @@ function useFireAction(args) {
1840
2085
  ...params && Object.keys(params).length > 0 ? {
1841
2086
  params: params
1842
2087
  } : {}
1843
- }), toast.push({
1844
- status: "success",
1845
- title: `${label} done`
1846
- }), telemetry2.log(WorkflowActionControlUsed, {
1847
- instanceId: instanceId,
1848
- surface: surface,
1849
- viaMenu: viaMenu,
1850
- success: !0
1851
- }), !0;
2088
+ }), report.dismiss(toastId), log(!0), !0;
1852
2089
  } catch (err) {
1853
- return console.error(`[workflow-studio-plugin] firing "${action}" on "${activity}" failed:`, err),
1854
- toast.push({
1855
- status: "error",
1856
- title: `${label} failed`,
1857
- description: describeError(err)
1858
- }), telemetry2.log(WorkflowActionControlUsed, {
1859
- instanceId: instanceId,
1860
- surface: surface,
1861
- viaMenu: viaMenu,
1862
- success: !1
1863
- }), !1;
2090
+ return report.rejected({
2091
+ err: err,
2092
+ context: `firing "${action}" on "${activity}"`,
2093
+ id: toastId,
2094
+ refused: `“${label}” isn’t available right now`,
2095
+ failed: `Failed to complete “${label}”`
2096
+ }), log(!1), !1;
1864
2097
  } finally {
1865
2098
  setLocalPending(!1), cluster?.onFireChange(!1);
1866
2099
  }
1867
- }, [ fireActionFor, instanceId, activity, action, label, pending, toast, cluster, telemetry2, surface, viaMenu ]),
2100
+ }, [ fireActionFor, instanceId, activity, action, label, pending, report, toastId, cluster, telemetry2, surface, placement, viaMenu ]),
1868
2101
  pending: pending
1869
2102
  };
1870
2103
  }
@@ -1905,13 +2138,14 @@ function RowClickShield({active: active, children: children}) {
1905
2138
  });
1906
2139
  }
1907
2140
 
1908
- function FireButton({instanceId: instanceId, activity: activity, action: action, label: label, surface: surface, mode: mode = "default", chrome: chrome, tone: tone = "default", icon: icon}) {
2141
+ function FireButton({instanceId: instanceId, activity: activity, action: action, label: label, surface: surface, placement: placement, mode: mode = "default", chrome: chrome, tone: tone = "default", icon: icon}) {
1909
2142
  const {fire: fire, pending: pending} = useFireAction({
1910
2143
  instanceId: instanceId,
1911
2144
  activity: activity,
1912
2145
  action: action,
1913
2146
  label: label,
1914
2147
  surface: surface,
2148
+ placement: placement,
1915
2149
  viaMenu: !1
1916
2150
  }), handleClick = e => {
1917
2151
  chrome?.inButtonCard === !0 && e.stopPropagation(), !pending && fire();
@@ -1933,7 +2167,7 @@ function FireButton({instanceId: instanceId, activity: activity, action: action,
1933
2167
  });
1934
2168
  }
1935
2169
 
1936
- function ActivityActionRow({actionEval: actionEval, instanceId: instanceId, activity: activity, surface: surface, chrome: chrome}) {
2170
+ function ActivityActionRow({actionEval: actionEval, instanceId: instanceId, activity: activity, surface: surface, placement: placement, chrome: chrome}) {
1937
2171
  const rowKind = actionRowKind(actionEval);
1938
2172
  return rowKind.kind === "disabled" ? /* @__PURE__ */ jsxRuntime.jsx(DisabledActionButton, {
1939
2173
  actionEval: actionEval,
@@ -1944,12 +2178,14 @@ function ActivityActionRow({actionEval: actionEval, instanceId: instanceId, acti
1944
2178
  instanceId: instanceId,
1945
2179
  activity: activity,
1946
2180
  chrome: chrome,
2181
+ placement: placement,
1947
2182
  surface: surface
1948
2183
  }) : /* @__PURE__ */ jsxRuntime.jsx(ParamsActionButton, {
1949
2184
  actionEval: actionEval,
1950
2185
  instanceId: instanceId,
1951
2186
  activity: activity,
1952
2187
  chrome: chrome,
2188
+ placement: placement,
1953
2189
  surface: surface
1954
2190
  });
1955
2191
  }
@@ -1975,7 +2211,7 @@ function DisabledActionButton({actionEval: actionEval, activity: activity, chrom
1975
2211
  }) : button;
1976
2212
  }
1977
2213
 
1978
- function PlainActionButton({actionEval: actionEval, instanceId: instanceId, activity: activity, surface: surface, chrome: chrome}) {
2214
+ function PlainActionButton({actionEval: actionEval, instanceId: instanceId, activity: activity, surface: surface, placement: placement, chrome: chrome}) {
1979
2215
  const {action: action} = actionEval, label = actionLabel(action), btn = actionButtonFace({
1980
2216
  actionEval: actionEval,
1981
2217
  activityName: activity
@@ -1987,6 +2223,7 @@ function PlainActionButton({actionEval: actionEval, instanceId: instanceId, acti
1987
2223
  mode: btn.mode,
1988
2224
  activity: activity,
1989
2225
  chrome: chrome,
2226
+ placement: placement,
1990
2227
  surface: surface,
1991
2228
  tone: btn.tone
1992
2229
  });
@@ -1996,13 +2233,14 @@ function PlainActionButton({actionEval: actionEval, instanceId: instanceId, acti
1996
2233
  }) : button;
1997
2234
  }
1998
2235
 
1999
- function ParamsActionDialog({actionEval: actionEval, instanceId: instanceId, activity: activity, surface: surface, viaMenu: viaMenu, onClose: onClose}) {
2236
+ function ParamsActionDialog({actionEval: actionEval, instanceId: instanceId, activity: activity, surface: surface, placement: placement, viaMenu: viaMenu, onClose: onClose}) {
2000
2237
  const {action: action} = actionEval, label = actionLabel(action), decls = action.params ?? [], [values, setValues] = react.useState({}), {fire: fire, pending: pending} = useFireAction({
2001
2238
  instanceId: instanceId,
2002
2239
  activity: activity,
2003
2240
  action: action.name,
2004
2241
  label: label,
2005
2242
  surface: surface,
2243
+ placement: placement,
2006
2244
  viaMenu: viaMenu
2007
2245
  }), built = buildParams(decls, values), confirm = async () => {
2008
2246
  await fire(built.params) && onClose();
@@ -2058,7 +2296,7 @@ function ParamsActionDialog({actionEval: actionEval, instanceId: instanceId, act
2058
2296
  });
2059
2297
  }
2060
2298
 
2061
- function ParamsActionButton({actionEval: actionEval, instanceId: instanceId, activity: activity, surface: surface, chrome: chrome}) {
2299
+ function ParamsActionButton({actionEval: actionEval, instanceId: instanceId, activity: activity, surface: surface, placement: placement, chrome: chrome}) {
2062
2300
  const [open, setOpen] = react.useState(!1), btn = actionButtonFace({
2063
2301
  actionEval: actionEval,
2064
2302
  activityName: activity
@@ -2084,6 +2322,7 @@ function ParamsActionButton({actionEval: actionEval, instanceId: instanceId, act
2084
2322
  activity: activity,
2085
2323
  instanceId: instanceId,
2086
2324
  onClose: () => setOpen(!1),
2325
+ placement: placement,
2087
2326
  surface: surface,
2088
2327
  viaMenu: !1
2089
2328
  })
@@ -2257,7 +2496,9 @@ function FieldInput$1({kind: kind, value: value, onChange: onChange, onEnter: on
2257
2496
  });
2258
2497
 
2259
2498
  case "date":
2499
+ case "dueDate":
2260
2500
  case "datetime":
2501
+ case "dueDatetime":
2261
2502
  /* @__PURE__ */
2262
2503
  return jsxRuntime.jsx(DateFieldInput, {
2263
2504
  kind: kind,
@@ -2303,22 +2544,76 @@ function FieldInput$1({kind: kind, value: value, onChange: onChange, onEnter: on
2303
2544
  }
2304
2545
  }
2305
2546
 
2306
- function LinkChip({hint: hint, children: children, as: as = "a", ...anchorProps}) {
2547
+ function useDelayedFlag(active, delayMs) {
2548
+ const [held, setHeld] = react.useState(!1);
2549
+ return react.useEffect(() => {
2550
+ if (!active) {
2551
+ setHeld(!1);
2552
+ return;
2553
+ }
2554
+ const timer = setTimeout(() => setHeld(!0), delayMs);
2555
+ return () => clearTimeout(timer);
2556
+ }, [ active, delayMs ]), held && active;
2557
+ }
2558
+
2559
+ function isCompact(layout) {
2560
+ return layout === "inline" || layout === "row";
2561
+ }
2562
+
2563
+ function docFaceChrome(args) {
2564
+ const {layout: layout, state: state} = args, compact = isCompact(layout);
2565
+ switch (state.kind) {
2566
+ case "linked":
2567
+ return {
2568
+ bareId: state.bareId,
2569
+ selfInset: !compact
2570
+ };
2571
+
2572
+ case "foreign":
2573
+ return {};
2574
+
2575
+ case "missing":
2576
+ return {
2577
+ tone: "caution"
2578
+ };
2579
+
2580
+ case "unopenable":
2581
+ return {};
2582
+
2583
+ case "pending":
2584
+ return compact ? {} : {
2585
+ selfInset: !0
2586
+ };
2587
+
2588
+ case "unresolvable":
2589
+ return {};
2590
+ }
2591
+ }
2592
+
2593
+ function chipPadding(fill) {
2594
+ return fill ? 3 : 2;
2595
+ }
2596
+
2597
+ function LinkChip({hint: hint, children: children, as: as = "a", fill: fill = !1, ...anchorProps}) {
2307
2598
  /* @__PURE__ */
2308
2599
  return jsxRuntime.jsx(HoverHint, {
2600
+ fill: fill,
2309
2601
  text: hint,
2310
2602
  children: /* @__PURE__ */ jsxRuntime.jsx(ui.Card, {
2311
2603
  __unstable_focusRing: !0,
2312
2604
  as: as,
2313
2605
  "data-as": "a",
2314
- padding: 2,
2606
+ padding: chipPadding(fill),
2315
2607
  radius: 3,
2316
2608
  style: {
2317
2609
  alignItems: "center",
2318
2610
  color: "inherit",
2319
2611
  display: "flex",
2320
2612
  minWidth: 0,
2321
- textDecoration: "none"
2613
+ textDecoration: "none",
2614
+ ...fill ? {
2615
+ width: "100%"
2616
+ } : {}
2322
2617
  },
2323
2618
  tone: "inherit",
2324
2619
  ...anchorProps,
@@ -2437,7 +2732,7 @@ function DocRefFace({gdr: gdr}) {
2437
2732
  });
2438
2733
  }
2439
2734
 
2440
- function ForeignRefNotice({bareId: bareId, resource: resource}) {
2735
+ function foreignNotice(bareId, resource) {
2441
2736
  const location = resource.type === "dataset" ? `another dataset (${resource.id})` : `${resource.type} (${resource.id})`;
2442
2737
  /* @__PURE__ */
2443
2738
  return jsxRuntime.jsxs(ui.Text, {
@@ -2447,44 +2742,22 @@ function ForeignRefNotice({bareId: bareId, resource: resource}) {
2447
2742
  });
2448
2743
  }
2449
2744
 
2450
- function MissingDocNotice({bareId: bareId, layout: layout}) {
2451
- return layout === "inline" ?
2452
- /* @__PURE__ */ jsxRuntime.jsx(ui.Box, {
2453
- padding: 2,
2454
- children: /* @__PURE__ */ jsxRuntime.jsxs(ui.Flex, {
2455
- align: "center",
2456
- gap: 2,
2457
- children: [
2458
- /* @__PURE__ */ jsxRuntime.jsx(ui.Text, {
2459
- muted: !0,
2460
- size: 1,
2461
- children: /* @__PURE__ */ jsxRuntime.jsx(WarningOutline.WarningOutlineIcon, {})
2462
- }),
2463
- /* @__PURE__ */ jsxRuntime.jsx(ui.Text, {
2464
- muted: !0,
2465
- size: 1,
2466
- children: "Document unavailable"
2467
- }) ]
2468
- })
2469
- }) : /* @__PURE__ */ jsxRuntime.jsx(ui.Card, {
2470
- border: !0,
2471
- padding: 2,
2472
- radius: 3,
2473
- tone: "caution",
2474
- children: /* @__PURE__ */ jsxRuntime.jsxs(ui.Flex, {
2475
- align: "center",
2476
- gap: 2,
2477
- children: [
2478
- /* @__PURE__ */ jsxRuntime.jsx(ui.Text, {
2479
- size: 1,
2480
- children: /* @__PURE__ */ jsxRuntime.jsx(WarningOutline.WarningOutlineIcon, {})
2481
- }),
2482
- /* @__PURE__ */ jsxRuntime.jsxs(ui.Text, {
2483
- muted: !0,
2484
- size: 1,
2485
- children: [ "Document unavailable — ", bareId ]
2486
- }) ]
2487
- })
2745
+ function missingNotice(bareId, layout) {
2746
+ /* @__PURE__ */
2747
+ return jsxRuntime.jsxs(ui.Flex, {
2748
+ align: "center",
2749
+ gap: 2,
2750
+ children: [
2751
+ /* @__PURE__ */ jsxRuntime.jsx(ui.Text, {
2752
+ muted: !0,
2753
+ size: 1,
2754
+ children: /* @__PURE__ */ jsxRuntime.jsx(WarningOutline.WarningOutlineIcon, {})
2755
+ }),
2756
+ /* @__PURE__ */ jsxRuntime.jsx(ui.Text, {
2757
+ muted: !0,
2758
+ size: 1,
2759
+ children: isCompact(layout) ? "Document unavailable" : `Document unavailable — ${bareId}`
2760
+ }) ]
2488
2761
  });
2489
2762
  }
2490
2763
 
@@ -2501,6 +2774,18 @@ function renderTypeIcon(icon) {
2501
2774
  return typeof icon == "function" ? react.createElement(icon) : react.isValidElement(icon) ? icon : /* @__PURE__ */ jsxRuntime.jsx(Document.DocumentIcon, {});
2502
2775
  }
2503
2776
 
2777
+ function TitleSkeleton() {
2778
+ /* @__PURE__ */
2779
+ return jsxRuntime.jsx(ui.TextSkeleton, {
2780
+ animated: !0,
2781
+ radius: 1,
2782
+ size: 1,
2783
+ style: {
2784
+ width: 96
2785
+ }
2786
+ });
2787
+ }
2788
+
2504
2789
  function InlineChipFace({bareId: bareId, schemaType: schemaType}) {
2505
2790
  const {preview: preview} = useStubValuePreview(bareId, schemaType);
2506
2791
  /* @__PURE__ */
@@ -2511,14 +2796,7 @@ function InlineChipFace({bareId: bareId, schemaType: schemaType}) {
2511
2796
  /* @__PURE__ */ jsxRuntime.jsx(ui.Text, {
2512
2797
  size: 1,
2513
2798
  children: renderTypeIcon(schemaType.icon)
2514
- }), preview.isLoading ? /* @__PURE__ */ jsxRuntime.jsx(ui.TextSkeleton, {
2515
- animated: !0,
2516
- radius: 1,
2517
- size: 1,
2518
- style: {
2519
- width: 96
2520
- }
2521
- }) : /* @__PURE__ */ jsxRuntime.jsx(ui.Text, {
2799
+ }), preview.isLoading ? /* @__PURE__ */ jsxRuntime.jsx(TitleSkeleton, {}) : /* @__PURE__ */ jsxRuntime.jsx(ui.Text, {
2522
2800
  size: 1,
2523
2801
  textOverflow: "ellipsis",
2524
2802
  weight: "medium",
@@ -2529,8 +2807,59 @@ function InlineChipFace({bareId: bareId, schemaType: schemaType}) {
2529
2807
  });
2530
2808
  }
2531
2809
 
2532
- function LinkedDocPreview({bareId: bareId, layout: layout, schemaType: schemaType}) {
2533
- const EditIntentLink = react.useMemo(() => function(linkProps) {
2810
+ const NOTICE_PADDING = 2;
2811
+
2812
+ function CompactDocRef({face: face, fill: fill, link: link, onClick: onClick}) {
2813
+ return link === void 0 ? /* @__PURE__ */ jsxRuntime.jsx(ui.Box, {
2814
+ padding: chipPadding(fill),
2815
+ style: fill ? {
2816
+ width: "100%"
2817
+ } : {},
2818
+ children: face.content
2819
+ }) : /* @__PURE__ */ jsxRuntime.jsx(LinkChip, {
2820
+ as: link,
2821
+ fill: fill,
2822
+ hint: "Open document",
2823
+ onClick: onClick,
2824
+ children: face.content
2825
+ });
2826
+ }
2827
+
2828
+ const PENDING_FACE_MAX_WAIT_MS = 4e3;
2829
+
2830
+ function PendingDocFace({bareId: bareId, layout: layout}) {
2831
+ const expired = useDelayedFlag(!0, PENDING_FACE_MAX_WAIT_MS), compact = isCompact(layout);
2832
+ if (expired) {
2833
+ const id = /* @__PURE__ */ jsxRuntime.jsx(ui.Text, {
2834
+ muted: !0,
2835
+ size: 1,
2836
+ children: bareId
2837
+ });
2838
+ return compact ? id : /* @__PURE__ */ jsxRuntime.jsx(ui.Box, {
2839
+ padding: NOTICE_PADDING,
2840
+ children: id
2841
+ });
2842
+ }
2843
+ return compact ?
2844
+ /* @__PURE__ */ jsxRuntime.jsxs(ui.Flex, {
2845
+ align: "center",
2846
+ gap: 2,
2847
+ children: [
2848
+ /* @__PURE__ */ jsxRuntime.jsx(ui.Text, {
2849
+ muted: !0,
2850
+ size: 1,
2851
+ children: /* @__PURE__ */ jsxRuntime.jsx(Document.DocumentIcon, {})
2852
+ }),
2853
+ /* @__PURE__ */ jsxRuntime.jsx(TitleSkeleton, {}) ]
2854
+ }) : /* @__PURE__ */ jsxRuntime.jsx(PreviewPlaceholder, {});
2855
+ }
2856
+
2857
+ function DocRefShell({face: face, layout: layout, source: source}) {
2858
+ const telemetry2 = workflowReact.useWorkflowTelemetry(), {bareId: bareId} = face, handleClick = e => {
2859
+ e.stopPropagation(), telemetry2.log(WorkflowDocumentLinkClicked, {
2860
+ source: source
2861
+ });
2862
+ }, EditIntentLink = react.useMemo(() => bareId === void 0 ? void 0 : function(linkProps) {
2534
2863
  /* @__PURE__ */
2535
2864
  return jsxRuntime.jsx(router.IntentLink, {
2536
2865
  ...linkProps,
@@ -2540,58 +2869,52 @@ function LinkedDocPreview({bareId: bareId, layout: layout, schemaType: schemaTyp
2540
2869
  }
2541
2870
  });
2542
2871
  }, [ bareId ]);
2543
- return layout === "inline" ? /* @__PURE__ */ jsxRuntime.jsx(LinkChip, {
2544
- as: EditIntentLink,
2545
- hint: "Open document",
2546
- onClick: e => e.stopPropagation(),
2547
- children: /* @__PURE__ */ jsxRuntime.jsx(InlineChipFace, {
2548
- bareId: bareId,
2549
- schemaType: schemaType
2550
- })
2551
- }) : /* @__PURE__ */ jsxRuntime.jsx(ui.Card, {
2872
+ if (isCompact(layout)) /* @__PURE__ */
2873
+ return jsxRuntime.jsx(CompactDocRef, {
2874
+ face: face,
2875
+ fill: layout === "row",
2876
+ link: EditIntentLink,
2877
+ onClick: handleClick
2878
+ });
2879
+ const padding = face.selfInset === !0 ? 0 : NOTICE_PADDING;
2880
+ /* @__PURE__ */
2881
+ return jsxRuntime.jsx(ui.Card, {
2552
2882
  __unstable_focusRing: !0,
2553
- as: EditIntentLink,
2554
- border: !0,
2555
- "data-as": "a",
2556
- onClick: e => e.stopPropagation(),
2557
- padding: 1,
2883
+ border: layout === "default",
2884
+ padding: padding,
2558
2885
  radius: 3,
2559
- style: {
2560
- color: "inherit",
2561
- textDecoration: "none",
2562
- display: "block"
2886
+ tone: face.tone ?? (layout === "bare" ? "inherit" : "default"),
2887
+ ...EditIntentLink === void 0 ? {} : {
2888
+ as: EditIntentLink,
2889
+ "data-as": "a",
2890
+ onClick: handleClick,
2891
+ style: {
2892
+ color: "inherit",
2893
+ textDecoration: "none",
2894
+ display: "block"
2895
+ }
2563
2896
  },
2564
- children: /* @__PURE__ */ jsxRuntime.jsx(StubPreview, {
2565
- id: bareId,
2566
- schemaType: schemaType
2567
- })
2897
+ children: face.content
2568
2898
  });
2569
2899
  }
2570
2900
 
2571
- function DocPreviewLink({gdr: gdr, layout: layout = "default"}) {
2572
- const state = useDocLink(gdr);
2901
+ function faceContent(args) {
2902
+ const {gdr: gdr, layout: layout, state: state} = args, compact = isCompact(layout);
2573
2903
  switch (state.kind) {
2574
2904
  case "linked":
2575
- /* @__PURE__ */
2576
- return jsxRuntime.jsx(LinkedDocPreview, {
2905
+ return compact ? /* @__PURE__ */ jsxRuntime.jsx(InlineChipFace, {
2577
2906
  bareId: state.bareId,
2578
- layout: layout,
2907
+ schemaType: state.schemaType
2908
+ }) : /* @__PURE__ */ jsxRuntime.jsx(StubPreview, {
2909
+ id: state.bareId,
2579
2910
  schemaType: state.schemaType
2580
2911
  });
2581
2912
 
2582
2913
  case "foreign":
2583
- /* @__PURE__ */
2584
- return jsxRuntime.jsx(ForeignRefNotice, {
2585
- bareId: state.bareId,
2586
- resource: state.resource
2587
- });
2914
+ return foreignNotice(state.bareId, state.resource);
2588
2915
 
2589
2916
  case "missing":
2590
- /* @__PURE__ */
2591
- return jsxRuntime.jsx(MissingDocNotice, {
2592
- bareId: state.bareId,
2593
- layout: layout
2594
- });
2917
+ return missingNotice(state.bareId, layout);
2595
2918
 
2596
2919
  case "unopenable":
2597
2920
  /* @__PURE__ */
@@ -2602,10 +2925,9 @@ function DocPreviewLink({gdr: gdr, layout: layout = "default"}) {
2602
2925
 
2603
2926
  case "pending":
2604
2927
  /* @__PURE__ */
2605
- return jsxRuntime.jsx(ui.Text, {
2606
- muted: !0,
2607
- size: 1,
2608
- children: state.bareId
2928
+ return jsxRuntime.jsx(PendingDocFace, {
2929
+ bareId: state.bareId,
2930
+ layout: layout
2609
2931
  });
2610
2932
 
2611
2933
  case "unresolvable":
@@ -2618,6 +2940,27 @@ function DocPreviewLink({gdr: gdr, layout: layout = "default"}) {
2618
2940
  }
2619
2941
  }
2620
2942
 
2943
+ function docFace(args) {
2944
+ return {
2945
+ ...docFaceChrome(args),
2946
+ content: faceContent(args)
2947
+ };
2948
+ }
2949
+
2950
+ function DocPreviewLink({gdr: gdr, layout: layout = "default", source: source}) {
2951
+ const state = useDocLink(gdr);
2952
+ /* @__PURE__ */
2953
+ return jsxRuntime.jsx(DocRefShell, {
2954
+ face: docFace({
2955
+ gdr: gdr,
2956
+ layout: layout,
2957
+ state: state
2958
+ }),
2959
+ layout: layout,
2960
+ source: source
2961
+ });
2962
+ }
2963
+
2621
2964
  function ReleaseLink({releaseName: releaseName, label: label}) {
2622
2965
  const {basePath: basePath} = sanity.useWorkspace(), href = `${basePath === "/" ? "" : basePath}/releases/${releaseName}`;
2623
2966
  /* @__PURE__ */
@@ -2676,7 +3019,8 @@ function renderTextValue(field) {
2676
3019
 
2677
3020
  function renderSingleDocRef(field) {
2678
3021
  return field.value ? /* @__PURE__ */ jsxRuntime.jsx(DocPreviewLink, {
2679
- gdr: field.value
3022
+ gdr: field.value,
3023
+ source: "field-value"
2680
3024
  }) : /* @__PURE__ */ jsxRuntime.jsx(Empty, {});
2681
3025
  }
2682
3026
 
@@ -2698,12 +3042,15 @@ const fieldValueRenderer = {
2698
3042
  children: formatBoolean(field.value)
2699
3043
  }),
2700
3044
  date: renderTextValue,
3045
+ dueDate: renderTextValue,
2701
3046
  datetime: renderTextValue,
3047
+ dueDatetime: renderTextValue,
2702
3048
  "doc.ref": renderSingleDocRef,
2703
3049
  "doc.refs": field => field.value.length > 0 ? /* @__PURE__ */ jsxRuntime.jsx(ui.Stack, {
2704
3050
  gap: 2,
2705
3051
  children: field.value.map(ref => /* @__PURE__ */ jsxRuntime.jsx(DocPreviewLink, {
2706
- gdr: ref
3052
+ gdr: ref,
3053
+ source: "field-value"
2707
3054
  }, ref.id))
2708
3055
  }) : /* @__PURE__ */ jsxRuntime.jsx(Empty, {}),
2709
3056
  number: renderTextValue,
@@ -2925,6 +3272,27 @@ function ReadOnlyField({entry: entry}) {
2925
3272
  });
2926
3273
  }
2927
3274
 
3275
+ function useEditField(surface) {
3276
+ const {editFieldFor: editFieldFor} = useWorkflowContext(), telemetry2 = workflowReact.useWorkflowTelemetry();
3277
+ return react.useCallback(async ({instanceId: instanceId, field: field, ...change}) => {
3278
+ const log = success => telemetry2.log(WorkflowFieldControlUsed, {
3279
+ instanceId: instanceId,
3280
+ surface: surface,
3281
+ fieldKind: field.type,
3282
+ success: success
3283
+ });
3284
+ try {
3285
+ await editFieldFor(instanceId, {
3286
+ ...change,
3287
+ target: workflowReact.editFieldTarget(field)
3288
+ });
3289
+ } catch (err) {
3290
+ throw log(!1), err;
3291
+ }
3292
+ log(!0);
3293
+ }, [ editFieldFor, surface, telemetry2 ]);
3294
+ }
3295
+
2928
3296
  function sameValue(a, b) {
2929
3297
  return (a ?? void 0) === (b ?? void 0);
2930
3298
  }
@@ -2961,11 +3329,12 @@ function useFieldDraft(args) {
2961
3329
  };
2962
3330
  }
2963
3331
 
2964
- function EditableFieldControl({instanceId: instanceId, field: field}) {
2965
- const {editFieldFor: editFieldFor, previewFieldFor: previewFieldFor, discardFieldPreviewFor: discardFieldPreviewFor} = useWorkflowContext(), selfActor = useSelfActor(), held = useHeldWorkflowEntry(instanceId), entry = held ? workflowEngine.resolveFieldEntry(held.instance, field) : void 0, evaluation = held?.evaluation, target = workflowReact.editFieldTarget(field), consequence = fieldConsequence(evaluation, field.name), advanceTo = advanceTargetTitle(evaluation, field.name);
3332
+ function EditableFieldControl({instanceId: instanceId, field: field, surface: surface}) {
3333
+ const {previewFieldFor: previewFieldFor, discardFieldPreviewFor: discardFieldPreviewFor} = useWorkflowContext(), editField = useEditField(surface), selfActor = useSelfActor(), held = useHeldWorkflowEntry(instanceId), entry = held ? workflowEngine.resolveFieldEntry(held.instance, field) : void 0, evaluation = held?.evaluation, target = workflowReact.editFieldTarget(field), consequence = fieldConsequence(evaluation, field.name), advanceTo = advanceTargetTitle(evaluation, field.name);
2966
3334
  /* @__PURE__ */
2967
3335
  return jsxRuntime.jsx(EditableField, {
2968
3336
  field: field,
3337
+ instanceId: instanceId,
2969
3338
  ...entry === void 0 ? {} : {
2970
3339
  entry: entry
2971
3340
  },
@@ -2978,30 +3347,33 @@ function EditableFieldControl({instanceId: instanceId, field: field}) {
2978
3347
  ...advanceTo === void 0 ? {} : {
2979
3348
  advanceTo: advanceTo
2980
3349
  },
2981
- onSave: value => editFieldFor(instanceId, {
2982
- target: target,
3350
+ onSave: value => editField({
3351
+ instanceId: instanceId,
3352
+ field: field,
2983
3353
  mode: "set",
2984
3354
  value: value
2985
- }).then(() => {}),
3355
+ }),
2986
3356
  onPreview: value => previewFieldFor(instanceId, {
2987
3357
  target: target,
2988
3358
  mode: "set",
2989
3359
  value: value
2990
3360
  }),
2991
3361
  onDiscardPreview: () => discardFieldPreviewFor(instanceId, target),
2992
- onUnset: () => editFieldFor(instanceId, {
2993
- target: target,
3362
+ onUnset: () => editField({
3363
+ instanceId: instanceId,
3364
+ field: field,
2994
3365
  mode: "unset"
2995
- }).then(() => {}),
2996
- onAppend: body => editFieldFor(instanceId, {
2997
- target: target,
3366
+ }),
3367
+ onAppend: body => editField({
3368
+ instanceId: instanceId,
3369
+ field: field,
2998
3370
  mode: "append",
2999
3371
  value: noteRow({
3000
3372
  body: body,
3001
3373
  actor: selfActor,
3002
3374
  at: /* @__PURE__ */ (new Date).toISOString()
3003
3375
  })
3004
- }).then(() => {})
3376
+ })
3005
3377
  });
3006
3378
  }
3007
3379
 
@@ -3029,28 +3401,34 @@ function EditableValueButton({children: children, hint: hint, hintDisabled: hint
3029
3401
  });
3030
3402
  }
3031
3403
 
3032
- function useSaveFailureToast() {
3033
- const toast = useClosableToast();
3034
- return err => {
3035
- console.error("[workflow-studio-plugin] field save failed:", err), toast.push({
3036
- status: "error",
3037
- title: "Saving failed",
3038
- description: describeError(err)
3039
- });
3040
- };
3404
+ function useFieldSaveReport(instanceId) {
3405
+ const report = useRejectionReport();
3406
+ return react.useMemo(() => {
3407
+ const id = instanceToastId("field-save", instanceId);
3408
+ return {
3409
+ rejected: err => report.rejected({
3410
+ err: err,
3411
+ context: "field save",
3412
+ id: id,
3413
+ refused: "This field can’t be edited right now",
3414
+ failed: "Failed to save the field"
3415
+ }),
3416
+ dismiss: () => report.dismiss(id)
3417
+ };
3418
+ }, [ report, instanceId ]);
3041
3419
  }
3042
3420
 
3043
- function useSaveField(args = {}) {
3044
- const reportFailure = useSaveFailureToast(), [saving, setSaving] = react.useState(!1);
3421
+ function useSaveField(args) {
3422
+ const report = useFieldSaveReport(args.instanceId), [saving, setSaving] = react.useState(!1);
3045
3423
  return {
3046
3424
  saving: saving,
3047
3425
  save: async commit => {
3048
3426
  if (!saving) {
3049
3427
  setSaving(!0);
3050
3428
  try {
3051
- await commit(), args.onSaved?.();
3429
+ await commit(), report.dismiss(), args.onSaved?.();
3052
3430
  } catch (err) {
3053
- reportFailure(err);
3431
+ report.rejected(err);
3054
3432
  } finally {
3055
3433
  setSaving(!1);
3056
3434
  }
@@ -3060,7 +3438,9 @@ function useSaveField(args = {}) {
3060
3438
  }
3061
3439
 
3062
3440
  function useActorPick(args) {
3063
- const {current: current, onSave: onSave, onUnset: onUnset} = args, {saving: saving, save: save} = useSaveField();
3441
+ const {current: current, onSave: onSave, onUnset: onUnset} = args, {saving: saving, save: save} = useSaveField({
3442
+ instanceId: args.instanceId
3443
+ });
3064
3444
  return {
3065
3445
  saving: saving,
3066
3446
  pick: member => {
@@ -3069,9 +3449,10 @@ function useActorPick(args) {
3069
3449
  };
3070
3450
  }
3071
3451
 
3072
- function ActorField({field: field, onSave: onSave, onUnset: onUnset}) {
3452
+ function ActorField({field: field, instanceId: instanceId, onSave: onSave, onUnset: onUnset}) {
3073
3453
  const [open, setOpen] = react.useState(!1), cur = isActorShape(field.value) ? field.value : null, {pick: pick} = useActorPick({
3074
3454
  current: cur,
3455
+ instanceId: instanceId,
3075
3456
  onSave: onSave,
3076
3457
  onUnset: onUnset
3077
3458
  }), pickAndClose = member => {
@@ -3106,7 +3487,9 @@ function ActorField({field: field, onSave: onSave, onUnset: onUnset}) {
3106
3487
  }
3107
3488
 
3108
3489
  function useAssigneePick(args) {
3109
- const {current: current, onSave: onSave, onUnset: onUnset} = args, {saving: saving, save: save} = useSaveField();
3490
+ const {current: current, onSave: onSave, onUnset: onUnset} = args, {saving: saving, save: save} = useSaveField({
3491
+ instanceId: args.instanceId
3492
+ });
3110
3493
  return {
3111
3494
  saving: saving,
3112
3495
  pick: assignee => {
@@ -3121,9 +3504,10 @@ function useAssigneePick(args) {
3121
3504
  };
3122
3505
  }
3123
3506
 
3124
- function AssigneeField({field: field, onSave: onSave, onUnset: onUnset}) {
3507
+ function AssigneeField({field: field, instanceId: instanceId, onSave: onSave, onUnset: onUnset}) {
3125
3508
  const [open, setOpen] = react.useState(!1), cur = isAssigneeShape(field.value) ? field.value : null, {pick: pick} = useAssigneePick({
3126
3509
  current: cur,
3510
+ instanceId: instanceId,
3127
3511
  onSave: onSave,
3128
3512
  onUnset: onUnset
3129
3513
  }), pickAndClose = assignee => {
@@ -3163,8 +3547,10 @@ function arrayRowsOf(value) {
3163
3547
  return Array.isArray(value) ? value.filter(row => typeof row == "object" && row !== null) : [];
3164
3548
  }
3165
3549
 
3166
- function NotesField({field: field, onAppend: onAppend}) {
3167
- const [body, setBody] = react.useState(""), {saving: saving, save: save} = useSaveField(), rows = arrayRowsOf(field.value), trimmed = body.trim(), add = () => {
3550
+ function NotesField({field: field, instanceId: instanceId, onAppend: onAppend}) {
3551
+ const [body, setBody] = react.useState(""), {saving: saving, save: save} = useSaveField({
3552
+ instanceId: instanceId
3553
+ }), rows = arrayRowsOf(field.value), trimmed = body.trim(), add = () => {
3168
3554
  saving || trimmed === "" || (setBody(""), save(async () => {
3169
3555
  try {
3170
3556
  await onAppend(trimmed);
@@ -3205,11 +3591,13 @@ function NotesField({field: field, onAppend: onAppend}) {
3205
3591
  });
3206
3592
  }
3207
3593
 
3208
- function DateField({field: field, onSave: onSave, onUnset: onUnset}) {
3209
- const {save: save} = useSaveField();
3594
+ function DateField({field: field, kind: kind, instanceId: instanceId, onSave: onSave, onUnset: onUnset}) {
3595
+ const {save: save} = useSaveField({
3596
+ instanceId: instanceId
3597
+ });
3210
3598
  /* @__PURE__ */
3211
3599
  return jsxRuntime.jsx(DateFieldInput, {
3212
- kind: field.type === "datetime" ? "datetime" : "date",
3600
+ kind: kind,
3213
3601
  onChange: next => {
3214
3602
  save(() => next === null && onUnset !== void 0 ? onUnset() : onSave(next));
3215
3603
  },
@@ -3217,8 +3605,10 @@ function DateField({field: field, onSave: onSave, onUnset: onUnset}) {
3217
3605
  });
3218
3606
  }
3219
3607
 
3220
- function DocRefField({field: field, entry: entry, onSave: onSave, onUnset: onUnset}) {
3221
- const {save: save} = useSaveField(), value = workflowEngine.isGdr(field.value) ? field.value : null, types2 = entry !== void 0 && workflowEngine.isSingleDocRefEntry(entry) ? entry.types : void 0;
3608
+ function DocRefField({field: field, entry: entry, instanceId: instanceId, onSave: onSave, onUnset: onUnset}) {
3609
+ const {save: save} = useSaveField({
3610
+ instanceId: instanceId
3611
+ }), value = workflowEngine.isGdr(field.value) ? field.value : null, types2 = entry !== void 0 && workflowEngine.isSingleDocRefEntry(entry) ? entry.types : void 0;
3222
3612
  return field.editable ? /* @__PURE__ */ jsxRuntime.jsx(DocPicker, {
3223
3613
  onChange: ref => {
3224
3614
  save(() => ref === null && onUnset !== void 0 ? onUnset() : onSave(ref));
@@ -3233,8 +3623,10 @@ function DocRefField({field: field, entry: entry, onSave: onSave, onUnset: onUns
3233
3623
  });
3234
3624
  }
3235
3625
 
3236
- function BooleanSwitchField({field: field, onSave: onSave}) {
3237
- const {save: save} = useSaveField(), committed = field.value === !0;
3626
+ function BooleanSwitchField({field: field, instanceId: instanceId, onSave: onSave}) {
3627
+ const {save: save} = useSaveField({
3628
+ instanceId: instanceId
3629
+ }), committed = field.value === !0;
3238
3630
  /* @__PURE__ */
3239
3631
  return jsxRuntime.jsx(ui.Flex, {
3240
3632
  align: "center",
@@ -3247,8 +3639,10 @@ function BooleanSwitchField({field: field, onSave: onSave}) {
3247
3639
  });
3248
3640
  }
3249
3641
 
3250
- function ChoiceField({field: field, options: options, onSave: onSave, onUnset: onUnset}) {
3251
- const {save: save} = useSaveField();
3642
+ function ChoiceField({field: field, instanceId: instanceId, options: options, onSave: onSave, onUnset: onUnset}) {
3643
+ const {save: save} = useSaveField({
3644
+ instanceId: instanceId
3645
+ });
3252
3646
  /* @__PURE__ */
3253
3647
  return jsxRuntime.jsx(ChoiceSelect, {
3254
3648
  onChange: value => {
@@ -3322,8 +3716,8 @@ function FieldEditRow({field: field, onSave: onSave, onCancel: onCancel, saving:
3322
3716
  });
3323
3717
  }
3324
3718
 
3325
- function GenericField({field: field, onSave: onSave, onPreview: onPreview, onDiscardPreview: onDiscardPreview}) {
3326
- const reportFailure = useSaveFailureToast(), canSave = value => scalarValidationIssue({
3719
+ function GenericField({field: field, onSave: onSave, instanceId: instanceId, onPreview: onPreview, onDiscardPreview: onDiscardPreview}) {
3720
+ const report = useFieldSaveReport(instanceId), canSave = value => scalarValidationIssue({
3327
3721
  kind: field.type,
3328
3722
  label: field.title ?? field.name,
3329
3723
  validation: field.validation,
@@ -3334,7 +3728,7 @@ function GenericField({field: field, onSave: onSave, onPreview: onPreview, onDis
3334
3728
  onPreview: onPreview,
3335
3729
  onDiscardPreview: onDiscardPreview,
3336
3730
  canSave: canSave,
3337
- onSaveFailure: reportFailure
3731
+ onSaveFailure: report.rejected
3338
3732
  }), validationIssue = scalarValidationIssue({
3339
3733
  kind: field.type,
3340
3734
  label: field.title ?? field.name,
@@ -3380,9 +3774,10 @@ function AdvanceHint({stageTitle: stageTitle2}) {
3380
3774
  });
3381
3775
  }
3382
3776
 
3383
- function arrayArm({field: field, entry: entry, onAppend: onAppend}) {
3777
+ function arrayArm({field: field, entry: entry, instanceId: instanceId, onAppend: onAppend}) {
3384
3778
  return field.editable && onAppend !== void 0 && entry !== void 0 && workflowEngine.isNotesEntry(entry) ? /* @__PURE__ */ jsxRuntime.jsx(NotesField, {
3385
3779
  field: field,
3780
+ instanceId: instanceId,
3386
3781
  onAppend: onAppend
3387
3782
  }) : /* @__PURE__ */ jsxRuntime.jsx(ArrayValueRows, {
3388
3783
  rows: arrayRowsOf(field.value)
@@ -3390,7 +3785,7 @@ function arrayArm({field: field, entry: entry, onAppend: onAppend}) {
3390
3785
  }
3391
3786
 
3392
3787
  function fieldArm({arm: arm, entry: entry, onUnset: onUnset, onAppend: onAppend, onPreview: onPreview, onDiscardPreview: onDiscardPreview}) {
3393
- const {field: field} = arm;
3788
+ const {field: field, instanceId: instanceId} = arm;
3394
3789
  return field.type === "actor" ? /* @__PURE__ */ jsxRuntime.jsx(ActorField, {
3395
3790
  ...arm,
3396
3791
  onUnset: onUnset
@@ -3403,11 +3798,13 @@ function fieldArm({arm: arm, entry: entry, onUnset: onUnset, onAppend: onAppend,
3403
3798
  }) : field.type === "array" ? arrayArm({
3404
3799
  field: field,
3405
3800
  entry: entry,
3801
+ instanceId: instanceId,
3406
3802
  onAppend: onAppend
3407
3803
  }) : field.type === "boolean" && field.editable ? /* @__PURE__ */ jsxRuntime.jsx(BooleanSwitchField, {
3408
3804
  ...arm
3409
- }) : (field.type === "date" || field.type === "datetime") && field.editable ? /* @__PURE__ */ jsxRuntime.jsx(DateField, {
3805
+ }) : isDateFieldKind(field.type) && field.editable ? /* @__PURE__ */ jsxRuntime.jsx(DateField, {
3410
3806
  ...arm,
3807
+ kind: field.type,
3411
3808
  onUnset: onUnset
3412
3809
  }) : workflowEngine.isSingleDocRefKind(field.type) ? /* @__PURE__ */ jsxRuntime.jsx(DocRefField, {
3413
3810
  ...arm,
@@ -3420,9 +3817,10 @@ function fieldArm({arm: arm, entry: entry, onUnset: onUnset, onAppend: onAppend,
3420
3817
  });
3421
3818
  }
3422
3819
 
3423
- function EditableField({field: field, entry: entry, description: description, onSave: onSave, onUnset: onUnset, onAppend: onAppend, onPreview: onPreview, onDiscardPreview: onDiscardPreview, consequence: consequence, advanceTo: advanceTo}) {
3820
+ function EditableField({field: field, entry: entry, description: description, instanceId: instanceId, onSave: onSave, onUnset: onUnset, onAppend: onAppend, onPreview: onPreview, onDiscardPreview: onDiscardPreview, consequence: consequence, advanceTo: advanceTo}) {
3424
3821
  const label = field.title ?? field.name, arm = {
3425
3822
  field: field,
3823
+ instanceId: instanceId,
3426
3824
  onSave: onSave
3427
3825
  }, content2 = entry?.options === void 0 ? fieldArm({
3428
3826
  arm: arm,
@@ -3454,11 +3852,15 @@ function EditableField({field: field, entry: entry, description: description, on
3454
3852
  });
3455
3853
  }
3456
3854
 
3457
- function MetaRow({label: label, children: children}) {
3855
+ function MetaRow({children: children, fillHeight: fillHeight, label: label}) {
3458
3856
  /* @__PURE__ */
3459
3857
  return jsxRuntime.jsxs(ui.Flex, {
3460
- align: "flex-start",
3461
3858
  gap: 4,
3859
+ ...fillHeight ? {
3860
+ flex: 1
3861
+ } : {
3862
+ align: "flex-start"
3863
+ },
3462
3864
  children: [
3463
3865
  /* @__PURE__ */ jsxRuntime.jsx(ui.Box, {
3464
3866
  style: {
@@ -3558,6 +3960,12 @@ function useSpaceToken(index) {
3558
3960
  return value;
3559
3961
  }
3560
3962
 
3963
+ function useRadiusToken(index) {
3964
+ const value = ui.useTheme_v2().radius[index];
3965
+ if (value === void 0) throw new Error(`theme is missing radius token ${index}`);
3966
+ return value;
3967
+ }
3968
+
3561
3969
  function useContainerToken(index) {
3562
3970
  const value = ui.useTheme_v2().container[index];
3563
3971
  if (value === void 0) throw new Error(`theme is missing container token ${index}`);
@@ -3678,8 +4086,8 @@ function UserAvatarGroup({ids: ids, hint: hint}) {
3678
4086
  });
3679
4087
  }
3680
4088
 
3681
- function AssignActivityControl({instanceId: instanceId, state: state, assigneeIds: assigneeIds = []}) {
3682
- const {editFieldFor: editFieldFor} = useWorkflowContext(), toast = useClosableToast(), [open, setOpen] = react.useState(!1), [busy, setBusy] = react.useState(!1);
4089
+ function AssignActivityControl({instanceId: instanceId, state: state, surface: surface, assigneeIds: assigneeIds = []}) {
4090
+ const editField = useEditField(surface), report = useRejectionReport(), [open, setOpen] = react.useState(!1), [busy, setBusy] = react.useState(!1);
3683
4091
  if (state.kind === "none") return assigneeIds.length === 0 ? null : /* @__PURE__ */ jsxRuntime.jsx(AvatarDisplay, {
3684
4092
  "aria-label": "Assignees",
3685
4093
  avatar: /* @__PURE__ */ jsxRuntime.jsx(UserAvatarGroup, {
@@ -3700,23 +4108,27 @@ function AssignActivityControl({instanceId: instanceId, state: state, assigneeId
3700
4108
  if (!(busy || field === void 0)) {
3701
4109
  setBusy(!0);
3702
4110
  try {
3703
- selectedIds.has(memberId) ? await editFieldFor(instanceId, {
3704
- target: workflowReact.editFieldTarget(field),
4111
+ selectedIds.has(memberId) ? await editField({
4112
+ instanceId: instanceId,
4113
+ field: field,
3705
4114
  mode: "set",
3706
4115
  value: members.filter(m => !(m.type === "user" && m.id === memberId))
3707
- }) : await editFieldFor(instanceId, {
3708
- target: workflowReact.editFieldTarget(field),
4116
+ }) : await editField({
4117
+ instanceId: instanceId,
4118
+ field: field,
3709
4119
  mode: "append",
3710
4120
  value: {
3711
4121
  type: "user",
3712
4122
  id: memberId
3713
4123
  }
3714
- });
4124
+ }), report.dismiss(instanceToastId("assign", instanceId));
3715
4125
  } catch (err) {
3716
- toast.push({
3717
- status: "error",
3718
- title: "Assigning failed",
3719
- description: describeError(err)
4126
+ report.rejected({
4127
+ err: err,
4128
+ context: "assignment",
4129
+ id: instanceToastId("assign", instanceId),
4130
+ refused: "Assignees can’t be changed right now",
4131
+ failed: "Failed to update assignees"
3720
4132
  });
3721
4133
  } finally {
3722
4134
  setBusy(!1);
@@ -3783,6 +4195,11 @@ function appendTargetFor(targets, filter) {
3783
4195
  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];
3784
4196
  }
3785
4197
 
4198
+ function canRemoveRow(args) {
4199
+ const {editTarget: editTarget, appendTarget: appendTarget} = args;
4200
+ return editTarget === void 0 || appendTarget === void 0 ? !1 : editTarget.scope === appendTarget.scope && editTarget.field === appendTarget.field && editTarget.activity === appendTarget.activity;
4201
+ }
4202
+
3786
4203
  function looksLikeDefinition(value) {
3787
4204
  return typeof value == "object" && value !== null && Array.isArray(value.stages);
3788
4205
  }
@@ -4024,6 +4441,21 @@ function AddItemControl({onAdd: onAdd, button: button, busy: busy}) {
4024
4441
  });
4025
4442
  }
4026
4443
 
4444
+ function RemoveItemButton({onClick: onClick}) {
4445
+ /* @__PURE__ */
4446
+ return jsxRuntime.jsx(HoverHint, {
4447
+ text: "Remove item",
4448
+ children: /* @__PURE__ */ jsxRuntime.jsx(ui.Button, {
4449
+ "aria-label": "Remove item",
4450
+ fontSize: 1,
4451
+ icon: Close.CloseIcon,
4452
+ mode: "bleed",
4453
+ onClick: onClick,
4454
+ padding: 2
4455
+ })
4456
+ });
4457
+ }
4458
+
4027
4459
  function BreadcrumbTail({segments: segments, style: style}) {
4028
4460
  /* @__PURE__ */
4029
4461
  return jsxRuntime.jsx(ui.Text, {
@@ -4090,7 +4522,7 @@ function WorkRow({lead: lead, children: children, end: end, onOpen: onOpen}) {
4090
4522
  });
4091
4523
  }
4092
4524
 
4093
- function TodoItemRowView({breadcrumb: breadcrumb, row: row, onToggle: onToggle, onPatch: onPatch}) {
4525
+ function TodoItemRowView({breadcrumb: breadcrumb, row: row, onToggle: onToggle, onPatch: onPatch, onRemove: onRemove}) {
4094
4526
  const {canClick: canClick, hint: hint} = rowInteractivity(row), editable = row.editTarget !== void 0, checkbox = /* @__PURE__ */ jsxRuntime.jsx(TodoCheckbox, {
4095
4527
  canClick: canClick,
4096
4528
  checked: isTodoDone(row.item),
@@ -4109,6 +4541,8 @@ function TodoItemRowView({breadcrumb: breadcrumb, row: row, onToggle: onToggle,
4109
4541
  editable: editable,
4110
4542
  item: row.item,
4111
4543
  onPatch: onPatch
4544
+ }), onRemove === void 0 ? null : /* @__PURE__ */ jsxRuntime.jsx(RemoveItemButton, {
4545
+ onClick: onRemove
4112
4546
  }) ]
4113
4547
  }),
4114
4548
  lead:
@@ -4135,37 +4569,41 @@ function TodoItemRowView({breadcrumb: breadcrumb, row: row, onToggle: onToggle,
4135
4569
  }
4136
4570
 
4137
4571
  function TodoItemsList({breadcrumb: breadcrumb, entry: entry, filter: filter, surface: surface}) {
4138
- const {instance: instance} = entry, definition = useDefinition(entry), {editFieldFor: editFieldFor, fireActionFor: fireActionFor} = useWorkflowContext(), telemetry2 = workflowReact.useWorkflowTelemetry(), toast = useClosableToast(), [busy, setBusy] = react.useState(!1), derivation = deriveTodoItems(entry), rows = derivation.rows.filter(row => rowMatches(row, filter)), appendTarget = appendTargetFor(derivation.appendTargets, filter), run = async op => {
4572
+ const {instance: instance} = entry, definition = useDefinition(entry), {editFieldFor: editFieldFor, fireActionFor: fireActionFor} = useWorkflowContext(), telemetry2 = workflowReact.useWorkflowTelemetry(), report = useRejectionReport(), [busy, setBusy] = react.useState(!1), derivation = deriveTodoItems(entry), rows = derivation.rows.filter(row => rowMatches(row, filter)), appendTarget = appendTargetFor(derivation.appendTargets, filter), run = async op => {
4139
4573
  if (busy) return !1;
4140
4574
  setBusy(!0);
4141
4575
  try {
4142
- return await op(), !0;
4576
+ return await op(), report.dismiss(instanceToastId("todo-write", instance._id)),
4577
+ !0;
4143
4578
  } catch (err) {
4144
- return toast.push({
4145
- status: "error",
4146
- title: "Updating to-dos failed",
4147
- description: describeError(err)
4579
+ return report.rejected({
4580
+ err: err,
4581
+ context: "to-do write",
4582
+ id: instanceToastId("todo-write", instance._id),
4583
+ refused: "To-dos can’t be changed right now",
4584
+ failed: "Failed to update to-dos"
4148
4585
  }), !1;
4149
4586
  } finally {
4150
4587
  setBusy(!1);
4151
4588
  }
4152
- }, patchItem = (row, patch) => {
4153
- if (!row.editTarget) return Promise.resolve();
4154
- const target = row.editTarget, next = row.items.map(it => it._key === row.item._key ? {
4155
- ...it,
4156
- ...patch
4157
- } : it);
4589
+ }, writeItems = (row, nextItems) => {
4590
+ if (!row.editTarget) return Promise.resolve(!1);
4591
+ const target = row.editTarget;
4158
4592
  return run(() => editFieldFor(instance._id, {
4159
4593
  target: target,
4160
4594
  mode: "set",
4161
- value: next
4595
+ value: nextItems()
4162
4596
  }));
4163
- }, toggleRow = async row => {
4597
+ }, patchItem = (row, patch) => writeItems(row, () => todoItemsPatched({
4598
+ items: row.items,
4599
+ key: row.item._key,
4600
+ patch: patch
4601
+ })), toggleRow = async row => {
4164
4602
  if (busy) return;
4165
4603
  if (row.editTarget) {
4166
4604
  const done = !isTodoDone(row.item), success = await patchItem(row, {
4167
4605
  status: toggledTodoStatus(row.item)
4168
- }) === !0;
4606
+ });
4169
4607
  telemetry2.log(WorkflowTodoToggled, {
4170
4608
  instanceId: instance._id,
4171
4609
  surface: surface,
@@ -4189,14 +4627,44 @@ function TodoItemsList({breadcrumb: breadcrumb, entry: entry, filter: filter, su
4189
4627
  success: success
4190
4628
  });
4191
4629
  }
4192
- }, addItem = label => appendTarget ? run(() => editFieldFor(instance._id, {
4193
- target: appendTarget,
4194
- mode: "append",
4195
- value: {
4196
- label: label,
4197
- status: "open"
4198
- }
4199
- })) : Promise.resolve(!1);
4630
+ }, addItem = async label => {
4631
+ if (busy || !appendTarget) return !1;
4632
+ const success = await run(() => editFieldFor(instance._id, {
4633
+ target: appendTarget,
4634
+ mode: "append",
4635
+ value: {
4636
+ label: label,
4637
+ status: "open"
4638
+ }
4639
+ }));
4640
+ return telemetry2.log(WorkflowTodoEdited, {
4641
+ instanceId: instance._id,
4642
+ surface: surface,
4643
+ kind: "add",
4644
+ success: success
4645
+ }), success;
4646
+ }, editRow = async (row, patch) => {
4647
+ if (busy || row.editTarget === void 0) return;
4648
+ const success = await patchItem(row, patch);
4649
+ telemetry2.log(WorkflowTodoEdited, {
4650
+ instanceId: instance._id,
4651
+ surface: surface,
4652
+ kind: todoEditKind(patch),
4653
+ success: success
4654
+ });
4655
+ }, removeRow = async row => {
4656
+ if (busy || row.editTarget === void 0) return;
4657
+ const success = await writeItems(row, () => todoItemsWithout({
4658
+ items: row.items,
4659
+ key: row.item._key
4660
+ }));
4661
+ telemetry2.log(WorkflowTodoEdited, {
4662
+ instanceId: instance._id,
4663
+ surface: surface,
4664
+ kind: "remove",
4665
+ success: success
4666
+ });
4667
+ };
4200
4668
  if (rows.length === 0 && !appendTarget) return null;
4201
4669
  const rowKey = row => `${row.scope}:${row.activityName ?? ""}:${row.fieldName}:${row.item._key}`, rowBreadcrumb = row => {
4202
4670
  if (breadcrumb === void 0 || row.activityName === void 0) return breadcrumb;
@@ -4216,8 +4684,16 @@ function TodoItemsList({breadcrumb: breadcrumb, entry: entry, filter: filter, su
4216
4684
  children: rows.map(row => /* @__PURE__ */ jsxRuntime.jsx(TodoItemRowView, {
4217
4685
  breadcrumb: rowBreadcrumb(row),
4218
4686
  onPatch: patch => {
4219
- patchItem(row, patch);
4687
+ editRow(row, patch);
4220
4688
  },
4689
+ ...canRemoveRow({
4690
+ editTarget: row.editTarget,
4691
+ appendTarget: appendTarget
4692
+ }) ? {
4693
+ onRemove: () => {
4694
+ removeRow(row);
4695
+ }
4696
+ } : {},
4221
4697
  onToggle: () => {
4222
4698
  toggleRow(row);
4223
4699
  },
@@ -4305,7 +4781,7 @@ const ACTIONS_MENU_TRIGGER = {
4305
4781
  padding: 2
4306
4782
  };
4307
4783
 
4308
- function ActionMenuItem({actionEval: actionEval, instanceId: instanceId, activity: activity, surface: surface, onCollectParams: onCollectParams}) {
4784
+ function ActionMenuItem({actionEval: actionEval, instanceId: instanceId, activity: activity, surface: surface, placement: placement, onCollectParams: onCollectParams}) {
4309
4785
  const rowKind = actionRowKind(actionEval), label = actionTriggerLabel(actionEval), {tone: tone, icon: icon} = actionButtonFace({
4310
4786
  actionEval: actionEval,
4311
4787
  activityName: activity
@@ -4317,6 +4793,7 @@ function ActionMenuItem({actionEval: actionEval, instanceId: instanceId, activit
4317
4793
  action: actionEval.action.name,
4318
4794
  label: label,
4319
4795
  surface: surface,
4796
+ placement: placement,
4320
4797
  viaMenu: !0
4321
4798
  });
4322
4799
  return rowKind.kind === "disabled" ? /* @__PURE__ */ jsxRuntime.jsx(ui.MenuItem, {
@@ -4353,7 +4830,7 @@ function rowShield(menuButton) {
4353
4830
  });
4354
4831
  }
4355
4832
 
4356
- function ActionsMenuButton({actions: actions, instanceId: instanceId, activity: activity, label: label, surface: surface, mode: mode = "ghost", inButtonCard: inButtonCard = !1}) {
4833
+ function ActionsMenuButton({actions: actions, instanceId: instanceId, activity: activity, label: label, surface: surface, placement: placement, mode: mode = "ghost", inButtonCard: inButtonCard = !1}) {
4357
4834
  const [paramsAction, setParamsAction] = react.useState(void 0), clusterPending = useActionClusterPending(), menuId = react.useId(), menuButton = /* @__PURE__ */ jsxRuntime.jsx(ui.MenuButton, {
4358
4835
  button: /* @__PURE__ */ jsxRuntime.jsx(ui.Button, {
4359
4836
  ...ACTIONS_MENU_TRIGGER,
@@ -4373,6 +4850,7 @@ function ActionsMenuButton({actions: actions, instanceId: instanceId, activity:
4373
4850
  activity: activity,
4374
4851
  instanceId: instanceId,
4375
4852
  onCollectParams: () => setParamsAction(a),
4853
+ placement: placement,
4376
4854
  surface: surface
4377
4855
  }, a.action.name))
4378
4856
  }),
@@ -4390,6 +4868,7 @@ function ActionsMenuButton({actions: actions, instanceId: instanceId, activity:
4390
4868
  activity: activity,
4391
4869
  instanceId: instanceId,
4392
4870
  onClose: () => setParamsAction(void 0),
4871
+ placement: placement,
4393
4872
  surface: surface,
4394
4873
  viaMenu: !0
4395
4874
  })
@@ -4408,7 +4887,8 @@ function TerminalFooter({actions: actions, activity: activity, instanceId: insta
4408
4887
  actionEval: only,
4409
4888
  activity: activity,
4410
4889
  instanceId: instanceId,
4411
- surface: "terminal-footer"
4890
+ placement: "terminal-footer",
4891
+ surface: "activity-dialog"
4412
4892
  })
4413
4893
  }) : /* @__PURE__ */ jsxRuntime.jsx(FittedActions, {
4414
4894
  actions: actions,
@@ -4463,14 +4943,16 @@ function FittedActions({actions: actions, activity: activity, instanceId: instan
4463
4943
  actionEval: a,
4464
4944
  activity: activity,
4465
4945
  instanceId: instanceId,
4466
- surface: "terminal-footer"
4946
+ placement: "terminal-footer",
4947
+ surface: "activity-dialog"
4467
4948
  }, a.action.name)), overflow.length > 0 ? /* @__PURE__ */ jsxRuntime.jsx(ActionsMenuButton, {
4468
4949
  actions: overflow,
4469
4950
  activity: activity,
4470
4951
  instanceId: instanceId,
4471
4952
  label: MORE_ACTIONS_LABEL,
4472
4953
  mode: "default",
4473
- surface: "terminal-footer"
4954
+ placement: "terminal-footer",
4955
+ surface: "activity-dialog"
4474
4956
  }) : null ]
4475
4957
  }) ]
4476
4958
  });
@@ -4605,7 +5087,8 @@ function MetaBlock({detail: detail, definition: definition, document: document,
4605
5087
  children: /* @__PURE__ */ jsxRuntime.jsx(ui.Flex, {
4606
5088
  children: /* @__PURE__ */ jsxRuntime.jsx(DocPreviewLink, {
4607
5089
  gdr: document,
4608
- layout: "inline"
5090
+ layout: "inline",
5091
+ source: "dialog-subject"
4609
5092
  })
4610
5093
  })
4611
5094
  }) : null,
@@ -4629,7 +5112,8 @@ function TopActions({detail: detail, definition: definition, instanceId: instanc
4629
5112
  actionEval: a,
4630
5113
  activity: activityName,
4631
5114
  instanceId: instanceId,
4632
- surface: "dialog-strip"
5115
+ placement: "dialog-strip",
5116
+ surface: "activity-dialog"
4633
5117
  }, a.action.name)), p.manualTarget ? /* @__PURE__ */ jsxRuntime.jsx(ui.Button, {
4634
5118
  as: "a",
4635
5119
  fontSize: 1,
@@ -4687,7 +5171,8 @@ function FieldRow({field: field, detail: detail, entry: entry, activityName: act
4687
5171
  state: {
4688
5172
  kind: "editable",
4689
5173
  field: assignField
4690
- }
5174
+ },
5175
+ surface: "activity-dialog"
4691
5176
  }) : null ]
4692
5177
  }) ]
4693
5178
  });
@@ -4695,7 +5180,8 @@ function FieldRow({field: field, detail: detail, entry: entry, activityName: act
4695
5180
  const editable = detail.editableByName.get(field.name);
4696
5181
  return editable ? /* @__PURE__ */ jsxRuntime.jsx(EditableFieldControl, {
4697
5182
  field: editable,
4698
- instanceId: instanceId
5183
+ instanceId: instanceId,
5184
+ surface: "activity-dialog"
4699
5185
  }) : /* @__PURE__ */ jsxRuntime.jsxs(ui.Stack, {
4700
5186
  gap: 2,
4701
5187
  children: [ head,
@@ -4864,7 +5350,7 @@ function ActivityRowTitle({dimmed: dimmed, children: children}) {
4864
5350
  });
4865
5351
  }
4866
5352
 
4867
- function RowTerminalActions({actions: actions, activity: activity, instanceId: instanceId}) {
5353
+ function RowTerminalActions({actions: actions, activity: activity, instanceId: instanceId, surface: surface}) {
4868
5354
  const lock = useActionClusterState(), [only, ...rest] = actions;
4869
5355
  return only ? /* @__PURE__ */ jsxRuntime.jsx(ActionClusterProvider, {
4870
5356
  value: lock,
@@ -4876,14 +5362,16 @@ function RowTerminalActions({actions: actions, activity: activity, instanceId: i
4876
5362
  inButtonCard: !0
4877
5363
  },
4878
5364
  instanceId: instanceId,
4879
- surface: "inline-row"
5365
+ placement: "inline-row",
5366
+ surface: surface
4880
5367
  }) : /* @__PURE__ */ jsxRuntime.jsx(ActionsMenuButton, {
4881
5368
  actions: actions,
4882
5369
  activity: activity,
4883
5370
  inButtonCard: !0,
4884
5371
  instanceId: instanceId,
4885
5372
  label: "Select action",
4886
- surface: "inline-row"
5373
+ placement: "inline-row",
5374
+ surface: surface
4887
5375
  })
4888
5376
  }) : null;
4889
5377
  }
@@ -4904,7 +5392,7 @@ function TitleTag({hint: hint, tone: tone, children: children}) {
4904
5392
  });
4905
5393
  }
4906
5394
 
4907
- function ActivityRow({face: face, breadcrumb: breadcrumb, assigneeIds: assigneeIds, assignState: assignState, dateControl: dateControl, instanceId: instanceId, onOpen: onOpen, terminalActions: terminalActions = []}) {
5395
+ function ActivityRow({face: face, breadcrumb: breadcrumb, assigneeIds: assigneeIds, assignState: assignState, dateControl: dateControl, instanceId: instanceId, onOpen: onOpen, surface: surface, terminalActions: terminalActions = []}) {
4908
5396
  const settled = workflowEngine.isTerminalActivityStatus(face.status), dimmed = settledDim(settled);
4909
5397
  /* @__PURE__ */
4910
5398
  return jsxRuntime.jsxs(WorkRow, {
@@ -4912,12 +5400,14 @@ function ActivityRow({face: face, breadcrumb: breadcrumb, assigneeIds: assigneeI
4912
5400
  children: [ settled || terminalActions.length === 0 ? null : /* @__PURE__ */ jsxRuntime.jsx(RowTerminalActions, {
4913
5401
  actions: terminalActions,
4914
5402
  activity: face.activityName,
4915
- instanceId: instanceId
5403
+ instanceId: instanceId,
5404
+ surface: surface
4916
5405
  }), dateControl,
4917
5406
  /* @__PURE__ */ jsxRuntime.jsx(AssignActivityControl, {
4918
5407
  assigneeIds: assigneeIds,
4919
5408
  instanceId: instanceId,
4920
- state: assignState
5409
+ state: assignState,
5410
+ surface: surface
4921
5411
  }) ]
4922
5412
  }),
4923
5413
  lead: /* @__PURE__ */ jsxRuntime.jsx(ActivityStatusLead, {
@@ -4942,7 +5432,7 @@ function ActivityRow({face: face, breadcrumb: breadcrumb, assigneeIds: assigneeI
4942
5432
  });
4943
5433
  }
4944
5434
 
4945
- function ActivitiesList({entry: entry, onOpenActivity: onOpenActivity}) {
5435
+ function ActivitiesList({entry: entry, onOpenActivity: onOpenActivity, surface: surface}) {
4946
5436
  const activities = (entry.evaluation?.currentStage.activities ?? []).filter(t => !t.scopedOut), activityState = stateByActivity(entry.instance);
4947
5437
  return activities.length === 0 ?
4948
5438
  /* @__PURE__ */ jsxRuntime.jsx(ui.Box, {
@@ -4962,7 +5452,8 @@ function ActivitiesList({entry: entry, onOpenActivity: onOpenActivity}) {
4962
5452
  editableFields: entry.evaluation?.editableFields
4963
5453
  }),
4964
5454
  instanceId: entry.instance._id,
4965
- onOpen: () => onOpenActivity(t.activity.name)
5455
+ onOpen: () => onOpenActivity(t.activity.name),
5456
+ surface: surface
4966
5457
  }, t.activity.name))
4967
5458
  });
4968
5459
  }
@@ -5026,7 +5517,9 @@ const EDITOR_BY_KIND = {
5026
5517
  assignees: "assignees",
5027
5518
  boolean: "scalar",
5028
5519
  date: "scalar",
5520
+ dueDate: "scalar",
5029
5521
  datetime: "scalar",
5522
+ dueDatetime: "scalar",
5030
5523
  number: "scalar",
5031
5524
  progress: "scalar",
5032
5525
  string: "scalar",
@@ -5036,7 +5529,9 @@ const EDITOR_BY_KIND = {
5036
5529
  array: e => e.value.length > 0 ? pluralize__default.default("item", e.value.length, !0) : void 0,
5037
5530
  boolean: e => e.value === null ? void 0 : formatBoolean(e.value),
5038
5531
  date: e => e.value === null ? void 0 : formatDate(e.value),
5532
+ dueDate: e => e.value === null ? void 0 : formatDate(e.value),
5039
5533
  datetime: e => e.value === null ? void 0 : formatDateTime(e.value),
5534
+ dueDatetime: e => e.value === null ? void 0 : formatDateTime(e.value),
5040
5535
  "doc.refs": e => e.value.length > 0 ? pluralize__default.default("document", e.value.length, !0) : void 0,
5041
5536
  object: e => e.value === null ? void 0 : "Set",
5042
5537
  "release.ref": e => e.value === null ? void 0 : e.value.releaseName
@@ -5160,7 +5655,7 @@ function TodoFieldDialog({entry: entry, scope: scope, field: field, title: title
5160
5655
 
5161
5656
  const MAX_VISIBLE_PILLS = 4;
5162
5657
 
5163
- function FieldPills({entry: entry, scope: scope, definition: definition}) {
5658
+ function FieldPills({entry: entry, scope: scope, definition: definition, surface: surface}) {
5164
5659
  const [expanded, setExpanded] = react.useState(!1), pills = deriveFieldPills({
5165
5660
  scope: scope,
5166
5661
  definition: definition,
@@ -5178,7 +5673,8 @@ function FieldPills({entry: entry, scope: scope, definition: definition}) {
5178
5673
  children: [ visible.map(pill => /* @__PURE__ */ jsxRuntime.jsx(FieldPill, {
5179
5674
  entry: entry,
5180
5675
  pill: pill,
5181
- scope: scope
5676
+ scope: scope,
5677
+ surface: surface
5182
5678
  }, pill.name)), overflow > 0 ?
5183
5679
  /* @__PURE__ */ jsxRuntime.jsx(ui.Button, {
5184
5680
  mode: "bleed",
@@ -5212,7 +5708,9 @@ function isEmptyFace(face) {
5212
5708
 
5213
5709
  const KIND_ICON = {
5214
5710
  date: Calendar.CalendarIcon,
5711
+ dueDate: Calendar.CalendarIcon,
5215
5712
  datetime: Calendar.CalendarIcon,
5713
+ dueDatetime: Calendar.CalendarIcon,
5216
5714
  "doc.ref": Document.DocumentIcon,
5217
5715
  "doc.refs": Document.DocumentIcon,
5218
5716
  subject: Document.DocumentIcon
@@ -5364,18 +5862,20 @@ function PillButton({children: children, pill: pill, hintDisabled: hintDisabled
5364
5862
  });
5365
5863
  }
5366
5864
 
5367
- function useFieldCommit({entry: entry, editability: editability}) {
5368
- const {editFieldFor: editFieldFor} = useWorkflowContext(), target = workflowReact.editFieldTarget(editability);
5865
+ function useFieldCommit({entry: entry, editability: editability, surface: surface}) {
5866
+ const editField = useEditField(surface), instanceId = entry.instance._id;
5369
5867
  return {
5370
- set: value => editFieldFor(entry.instance._id, {
5371
- target: target,
5868
+ set: value => editField({
5869
+ instanceId: instanceId,
5870
+ field: editability,
5372
5871
  mode: "set",
5373
5872
  value: value
5374
- }).then(() => {}),
5375
- unset: () => editFieldFor(entry.instance._id, {
5376
- target: target,
5873
+ }),
5874
+ unset: () => editField({
5875
+ instanceId: instanceId,
5876
+ field: editability,
5377
5877
  mode: "unset"
5378
- }).then(() => {})
5878
+ })
5379
5879
  };
5380
5880
  }
5381
5881
 
@@ -5445,11 +5945,28 @@ function ReadOnlyPill({pill: pill}) {
5445
5945
  });
5446
5946
  }
5447
5947
 
5448
- function ScalarPill({entry: entry, pill: pill, editability: editability}) {
5449
- const [open, setOpen] = react.useState(!1), {set: set} = useFieldCommit({
5948
+ function usePillWrite(args) {
5949
+ const {entry: entry, editability: editability, surface: surface, onSaved: onSaved} = args, commit = useFieldCommit({
5950
+ entry: entry,
5951
+ editability: editability,
5952
+ surface: surface
5953
+ }), saver = useSaveField({
5954
+ instanceId: entry.instance._id,
5955
+ ...onSaved === void 0 ? {} : {
5956
+ onSaved: onSaved
5957
+ }
5958
+ });
5959
+ return {
5960
+ ...commit,
5961
+ ...saver
5962
+ };
5963
+ }
5964
+
5965
+ function ScalarPill({entry: entry, pill: pill, editability: editability, surface: surface}) {
5966
+ const [open, setOpen] = react.useState(!1), {set: set, saving: saving, save: save} = usePillWrite({
5450
5967
  entry: entry,
5451
- editability: editability
5452
- }), {saving: saving, save: save} = useSaveField({
5968
+ editability: editability,
5969
+ surface: surface,
5453
5970
  onSaved: () => setOpen(!1)
5454
5971
  });
5455
5972
  /* @__PURE__ */
@@ -5475,18 +5992,21 @@ function ScalarPill({entry: entry, pill: pill, editability: editability}) {
5475
5992
  });
5476
5993
  }
5477
5994
 
5478
- function DatePill({entry: entry, pill: pill, editability: editability, kind: kind}) {
5995
+ function DatePill({entry: entry, pill: pill, editability: editability, surface: surface, kind: kind}) {
5479
5996
  const [open, setOpen] = react.useState(!1), {set: set} = useFieldCommit({
5480
5997
  entry: entry,
5481
- editability: editability
5482
- }), {save: save} = useSaveField();
5998
+ editability: editability,
5999
+ surface: surface
6000
+ }), {save: save} = useSaveField({
6001
+ instanceId: entry.instance._id
6002
+ });
5483
6003
  /* @__PURE__ */
5484
6004
  return jsxRuntime.jsx(PillPopover, {
5485
6005
  content: /* @__PURE__ */ jsxRuntime.jsx(workflowComponents.DatePicker, {
5486
6006
  onSelect: next => {
5487
- kind === "date" && setOpen(!1), save(() => set(serializeDateFieldValue(next, kind)));
6007
+ hasTimeOfDay(kind) || setOpen(!1), save(() => set(serializeDateFieldValue(next, kind)));
5488
6008
  },
5489
- selectTime: kind === "datetime",
6009
+ selectTime: hasTimeOfDay(kind),
5490
6010
  value: parseDateFieldValue(pill.entry?.value, kind)
5491
6011
  }),
5492
6012
  onDismiss: () => setOpen(!1),
@@ -5496,11 +6016,12 @@ function DatePill({entry: entry, pill: pill, editability: editability, kind: kin
5496
6016
  });
5497
6017
  }
5498
6018
 
5499
- function BooleanPill({entry: entry, pill: pill, editability: editability}) {
5500
- const {set: set} = useFieldCommit({
6019
+ function BooleanPill({entry: entry, pill: pill, editability: editability, surface: surface}) {
6020
+ const {set: set, save: save} = usePillWrite({
5501
6021
  entry: entry,
5502
- editability: editability
5503
- }), {save: save} = useSaveField(), chrome = usePillChrome(), current = pill.entry?._type === "boolean" ? pill.entry.value : null, menuId = react.useId();
6022
+ editability: editability,
6023
+ surface: surface
6024
+ }), chrome = usePillChrome(), current = pill.entry?._type === "boolean" ? pill.entry.value : null, menuId = react.useId();
5504
6025
  /* @__PURE__ */
5505
6026
  return jsxRuntime.jsx(PillHint, {
5506
6027
  pill: pill,
@@ -5544,12 +6065,14 @@ function BooleanPill({entry: entry, pill: pill, editability: editability}) {
5544
6065
  });
5545
6066
  }
5546
6067
 
5547
- function ActorPill({entry: entry, pill: pill, editability: editability}) {
6068
+ function ActorPill({entry: entry, pill: pill, editability: editability, surface: surface}) {
5548
6069
  const [open, setOpen] = react.useState(!1), {set: set, unset: unset} = useFieldCommit({
5549
6070
  entry: entry,
5550
- editability: editability
6071
+ editability: editability,
6072
+ surface: surface
5551
6073
  }), current = isActorShape(pill.entry?.value) ? pill.entry.value : null, {pick: pick} = useActorPick({
5552
6074
  current: current,
6075
+ instanceId: entry.instance._id,
5553
6076
  onSave: set,
5554
6077
  onUnset: unset
5555
6078
  });
@@ -5569,12 +6092,14 @@ function ActorPill({entry: entry, pill: pill, editability: editability}) {
5569
6092
  });
5570
6093
  }
5571
6094
 
5572
- function AssigneePill({entry: entry, pill: pill, editability: editability}) {
6095
+ function AssigneePill({entry: entry, pill: pill, editability: editability, surface: surface}) {
5573
6096
  const [open, setOpen] = react.useState(!1), {set: set, unset: unset} = useFieldCommit({
5574
6097
  entry: entry,
5575
- editability: editability
6098
+ editability: editability,
6099
+ surface: surface
5576
6100
  }), current = pill.entry?._type === "assignee" ? pill.entry.value : null, {pick: pick} = useAssigneePick({
5577
6101
  current: current,
6102
+ instanceId: entry.instance._id,
5578
6103
  onSave: set,
5579
6104
  onUnset: unset
5580
6105
  });
@@ -5594,11 +6119,12 @@ function AssigneePill({entry: entry, pill: pill, editability: editability}) {
5594
6119
  });
5595
6120
  }
5596
6121
 
5597
- function AssigneesPill({entry: entry, pill: pill, editability: editability}) {
5598
- const [open, setOpen] = react.useState(!1), {set: set} = useFieldCommit({
6122
+ function AssigneesPill({entry: entry, pill: pill, editability: editability, surface: surface}) {
6123
+ const [open, setOpen] = react.useState(!1), {set: set, saving: saving, save: save} = usePillWrite({
5599
6124
  entry: entry,
5600
- editability: editability
5601
- }), {saving: saving, save: save} = useSaveField(), current = pill.face.kind === "assignees" ? pill.face.assignees : [];
6125
+ editability: editability,
6126
+ surface: surface
6127
+ }), current = pill.face.kind === "assignees" ? pill.face.assignees : [];
5602
6128
  /* @__PURE__ */
5603
6129
  return jsxRuntime.jsx(PillPopover, {
5604
6130
  content: /* @__PURE__ */ jsxRuntime.jsx(AssigneePicker, {
@@ -5641,46 +6167,53 @@ function TodoPill({entry: entry, pill: pill, scope: scope}) {
5641
6167
  });
5642
6168
  }
5643
6169
 
5644
- function ScalarEditorPill({entry: entry, pill: pill, editability: editability}) {
6170
+ function ScalarEditorPill({entry: entry, pill: pill, editability: editability, surface: surface}) {
5645
6171
  return editability.type === "boolean" ? /* @__PURE__ */ jsxRuntime.jsx(BooleanPill, {
5646
6172
  editability: editability,
5647
6173
  entry: entry,
5648
- pill: pill
5649
- }) : editability.type === "date" || editability.type === "datetime" ? /* @__PURE__ */ jsxRuntime.jsx(DatePill, {
6174
+ pill: pill,
6175
+ surface: surface
6176
+ }) : isDateFieldKind(editability.type) ? /* @__PURE__ */ jsxRuntime.jsx(DatePill, {
5650
6177
  editability: editability,
5651
6178
  entry: entry,
5652
6179
  kind: editability.type,
5653
- pill: pill
6180
+ pill: pill,
6181
+ surface: surface
5654
6182
  }) : /* @__PURE__ */ jsxRuntime.jsx(ScalarPill, {
5655
6183
  editability: editability,
5656
6184
  entry: entry,
5657
- pill: pill
6185
+ pill: pill,
6186
+ surface: surface
5658
6187
  });
5659
6188
  }
5660
6189
 
5661
- function EditorPill({entry: entry, pill: pill, editability: editability}) {
6190
+ function EditorPill({entry: entry, pill: pill, editability: editability, surface: surface}) {
5662
6191
  return pill.editor === "scalar" ? /* @__PURE__ */ jsxRuntime.jsx(ScalarEditorPill, {
5663
6192
  editability: editability,
5664
6193
  entry: entry,
5665
- pill: pill
6194
+ pill: pill,
6195
+ surface: surface
5666
6196
  }) : pill.editor === "actor" ? /* @__PURE__ */ jsxRuntime.jsx(ActorPill, {
5667
6197
  editability: editability,
5668
6198
  entry: entry,
5669
- pill: pill
6199
+ pill: pill,
6200
+ surface: surface
5670
6201
  }) : pill.editor === "assignee" ? /* @__PURE__ */ jsxRuntime.jsx(AssigneePill, {
5671
6202
  editability: editability,
5672
6203
  entry: entry,
5673
- pill: pill
6204
+ pill: pill,
6205
+ surface: surface
5674
6206
  }) : pill.editor === "assignees" ? /* @__PURE__ */ jsxRuntime.jsx(AssigneesPill, {
5675
6207
  editability: editability,
5676
6208
  entry: entry,
5677
- pill: pill
6209
+ pill: pill,
6210
+ surface: surface
5678
6211
  }) : /* @__PURE__ */ jsxRuntime.jsx(ReadOnlyPill, {
5679
6212
  pill: pill
5680
6213
  });
5681
6214
  }
5682
6215
 
5683
- function FieldPill({entry: entry, pill: pill, scope: scope}) {
6216
+ function FieldPill({entry: entry, pill: pill, scope: scope, surface: surface}) {
5684
6217
  if (pill.editor === "todoList" && pill.entry !== void 0) /* @__PURE__ */
5685
6218
  return jsxRuntime.jsx(TodoPill, {
5686
6219
  entry: entry,
@@ -5693,7 +6226,8 @@ function FieldPill({entry: entry, pill: pill, scope: scope}) {
5693
6226
  }) : /* @__PURE__ */ jsxRuntime.jsx(EditorPill, {
5694
6227
  editability: editability,
5695
6228
  entry: entry,
5696
- pill: pill
6229
+ pill: pill,
6230
+ surface: surface
5697
6231
  });
5698
6232
  }
5699
6233
 
@@ -5824,7 +6358,7 @@ function InstanceToolLink({entry: entry}) {
5824
6358
  }
5825
6359
  });
5826
6360
  }, [ instanceId ]);
5827
- return tools.some(tool => tool.name === WORKFLOWS_TOOL_NAME) ? /* @__PURE__ */ jsxRuntime.jsx(ui.Flex, {
6361
+ return workflowsToolAvailable(tools) ? /* @__PURE__ */ jsxRuntime.jsx(ui.Flex, {
5828
6362
  children: /* @__PURE__ */ jsxRuntime.jsx(ui.Button, {
5829
6363
  as: WorkflowIntentLink,
5830
6364
  fontSize: 1,
@@ -6027,6 +6561,7 @@ function StageGlyph(props) {
6027
6561
  }
6028
6562
 
6029
6563
  function StageFace({completed: completed = !1, detail: detail, title: title}) {
6564
+ const tone = completed ? "default" : "primary";
6030
6565
  /* @__PURE__ */
6031
6566
  return jsxRuntime.jsxs(ui.Flex, {
6032
6567
  align: "center",
@@ -6035,8 +6570,8 @@ function StageFace({completed: completed = !1, detail: detail, title: title}) {
6035
6570
  children: [
6036
6571
  /* @__PURE__ */ jsxRuntime.jsx(sanity.TextWithTone, {
6037
6572
  size: 1,
6038
- tone: "primary",
6039
- children: completed ? /* @__PURE__ */ jsxRuntime.jsx(CheckmarkCircle.CheckmarkCircleIcon, {
6573
+ tone: tone,
6574
+ children: completed ? /* @__PURE__ */ jsxRuntime.jsx(CheckmarkCircleFilledIcon, {
6040
6575
  style: {
6041
6576
  color: "inherit"
6042
6577
  }
@@ -6048,7 +6583,7 @@ function StageFace({completed: completed = !1, detail: detail, title: title}) {
6048
6583
  }),
6049
6584
  /* @__PURE__ */ jsxRuntime.jsx(sanity.TextWithTone, {
6050
6585
  size: 1,
6051
- tone: "primary",
6586
+ tone: tone,
6052
6587
  weight: "medium",
6053
6588
  children: title
6054
6589
  }), detail === void 0 ? null : /* @__PURE__ */ jsxRuntime.jsx(ui.Text, {
@@ -6066,10 +6601,10 @@ function StageChip({completed: completed = !1, detail: detail, interactive: inte
6066
6601
  padding: 3,
6067
6602
  radius: 4,
6068
6603
  style: {
6069
- boxShadow: `inset 0 0 0 1px ${color.focusRing}`,
6604
+ boxShadow: `inset 0 0 0 1px ${completed ? color.badge.default.fg : color.focusRing}`,
6070
6605
  cursor: interactive ? "help" : "default"
6071
6606
  },
6072
- tone: "primary",
6607
+ tone: completed ? "default" : "primary",
6073
6608
  ...interactive ? {
6074
6609
  tabIndex: 0
6075
6610
  } : {},
@@ -6297,7 +6832,8 @@ function WorkflowInstanceSection({defaultOpen: defaultOpen, entry: entry, onOpen
6297
6832
  children: [
6298
6833
  /* @__PURE__ */ jsxRuntime.jsx(InstanceSnapshotBody, {
6299
6834
  entry: entry,
6300
- onOpenActivity: onOpenActivity
6835
+ onOpenActivity: onOpenActivity,
6836
+ surface: "document-view"
6301
6837
  }),
6302
6838
  /* @__PURE__ */ jsxRuntime.jsx(InstanceToolLink, {
6303
6839
  entry: entry
@@ -6306,7 +6842,7 @@ function WorkflowInstanceSection({defaultOpen: defaultOpen, entry: entry, onOpen
6306
6842
  });
6307
6843
  }
6308
6844
 
6309
- function InstanceSnapshotBody({entry: entry, onOpenActivity: onOpenActivity}) {
6845
+ function InstanceSnapshotBody({entry: entry, onOpenActivity: onOpenActivity, surface: surface}) {
6310
6846
  const definition = useDefinition(entry), {instance: instance} = entry;
6311
6847
  /* @__PURE__ */
6312
6848
  return jsxRuntime.jsxs(ui.Stack, {
@@ -6317,7 +6853,8 @@ function InstanceSnapshotBody({entry: entry, onOpenActivity: onOpenActivity}) {
6317
6853
  /* @__PURE__ */ jsxRuntime.jsx(FieldPills, {
6318
6854
  definition: definition,
6319
6855
  entry: entry,
6320
- scope: "workflow"
6856
+ scope: "workflow",
6857
+ surface: surface
6321
6858
  }),
6322
6859
  /* @__PURE__ */ jsxRuntime.jsxs(ui.Card, {
6323
6860
  border: !0,
@@ -6342,14 +6879,15 @@ function InstanceSnapshotBody({entry: entry, onOpenActivity: onOpenActivity}) {
6342
6879
  padding: 2,
6343
6880
  children: /* @__PURE__ */ jsxRuntime.jsx(StageSection, {
6344
6881
  entry: entry,
6345
- onOpenActivity: onOpenActivity
6882
+ onOpenActivity: onOpenActivity,
6883
+ surface: surface
6346
6884
  })
6347
6885
  }) ]
6348
6886
  }) ]
6349
6887
  });
6350
6888
  }
6351
6889
 
6352
- function StageSection({entry: entry, onOpenActivity: onOpenActivity}) {
6890
+ function StageSection({entry: entry, onOpenActivity: onOpenActivity, surface: surface}) {
6353
6891
  const definition = useDefinition(entry), notice = instanceNotice(entry);
6354
6892
  return notice !== null ? notice : /* @__PURE__ */ jsxRuntime.jsx(StaleLock, {
6355
6893
  stale: isEvaluationStale(entry),
@@ -6359,11 +6897,13 @@ function StageSection({entry: entry, onOpenActivity: onOpenActivity}) {
6359
6897
  /* @__PURE__ */ jsxRuntime.jsx(FieldPills, {
6360
6898
  definition: definition,
6361
6899
  entry: entry,
6362
- scope: "stage"
6900
+ scope: "stage",
6901
+ surface: surface
6363
6902
  }),
6364
6903
  /* @__PURE__ */ jsxRuntime.jsx(ActivitiesList, {
6365
6904
  entry: entry,
6366
- onOpenActivity: onOpenActivity
6905
+ onOpenActivity: onOpenActivity,
6906
+ surface: surface
6367
6907
  }) ]
6368
6908
  })
6369
6909
  });
@@ -6372,8 +6912,9 @@ function StageSection({entry: entry, onOpenActivity: onOpenActivity}) {
6372
6912
  function CautionNote({action: action, label: label}) {
6373
6913
  /* @__PURE__ */
6374
6914
  return jsxRuntime.jsxs(ui.Card, {
6375
- padding: 2,
6376
6915
  paddingLeft: 3,
6916
+ paddingRight: 2,
6917
+ paddingY: 3,
6377
6918
  radius: 3,
6378
6919
  style: {
6379
6920
  alignItems: "center",
@@ -6401,18 +6942,20 @@ function CautionNote({action: action, label: label}) {
6401
6942
  }
6402
6943
 
6403
6944
  function CopyDetailsButton({unreadable: unreadable}) {
6404
- const toast = useClosableToast();
6945
+ const toast = useWorkflowToast();
6405
6946
  /* @__PURE__ */
6406
6947
  return jsxRuntime.jsx(ui.Button, {
6407
6948
  fontSize: 1,
6408
6949
  mode: "ghost",
6409
6950
  onClick: () => {
6410
6951
  navigator.clipboard.writeText(unreadableDocsReport(unreadable)).then(() => toast.push({
6411
- status: "success",
6412
- title: "Details copied"
6952
+ id: TOAST_ID.detailsCopy,
6953
+ status: "info",
6954
+ title: "Details copied to clipboard"
6413
6955
  }), () => toast.push({
6956
+ id: TOAST_ID.detailsCopy,
6414
6957
  status: "error",
6415
- title: "Could not copy the details"
6958
+ title: "Failed to copy the details"
6416
6959
  }));
6417
6960
  },
6418
6961
  padding: 2,
@@ -6438,7 +6981,7 @@ const HEADLINES = {
6438
6981
  };
6439
6982
 
6440
6983
  function remediation(invalid) {
6441
- 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.`;
6984
+ 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.`;
6442
6985
  }
6443
6986
 
6444
6987
  function InvalidDocNotice({invalid: invalid}) {
@@ -6489,18 +7032,6 @@ function TabSwitch({ariaControls: ariaControls, idPrefix: idPrefix, options: opt
6489
7032
  });
6490
7033
  }
6491
7034
 
6492
- function useDelayedFlag(active, delayMs) {
6493
- const [held, setHeld] = react.useState(!1);
6494
- return react.useEffect(() => {
6495
- if (!active) {
6496
- setHeld(!1);
6497
- return;
6498
- }
6499
- const timer = setTimeout(() => setHeld(!0), delayMs);
6500
- return () => clearTimeout(timer);
6501
- }, [ active, delayMs ]), held && active;
6502
- }
6503
-
6504
7035
  function openActivityGone(args) {
6505
7036
  const {entry: entry, target: target} = args;
6506
7037
  if (entry === void 0 || entry.instance.currentStage !== target.stage) return !0;
@@ -6633,7 +7164,9 @@ const asInitial = candidate => candidate, scalarInitialValue = (entry, value) =>
6633
7164
  value: value === !0
6634
7165
  }),
6635
7166
  date: scalarInitialValue,
7167
+ dueDate: scalarInitialValue,
6636
7168
  datetime: scalarInitialValue,
7169
+ dueDatetime: scalarInitialValue,
6637
7170
  "doc.ref": singleRefInitialValue,
6638
7171
  "doc.refs": (entry, value) => asInitial({
6639
7172
  type: entry.type,
@@ -6784,15 +7317,36 @@ function classifyStartError(err) {
6784
7317
  };
6785
7318
  }
6786
7319
 
7320
+ function startOutcomeToast(outcome, label) {
7321
+ return outcome.kind === "started-not-settled" ? {
7322
+ id: TOAST_ID.start,
7323
+ status: "warning",
7324
+ title: `“${label}” started but didn’t finish`,
7325
+ description: outcome.description
7326
+ } : outcome.kind === "not-allowed" ? {
7327
+ id: TOAST_ID.start,
7328
+ status: "warning",
7329
+ title: `“${label}” can’t be started right now`,
7330
+ description: outcome.description
7331
+ } : {
7332
+ id: TOAST_ID.start,
7333
+ status: "error",
7334
+ title: `Failed to start “${label}”`,
7335
+ description: outcome.description
7336
+ };
7337
+ }
7338
+
6787
7339
  function boundReleaseId(mapping, selectedReleaseId) {
6788
7340
  return mapping?.perspectiveField !== void 0 && selectedReleaseId !== void 0 ? selectedReleaseId : void 0;
6789
7341
  }
6790
7342
 
7343
+ const MAPPING_BROKEN_HINT = docTypeLabel => `Unavailable — this workflow isn’t set up correctly for ${docTypeLabel} documents`;
7344
+
6791
7345
  function startGate(args) {
6792
7346
  const {mapping: mapping, mappingIssue: mappingIssue, selectedReleaseId: selectedReleaseId, releaseActive: releaseActive} = args;
6793
7347
  if (mappingIssue !== void 0) return {
6794
7348
  blocked: !0,
6795
- tooltip: mappingIssue
7349
+ tooltip: MAPPING_BROKEN_HINT(args.docTypeLabel)
6796
7350
  };
6797
7351
  if (mapping.perspectiveField?.required === !0 && selectedReleaseId === void 0) return {
6798
7352
  blocked: !0,
@@ -6804,7 +7358,7 @@ function startGate(args) {
6804
7358
  };
6805
7359
  if (args.startFilterFailed === !0) return {
6806
7360
  blocked: !0,
6807
- tooltip: `${mapping.label} can't start for this document right now — the workflow's start condition isn't met`
7361
+ tooltip: `${mapping.label} cant start for this document right now — the workflows start condition isnt met`
6808
7362
  };
6809
7363
  if (args.unmetRequirement !== void 0) {
6810
7364
  const requirement = args.unmetRequirement;
@@ -7066,7 +7620,7 @@ function showRowOnError(key, mapping) {
7066
7620
  }
7067
7621
 
7068
7622
  function useStartWorkflow(args) {
7069
- const {mapping: mapping, docId: docId, initialValue: initialValue, source: source} = args, toast = useClosableToast(), {engine: engine, openStartDialog: openStartDialog, mappingIssues: mappingIssues2, mappingStarts: mappingStarts} = useWorkflowContext(), observer = workflowStudio.useStudioObserver({
7623
+ const {mapping: mapping, docId: docId, initialValue: initialValue, source: source} = args, toast = useWorkflowToast(), schema = sanity.useSchema(), {engine: engine, openStartDialog: openStartDialog, mappingIssues: mappingIssues2, mappingStarts: mappingStarts} = useWorkflowContext(), observer = workflowStudio.useStudioObserver({
7070
7624
  engine: engine
7071
7625
  }), [starting, setStarting] = react.useState(!1), {selectedReleaseId: selectedReleaseId} = sanity.usePerspective(), releaseActive = sanity.useIsReleaseActive(), startBlock = mappingStarts.get(mappingKey(mapping)), hidden = workflowEngine.startKindOf({
7072
7626
  start: startBlock
@@ -7086,6 +7640,7 @@ function useStartWorkflow(args) {
7086
7640
  }), {blocked: blocked, tooltip: tooltip} = startGate({
7087
7641
  mapping: mapping,
7088
7642
  mappingIssue: mappingIssues2.get(mappingKey(mapping)),
7643
+ docTypeLabel: schema.get(mapping.docType)?.title ?? mapping.docType,
7089
7644
  selectedReleaseId: selectedReleaseId,
7090
7645
  releaseActive: releaseActive,
7091
7646
  startFilterFailed: filterFailed,
@@ -7109,8 +7664,9 @@ function useStartWorkflow(args) {
7109
7664
  selectedReleaseId: selectedReleaseId,
7110
7665
  ensureDocumentExists: observer.ensureDocumentExists,
7111
7666
  onPersistFailure: err => toast.push({
7667
+ id: TOAST_ID.documentSave,
7112
7668
  status: "error",
7113
- title: "Could not persist the document before starting",
7669
+ title: "Failed to save the document",
7114
7670
  description: describeError(err)
7115
7671
  }),
7116
7672
  openStartDialog: request => openStartDialog({
@@ -7251,7 +7807,8 @@ function ForMeList({entry: entry, work: work, identity: identity, onOpenActivity
7251
7807
  }),
7252
7808
  breadcrumb: breadcrumb,
7253
7809
  instanceId: instance._id,
7254
- onOpen: () => onOpenActivity(activityEval.activity.name)
7810
+ onOpen: () => onOpenActivity(activityEval.activity.name),
7811
+ surface: "document-view"
7255
7812
  }, activityEval.activity.name)), itemCount > 0 ? /* @__PURE__ */ jsxRuntime.jsx(TodoItemsList, {
7256
7813
  breadcrumb: breadcrumb,
7257
7814
  entry: entry,
@@ -7599,6 +8156,23 @@ function workflowIssue(args) {
7599
8156
  if (!workflowEngine.isInputSourced(subject)) return `autoStart: "${docType}" → workflow "${name}" has a self-filling subject (not caller-provided), so the document can't be its subject — skipped.`;
7600
8157
  }
7601
8158
 
8159
+ function createSubscribers() {
8160
+ const listeners = /* @__PURE__ */ new Set;
8161
+ return {
8162
+ subscribe(listener) {
8163
+ return listeners.add(listener), () => {
8164
+ listeners.delete(listener);
8165
+ };
8166
+ },
8167
+ notify() {
8168
+ for (const listener of [ ...listeners ]) listener();
8169
+ },
8170
+ clear() {
8171
+ listeners.clear();
8172
+ }
8173
+ };
8174
+ }
8175
+
7602
8176
  function actualType$(previews, bareId) {
7603
8177
  return previews.unstable_observeDocumentPairAvailability(bareId).pipe(operators.switchMap(({draft: draft, published: published}) => draft.available ? previews.observeDocumentTypeFromId(csm.getDraftId(bareId)) : published.available ? previews.observeDocumentTypeFromId(bareId) : draft.reason === "PERMISSION_DENIED" || published.reason === "PERMISSION_DENIED" ? rxjs.of(void 0) : previews.unstable_observeVersionDocumentIds(bareId).pipe(operators.switchMap(([firstVersionId]) => firstVersionId === void 0 ? rxjs.of(null) : previews.observeDocumentTypeFromId(firstVersionId)))), operators.distinctUntilChanged());
7604
8178
  }
@@ -7606,12 +8180,10 @@ function actualType$(previews, bareId) {
7606
8180
  const REBUILD_DELAY_MS = 5e3;
7607
8181
 
7608
8182
  function createActualTypeProbeStore(previews) {
7609
- const verdicts = /* @__PURE__ */ new Map, live = /* @__PURE__ */ new Map, listeners = /* @__PURE__ */ new Set, notify = () => {
7610
- for (const listener of [ ...listeners ]) listener();
7611
- }, start = (bareId, entry) => actualType$(previews, bareId).subscribe({
8183
+ const verdicts = /* @__PURE__ */ new Map, live = /* @__PURE__ */ new Map, subscribers = createSubscribers(), start = (bareId, entry) => actualType$(previews, bareId).subscribe({
7612
8184
  next: value => {
7613
8185
  verdicts.has(bareId) && verdicts.get(bareId) === value || (verdicts.set(bareId, value),
7614
- notify());
8186
+ subscribers.notify());
7615
8187
  },
7616
8188
  error: err => {
7617
8189
  console.error(`[workflow-studio-plugin] actual-type probe for "${bareId}" failed:`, err),
@@ -7621,12 +8193,14 @@ function createActualTypeProbeStore(previews) {
7621
8193
  }
7622
8194
  });
7623
8195
  return {
7624
- subscribe(listener) {
7625
- return listeners.add(listener), () => {
7626
- listeners.delete(listener);
7627
- };
7628
- },
8196
+ subscribe: subscribers.subscribe,
7629
8197
  read: bareId => verdicts.get(bareId),
8198
+ seed(types2) {
8199
+ let changed = !1;
8200
+ for (const [bareId, actualType] of types2) verdicts.has(bareId) || (verdicts.set(bareId, actualType),
8201
+ changed = !0);
8202
+ changed && subscribers.notify();
8203
+ },
7630
8204
  track(bareId) {
7631
8205
  let entry = live.get(bareId);
7632
8206
  if (entry === void 0) {
@@ -7647,10 +8221,6 @@ function createActualTypeProbeStore(previews) {
7647
8221
  };
7648
8222
  }
7649
8223
 
7650
- function contentDocumentTypes(schema) {
7651
- return schema.getTypeNames().filter(name => schema.get(name)?.type?.name === "document" && !WORKFLOW_SYSTEM_TYPES.includes(name));
7652
- }
7653
-
7654
8224
  async function readDeployedDefinitions(engine) {
7655
8225
  return (await engine.query({
7656
8226
  groq: workflowEngine.latestDefinitionsGroq()
@@ -7825,7 +8395,7 @@ const REPORT_FLUSH_MS = 50, EMPTY_COMMITTED = {
7825
8395
 
7826
8396
  function createEntriesStore() {
7827
8397
  let committed = EMPTY_COMMITTED, reports = /* @__PURE__ */ new Map, byInstance = /* @__PURE__ */ new Map, byDocument = /* @__PURE__ */ new Map;
7828
- const listeners = /* @__PURE__ */ new Set;
8398
+ const subscribers = createSubscribers();
7829
8399
  let flushTimer;
7830
8400
  const recompute = () => {
7831
8401
  flushTimer !== void 0 && (clearTimeout(flushTimer), flushTimer = void 0);
@@ -7838,10 +8408,8 @@ function createEntriesStore() {
7838
8408
  byInstance: nextByInstance,
7839
8409
  previous: byDocument
7840
8410
  });
7841
- if (!(nextByInstance === byInstance && nextByDocument === byDocument)) {
7842
- byInstance = nextByInstance, byDocument = nextByDocument;
7843
- for (const listener of [ ...listeners ]) listener();
7844
- }
8411
+ nextByInstance === byInstance && nextByDocument === byDocument || (byInstance = nextByInstance,
8412
+ byDocument = nextByDocument, subscribers.notify());
7845
8413
  };
7846
8414
  return {
7847
8415
  setCommitted(inputs) {
@@ -7857,13 +8425,9 @@ function createEntriesStore() {
7857
8425
  getReport: instanceId => reports.get(instanceId),
7858
8426
  getInstance: instanceId => byInstance.get(instanceId),
7859
8427
  getDocument: docId => byDocument.get(docId) ?? EMPTY_ENTRIES,
7860
- subscribe(listener) {
7861
- return listeners.add(listener), () => {
7862
- listeners.delete(listener);
7863
- };
7864
- },
8428
+ subscribe: subscribers.subscribe,
7865
8429
  dispose() {
7866
- flushTimer !== void 0 && clearTimeout(flushTimer), flushTimer = void 0, listeners.clear();
8430
+ flushTimer !== void 0 && clearTimeout(flushTimer), flushTimer = void 0, subscribers.clear();
7867
8431
  }
7868
8432
  };
7869
8433
  }
@@ -7994,7 +8558,7 @@ function WorkflowProvider(props) {
7994
8558
  try {
7995
8559
  await (drainRef.current?.(instanceId));
7996
8560
  } catch (err) {
7997
- throw new Error(`The change was committed, but running its effects failed: ${describeError(err)}`, {
8561
+ throw new EffectsIncompleteError(describeError(err), {
7998
8562
  cause: err
7999
8563
  });
8000
8564
  }
@@ -8125,12 +8689,19 @@ function WorkflowProvider(props) {
8125
8689
  });
8126
8690
  }
8127
8691
 
8128
- function sameEntries(a, b) {
8129
- if (a.size !== b.size) return !1;
8130
- for (const [key, value] of b) if (a.get(key) !== value) return !1;
8131
- return !0;
8692
+ function entriesSameBy(equal) {
8693
+ return (a, b) => {
8694
+ if (a.size !== b.size) return !1;
8695
+ for (const [key, value] of b) {
8696
+ const previous = a.get(key);
8697
+ if (previous === void 0 || !equal(previous, value)) return !1;
8698
+ }
8699
+ return !0;
8700
+ };
8132
8701
  }
8133
8702
 
8703
+ const sameIssues = entriesSameBy(sameMappingIssue), sameVersions = entriesSameBy(Object.is);
8704
+
8134
8705
  function sameMappings(a, b) {
8135
8706
  return a.length === b.length && a.every((mapping, index) => {
8136
8707
  const other = b[index];
@@ -8154,10 +8725,7 @@ function useDeployedDefinitions(args) {
8154
8725
  contentResource: contentResource,
8155
8726
  schemaContentTypes: schemaContentTypes
8156
8727
  });
8157
- for (const [rowKey, message] of found) {
8158
- const signature = `${rowKey}|${message}`;
8159
- logged.current.has(signature) || (logged.current.add(signature), console.error(`[workflow-studio-plugin] ${message}`));
8160
- }
8728
+ logOnce(mappingIssueLogLines(found), logged.current);
8161
8729
  const resolvedAutoStart = resolveAutoStart({
8162
8730
  autoStart: mappingAutoStartMap(effectiveMappings),
8163
8731
  knownDocTypes: new Set(schema.getTypeNames()),
@@ -8165,7 +8733,7 @@ function useDeployedDefinitions(args) {
8165
8733
  });
8166
8734
  if (logOnce(resolvedAutoStart.warnings, logged.current), cancelled) return;
8167
8735
  setMappings(prev => sameMappings(prev, effectiveMappings) ? prev : effectiveMappings),
8168
- setIssues(prev => sameEntries(prev, found) ? prev : found), setStarts(mappingStartBlocks({
8736
+ setIssues(prev => sameIssues(prev, found) ? prev : found), setStarts(mappingStartBlocks({
8169
8737
  mappings: effectiveMappings,
8170
8738
  definitions: definitions
8171
8739
  })), setFields(mappingDeclaredFields({
@@ -8173,7 +8741,7 @@ function useDeployedDefinitions(args) {
8173
8741
  definitions: definitions
8174
8742
  }));
8175
8743
  const versions = new Map(workflowEngine.latestDeployedDefinitions(definitions).map(d => [ d.name, d.version ]));
8176
- setLatestVersions(prev => sameEntries(prev, versions) ? prev : versions), setAutoStartByType(resolvedAutoStart.byType),
8744
+ setLatestVersions(prev => sameVersions(prev, versions) ? prev : versions), setAutoStartByType(resolvedAutoStart.byType),
8177
8745
  setAutoStartDefinitions(resolvedAutoStart.definitions);
8178
8746
  })().catch(err => {
8179
8747
  console.error("[workflow-studio-plugin] mapping discovery failed — keeping the last resolved workflow state:", err);
@@ -8317,16 +8885,8 @@ function ChecklistInput({value: value, onChange: onChange}) {
8317
8885
  value: it.label
8318
8886
  })
8319
8887
  }),
8320
- /* @__PURE__ */ jsxRuntime.jsx(HoverHint, {
8321
- text: "Remove item",
8322
- children: /* @__PURE__ */ jsxRuntime.jsx(ui.Button, {
8323
- "aria-label": "Remove item",
8324
- fontSize: 1,
8325
- icon: Close.CloseIcon,
8326
- mode: "bleed",
8327
- onClick: () => remove(i),
8328
- padding: 2
8329
- })
8888
+ /* @__PURE__ */ jsxRuntime.jsx(RemoveItemButton, {
8889
+ onClick: () => remove(i)
8330
8890
  }) ]
8331
8891
  }, it._key)),
8332
8892
  /* @__PURE__ */ jsxRuntime.jsx(ui.Flex, {
@@ -8430,7 +8990,7 @@ function useLatestDefinition(definitionName) {
8430
8990
  function useCreateDoc(args) {
8431
8991
  const {releaseId: releaseId, onCreated: onCreated} = args, {engine: engine, binding: binding} = useWorkflowContext(), observer = workflowStudio.useStudioObserver({
8432
8992
  engine: engine
8433
- }), schema = sanity.useSchema(), templates = sanity.useTemplates(), resolverContext = sanity.useInitialValueResolverContext(), toast = useClosableToast(), [creating, setCreating] = react.useState(!1);
8993
+ }), schema = sanity.useSchema(), templates = sanity.useTemplates(), resolverContext = sanity.useInitialValueResolverContext(), toast = useWorkflowToast(), [creating, setCreating] = react.useState(!1);
8434
8994
  return {
8435
8995
  creating: creating,
8436
8996
  createDoc: async type => {
@@ -8455,8 +9015,9 @@ function useCreateDoc(args) {
8455
9015
  }));
8456
9016
  } catch (err) {
8457
9017
  toast.push({
9018
+ id: TOAST_ID.documentCreate,
8458
9019
  status: "error",
8459
- title: "Could not create document",
9020
+ title: "Failed to create the document",
8460
9021
  description: describeError(err)
8461
9022
  });
8462
9023
  } finally {
@@ -8773,31 +9334,12 @@ function ResumeNote({onStartNew: onStartNew}) {
8773
9334
 
8774
9335
  function handleStartError(args) {
8775
9336
  const {label: label, toast: toast, seedInstance: seedInstance, onClose: onClose} = args, outcome = classifyStartError(args.err);
8776
- if (outcome.kind === "started-not-settled") {
8777
- toast.push({
8778
- status: "warning",
8779
- title: `${label} started, but didn’t finish auto-advancing`,
8780
- description: outcome.description
8781
- }), outcome.instance !== void 0 && seedInstance(outcome.instance), onClose();
8782
- return;
8783
- }
8784
- if (outcome.kind === "not-allowed") {
8785
- toast.push({
8786
- status: "warning",
8787
- title: `${label} can't be started right now`,
8788
- description: outcome.description
8789
- });
8790
- return;
8791
- }
8792
- toast.push({
8793
- status: "error",
8794
- title: `Failed to start ${label}`,
8795
- description: outcome.description
8796
- });
9337
+ toast.push(startOutcomeToast(outcome, label)), outcome.kind === "started-not-settled" && (outcome.instance !== void 0 && seedInstance(outcome.instance),
9338
+ onClose());
8797
9339
  }
8798
9340
 
8799
9341
  function StartWorkflowForm({request: request, onClose: onClose}) {
8800
- const {definition: definitionName, label: label, mapping: mapping, subjectDocId: subjectDocId} = request, {engine: engine, binding: binding, seedInstance: seedInstance} = useWorkflowContext(), telemetry2 = workflowReact.useWorkflowTelemetry(), toast = useClosableToast(), {def: definition, error: definitionError} = useLatestDefinition(definitionName), {selectedReleaseId: selectedReleaseId} = sanity.usePerspective(), releaseId = boundReleaseId(mapping, selectedReleaseId), [values, setValues] = react.useState({}), [attempt, setAttempt] = react.useState(void 0), starting = attempt !== void 0, [heldInstanceId, setHeldInstanceId] = react.useState(void 0), [startNew, setStartNew] = react.useState(!1), {entries: entries} = useWorkflowsForDocument(subjectDocId), resumeEntry = presentedResumeEntry({
9342
+ const {definition: definitionName, label: label, mapping: mapping, subjectDocId: subjectDocId} = request, {engine: engine, binding: binding, seedInstance: seedInstance} = useWorkflowContext(), telemetry2 = workflowReact.useWorkflowTelemetry(), toast = useWorkflowToast(), {def: definition, error: definitionError} = useLatestDefinition(definitionName), {selectedReleaseId: selectedReleaseId} = sanity.usePerspective(), releaseId = boundReleaseId(mapping, selectedReleaseId), [values, setValues] = react.useState({}), [attempt, setAttempt] = react.useState(void 0), starting = attempt !== void 0, [heldInstanceId, setHeldInstanceId] = react.useState(void 0), [startNew, setStartNew] = react.useState(!1), {entries: entries} = useWorkflowsForDocument(subjectDocId), resumeEntry = presentedResumeEntry({
8801
9343
  entries: entries,
8802
9344
  definitionName: definitionName,
8803
9345
  heldInstanceId: heldInstanceId,
@@ -8837,8 +9379,9 @@ function StartWorkflowForm({request: request, onClose: onClose}) {
8837
9379
  values: values
8838
9380
  }));
8839
9381
  toast.push({
8840
- status: "success",
8841
- title: `${definition?.title ?? label} started`,
9382
+ id: TOAST_ID.start,
9383
+ status: "info",
9384
+ title: `“${definition?.title ?? label}” started`,
8842
9385
  description: `Stage: ${stageTitle(definition ?? void 0, result.instance.currentStage)}`
8843
9386
  }), seedInstance(result.instance), onClose();
8844
9387
  } catch (err) {
@@ -9340,6 +9883,22 @@ function finishedLinesOf(entries) {
9340
9883
  return [ ...latestByType.values() ].sort((a, b) => b.at - a.at).map(({entry: entry}) => entry);
9341
9884
  }
9342
9885
 
9886
+ function openStageTaskCount(evaluation) {
9887
+ if (evaluation !== void 0) return evaluation.currentStage.activities.filter(activity => isOpenActivityStatus(activity.status)).length;
9888
+ }
9889
+
9890
+ const OPEN_VIEW = "Open the Workflows view";
9891
+
9892
+ function unassignedLineHint(args) {
9893
+ return !args.identityKnown || args.openTaskCount === void 0 ? {
9894
+ text: OPEN_VIEW
9895
+ } : args.openTaskCount === 0 ? {
9896
+ text: "No open tasks in this stage"
9897
+ } : {
9898
+ text: `${pluralize__default.default("open task", args.openTaskCount, !0)}, none assigned to you`
9899
+ };
9900
+ }
9901
+
9343
9902
  function WorkflowFormStrip(props) {
9344
9903
  const {mappings: mappings} = props, {isDocResolved: isDocResolved, discoveryInvalid: discoveryInvalid} = useWorkflowContext(), {docId: docId, entries: entries} = useWorkflowsForDocument(props.value?._id ?? null), {params: params, setParams: setParams} = structure.usePaneRouter(), telemetry2 = workflowReact.useWorkflowTelemetry(), openWorkflowsView = focusId => {
9345
9904
  telemetry2.log(WorkflowFormStripClicked), setParams(focusedViewParams(params, focusId));
@@ -9384,18 +9943,17 @@ function StripLines({active: active, docId: docId, finished: finished, initialVa
9384
9943
  });
9385
9944
  }
9386
9945
 
9387
- function lineHint(identity, forMe) {
9946
+ function lineHint(entry, identity) {
9947
+ const forMe = forMeWorkOf([ entry ], identity);
9388
9948
  return forMe.work.some(({shown: shown}) => hasOpenAssignedWork(shown)) ? {
9389
9949
  content: /* @__PURE__ */ jsxRuntime.jsx(AssignedTasksHint, {
9390
9950
  work: forMe.work
9391
9951
  }),
9392
9952
  wide: !0
9393
- } : identity !== void 0 ? {
9394
- text: "Open the Workflows view",
9395
- description: "Nothing here is assigned to you"
9396
- } : {
9397
- text: "Open the Workflows view"
9398
- };
9953
+ } : unassignedLineHint({
9954
+ identityKnown: identity !== void 0,
9955
+ openTaskCount: openStageTaskCount(entry.evaluation)
9956
+ });
9399
9957
  }
9400
9958
 
9401
9959
  function StripLine({aside: aside, children: children, hint: hint, onOpen: onOpen}) {
@@ -9428,7 +9986,7 @@ function InstanceLine({entry: entry, onOpen: onOpen}) {
9428
9986
  aside: unprimed ? void 0 : /* @__PURE__ */ jsxRuntime.jsx(TaskCountSpinner, {
9429
9987
  entry: entry
9430
9988
  }),
9431
- hint: lineHint(identity, forMeWorkOf([ entry ], identity)),
9989
+ hint: lineHint(entry, identity),
9432
9990
  onOpen: onOpen,
9433
9991
  children: [
9434
9992
  /* @__PURE__ */ jsxRuntime.jsx(ui.Flex, {
@@ -9550,7 +10108,7 @@ const workflowsTool = {
9550
10108
  title: "Workflows",
9551
10109
  icon: Transfer.TransferIcon,
9552
10110
  component: LazyWorkflowsTool,
9553
- router: router.route.create("/", [ router.route.create("/instance/:instanceId"), router.route.create("/definition/:definitionName"), router.route.create("/:workflowsTab") ]),
10111
+ router: router.route.create("/", [ router.route.create("/instance/:instanceId"), router.route.create("/definition/:definitionName"), router.route.create("/documents/:boardDefinition"), router.route.create("/:workflowsTab") ]),
9554
10112
  canHandleIntent: (intent, params) => handlesWorkflowIntent(intent, params),
9555
10113
  getIntentState: (intent, params) => workflowIntentState(intent, params)
9556
10114
  }, LOCKABLE_ACTIONS = /* @__PURE__ */ new Map([ [ "delete", "delete" ], [ "publish", "publish" ], [ "unpublish", "unpublish" ] ]);
@@ -9654,12 +10212,16 @@ exports.CautionNote = CautionNote;
9654
10212
 
9655
10213
  exports.CollapsibleBand = CollapsibleBand;
9656
10214
 
10215
+ exports.CountedLabel = CountedLabel;
10216
+
9657
10217
  exports.DismissablePopover = DismissablePopover;
9658
10218
 
9659
10219
  exports.DocPreviewLink = DocPreviewLink;
9660
10220
 
9661
10221
  exports.DocRefFace = DocRefFace;
9662
10222
 
10223
+ exports.EmptyState = EmptyState;
10224
+
9663
10225
  exports.ForMeEmptyState = ForMeEmptyState;
9664
10226
 
9665
10227
  exports.HintedMenuButton = HintedMenuButton;
@@ -9674,14 +10236,20 @@ exports.LinkChip = LinkChip;
9674
10236
 
9675
10237
  exports.LoadingRow = LoadingRow;
9676
10238
 
10239
+ exports.LogEventOnMount = LogEventOnMount;
10240
+
9677
10241
  exports.MetaRow = MetaRow;
9678
10242
 
10243
+ exports.NOTICE_PADDING = NOTICE_PADDING;
10244
+
9679
10245
  exports.SpinnerSlot = SpinnerSlot;
9680
10246
 
9681
10247
  exports.StageFace = StageFace;
9682
10248
 
9683
10249
  exports.StaleLock = StaleLock;
9684
10250
 
10251
+ exports.TOAST_ID = TOAST_ID;
10252
+
9685
10253
  exports.TabSwitch = TabSwitch;
9686
10254
 
9687
10255
  exports.TrailingHairline = TrailingHairline;
@@ -9692,22 +10260,36 @@ exports.UserAvatar = UserAvatar;
9692
10260
 
9693
10261
  exports.WORKFLOW_API_VERSION = WORKFLOW_API_VERSION;
9694
10262
 
10263
+ exports.WorkflowBoardLayoutChanged = WorkflowBoardLayoutChanged;
10264
+
10265
+ exports.WorkflowBoardWorkflowSelected = WorkflowBoardWorkflowSelected;
10266
+
10267
+ exports.WorkflowDefinitionDetailViewed = WorkflowDefinitionDetailViewed;
10268
+
9695
10269
  exports.WorkflowInstanceDetailViewed = WorkflowInstanceDetailViewed;
9696
10270
 
9697
10271
  exports.WorkflowTaskFiltersApplied = WorkflowTaskFiltersApplied;
9698
10272
 
10273
+ exports.WorkflowTitleSeedDrifted = WorkflowTitleSeedDrifted;
10274
+
9699
10275
  exports.WorkflowToolOpened = WorkflowToolOpened;
9700
10276
 
9701
10277
  exports.activityRowProps = activityRowProps;
9702
10278
 
9703
10279
  exports.assigneeUserIdsOf = assigneeUserIdsOf;
9704
10280
 
10281
+ exports.chipPadding = chipPadding;
10282
+
9705
10283
  exports.committedRowFace = committedRowFace;
9706
10284
 
10285
+ exports.createSubscribers = createSubscribers;
10286
+
9707
10287
  exports.dateControlKind = dateControlKind;
9708
10288
 
9709
10289
  exports.dateControlValue = dateControlValue;
9710
10290
 
10291
+ exports.definitionFingerprint = definitionFingerprint;
10292
+
9711
10293
  exports.definitionSnapshotOf = definitionSnapshotOf;
9712
10294
 
9713
10295
  exports.describeError = describeError;
@@ -9722,18 +10304,32 @@ exports.formatDateTime = formatDateTime;
9722
10304
 
9723
10305
  exports.formatShortAgo = formatShortAgo;
9724
10306
 
10307
+ exports.formatShortDateTime = formatShortDateTime;
10308
+
10309
+ exports.formatTimeAgo = formatTimeAgo;
10310
+
9725
10311
  exports.gdrLocality = gdrLocality;
9726
10312
 
10313
+ exports.hasTimeOfDay = hasTimeOfDay;
10314
+
9727
10315
  exports.instanceBreadcrumb = instanceBreadcrumb;
9728
10316
 
9729
10317
  exports.instanceTitle = instanceTitle;
9730
10318
 
9731
10319
  exports.isActivityAssignedTo = isActivityAssignedTo;
9732
10320
 
10321
+ exports.isDateFieldKind = isDateFieldKind;
10322
+
9733
10323
  exports.isEvaluationStale = isEvaluationStale;
9734
10324
 
10325
+ exports.isLiveEntry = isLiveEntry;
10326
+
9735
10327
  exports.isOpenActivityStatus = isOpenActivityStatus;
9736
10328
 
10329
+ exports.mappingIssueDetail = mappingIssueDetail;
10330
+
10331
+ exports.namesNoDeployedDefinition = namesNoDeployedDefinition;
10332
+
9737
10333
  exports.openActivityGone = openActivityGone;
9738
10334
 
9739
10335
  exports.openableSchemaType = openableSchemaType;
@@ -9766,16 +10362,20 @@ exports.useAvatarSize = useAvatarSize;
9766
10362
 
9767
10363
  exports.useBadgeCapTrim = useBadgeCapTrim;
9768
10364
 
9769
- exports.useClosableToast = useClosableToast;
9770
-
9771
10365
  exports.useContainerToken = useContainerToken;
9772
10366
 
9773
10367
  exports.useDefinition = useDefinition;
9774
10368
 
10369
+ exports.useDelayedFlag = useDelayedFlag;
10370
+
10371
+ exports.useEditField = useEditField;
10372
+
9775
10373
  exports.useLogEventOnMount = useLogEventOnMount;
9776
10374
 
9777
10375
  exports.useProjectMembers = useProjectMembers;
9778
10376
 
10377
+ exports.useRadiusToken = useRadiusToken;
10378
+
9779
10379
  exports.useSaveField = useSaveField;
9780
10380
 
9781
10381
  exports.useSpaceToken = useSpaceToken;
@@ -9788,6 +10388,8 @@ exports.useWorkflowContext = useWorkflowContext;
9788
10388
 
9789
10389
  exports.useWorkflowInstanceEntry = useWorkflowInstanceEntry;
9790
10390
 
10391
+ exports.useWorkflowToast = useWorkflowToast;
10392
+
9791
10393
  exports.workflowDefaultDocumentNode = workflowDefaultDocumentNode;
9792
10394
 
9793
10395
  exports.workflowStudioPlugin = workflowStudioPlugin;