@sanity/workflow-studio-plugin 0.32.0 → 0.34.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.
@@ -8,27 +8,27 @@ import { EllipsisHorizontalIcon } from "@sanity/icons/EllipsisHorizontal";
8
8
 
9
9
  import { LaunchIcon } from "@sanity/icons/Launch";
10
10
 
11
- import { Box, Text, useTheme_v2, Button, Card, useElementRect, Flex, Stack, Dialog, MenuButton, Menu, MenuGroup, MenuItem, MenuDivider, TextInput, Checkbox, Popover, KBD, TabPanel } from "@sanity/ui";
11
+ import { Box, Text, Flex, Stack, Button, useTheme_v2, Card, Dialog, TextInput, Checkbox, KBD, TabPanel } from "@sanity/ui";
12
+
13
+ import { MenuButton, Menu, MenuGroup, MenuItem, MenuDivider } from "@sanity/ui/menu";
12
14
 
13
15
  import { useWorkflowTelemetry } from "@sanity/workflow-react";
14
16
 
15
- import { useMemo, useCallback, useState, useLayoutEffect, useEffect, useRef, memo, Fragment as Fragment$1, Activity } from "react";
17
+ import { useState, useEffect, useMemo, useRef, useLayoutEffect, useCallback, Fragment as Fragment$1, memo, Activity } from "react";
16
18
 
17
19
  import { StateLink, useRouter } from "sanity/router";
18
20
 
19
- import { dueDatesOf, isDueDatePast, isOpenActivityStatus, parseStoredDateValue, findActivity, isHandsOff, assigneesOf, activityLabel, countBy, stageTitle, userIdsOf, RUN_SEARCH_PARAM, toolTabState, namesNoDeployedDefinition, mappingIssueDetail, formatTimeAgo, formatShortDateTime, useSpaceToken, useWorkflowContext, readDeployedDefinitions, describeError, useMinuteClock, NoteBanner, LoadingRow, EmptyState, AgoStamp, AlertGlyph, gdrLocality, openableSchemaType, assignmentHolding, HoverHint, isEvaluationStale, SpinnerSlot, CodeChip, useWorkflowInstanceEntry, useDefinition, deriveActivityDetail, Breadcrumb, instanceBreadcrumb, InvalidDocNotice, openActivityGone, ActivityDetailBody, MetricLockup, shortSpanOf, formatDate, dueMomentSentence, useAvatarSize, OverlineHeading, useUserDisplays, uniqueIds, disambiguatedNames, useProjectMembers, formatShortAgo, MetricPair, AlertChip, DocRefFace, RowAssignees, isLiveEntry, SectionHeading, AbortWorkflowDialog, useLogEventOnMount, WorkflowInstanceDetailViewed, instanceTitle, useContainerToken, InstanceFaultNote, InstanceSnapshotBody, ActivityLog, ActivityDetailDialog, DocPreviewLink, ForMeEmptyState, FOR_ME_SECTION_COPY, ForMeSectionHeading, useCapTrimFor, useTextIconSize, CountedLabel, useRadiusToken, WORKFLOW_API_VERSION, WorkflowTitleSeedDrifted, LogEventOnMount, WorkflowBoardWorkflowSelected, definitionFingerprint, useCurrentUserId, useReleaseTitles, identityOf, UnreadableDocsNote, DismissablePopover, MetaRow, WorkflowDefinitionDetailViewed, toolRoute, landingState, TabSwitch, tabSelectionNavigates, WorkflowToolOpened, workflowState, definitionsRouteOf, TOOL_TABS, useAssignmentIdentity } from "./index.js";
21
+ import { userIdsOf, runRowsOf, RUN_SEARCH_PARAM, toolTabState, countBy, namesNoDeployedDefinition, mappingIssueDetail, formatTimeAgo, useSpaceToken, useWorkflowContext, readDeployedDefinitions, describeError, useMinuteClock, NoteBanner, LoadingRow, EmptyState, useTableStyles, scrollParentOf, SortHeaderButton, TableRowCard, AlertGlyph, gdrLocality, UNREADABLE_DOCUMENT, openableSchemaType, isEvaluationStale, SpinnerSlot, CodeChip, useWorkflowInstanceEntry, useDefinition, deriveActivityDetail, Breadcrumb, instanceBreadcrumb, InvalidDocNotice, openActivityGone, ActivityDetailBody, documentRefsOf, ForMeTable, ForMeEmptyState, FOR_ME_SECTION_COPY, ForMeSectionHeading, forMeSummaryOf, isLiveEntry, SectionHeading, AbortWorkflowDialog, useLogEventOnMount, WorkflowInstanceDetailViewed, instanceTitle, stageTitle, useContainerToken, InstanceFaultNote, InstanceSnapshotBody, ActivityLog, ActivityDetailDialog, DocPreviewLink, blockedRunDetail, overdueRunDetail, stageTasksOf, useAlertChipSize, AttentionMark, DocRefFace, useCapTrimFor, useTextIconSize, StageTaskGroups, CountedLabel, MetricPair, ATTENTION_FACES, overdueAttentionHint, blockedAttentionHint, useRadiusToken, WORKFLOW_API_VERSION, WorkflowTitleSeedDrifted, LogEventOnMount, WorkflowBoardWorkflowSelected, definitionFingerprint, useCurrentUserId, unassignedRunCount, noReleaseRunCount, runAttentionCounts, useReleaseTitles, runCountsByRelease, runCountsByStage, useProjectMembers, runCountsByAssignee, runCountsByRole, useUserDisplays, useAvatarSize, runsScopeOf, rowHasTaskHeldBy, forMeRowId, RunsTable, runCountsByWorkflow, forMeTaskRowsOf, forMeSectionsOf, resolveForMeAddress, identityOf, UnreadableDocsNote, DismissablePopover, MetaRow, WorkflowDefinitionDetailViewed, toolRoute, landingState, TabSwitch, tabSelectionNavigates, WorkflowToolOpened, workflowState, definitionsRouteOf, TOOL_TABS, useAssignmentIdentity } from "./index.js";
20
22
 
21
23
  import { TransferIcon } from "@sanity/icons/Transfer";
22
24
 
23
25
  import { WarningOutlineIcon } from "@sanity/icons/WarningOutline";
24
26
 
25
- import { useSchema, useDocumentPreviewStore, usePerspective, useClient } from "sanity";
26
-
27
- import { assignmentMatch, MemberAvatar, roleMemberCount, roleLabel, memberRoleFor, memberCountLabel, RoleAvatar, roleLabelFor, AssigneeStack } from "@sanity/workflow-components";
27
+ import { assignmentMatch, _formatShortDateTime, AgoStamp, _HoverHint, RoleAvatar, MemberAvatar, roleLabelFor, AssigneeStack } from "@sanity/workflow-components";
28
28
 
29
- import { entryDocRefs, toBareId, findOpenStageEntry, findStageNode, deriveWorkflowAutonomy, deriveExecutorClassification, terminalState, openActivityAssignments, assignmentState, activeAssignmentMembers, startKindOf, isSubjectEntry, isInputSourced, latestDeployedDefinitions, isTerminalStage, isStartableDefinition } from "@sanity/workflow-engine";
29
+ import { useSchema, useDocumentPreviewStore, usePerspective, useClient } from "sanity";
30
30
 
31
- import { useVirtualizer } from "@tanstack/react-virtual";
31
+ import { activeAssignmentMembers, terminalState, startKindOf, isSubjectEntry, isInputSourced, latestDeployedDefinitions, isTerminalStage, findOpenStageEntry, isStartableDefinition } from "@sanity/workflow-engine";
32
32
 
33
33
  import { useWorkflowInstancePreviews } from "@sanity/workflow-studio";
34
34
 
@@ -42,13 +42,7 @@ import { ExpandIcon } from "@sanity/icons/Expand";
42
42
 
43
43
  import { useReducedMotion, motion, useSpring, useMotionValueEvent } from "motion/react";
44
44
 
45
- import { CalendarIcon } from "@sanity/icons/Calendar";
46
-
47
- import { ErrorOutlineIcon } from "@sanity/icons/ErrorOutline";
48
-
49
- import { UserIcon } from "@sanity/icons/User";
50
-
51
- import { UsersIcon } from "@sanity/icons/Users";
45
+ import { useVirtualizer } from "@tanstack/react-virtual";
52
46
 
53
47
  import { createPortal } from "react-dom";
54
48
 
@@ -56,6 +50,10 @@ import { styled } from "styled-components";
56
50
 
57
51
  import { isReferenceSchemaType } from "@sanity/types";
58
52
 
53
+ import { UserIcon } from "@sanity/icons/User";
54
+
55
+ import { Popover } from "@sanity/ui/popover";
56
+
59
57
  import { AddIcon } from "@sanity/icons/Add";
60
58
 
61
59
  import { CheckmarkIcon } from "@sanity/icons/Checkmark";
@@ -76,400 +74,6 @@ function MutedNote({text: text}) {
76
74
  });
77
75
  }
78
76
 
79
- function documentRefsOf(instance) {
80
- const seen = /* @__PURE__ */ new Map;
81
- for (const ref of entryDocRefs(instance.fields)) seen.has(ref.id) || seen.set(ref.id, ref);
82
- return [ ...seen.values() ];
83
- }
84
-
85
- function rootInstanceOf(instance, byId) {
86
- const rootRef = instance.ancestors[0];
87
- return rootRef ? byId.get(toBareId(rootRef.id)) ?? instance : instance;
88
- }
89
-
90
- function openActivitiesOf(instance) {
91
- return (findOpenStageEntry(instance)?.activities ?? []).filter(activity => isOpenActivityStatus(activity.status));
92
- }
93
-
94
- function overdueTasks(instance, now) {
95
- return openActivitiesOf(instance).filter(activity => dueDatesOf(activity.fields ?? []).some(due => isDueDatePast(due, now)));
96
- }
97
-
98
- function earliestDue(activity) {
99
- return earliestOf(dueDatesOf(activity.fields ?? []));
100
- }
101
-
102
- function earliestPastDue(activity, now) {
103
- return earliestPastDueAcross([ activity ], now);
104
- }
105
-
106
- function earliestPastDueAcross(activities, now) {
107
- return earliestOf(activities.flatMap(activity => dueDatesOf(activity.fields ?? []).filter(due => isDueDatePast(due, now))));
108
- }
109
-
110
- function earliestOf(values) {
111
- let earliest;
112
- for (const value of values) {
113
- const time = parseStoredDateValue(value)?.getTime();
114
- time !== void 0 && (earliest === void 0 || time < earliest.time) && (earliest = {
115
- time: time,
116
- value: value
117
- });
118
- }
119
- return earliest?.value;
120
- }
121
-
122
- const AUTONOMY_BY_DEFINITION = /* @__PURE__ */ new WeakMap;
123
-
124
- function cachedAutonomy(definition) {
125
- const hit = AUTONOMY_BY_DEFINITION.get(definition);
126
- if (hit !== void 0) return hit;
127
- const derived = deriveWorkflowAutonomy(definition);
128
- return AUTONOMY_BY_DEFINITION.set(definition, derived), derived;
129
- }
130
-
131
- function isAutomatedActivity(args) {
132
- const stage = args.autonomy?.stages.find(entry => entry.stage === args.stageName);
133
- return isHandsOff({
134
- classification: deriveExecutorClassification(args.activity),
135
- completesWithoutCaller: stage?.activities[args.activity.name]?.completesWithoutCaller
136
- });
137
- }
138
-
139
- function taskOf(args) {
140
- const {entry: entry, now: now, openedAt: openedAt, roleAliases: roleAliases, title: title} = args;
141
- return {
142
- name: entry.name,
143
- title: title,
144
- assignees: assigneesOf(entry.fields ?? []),
145
- roleAliases: roleAliases,
146
- openedAt: openedAt,
147
- due: earliestDue(entry),
148
- overdueSince: earliestPastDue(entry, now),
149
- status: entry.status
150
- };
151
- }
152
-
153
- function humanTask(args) {
154
- const {activity: activity, autonomy: autonomy, entry: entry, now: now, openedAt: openedAt, roleAliases: roleAliases, stageName: stageName} = args;
155
- return entry === void 0 ? [] : isAutomatedActivity({
156
- activity: activity,
157
- autonomy: autonomy,
158
- stageName: stageName
159
- }) ? [] : [ taskOf({
160
- entry: entry,
161
- now: now,
162
- openedAt: openedAt,
163
- roleAliases: roleAliases,
164
- title: activityLabel(activity)
165
- }) ];
166
- }
167
-
168
- function undeclaredTasks(args) {
169
- const {definition: definition, now: now, open: open, openedAt: openedAt, roleAliases: roleAliases, seen: seen, stageName: stageName} = args;
170
- return open.filter(entry => !seen.has(entry.name)).map(entry => taskOf({
171
- entry: entry,
172
- now: now,
173
- openedAt: openedAt,
174
- roleAliases: roleAliases,
175
- title: findActivity({
176
- activityName: entry.name,
177
- definition: definition,
178
- stageName: stageName
179
- }).title
180
- }));
181
- }
182
-
183
- function definitionForPinned(definition, pinnedVersion) {
184
- if (!(definition === void 0 || definition.version !== pinnedVersion)) return definition;
185
- }
186
-
187
- function stageTasksOf(args) {
188
- const {definition: definition, instance: instance, now: now} = args, stageEntry = findOpenStageEntry(instance);
189
- if (stageEntry === void 0) return [];
190
- const listed = listedStageActivities(stageEntry);
191
- if (listed.length === 0) return [];
192
- const openedAt = stageEntry.enteredAt, pinnedDefinition = definitionForPinned(definition, instance.pinnedVersion), autonomy = pinnedDefinition === void 0 ? void 0 : cachedAutonomy(pinnedDefinition), roleAliases = pinnedDefinition?.roleAliases, stageName = instance.currentStage, openByName = new Map(listed.map(entry => [ entry.name, entry ])), declared = findStageNode({
193
- definition: definition,
194
- stageName: stageName
195
- })?.activities ?? [];
196
- return [ ...declared.flatMap(activity => humanTask({
197
- activity: activity,
198
- autonomy: autonomy,
199
- entry: openByName.get(activity.name),
200
- now: now,
201
- openedAt: openedAt,
202
- roleAliases: roleAliases,
203
- stageName: stageName
204
- })), ...undeclaredTasks({
205
- definition: definition,
206
- now: now,
207
- open: listed,
208
- openedAt: openedAt,
209
- roleAliases: roleAliases,
210
- seen: new Set(declared.map(activity => activity.name)),
211
- stageName: stageName
212
- }) ];
213
- }
214
-
215
- function listedStageActivities(stage) {
216
- return stage.activities.filter(entry => isOpenActivityStatus(entry.status) || entry.status === "failed");
217
- }
218
-
219
- function groupWidthOf(task, metrics) {
220
- const mark = taskAssignmentMarkOf(task.assignees), faces = mark.kind === "held" ? mark.members.length : 1;
221
- return metrics.face + (faces - 1) * (metrics.face - metrics.overlap);
222
- }
223
-
224
- function rowWidthOf(tasks, metrics) {
225
- return tasks.reduce((total, task) => total + groupWidthOf(task, metrics), 0) + Math.max(0, tasks.length - 1) * metrics.gap;
226
- }
227
-
228
- function countWithin(args) {
229
- const {budget: budget, metrics: metrics, tasks: tasks} = args;
230
- let used = 0, count = 0;
231
- for (const task of tasks) {
232
- const next = used + (count === 0 ? 0 : metrics.gap) + groupWidthOf(task, metrics);
233
- if (next > budget) break;
234
- used = next, count += 1;
235
- }
236
- return Math.max(1, count);
237
- }
238
-
239
- function visibleStageTasks(args) {
240
- const {metrics: metrics, room: room, tasks: tasks} = args;
241
- if (rowWidthOf(tasks, metrics) <= room) return {
242
- overflow: 0,
243
- visible: tasks
244
- };
245
- const shown = countWithin({
246
- budget: room - metrics.gap - metrics.counter,
247
- metrics: metrics,
248
- tasks: tasks
249
- });
250
- return {
251
- overflow: tasks.length - shown,
252
- visible: tasks.slice(0, shown)
253
- };
254
- }
255
-
256
- function taskAssignmentMarkOf(assignees) {
257
- const members = assignees.filter(assignee => assignee.type === "user");
258
- if (members.length > 0) return {
259
- kind: "held",
260
- members: members
261
- };
262
- const roles = assignees.flatMap(assignee => assignee.type === "role" ? [ assignee.role ] : []);
263
- return roles.length > 0 ? {
264
- kind: "routed",
265
- roles: roles
266
- } : {
267
- kind: "unassigned"
268
- };
269
- }
270
-
271
- function runsScopeOf(row) {
272
- return row.endedAt === void 0 ? "open" : "closed";
273
- }
274
-
275
- function rowHasTaskHeldBy(row, who) {
276
- return row.tasks.some(task => assignmentMatch(task.assignees, who) !== void 0);
277
- }
278
-
279
- function runCountsByWorkflow(rows) {
280
- return countBy(rows, row => [ row.workflowName ]);
281
- }
282
-
283
- function runCountsByAssignee(rows) {
284
- return countBy(rows, row => new Set(userIdsOf(row.assignees)));
285
- }
286
-
287
- function runCountsByRole(rows) {
288
- return countBy(rows, row => new Set(row.assignees.flatMap(assignee => assignee.type === "role" ? [ assignee.role ] : [])));
289
- }
290
-
291
- function runAttentionCounts(rows) {
292
- let blocked = 0, overdue = 0;
293
- for (const row of rows) row.attention === "blocked" && (blocked += 1), row.attention === "overdue" && (overdue += 1);
294
- return {
295
- blocked: blocked,
296
- overdue: overdue
297
- };
298
- }
299
-
300
- function unassignedRunCount(rows) {
301
- return rows.filter(row => row.assignmentStateCounts.unrouted > 0).length;
302
- }
303
-
304
- function runCountsByStage(rows) {
305
- return countBy(rows, row => [ row.stage ]);
306
- }
307
-
308
- function runCountsByRelease(rows) {
309
- return countBy(rows, row => new Set(row.releases));
310
- }
311
-
312
- function noReleaseRunCount(rows) {
313
- return rows.filter(row => row.releases.length === 0).length;
314
- }
315
-
316
- function releasesOfPerspective(perspective) {
317
- return Array.isArray(perspective) ? perspective.filter(name => name !== "drafts") : [];
318
- }
319
-
320
- function runRowsOf(args) {
321
- const byId = new Map(args.previews.map(preview => [ preview._id, preview ]));
322
- return args.previews.map(preview => runRowOf({
323
- byId: byId,
324
- definitions: args.definitions,
325
- now: args.now,
326
- preview: preview
327
- }));
328
- }
329
-
330
- function runRowOf(args) {
331
- const {byId: byId, definitions: definitions, now: now, preview: preview} = args, definition = definitions.get(preview.definition), settled = terminalState(preview) !== "in-flight", held = settled ? NO_ASSIGNEES : openAssignees(preview), attentionDetail = settled ? void 0 : blockedRunDetail({
332
- definition: definition,
333
- preview: preview
334
- }) ?? overdueRunDetail({
335
- definition: definition,
336
- now: now,
337
- preview: preview
338
- });
339
- return {
340
- id: preview._id,
341
- document: documentRefsOf(rootInstanceOf(preview, byId))[0],
342
- workflowName: preview.definition,
343
- workflowTitle: definition?.title ?? preview.definition,
344
- stage: preview.currentStage,
345
- stageTitle: stageTitle(definition, preview.currentStage),
346
- releases: releasesOfPerspective(preview.perspective),
347
- startedAt: preview.startedAt,
348
- endedAt: settled ? preview.completedAt ?? preview.abortedAt : void 0,
349
- outcome: outcomeOf(preview, definition),
350
- attention: attentionKindOf(attentionDetail),
351
- attentionDetail: attentionDetail,
352
- assignees: held.assignees,
353
- assignments: held.assignments,
354
- assignmentStateCounts: held.counts,
355
- tasks: settled ? [] : stageTasksOf({
356
- definition: definition,
357
- instance: preview,
358
- now: now
359
- })
360
- };
361
- }
362
-
363
- function attentionKindOf(detail) {
364
- if (detail !== void 0) return detail.kind === "overdue" ? "overdue" : "blocked";
365
- }
366
-
367
- function outcomeOf(preview, definition) {
368
- const state = terminalState(preview);
369
- if (state !== "in-flight") return state === "aborted" ? "Aborted" : stageTitle(definition, preview.currentStage);
370
- }
371
-
372
- function blockedRunDetail(args) {
373
- const {definition: definition, preview: preview} = args, {stage: stage, titleOf: titleOf} = activityTitleResolver(preview, definition), failed = (stage?.activities ?? []).filter(activity => activity.status === "failed");
374
- if (failed.length > 1) return {
375
- count: failed.length,
376
- kind: "blocked-many"
377
- };
378
- const only = failed[0];
379
- if (only !== void 0) return {
380
- kind: "blocked",
381
- task: titleOf(only.name)
382
- };
383
- const stuck = stuckEffectOf({
384
- definition: definition,
385
- preview: preview,
386
- stage: stage
387
- });
388
- return stuck === void 0 ? void 0 : {
389
- effect: stuck.effect.title ?? stuck.effect.name,
390
- failed: stuck.failed,
391
- kind: "blocked-effect"
392
- };
393
- }
394
-
395
- function stuckEffectOf(args) {
396
- const reported = failedDeclaredEffect(args);
397
- if (reported !== void 0) return {
398
- effect: reported,
399
- failed: !0
400
- };
401
- const claimed = args.preview.claimedEffects[0];
402
- return claimed === void 0 ? void 0 : {
403
- effect: claimed,
404
- failed: !1
405
- };
406
- }
407
-
408
- function failedDeclaredEffect(args) {
409
- const {definition: definition, preview: preview, stage: stage} = args;
410
- if (definition === void 0 || definition.version !== preview.pinnedVersion || stage === void 0) return;
411
- const stageNode = findStageNode({
412
- definition: definition,
413
- stageName: stage.name
414
- }), unresolved = new Set(stage.activities.filter(activity => activity.status !== "done" && activity.status !== "skipped").map(activity => activity.name)), declared = new Set((stageNode?.activities ?? []).filter(activity => unresolved.has(activity.name)).flatMap(activity => (activity.actions ?? []).flatMap(action => (action.effects ?? []).map(e => e.name))));
415
- return [ ...preview.failedEffects ].reverse().find(effect => declared.has(effect.name));
416
- }
417
-
418
- function overdueRunDetail(args) {
419
- const {definition: definition, now: now, preview: preview} = args, late = overdueTasks(preview, now);
420
- if (late.length === 0) return;
421
- const {titleOf: titleOf} = activityTitleResolver(preview, definition), only = late.length === 1 ? late[0] : void 0;
422
- return {
423
- count: late.length,
424
- due: earliestPastDueAcross(late, now),
425
- kind: "overdue",
426
- task: only === void 0 ? void 0 : titleOf(only.name)
427
- };
428
- }
429
-
430
- function activityTitleResolver(preview, definition) {
431
- const stage = findOpenStageEntry(preview);
432
- return {
433
- stage: stage,
434
- titleOf: activityName => findActivity({
435
- activityName: activityName,
436
- definition: definition,
437
- stageName: stage?.name ?? ""
438
- }).title
439
- };
440
- }
441
-
442
- const NO_ASSIGNEES = {
443
- assignees: [],
444
- assignments: [],
445
- counts: {
446
- unrouted: 0,
447
- routed: 0,
448
- held: 0
449
- }
450
- };
451
-
452
- function openAssignees(instance) {
453
- const users = /* @__PURE__ */ new Map, roles = /* @__PURE__ */ new Map, assignments = openActivityAssignments(instance), counts = {
454
- unrouted: 0,
455
- routed: 0,
456
- held: 0
457
- };
458
- for (const members of assignments) counts[assignmentState(members)] += 1, recordAssignees(activeAssignmentMembers(members), {
459
- users: users,
460
- roles: roles
461
- });
462
- return {
463
- assignees: [ ...users.values(), ...roles.values() ],
464
- assignments: assignments,
465
- counts: counts
466
- };
467
- }
468
-
469
- function recordAssignees(assignees, maps) {
470
- for (const assignee of assignees) (assignee.type === "user" ? maps.users : maps.roles).set(assignee.type === "user" ? assignee.id : assignee.role, assignee);
471
- }
472
-
473
77
  function clausePolarity(operator) {
474
78
  return operator === "isNot" || operator === "isNoneOf" ? "isNot" : "is";
475
79
  }
@@ -843,7 +447,7 @@ function deployedPhrase(definition) {
843
447
  const deployedAt = deployedAtOf(definition);
844
448
  if (deployedAt === void 0) return `v${definition.version}`;
845
449
  const ago = formatTimeAgo(deployedAt);
846
- return ago === "" ? formatShortDateTime(deployedAt) : `${formatShortDateTime(deployedAt)} (${ago})`;
450
+ return ago === "" ? _formatShortDateTime(deployedAt) : `${_formatShortDateTime(deployedAt)} (${ago})`;
847
451
  }
848
452
 
849
453
  const INSTANCES_READ_FAILED = "Couldn’t load workflow data. Try again later.", TOOL_PANEL_PADDING = 3, TOOL_HEADING_PADDING = 2, PANEL_STEP = 3;
@@ -861,207 +465,6 @@ function TabStatusRow({children: children}) {
861
465
  });
862
466
  }
863
467
 
864
- function useTableStyles() {
865
- const {color: color} = useTheme_v2(), headTop = useSpaceToken(3), cellX = useSpaceToken(2);
866
- return useMemo(() => ({
867
- cell: {
868
- borderBottom: `1px solid ${color.border}`,
869
- boxSizing: "border-box",
870
- padding: `0 ${cellX}px`,
871
- verticalAlign: "middle",
872
- whiteSpace: "nowrap"
873
- },
874
- head: {
875
- background: color.bg,
876
- borderBottom: `1px solid ${color.border}`,
877
- boxSizing: "border-box",
878
- padding: `${headTop}px 0 6px`,
879
- position: "sticky",
880
- textAlign: "left",
881
- top: 0,
882
- zIndex: 1
883
- }
884
- }), [ cellX, color, headTop ]);
885
- }
886
-
887
- function scrollParentOf(el) {
888
- for (let node = el.parentElement; node !== null; node = node.parentElement) {
889
- const overflowY = getComputedStyle(node).overflowY;
890
- if (overflowY === "auto" || overflowY === "scroll") return node;
891
- }
892
- }
893
-
894
- function useRowWindow(args) {
895
- const {element: element, keyAt: keyAt, rowCount: rowCount} = args, [scroller, setScroller] = useState(null);
896
- useLayoutEffect(() => {
897
- setScroller(element === null ? null : scrollParentOf(element) ?? null);
898
- }, [ element ]);
899
- const [margin, setMargin] = useState(0);
900
- useLayoutEffect(() => {
901
- element === null || scroller === null || setMargin(element.getBoundingClientRect().top - scroller.getBoundingClientRect().top + scroller.scrollTop);
902
- }, [ element, rowCount, scroller ]);
903
- const virtualizer = useVirtualizer({
904
- count: rowCount,
905
- estimateSize: () => 44,
906
- getItemKey: keyAt,
907
- getScrollElement: () => scroller,
908
- overscan: 10,
909
- scrollMargin: margin
910
- }), items = virtualizer.getVirtualItems(), first = items[0], last = items[items.length - 1];
911
- return {
912
- items: items,
913
- measureRow: virtualizer.measureElement,
914
- padBottom: last === void 0 ? 0 : virtualizer.getTotalSize() - (last.end - margin),
915
- padTop: first === void 0 ? 0 : first.start - margin
916
- };
917
- }
918
-
919
- function SpacerRow({height: height}) {
920
- return height <= 0 ? null : /* @__PURE__ */ jsx("tr", {
921
- "aria-hidden": !0,
922
- style: {
923
- height: height
924
- },
925
- children: /* @__PURE__ */ jsx("td", {
926
- colSpan: 99,
927
- style: {
928
- border: 0,
929
- padding: 0
930
- }
931
- })
932
- });
933
- }
934
-
935
- const TABLE_TIME_WIDTH = 112, TABLE_WORKFLOW_WIDTH = {
936
- cap: 260,
937
- fraction: .18
938
- }, TABLE_STAGE_WIDTH = {
939
- cap: 260,
940
- fraction: .16
941
- };
942
-
943
- function SortableHeaderCells({children: children, columns: columns, onSort: onSort, sort: sort, styles: styles, tableWidth: tableWidth, widthOf: widthOf}) {
944
- /* @__PURE__ */
945
- return jsxs(Fragment, {
946
- children: [ columns.map(column => {
947
- const width = widthOf(column, tableWidth);
948
- /* @__PURE__ */
949
- return jsx("th", {
950
- style: {
951
- ...styles.head,
952
- ...width === void 0 ? {} : {
953
- width: width
954
- }
955
- },
956
- children: /* @__PURE__ */ jsx(SortHeaderButton, {
957
- active: sort.key === column.key,
958
- dir: sort.dir,
959
- label: column.label,
960
- onSort: () => onSort(column.key)
961
- })
962
- }, column.key);
963
- }), children ]
964
- });
965
- }
966
-
967
- function VirtualTable({keyAt: keyAt, renderHeader: renderHeader, renderRow: renderRow, rowCount: rowCount}) {
968
- const styles = useTableStyles(), [element, setElement] = useState(null), tableWidth = useTableWidth(element), window2 = useRowWindow({
969
- element: element,
970
- keyAt: keyAt,
971
- rowCount: rowCount
972
- });
973
- /* @__PURE__ */
974
- return jsx("div", {
975
- ref: setElement,
976
- style: {
977
- overflowX: "clip",
978
- ...tableWidth === void 0 ? {
979
- visibility: "hidden"
980
- } : {}
981
- },
982
- children: /* @__PURE__ */ jsxs("table", {
983
- style: {
984
- borderCollapse: "separate",
985
- borderSpacing: 0,
986
- tableLayout: "fixed",
987
- width: "100%"
988
- },
989
- children: [
990
- /* @__PURE__ */ jsx("thead", {
991
- children: /* @__PURE__ */ jsx("tr", {
992
- children: renderHeader({
993
- styles: styles,
994
- tableWidth: tableWidth
995
- })
996
- })
997
- }),
998
- /* @__PURE__ */ jsxs("tbody", {
999
- children: [
1000
- /* @__PURE__ */ jsx(SpacerRow, {
1001
- height: window2.padTop
1002
- }), window2.items.map(item => renderRow({
1003
- index: item.index,
1004
- key: item.key,
1005
- measureRow: window2.measureRow,
1006
- tableWidth: tableWidth
1007
- })),
1008
- /* @__PURE__ */ jsx(SpacerRow, {
1009
- height: window2.padBottom
1010
- }) ]
1011
- }) ]
1012
- })
1013
- });
1014
- }
1015
-
1016
- function useTableWidth(element) {
1017
- const observed = useElementRect(element), [mounted, setMounted] = useState(void 0);
1018
- return useLayoutEffect(() => {
1019
- setMounted(element === null ? void 0 : element.getBoundingClientRect().width);
1020
- }, [ element ]), observed?.width ?? mounted;
1021
- }
1022
-
1023
- function SortHeaderButton({active: active, dir: dir, label: label, onSort: onSort}) {
1024
- /* @__PURE__ */
1025
- return jsx(Button, {
1026
- fontSize: 1,
1027
- mode: "bleed",
1028
- onClick: onSort,
1029
- padding: 2,
1030
- text: `${label}${active ? dir === "asc" ? " ↑" : " ↓" : ""}`
1031
- });
1032
- }
1033
-
1034
- function TableRowCard({children: children, dataIndex: dataIndex, onClick: onClick, onKeyDown: onKeyDown, rowRef: rowRef, selected: selected, selectedRef: selectedRef}) {
1035
- const setRow = useCallback(element => {
1036
- rowRef?.(element), selected === !0 && selectedRef?.(element);
1037
- }, [ rowRef, selected, selectedRef ]);
1038
- /* @__PURE__ */
1039
- return jsx(Card, {
1040
- as: "tr",
1041
- "data-as": "a",
1042
- onClick: event => {
1043
- event.currentTarget.focus(), onClick();
1044
- },
1045
- onKeyDown: selected === !0 ? onKeyDown : void 0,
1046
- style: {
1047
- cursor: "pointer",
1048
- display: "table-row"
1049
- },
1050
- ...dataIndex === void 0 ? {} : {
1051
- "data-index": dataIndex
1052
- },
1053
- ...rowRef === void 0 && selectedRef === void 0 ? {} : {
1054
- ref: setRow
1055
- },
1056
- ...selected === void 0 ? {} : {
1057
- "aria-selected": selected,
1058
- pressed: selected,
1059
- tabIndex: selected ? 0 : -1
1060
- },
1061
- children: children
1062
- });
1063
- }
1064
-
1065
468
  const logged = /* @__PURE__ */ new WeakSet;
1066
469
 
1067
470
  function logReadFailure(what, error) {
@@ -1259,7 +662,7 @@ function UndeployedWorkflows({notices: notices}) {
1259
662
  });
1260
663
  }
1261
664
 
1262
- const COLUMNS$1 = [ {
665
+ const COLUMNS = [ {
1263
666
  key: "workflow",
1264
667
  label: "Workflow"
1265
668
  }, {
@@ -1299,7 +702,7 @@ function DefinitionsTable({countKnown: countKnown, now: now, onOpenWorkflow: onO
1299
702
  children: [
1300
703
  /* @__PURE__ */ jsx("thead", {
1301
704
  children: /* @__PURE__ */ jsxs("tr", {
1302
- children: [ COLUMNS$1.map(column => /* @__PURE__ */ jsx("th", {
705
+ children: [ COLUMNS.map(column => /* @__PURE__ */ jsx("th", {
1303
706
  style: {
1304
707
  ...head,
1305
708
  ...column.width === void 0 ? {} : {
@@ -1357,7 +760,7 @@ function DefinitionRow({countKnown: countKnown, now: now, onOpen: onOpen, row: r
1357
760
  paddingRight: titleGap
1358
761
  },
1359
762
  children: /* @__PURE__ */ jsxs(Stack, {
1360
- space: 3,
763
+ gap: 3,
1361
764
  children: [
1362
765
  /* @__PURE__ */ jsx(Text, {
1363
766
  size: 1,
@@ -1476,7 +879,7 @@ function useDocPreviewTitles(documents) {
1476
879
  }, evaluate = () => {
1477
880
  for (const {doc: doc, bareId: bareId} of localDocs) {
1478
881
  const probe = actualTypes.read(bareId);
1479
- if (probe === null) {
882
+ if (probe === null || probe === UNREADABLE_DOCUMENT) {
1480
883
  dropPreview(doc.id), resolved.add(doc.id);
1481
884
  continue;
1482
885
  }
@@ -1554,86 +957,18 @@ function outsiderIds(args) {
1554
957
  return [ ...new Set(candidates.filter(id => !memberIds.has(id))) ];
1555
958
  }
1556
959
 
1557
- function forMeRowId(instanceId, activityName) {
1558
- return `${instanceId}\t${activityName}`;
960
+ function documentTitleKey(row, titles) {
961
+ return row.document === void 0 ? "" : titles.get(row.document.id) ?? "";
1559
962
  }
1560
963
 
1561
- function forMeTaskRowsOf(args) {
1562
- const {now: now, rows: rows, who: who} = args;
1563
- return rows.flatMap(row => row.tasks.flatMap(task => {
1564
- const assignment = assignmentHolding(task.assignees, who);
1565
- if (assignment === "other") return [];
1566
- const attentionDetail = taskAttentionDetail({
1567
- now: now,
1568
- row: row,
1569
- task: task
1570
- });
1571
- return [ {
1572
- id: forMeRowId(row.id, task.name),
1573
- instanceId: row.id,
1574
- activityName: task.name,
1575
- title: task.title,
1576
- document: row.document,
1577
- workflowTitle: row.workflowTitle,
1578
- releases: row.releases,
1579
- openedAt: task.openedAt,
1580
- due: task.due,
1581
- attention: attentionKindOf(attentionDetail),
1582
- attentionDetail: attentionDetail,
1583
- assignees: task.assignees,
1584
- assignment: assignment
1585
- } ];
1586
- }));
964
+ function namedRowComparator(key, titles) {
965
+ return key === "document" ? (a, b) => documentTitleKey(a, titles).localeCompare(documentTitleKey(b, titles)) : (a, b) => a.workflowTitle.localeCompare(b.workflowTitle);
1587
966
  }
1588
967
 
1589
- function forMeSummaryOf(rows) {
1590
- const documents = new Set(rows.flatMap(row => row.document === void 0 ? [] : [ row.document.id ])), releases = new Set(rows.flatMap(row => row.releases));
968
+ function defaultForMeSort() {
1591
969
  return {
1592
- lead: rows.length === 0 ? "No tasks" : pluralize("task", rows.length, !0),
1593
- subjects: `on ${pluralize("document", documents.size, !0)}, and ${pluralize("release", releases.size, !0)}`
1594
- };
1595
- }
1596
-
1597
- function forMeSectionsOf(rows) {
1598
- return {
1599
- assignedToUser: rows.filter(row => row.assignment === "you"),
1600
- assignedToRoles: rows.filter(row => row.assignment === "role")
1601
- };
1602
- }
1603
-
1604
- function resolveForMeAddress(args) {
1605
- const {rows: rows, run: run, task: task} = args;
1606
- if (run === void 0) return;
1607
- if (task !== void 0) return rows.some(row => row.instanceId === run && row.activityName === task) ? {
1608
- run: run,
1609
- task: task
1610
- } : void 0;
1611
- const first = rows.find(row => row.instanceId === run);
1612
- return first === void 0 ? void 0 : {
1613
- run: first.instanceId,
1614
- task: first.activityName
1615
- };
1616
- }
1617
-
1618
- function taskAttentionDetail(args) {
1619
- const {now: now, row: row, task: task} = args;
1620
- if (task.status === "failed") return {
1621
- kind: "blocked",
1622
- task: task.title
1623
- };
1624
- if (row.attention === "blocked") return row.attentionDetail;
1625
- if (task.due !== void 0 && isDueDatePast(task.due, now)) return {
1626
- count: 1,
1627
- due: task.due,
1628
- kind: "overdue",
1629
- task: task.title
1630
- };
1631
- }
1632
-
1633
- function defaultForMeSort() {
1634
- return {
1635
- dir: "asc",
1636
- key: "due"
970
+ dir: "asc",
971
+ key: "due"
1637
972
  };
1638
973
  }
1639
974
 
@@ -1664,17 +999,11 @@ function forMeCompare(args) {
1664
999
  return (a, b) => dir * named(a, b);
1665
1000
  }
1666
1001
 
1667
- function documentTitleKey$1(row, titles) {
1668
- return row.document === void 0 ? "" : titles.get(row.document.id) ?? "";
1669
- }
1670
-
1671
1002
  function namedCompare(key, titles) {
1672
1003
  switch (key) {
1673
1004
  case "document":
1674
- return (a, b) => documentTitleKey$1(a, titles).localeCompare(documentTitleKey$1(b, titles));
1675
-
1676
1005
  case "workflow":
1677
- return (a, b) => a.workflowTitle.localeCompare(b.workflowTitle);
1006
+ return namedRowComparator(key, titles);
1678
1007
 
1679
1008
  default:
1680
1009
  return (a, b) => a.title.localeCompare(b.title);
@@ -1922,7 +1251,7 @@ function PanelResizeHandle({enabled: enabled, onClose: onClose, onCommit: onComm
1922
1251
  top: 0
1923
1252
  }
1924
1253
  }),
1925
- /* @__PURE__ */ jsx(HoverHint, {
1254
+ /* @__PURE__ */ jsx(_HoverHint, {
1926
1255
  anchor: anchor,
1927
1256
  disabled: !enabled || dragging,
1928
1257
  open: pointed,
@@ -2432,567 +1761,96 @@ function ForMeDetailPanel({activityName: activityName, instanceId: instanceId, o
2432
1761
  });
2433
1762
  }
2434
1763
 
2435
- const LATE_FACE = {
2436
- Icon: CalendarIcon,
2437
- tone: "caution"
2438
- };
2439
-
2440
- function LateSpan({now: now, since: since}) {
2441
- /* @__PURE__ */
2442
- return jsx(MetricLockup, {
2443
- Icon: LATE_FACE.Icon,
2444
- tone: LATE_FACE.tone,
2445
- value: shortSpanOf(parseStoredDateValue(since), now)
2446
- });
2447
- }
2448
-
2449
- function DueStamp({due: due, now: now}) {
2450
- /* @__PURE__ */
2451
- return jsx(Flex, {
2452
- align: "center",
2453
- children: /* @__PURE__ */ jsx(HoverHint, {
2454
- text: dueMomentSentence(due, now),
2455
- children: isDueDatePast(due, now) ? /* @__PURE__ */ jsx(LateSpan, {
2456
- now: now,
2457
- since: due
2458
- }) :
2459
- /* @__PURE__ */ jsx(Text, {
2460
- muted: !0,
2461
- size: 1,
2462
- style: {
2463
- whiteSpace: "nowrap"
2464
- },
2465
- children: formatDate(due)
2466
- })
2467
- })
2468
- });
2469
- }
2470
-
2471
- function resolveColumnWidth(width, tableWidth) {
2472
- return typeof width != "object" ? width : tableWidth === void 0 ? `${width.fraction * 100}%` : Math.min(width.cap, Math.round(tableWidth * width.fraction));
2473
- }
2474
-
2475
- function fillColumnWidth(args) {
2476
- const {columns: columns, tableWidth: tableWidth, trailingWidth: trailingWidth} = args;
2477
- if (tableWidth === void 0) return;
2478
- const fixed = columns.reduce((sum, column) => {
2479
- const width = resolveColumnWidth(column.width, tableWidth);
2480
- return typeof width == "number" ? sum + width : sum;
2481
- }, trailingWidth);
2482
- return Math.max(160, Math.floor(tableWidth - fixed));
2483
- }
2484
-
2485
- const HOLDER_OVERLAP = 7, HOLDER_RING = 1.5, GROUP_GAP_TOKEN = 3;
2486
-
2487
- function useDisplayById(ids) {
2488
- const displays = useUserDisplays(uniqueIds(ids)), labels = disambiguatedNames(displays);
2489
- return new Map(displays.map((display, index) => [ display.id, {
2490
- ...display,
2491
- label: labels[index] ?? display.name
2492
- } ]));
2493
- }
2494
-
2495
- function holderKey(assignee, index) {
2496
- return `${assignee.id}-${index}`;
2497
- }
2498
-
2499
- function stageTasksFace(args) {
2500
- return {
2501
- content: /* @__PURE__ */ jsx(StageTasksCard, {
2502
- now: args.now,
2503
- tasks: args.tasks
2504
- }),
2505
- flush: !0,
2506
- wide: !0
2507
- };
2508
- }
2509
-
2510
- function StageTaskGroups({now: now, room: room, tasks: tasks}) {
2511
- const gap = useSpaceToken(GROUP_GAP_TOKEN), face = useAvatarSize(), {overflow: overflow, visible: visible} = visibleStageTasks({
2512
- metrics: {
2513
- counter: face,
2514
- face: face,
2515
- gap: gap,
2516
- overlap: HOLDER_OVERLAP
2517
- },
2518
- room: room ?? face * 3 + gap * 2,
2519
- tasks: tasks
2520
- });
2521
- return tasks.length === 0 ? null : /* @__PURE__ */ jsx(HoverHint, {
2522
- ...stageTasksFace({
2523
- now: now,
2524
- tasks: tasks
2525
- }),
2526
- children: /* @__PURE__ */ jsxs(Flex, {
2527
- align: "center",
2528
- "aria-label": "Tasks",
2529
- style: {
2530
- columnGap: gap
2531
- },
2532
- children: [ visible.map(task => /* @__PURE__ */ jsx(TaskGroupFace, {
2533
- assignees: task.assignees
2534
- }, task.name)), overflow === 0 ? null : /* @__PURE__ */ jsxs(Text, {
2535
- muted: !0,
2536
- size: 1,
2537
- children: [ "+", overflow ]
2538
- }) ]
2539
- })
2540
- });
2541
- }
2542
-
2543
- function TaskGroupFace({assignees: assignees}) {
2544
- const mark = taskAssignmentMarkOf(assignees);
2545
- return mark.kind === "unassigned" ? /* @__PURE__ */ jsx(PersonToken, {}) : mark.kind === "routed" ? /* @__PURE__ */ jsx(PersonToken, {
2546
- routed: !0
2547
- }) : /* @__PURE__ */ jsx(OverlappedHolders, {
2548
- assignees: mark.members
2549
- });
2550
- }
2551
-
2552
- function HolderFace({assignee: assignee, displayById: displayById}) {
2553
- const display = displayById.get(assignee.id);
2554
- /* @__PURE__ */
2555
- return jsx(MemberAvatar, {
2556
- imageUrl: display?.imageUrl,
2557
- name: display?.name ?? assignee.id,
2558
- size: 0
2559
- });
2560
- }
2561
-
2562
- function OverlappedHolders({assignees: assignees}) {
2563
- const {color: color} = useTheme_v2(), displayById = useDisplayById(userIdsOf(assignees)), ring = `0 0 0 ${HOLDER_RING}px ${color.bg}`;
2564
- /* @__PURE__ */
2565
- return jsx(Flex, {
2566
- align: "center",
2567
- style: {
2568
- flexShrink: 0,
2569
- isolation: "isolate"
2570
- },
2571
- children: assignees.map((assignee, index) => /* @__PURE__ */ jsx(Box, {
2572
- style: {
2573
- borderRadius: "50%",
2574
- boxShadow: ring,
2575
- flexShrink: 0,
2576
- marginLeft: index === 0 ? 0 : -HOLDER_OVERLAP,
2577
- position: "relative",
2578
- zIndex: index
2579
- },
2580
- children: /* @__PURE__ */ jsx(HolderFace, {
2581
- assignee: assignee,
2582
- displayById: displayById
2583
- })
2584
- }, holderKey(assignee, index)))
2585
- });
2586
- }
2587
-
2588
- function PersonToken({routed: routed = !1}) {
2589
- const size = useAvatarSize(), {color: color} = useTheme_v2();
2590
- /* @__PURE__ */
2591
- return jsxs(Box, {
2592
- "aria-label": routed ? "Routed, no person assigned" : "Unassigned",
2593
- role: "img",
2594
- style: {
2595
- flexShrink: 0,
2596
- height: size,
2597
- position: "relative",
2598
- width: size
2599
- },
1764
+ function ForMeTables({loading: loading, now: now, onNavigateKey: onNavigateKey, onSelect: onSelect, onSort: onSort, selectedId: selectedId, selectedRef: selectedRef, sort: sort, sections: sections}) {
1765
+ return loading ? /* @__PURE__ */ jsxs(Fragment, {
2600
1766
  children: [
2601
- /* @__PURE__ */ jsx(Flex, {
2602
- align: "center",
2603
- justify: "center",
2604
- style: {
2605
- border: `1px dashed ${color.border}`,
2606
- borderRadius: "50%",
2607
- boxSizing: "border-box",
2608
- height: size,
2609
- width: size
2610
- },
2611
- children: /* @__PURE__ */ jsx(Text, {
2612
- size: 0,
2613
- children: /* @__PURE__ */ jsx(UserIcon, {
2614
- style: {
2615
- color: color.input.default.enabled.placeholder
2616
- }
2617
- })
2618
- })
2619
- }), routed ? /* @__PURE__ */ jsx(Card, {
2620
- radius: 1,
2621
- tone: "primary",
2622
- style: {
2623
- bottom: -3,
2624
- position: "absolute",
2625
- right: -3
2626
- },
2627
- children: /* @__PURE__ */ jsx(Flex, {
2628
- align: "center",
2629
- justify: "center",
2630
- style: {
2631
- height: 13,
2632
- width: 13
2633
- },
2634
- children: /* @__PURE__ */ jsx(Text, {
2635
- size: 0,
2636
- children: /* @__PURE__ */ jsx(UsersIcon, {})
2637
- })
1767
+ /* @__PURE__ */ jsx(LoadingRow, {
1768
+ label: "Loading…",
1769
+ padding: 2
1770
+ }), selectedId === void 0 ? null : /* @__PURE__ */ jsx(LoadingTablePlaceholder, {
1771
+ children: /* @__PURE__ */ jsx(ForMeTable, {
1772
+ now: now,
1773
+ onNavigateKey: onNavigateKey,
1774
+ onSelect: onSelect,
1775
+ onSort: onSort,
1776
+ rows: [],
1777
+ selectedId: void 0,
1778
+ selectedRef: selectedRef,
1779
+ sort: sort
2638
1780
  })
2639
- }) : null ]
2640
- });
2641
- }
2642
-
2643
- function StageTasksCard({now: now, tasks: tasks}) {
2644
- const displayById = useDisplayById(tasks.flatMap(task => userIdsOf(task.assignees)));
2645
- /* @__PURE__ */
2646
- return jsxs(Stack, {
2647
- gap: 4,
2648
- padding: 3,
1781
+ }) ]
1782
+ }) : sections.assignedToUser.length === 0 && sections.assignedToRoles.length === 0 ? /* @__PURE__ */ jsx(ForMeEmptyState, {}) : /* @__PURE__ */ jsxs(Stack, {
1783
+ gap: 6,
2649
1784
  children: [
2650
- /* @__PURE__ */ jsx(OverlineHeading, {
2651
- children: "Tasks in this stage"
1785
+ /* @__PURE__ */ jsx(ForMeSection, {
1786
+ description: /* @__PURE__ */ jsx(ForMeSectionCount, {
1787
+ rows: sections.assignedToUser
1788
+ }),
1789
+ now: now,
1790
+ onNavigateKey: onNavigateKey,
1791
+ onSelect: onSelect,
1792
+ onSort: onSort,
1793
+ rows: sections.assignedToUser,
1794
+ selectedId: selectedId,
1795
+ selectedRef: selectedRef,
1796
+ sort: sort,
1797
+ title: FOR_ME_SECTION_COPY.assignedTitle
2652
1798
  }),
2653
- /* @__PURE__ */ jsx(Stack, {
2654
- gap: 4,
2655
- children: tasks.map(task => /* @__PURE__ */ jsx(TaskCardRow, {
2656
- displayById: displayById,
2657
- now: now,
2658
- task: task
2659
- }, task.name))
1799
+ /* @__PURE__ */ jsx(ForMeSection, {
1800
+ description: FOR_ME_SECTION_COPY.roleDescription,
1801
+ now: now,
1802
+ onNavigateKey: onNavigateKey,
1803
+ onSelect: onSelect,
1804
+ onSort: onSort,
1805
+ rows: sections.assignedToRoles,
1806
+ selectedId: selectedId,
1807
+ selectedRef: selectedRef,
1808
+ sort: sort,
1809
+ title: FOR_ME_SECTION_COPY.roleTitle
2660
1810
  }) ]
2661
1811
  });
2662
1812
  }
2663
1813
 
2664
- function TaskCardRow({displayById: displayById, now: now, task: task}) {
2665
- const mark = taskAssignmentMarkOf(task.assignees);
2666
- /* @__PURE__ */
2667
- return jsxs(Stack, {
1814
+ function ForMeSection({description: description, now: now, onNavigateKey: onNavigateKey, onSelect: onSelect, onSort: onSort, rows: rows, selectedId: selectedId, selectedRef: selectedRef, sort: sort, title: title}) {
1815
+ return rows.length === 0 ? null : /* @__PURE__ */ jsxs(Stack, {
2668
1816
  gap: 3,
2669
1817
  children: [
2670
- /* @__PURE__ */ jsxs(Stack, {
2671
- gap: 2,
2672
- children: [
2673
- /* @__PURE__ */ jsxs(Flex, {
2674
- align: "center",
2675
- gap: 3,
2676
- children: [
2677
- /* @__PURE__ */ jsx(Text, {
2678
- size: 1,
2679
- children: task.title
2680
- }), task.overdueSince === void 0 ? null : /* @__PURE__ */ jsx(LateSpan, {
2681
- now: now,
2682
- since: task.overdueSince
2683
- }) ]
2684
- }), task.due === void 0 ? null : /* @__PURE__ */ jsx(Text, {
2685
- muted: !0,
2686
- size: 1,
2687
- children: dueMomentSentence(task.due, now)
2688
- }) ]
1818
+ /* @__PURE__ */ jsx(ForMeSectionHeading, {
1819
+ description: description,
1820
+ title: title
2689
1821
  }),
2690
- /* @__PURE__ */ jsx(AssignmentLine, {
2691
- displayById: displayById,
2692
- mark: mark,
1822
+ /* @__PURE__ */ jsx(ForMeTable, {
2693
1823
  now: now,
2694
- openedAt: task.openedAt,
2695
- roleAliases: task.roleAliases
2696
- }) ]
2697
- });
2698
- }
2699
-
2700
- function AssignmentLine({displayById: displayById, mark: mark, now: now, openedAt: openedAt, roleAliases: roleAliases}) {
2701
- return mark.kind === "unassigned" ? /* @__PURE__ */ jsxs(Flex, {
2702
- align: "center",
2703
- gap: 2,
2704
- children: [
2705
- /* @__PURE__ */ jsx(PersonToken, {}),
2706
- /* @__PURE__ */ jsx(Text, {
2707
- muted: !0,
2708
- size: 1,
2709
- children: "Unassigned"
1824
+ onNavigateKey: onNavigateKey,
1825
+ onSelect: onSelect,
1826
+ onSort: onSort,
1827
+ rows: rows,
1828
+ selectedId: selectedId,
1829
+ selectedRef: selectedRef,
1830
+ sort: sort
2710
1831
  }) ]
2711
- }) : mark.kind === "routed" ? /* @__PURE__ */ jsx(RoutedAssignmentLine, {
2712
- mark: mark,
2713
- now: now,
2714
- openedAt: openedAt,
2715
- roleAliases: roleAliases
2716
- }) : /* @__PURE__ */ jsx(Stack, {
2717
- gap: 2,
2718
- children: mark.members.map((assignee, index) => /* @__PURE__ */ jsxs(Flex, {
2719
- align: "center",
2720
- gap: 2,
2721
- children: [
2722
- /* @__PURE__ */ jsx(HolderFace, {
2723
- assignee: assignee,
2724
- displayById: displayById
2725
- }),
2726
- /* @__PURE__ */ jsx(Text, {
2727
- size: 1,
2728
- children: displayById.get(assignee.id)?.label ?? assignee.id
2729
- }) ]
2730
- }, holderKey(assignee, index)))
2731
1832
  });
2732
1833
  }
2733
1834
 
2734
- function RoutedAssignmentLine({mark: mark, now: now, openedAt: openedAt, roleAliases: roleAliases}) {
2735
- const vocabulary = useProjectMembers(), count = roleMemberCount({
2736
- members: vocabulary.members,
2737
- requiredRoles: mark.roles,
2738
- roleAliases: roleAliases
2739
- }), names = mark.roles.map(role => roleLabel(memberRoleFor(vocabulary, role)));
1835
+ function ForMeSectionCount({rows: rows}) {
1836
+ const summary = forMeSummaryOf(rows);
2740
1837
  /* @__PURE__ */
2741
1838
  return jsxs(Flex, {
2742
1839
  align: "center",
2743
- gap: 2,
2744
- children: [
2745
- /* @__PURE__ */ jsx(PersonToken, {
2746
- routed: !0
2747
- }),
2748
- /* @__PURE__ */ jsxs(Stack, {
2749
- gap: 1,
2750
- children: [
2751
- /* @__PURE__ */ jsx(Text, {
2752
- size: 1,
2753
- children: names.join(", ")
2754
- }),
2755
- /* @__PURE__ */ jsxs(Text, {
2756
- muted: !0,
2757
- size: 1,
2758
- children: [ memberCountLabel(count), " · Open ", formatShortAgo(openedAt, now) ]
2759
- }) ]
2760
- }) ]
2761
- });
2762
- }
2763
-
2764
- function overdueAttentionHint(documents) {
2765
- const task = documents === 1 ? "an overdue task" : "overdue tasks";
2766
- return `${pluralize("document", documents, !0)} ${documents === 1 ? "has" : "have"} ${task}`;
2767
- }
2768
-
2769
- function blockedAttentionHint(documents) {
2770
- return `${pluralize("document", documents, !0)} ${documents === 1 ? "is" : "are"} blocked`;
2771
- }
2772
-
2773
- function overdueMark(detail, now) {
2774
- const span = overdueSpan(detail.due, now), tasks = pluralize("task", detail.count, !0);
2775
- return detail.count === 1 && detail.task !== void 0 ? {
2776
- hint: `“${detail.task}” — ${span === void 0 ? "overdue" : `${span} overdue`}`,
2777
- value: span ?? tasks
2778
- } : {
2779
- hint: span === void 0 ? `${tasks} overdue` : `${tasks} overdue — the longest by ${span}`,
2780
- value: tasks
2781
- };
2782
- }
2783
-
2784
- function overdueSpan(due, now) {
2785
- const from = parseStoredDateValue(due);
2786
- if (from !== void 0) return shortSpanOf(from, now);
2787
- }
2788
-
2789
- function overdueMarkOpensPanel(tasks) {
2790
- return tasks.some(task => task.overdueSince !== void 0);
2791
- }
2792
-
2793
- function blockedMarkHint(detail) {
2794
- return detail.kind === "blocked-many" ? `${pluralize("task", detail.count, !0)} were sent back` : detail.kind === "blocked-effect" ? `Automation “${detail.effect}” ${detail.failed ? "failed" : "didn’t finish"}` : detail.task === void 0 ? "A task was sent back" : `“${detail.task}” was sent back`;
2795
- }
2796
-
2797
- const ATTENTION_FACES = {
2798
- blocked: {
2799
- Icon: ErrorOutlineIcon,
2800
- tone: "critical"
2801
- },
2802
- overdue: LATE_FACE
2803
- };
2804
-
2805
- function AttentionMark({detail: detail, now: now, tasks: tasks}) {
2806
- if (detail.kind === "overdue") {
2807
- const {hint: hint2, value: value} = overdueMark(detail, now);
2808
- /* @__PURE__ */
2809
- return jsx(MetricPair, {
2810
- Icon: ATTENTION_FACES.overdue.Icon,
2811
- face: overdueMarkOpensPanel(tasks) ? stageTasksFace({
2812
- now: now,
2813
- tasks: tasks
2814
- }) : {
2815
- text: hint2
2816
- },
2817
- label: hint2,
2818
- tone: ATTENTION_FACES.overdue.tone,
2819
- value: value
2820
- });
2821
- }
2822
- const hint = blockedMarkHint(detail);
2823
- /* @__PURE__ */
2824
- return jsx(AlertChip, {
2825
- Icon: ATTENTION_FACES.blocked.Icon,
2826
- hint: hint,
2827
- label: hint,
2828
- tone: ATTENTION_FACES.blocked.tone
2829
- });
2830
- }
2831
-
2832
- const TASK_WIDTH = {
2833
- cap: 280,
2834
- fraction: .22
2835
- }, ATTENTION_WIDTH$1 = 48, ASSIGNEE_WIDTH = 96, COLUMNS = [ {
2836
- key: "document",
2837
- label: "Workflow subject"
2838
- }, {
2839
- key: "task",
2840
- label: "Task",
2841
- width: TASK_WIDTH
2842
- }, {
2843
- key: "opened",
2844
- label: "Opened",
2845
- width: TABLE_TIME_WIDTH
2846
- }, {
2847
- key: "workflow",
2848
- label: "Workflow",
2849
- width: TABLE_WORKFLOW_WIDTH
2850
- }, {
2851
- key: "due",
2852
- label: "Due",
2853
- width: TABLE_TIME_WIDTH
2854
- } ];
2855
-
2856
- function documentWidthOf$1(tableWidth) {
2857
- return fillColumnWidth({
2858
- columns: COLUMNS,
2859
- tableWidth: tableWidth,
2860
- trailingWidth: ASSIGNEE_WIDTH + ATTENTION_WIDTH$1
2861
- });
2862
- }
2863
-
2864
- function ForMeTable({now: now, onNavigateKey: onNavigateKey, onSelect: onSelect, onSort: onSort, rows: rows, selectedId: selectedId, selectedRef: selectedRef, sort: sort}) {
2865
- /* @__PURE__ */
2866
- return jsx(VirtualTable, {
2867
- renderHeader: args => /* @__PURE__ */ jsxs(SortableHeaderCells, {
2868
- columns: COLUMNS,
2869
- onSort: onSort,
2870
- sort: sort,
2871
- styles: args.styles,
2872
- tableWidth: args.tableWidth,
2873
- widthOf: (column, tableWidth) => column.key === "document" ? documentWidthOf$1(tableWidth) : resolveColumnWidth(column.width, tableWidth),
2874
- children: [
2875
- /* @__PURE__ */ jsx("th", {
2876
- style: {
2877
- ...args.styles.head,
2878
- width: ASSIGNEE_WIDTH
2879
- },
2880
- children: /* @__PURE__ */ jsx(Box, {
2881
- padding: 2,
2882
- children: /* @__PURE__ */ jsx(Text, {
2883
- muted: !0,
2884
- size: 1,
2885
- children: "Assignee"
2886
- })
2887
- })
2888
- }),
2889
- /* @__PURE__ */ jsx("th", {
2890
- "aria-label": "Attention",
2891
- style: {
2892
- ...args.styles.head,
2893
- width: ATTENTION_WIDTH$1
2894
- }
2895
- }) ]
2896
- }),
2897
- keyAt: index => rows[index]?.id ?? String(index),
2898
- renderRow: ({index: index, key: key, measureRow: measureRow}) => {
2899
- const row = rows[index];
2900
- return row === void 0 ? null : /* @__PURE__ */ jsx(ForMeTableRow, {
2901
- dataIndex: index,
2902
- measureRow: measureRow,
2903
- now: now,
2904
- onNavigateKey: onNavigateKey,
2905
- onSelect: onSelect,
2906
- row: row,
2907
- selected: row.id === selectedId,
2908
- selectedRef: selectedRef
2909
- }, key);
2910
- },
2911
- rowCount: rows.length
2912
- });
2913
- }
2914
-
2915
- const ForMeTableRow = memo(function({dataIndex: dataIndex, measureRow: measureRow, now: now, onNavigateKey: onNavigateKey, onSelect: onSelect, row: row, selected: selected, selectedRef: selectedRef}) {
2916
- const styles = useTableStyles(), documentInset = useSpaceToken(1);
2917
- /* @__PURE__ */
2918
- return jsxs(TableRowCard, {
2919
- dataIndex: dataIndex,
2920
- onClick: () => onSelect(row),
2921
- onKeyDown: onNavigateKey,
2922
- rowRef: measureRow,
2923
- selected: selected,
2924
- selectedRef: selectedRef,
1840
+ gap: 1,
2925
1841
  children: [
2926
- /* @__PURE__ */ jsx("td", {
2927
- style: {
2928
- ...styles.cell,
2929
- paddingLeft: documentInset
2930
- },
2931
- children: row.document === void 0 ? /* @__PURE__ */ jsx(Text, {
2932
- muted: !0,
2933
- size: 1,
2934
- textOverflow: "ellipsis",
2935
- children: "No document"
2936
- }) : /* @__PURE__ */ jsx(DocRefFace, {
2937
- gdr: row.document
2938
- })
2939
- }),
2940
- /* @__PURE__ */ jsx("td", {
2941
- style: styles.cell,
2942
- children: /* @__PURE__ */ jsx(Text, {
2943
- size: 1,
2944
- textOverflow: "ellipsis",
2945
- children: row.title
2946
- })
2947
- }),
2948
- /* @__PURE__ */ jsx("td", {
2949
- style: styles.cell,
2950
- children: /* @__PURE__ */ jsx(AgoStamp, {
2951
- at: row.openedAt,
2952
- now: now
2953
- })
2954
- }),
2955
- /* @__PURE__ */ jsx("td", {
2956
- style: styles.cell,
2957
- children: /* @__PURE__ */ jsx(Text, {
2958
- muted: !0,
2959
- size: 1,
2960
- textOverflow: "ellipsis",
2961
- children: row.workflowTitle
2962
- })
2963
- }),
2964
- /* @__PURE__ */ jsx("td", {
2965
- style: styles.cell,
2966
- children: row.due === void 0 ? null : /* @__PURE__ */ jsx(DueStamp, {
2967
- due: row.due,
2968
- now: now
2969
- })
2970
- }),
2971
- /* @__PURE__ */ jsx("td", {
2972
- style: {
2973
- ...styles.cell,
2974
- overflow: "hidden"
2975
- },
2976
- children: /* @__PURE__ */ jsx(Flex, {
2977
- align: "center",
2978
- children: /* @__PURE__ */ jsx(RowAssignees, {
2979
- assignees: row.assignees
2980
- })
2981
- })
2982
- }),
2983
- /* @__PURE__ */ jsx("td", {
2984
- style: styles.cell,
2985
- children: row.attentionDetail === void 0 || row.attentionDetail.kind === "overdue" ? null : /* @__PURE__ */ jsx(Flex, {
2986
- align: "center",
2987
- children: /* @__PURE__ */ jsx(AttentionMark, {
2988
- detail: row.attentionDetail,
2989
- now: now,
2990
- tasks: []
2991
- })
2992
- })
1842
+ /* @__PURE__ */ jsx(Text, {
1843
+ size: 1,
1844
+ weight: "semibold",
1845
+ children: summary.lead
1846
+ }),
1847
+ /* @__PURE__ */ jsx(Text, {
1848
+ muted: !0,
1849
+ size: 1,
1850
+ children: summary.subjects
2993
1851
  }) ]
2994
1852
  });
2995
- });
1853
+ }
2996
1854
 
2997
1855
  function AbortWorkflowSection({entry: entry}) {
2998
1856
  const [aborting, setAborting] = useState(!1);
@@ -3270,7 +2128,7 @@ function ForMeWorkArea({previews: previews, loading: loading, model: model, now:
3270
2128
  loading: loading,
3271
2129
  previews: previews,
3272
2130
  resetKey: `${sort.dir}:${sort.key}`,
3273
- children: /* @__PURE__ */ jsx(ForMeBody, {
2131
+ children: /* @__PURE__ */ jsx(ForMeTables, {
3274
2132
  loading: loading,
3275
2133
  now: now,
3276
2134
  onNavigateKey: keyboardNavigation.onKeyDown,
@@ -3295,97 +2153,6 @@ function ForMeWorkArea({previews: previews, loading: loading, model: model, now:
3295
2153
  });
3296
2154
  }
3297
2155
 
3298
- function ForMeBody({loading: loading, now: now, onNavigateKey: onNavigateKey, onSelect: onSelect, onSort: onSort, selectedId: selectedId, selectedRef: selectedRef, sort: sort, sections: sections}) {
3299
- return loading ? /* @__PURE__ */ jsxs(Fragment, {
3300
- children: [
3301
- /* @__PURE__ */ jsx(LoadingRow, {
3302
- label: "Loading…",
3303
- padding: 2
3304
- }), selectedId === void 0 ? null : /* @__PURE__ */ jsx(LoadingTablePlaceholder, {
3305
- children: /* @__PURE__ */ jsx(ForMeTable, {
3306
- now: now,
3307
- onNavigateKey: onNavigateKey,
3308
- onSelect: onSelect,
3309
- onSort: onSort,
3310
- rows: [],
3311
- selectedId: void 0,
3312
- selectedRef: selectedRef,
3313
- sort: sort
3314
- })
3315
- }) ]
3316
- }) : sections.assignedToUser.length === 0 && sections.assignedToRoles.length === 0 ? /* @__PURE__ */ jsx(ForMeEmptyState, {}) : /* @__PURE__ */ jsxs(Stack, {
3317
- gap: 6,
3318
- children: [
3319
- /* @__PURE__ */ jsx(ForMeSection, {
3320
- description: /* @__PURE__ */ jsx(ForMeSectionCount, {
3321
- rows: sections.assignedToUser
3322
- }),
3323
- now: now,
3324
- onNavigateKey: onNavigateKey,
3325
- onSelect: onSelect,
3326
- onSort: onSort,
3327
- rows: sections.assignedToUser,
3328
- selectedId: selectedId,
3329
- selectedRef: selectedRef,
3330
- sort: sort,
3331
- title: FOR_ME_SECTION_COPY.assignedTitle
3332
- }),
3333
- /* @__PURE__ */ jsx(ForMeSection, {
3334
- description: FOR_ME_SECTION_COPY.roleDescription,
3335
- now: now,
3336
- onNavigateKey: onNavigateKey,
3337
- onSelect: onSelect,
3338
- onSort: onSort,
3339
- rows: sections.assignedToRoles,
3340
- selectedId: selectedId,
3341
- selectedRef: selectedRef,
3342
- sort: sort,
3343
- title: FOR_ME_SECTION_COPY.roleTitle
3344
- }) ]
3345
- });
3346
- }
3347
-
3348
- function ForMeSection({description: description, now: now, onNavigateKey: onNavigateKey, onSelect: onSelect, onSort: onSort, rows: rows, selectedId: selectedId, selectedRef: selectedRef, sort: sort, title: title}) {
3349
- return rows.length === 0 ? null : /* @__PURE__ */ jsxs(Stack, {
3350
- gap: 3,
3351
- children: [
3352
- /* @__PURE__ */ jsx(ForMeSectionHeading, {
3353
- description: description,
3354
- title: title
3355
- }),
3356
- /* @__PURE__ */ jsx(ForMeTable, {
3357
- now: now,
3358
- onNavigateKey: onNavigateKey,
3359
- onSelect: onSelect,
3360
- onSort: onSort,
3361
- rows: rows,
3362
- selectedId: selectedId,
3363
- selectedRef: selectedRef,
3364
- sort: sort
3365
- }) ]
3366
- });
3367
- }
3368
-
3369
- function ForMeSectionCount({rows: rows}) {
3370
- const summary = forMeSummaryOf(rows);
3371
- /* @__PURE__ */
3372
- return jsxs(Flex, {
3373
- align: "center",
3374
- gap: 1,
3375
- children: [
3376
- /* @__PURE__ */ jsx(Text, {
3377
- size: 1,
3378
- weight: "semibold",
3379
- children: summary.lead
3380
- }),
3381
- /* @__PURE__ */ jsx(Text, {
3382
- muted: !0,
3383
- size: 1,
3384
- children: summary.subjects
3385
- }) ]
3386
- });
3387
- }
3388
-
3389
2156
  function defaultRunSort(scope) {
3390
2157
  return scope === "closed" ? {
3391
2158
  key: "ended",
@@ -3411,17 +2178,11 @@ function sortRunRows(args) {
3411
2178
  return [ ...rows ].sort((a, b) => dir * primary(a, b) || tiebreak(a, b));
3412
2179
  }
3413
2180
 
3414
- function documentTitleKey(row, titles) {
3415
- return row.document === void 0 ? "" : titles.get(row.document.id) ?? "";
3416
- }
3417
-
3418
2181
  function comparatorFor(key, titles) {
3419
2182
  switch (key) {
3420
2183
  case "document":
3421
- return (a, b) => documentTitleKey(a, titles).localeCompare(documentTitleKey(b, titles));
3422
-
3423
2184
  case "workflow":
3424
- return (a, b) => a.workflowTitle.localeCompare(b.workflowTitle);
2185
+ return namedRowComparator(key, titles);
3425
2186
 
3426
2187
  case "stage":
3427
2188
  return (a, b) => a.stageTitle.localeCompare(b.stageTitle);
@@ -3455,7 +2216,7 @@ function cardFacts(args) {
3455
2216
  now: args.now,
3456
2217
  preview: preview
3457
2218
  }),
3458
- blocked: blockedRunDetail({
2219
+ blocked: settled ? void 0 : blockedRunDetail({
3459
2220
  definition: args.definition,
3460
2221
  preview: preview
3461
2222
  }),
@@ -3814,9 +2575,9 @@ function boardDocuments(board) {
3814
2575
  const CARD_RADIUS = 3;
3815
2576
 
3816
2577
  function BoardCard({card: card, wiring: wiring}) {
3817
- const {facts: facts, now: now, onNavigateKey: onNavigateKey, onSelect: onSelect, selectedInstanceId: selectedInstanceId, selectedRef: selectedRef} = wiring, {color: color} = useTheme_v2(), faceInset = useSpaceToken(2), selected = card.instanceId === selectedInstanceId, held = facts.get(card.instanceId);
2578
+ const {facts: facts, now: now, onNavigateKey: onNavigateKey, onSelect: onSelect, selectedInstanceId: selectedInstanceId, selectedRef: selectedRef} = wiring, {color: color} = useTheme_v2(), faceInset = useSpaceToken(2), markClearance = useAlertChipSize() + useSpaceToken(3), selected = card.instanceId === selectedInstanceId, held = facts.get(card.instanceId), blocked = held?.blocked;
3818
2579
  /* @__PURE__ */
3819
- return jsx(Card, {
2580
+ return jsxs(Card, {
3820
2581
  "aria-pressed": selected,
3821
2582
  as: "button",
3822
2583
  onClick: event => {
@@ -3830,18 +2591,32 @@ function BoardCard({card: card, wiring: wiring}) {
3830
2591
  border: `1px solid ${color.border}`,
3831
2592
  display: "flex",
3832
2593
  flexDirection: "column",
2594
+ position: "relative",
3833
2595
  textAlign: "left",
3834
2596
  width: "100%"
3835
2597
  },
3836
2598
  ...selected ? {
3837
2599
  ref: selectedRef
3838
2600
  } : {},
3839
- children: /* @__PURE__ */ jsxs(Stack, {
2601
+ children: [ held === void 0 || blocked === void 0 ? null : /* @__PURE__ */ jsx(Box, {
2602
+ style: {
2603
+ position: "absolute",
2604
+ right: faceInset,
2605
+ top: faceInset
2606
+ },
2607
+ children: /* @__PURE__ */ jsx(AttentionMark, {
2608
+ detail: blocked,
2609
+ now: now,
2610
+ tasks: held.tasks
2611
+ })
2612
+ }),
2613
+ /* @__PURE__ */ jsxs(Stack, {
3840
2614
  gap: 2,
3841
2615
  children: [
3842
2616
  /* @__PURE__ */ jsx(Box, {
3843
2617
  style: {
3844
2618
  minWidth: 0,
2619
+ paddingRight: blocked === void 0 ? void 0 : markClearance,
3845
2620
  ...card.face.kind === "document" ? {
3846
2621
  margin: `${-faceInset}px 0 ${-faceInset}px ${-faceInset}px`
3847
2622
  } : {}
@@ -3859,13 +2634,13 @@ function BoardCard({card: card, wiring: wiring}) {
3859
2634
  facts: held,
3860
2635
  now: now
3861
2636
  }) ]
3862
- })
2637
+ }) ]
3863
2638
  });
3864
2639
  }
3865
2640
 
3866
2641
  function CardMetrics({facts: facts, now: now}) {
3867
- const markOverhang = -useCapTrimFor(useTextIconSize()), bare = facts.tasks.length === 0 && facts.overdueDetail === void 0 && facts.blocked === void 0;
3868
- return facts.settled || bare ? null : /* @__PURE__ */ jsx(Box, {
2642
+ const markOverhang = -useCapTrimFor(useTextIconSize());
2643
+ return facts.settled || facts.tasks.length === 0 && facts.overdueDetail === void 0 ? null : /* @__PURE__ */ jsx(Box, {
3869
2644
  padding: 1,
3870
2645
  children: /* @__PURE__ */ jsxs(Flex, {
3871
2646
  align: "center",
@@ -3874,8 +2649,7 @@ function CardMetrics({facts: facts, now: now}) {
3874
2649
  /* @__PURE__ */ jsx(StageTaskGroups, {
3875
2650
  now: now,
3876
2651
  tasks: facts.tasks
3877
- }),
3878
- /* @__PURE__ */ jsxs(Flex, {
2652
+ }), facts.overdueDetail === void 0 ? null : /* @__PURE__ */ jsx(Flex, {
3879
2653
  align: "center",
3880
2654
  flex: 1,
3881
2655
  gap: 3,
@@ -3883,15 +2657,11 @@ function CardMetrics({facts: facts, now: now}) {
3883
2657
  style: {
3884
2658
  paddingRight: markOverhang
3885
2659
  },
3886
- children: [ facts.overdueDetail === void 0 ? null : /* @__PURE__ */ jsx(AttentionMark, {
2660
+ children: /* @__PURE__ */ jsx(AttentionMark, {
3887
2661
  detail: facts.overdueDetail,
3888
2662
  now: now,
3889
2663
  tasks: facts.tasks
3890
- }), facts.blocked === void 0 ? null : /* @__PURE__ */ jsx(AttentionMark, {
3891
- detail: facts.blocked,
3892
- now: now,
3893
- tasks: facts.tasks
3894
- }) ]
2664
+ })
3895
2665
  }) ]
3896
2666
  })
3897
2667
  });
@@ -4614,7 +3384,7 @@ function Segment({active: active, joined: joined, mode: mode, onPick: onPick, op
4614
3384
  tone: tone
4615
3385
  }
4616
3386
  });
4617
- return option.tooltip === void 0 ? button : /* @__PURE__ */ jsx(HoverHint, {
3387
+ return option.tooltip === void 0 ? button : /* @__PURE__ */ jsx(_HoverHint, {
4618
3388
  text: option.tooltip,
4619
3389
  children: button
4620
3390
  });
@@ -5825,272 +4595,6 @@ function walkIdOf(view) {
5825
4595
  if (view.run !== void 0) return view.task === void 0 ? view.run : forMeRowId(view.run, view.task);
5826
4596
  }
5827
4597
 
5828
- const OPEN_COLUMNS = [ {
5829
- key: "document",
5830
- label: "Workflow subject"
5831
- }, {
5832
- key: "workflow",
5833
- label: "Workflow",
5834
- width: TABLE_WORKFLOW_WIDTH
5835
- }, {
5836
- key: "stage",
5837
- label: "Stage",
5838
- width: TABLE_STAGE_WIDTH
5839
- }, {
5840
- key: "started",
5841
- label: "Started",
5842
- width: TABLE_TIME_WIDTH
5843
- } ], CLOSED_COLUMNS = [ {
5844
- key: "document",
5845
- label: "Workflow subject"
5846
- }, {
5847
- key: "workflow",
5848
- label: "Workflow",
5849
- width: TABLE_WORKFLOW_WIDTH
5850
- }, {
5851
- key: "outcome",
5852
- label: "Outcome",
5853
- width: TABLE_STAGE_WIDTH
5854
- }, {
5855
- key: "started",
5856
- label: "Started",
5857
- width: TABLE_TIME_WIDTH
5858
- }, {
5859
- key: "ended",
5860
- label: "Closed",
5861
- width: TABLE_TIME_WIDTH
5862
- } ], TASKS_WIDTH = 120, TASKS_WIDTH_ROOMY = 168, ROOMY_TABLE_WIDTH = 1040;
5863
-
5864
- function tasksWidthOf(tableWidth) {
5865
- return tableWidth === void 0 ? TASKS_WIDTH : tableWidth >= ROOMY_TABLE_WIDTH ? TASKS_WIDTH_ROOMY : TASKS_WIDTH;
5866
- }
5867
-
5868
- function taskRoomOf(args) {
5869
- return tasksWidthOf(args.tableWidth) - args.inset * 2;
5870
- }
5871
-
5872
- const ATTENTION_WIDTH = 96;
5873
-
5874
- function documentWidthOf(args) {
5875
- const {columns: columns, scope: scope, tableWidth: tableWidth} = args, trailing = scope === "open" ? tasksWidthOf(tableWidth) + ATTENTION_WIDTH : 0;
5876
- return fillColumnWidth({
5877
- columns: columns,
5878
- tableWidth: tableWidth,
5879
- trailingWidth: trailing
5880
- });
5881
- }
5882
-
5883
- function RunsTable({now: now, onNavigateKey: onNavigateKey, onSelectRun: onSelectRun, onSort: onSort, rows: rows, scope: scope, scopedToWorkflow: scopedToWorkflow, selectedId: selectedId, selectedRef: selectedRef, sort: sort}) {
5884
- const columns = (scope === "closed" ? CLOSED_COLUMNS : OPEN_COLUMNS).filter(column => !(scopedToWorkflow && column.key === "workflow")), cellInset = useSpaceToken(2);
5885
- /* @__PURE__ */
5886
- return jsx(VirtualTable, {
5887
- renderHeader: args => /* @__PURE__ */ jsx(RunsHeader, {
5888
- columns: columns,
5889
- onSort: onSort,
5890
- scope: scope,
5891
- sort: sort,
5892
- styles: args.styles,
5893
- tableWidth: args.tableWidth
5894
- }),
5895
- keyAt: index => rows[index]?.id ?? String(index),
5896
- renderRow: ({index: index, key: key, measureRow: measureRow, tableWidth: tableWidth}) => {
5897
- const row = rows[index];
5898
- return row === void 0 ? null : /* @__PURE__ */ jsx(RunTableRow, {
5899
- dataIndex: index,
5900
- measureRow: measureRow,
5901
- now: now,
5902
- onNavigateKey: onNavigateKey,
5903
- onSelectRun: onSelectRun,
5904
- row: row,
5905
- scope: scope,
5906
- scopedToWorkflow: scopedToWorkflow,
5907
- selected: row.id === selectedId,
5908
- selectedRef: selectedRef,
5909
- taskRoom: taskRoomOf({
5910
- inset: cellInset,
5911
- tableWidth: tableWidth
5912
- })
5913
- }, key);
5914
- },
5915
- rowCount: rows.length
5916
- });
5917
- }
5918
-
5919
- function RunsHeader({columns: columns, onSort: onSort, scope: scope, sort: sort, styles: styles, tableWidth: tableWidth}) {
5920
- /* @__PURE__ */
5921
- return jsx(SortableHeaderCells, {
5922
- columns: columns,
5923
- onSort: onSort,
5924
- sort: sort,
5925
- styles: styles,
5926
- tableWidth: tableWidth,
5927
- widthOf: (column, width) => column.key === "document" ? documentWidthOf({
5928
- columns: columns,
5929
- scope: scope,
5930
- tableWidth: width
5931
- }) : resolveColumnWidth(column.width, width),
5932
- children: scope === "open" ? /* @__PURE__ */ jsxs(Fragment, {
5933
- children: [
5934
- /* @__PURE__ */ jsx("th", {
5935
- style: {
5936
- ...styles.head,
5937
- width: tasksWidthOf(tableWidth)
5938
- },
5939
- children: /* @__PURE__ */ jsx(Box, {
5940
- padding: 2,
5941
- children: /* @__PURE__ */ jsx(Text, {
5942
- muted: !0,
5943
- size: 1,
5944
- children: "Tasks"
5945
- })
5946
- })
5947
- }),
5948
- /* @__PURE__ */ jsx("th", {
5949
- "aria-label": "Attention",
5950
- style: {
5951
- ...styles.head,
5952
- width: ATTENTION_WIDTH
5953
- }
5954
- }) ]
5955
- }) : null
5956
- });
5957
- }
5958
-
5959
- const RunTableRow = memo(function({dataIndex: dataIndex, measureRow: measureRow, now: now, onNavigateKey: onNavigateKey, onSelectRun: onSelectRun, row: row, scope: scope, scopedToWorkflow: scopedToWorkflow, selected: selected, selectedRef: selectedRef, taskRoom: taskRoom}) {
5960
- const styles = useTableStyles(), documentInset = useSpaceToken(1);
5961
- /* @__PURE__ */
5962
- return jsxs(TableRowCard, {
5963
- dataIndex: dataIndex,
5964
- onClick: () => onSelectRun(row),
5965
- onKeyDown: onNavigateKey,
5966
- rowRef: measureRow,
5967
- selected: selected,
5968
- selectedRef: selectedRef,
5969
- children: [
5970
- /* @__PURE__ */ jsx("td", {
5971
- style: {
5972
- ...styles.cell,
5973
- paddingLeft: documentInset
5974
- },
5975
- children: /* @__PURE__ */ jsx(DocumentCell, {
5976
- row: row
5977
- })
5978
- }), scopedToWorkflow ? null : /* @__PURE__ */ jsx("td", {
5979
- style: styles.cell,
5980
- children: /* @__PURE__ */ jsx(Text, {
5981
- muted: !0,
5982
- size: 1,
5983
- textOverflow: "ellipsis",
5984
- children: row.workflowTitle
5985
- })
5986
- }), scope === "closed" ? /* @__PURE__ */ jsx(ClosedCells, {
5987
- now: now,
5988
- row: row
5989
- }) : /* @__PURE__ */ jsx(OpenCells, {
5990
- now: now,
5991
- row: row,
5992
- taskRoom: taskRoom
5993
- }) ]
5994
- });
5995
- });
5996
-
5997
- function DocumentCell({row: row}) {
5998
- return row.document === void 0 ? /* @__PURE__ */ jsx(Text, {
5999
- muted: !0,
6000
- size: 1,
6001
- textOverflow: "ellipsis",
6002
- children: "No document"
6003
- }) : /* @__PURE__ */ jsx(DocRefFace, {
6004
- gdr: row.document
6005
- });
6006
- }
6007
-
6008
- function OpenCells({now: now, row: row, taskRoom: taskRoom}) {
6009
- const styles = useTableStyles();
6010
- /* @__PURE__ */
6011
- return jsxs(Fragment, {
6012
- children: [
6013
- /* @__PURE__ */ jsx("td", {
6014
- style: styles.cell,
6015
- children: /* @__PURE__ */ jsx(Text, {
6016
- size: 1,
6017
- textOverflow: "ellipsis",
6018
- children: row.stageTitle
6019
- })
6020
- }),
6021
- /* @__PURE__ */ jsx("td", {
6022
- style: styles.cell,
6023
- children: /* @__PURE__ */ jsx(AgoStamp, {
6024
- at: row.startedAt,
6025
- now: now
6026
- })
6027
- }),
6028
- /* @__PURE__ */ jsx("td", {
6029
- style: {
6030
- ...styles.cell,
6031
- overflow: "hidden"
6032
- },
6033
- children: /* @__PURE__ */ jsx(Flex, {
6034
- align: "center",
6035
- children: /* @__PURE__ */ jsx(StageTaskGroups, {
6036
- now: now,
6037
- room: taskRoom,
6038
- tasks: row.tasks
6039
- })
6040
- })
6041
- }),
6042
- /* @__PURE__ */ jsx("td", {
6043
- style: styles.cell,
6044
- children: /* @__PURE__ */ jsx(AttentionCell, {
6045
- now: now,
6046
- row: row
6047
- })
6048
- }) ]
6049
- });
6050
- }
6051
-
6052
- function ClosedCells({now: now, row: row}) {
6053
- const styles = useTableStyles();
6054
- /* @__PURE__ */
6055
- return jsxs(Fragment, {
6056
- children: [
6057
- /* @__PURE__ */ jsx("td", {
6058
- style: styles.cell,
6059
- children: /* @__PURE__ */ jsx(Text, {
6060
- size: 1,
6061
- textOverflow: "ellipsis",
6062
- children: row.outcome
6063
- })
6064
- }),
6065
- /* @__PURE__ */ jsx("td", {
6066
- style: styles.cell,
6067
- children: /* @__PURE__ */ jsx(AgoStamp, {
6068
- at: row.startedAt,
6069
- now: now
6070
- })
6071
- }),
6072
- /* @__PURE__ */ jsx("td", {
6073
- style: styles.cell,
6074
- children: row.endedAt === void 0 ? null : /* @__PURE__ */ jsx(AgoStamp, {
6075
- at: row.endedAt,
6076
- now: now
6077
- })
6078
- }) ]
6079
- });
6080
- }
6081
-
6082
- function AttentionCell({now: now, row: row}) {
6083
- return row.attentionDetail === void 0 ? null :
6084
- /* @__PURE__ */ jsx(Flex, {
6085
- align: "center",
6086
- children: /* @__PURE__ */ jsx(AttentionMark, {
6087
- detail: row.attentionDetail,
6088
- now: now,
6089
- tasks: row.tasks
6090
- })
6091
- });
6092
- }
6093
-
6094
4598
  function RunsWorkArea({boardMode: boardMode, boardState: boardState, previews: previews, loading: loading, model: model, navigatorSlot: navigatorSlot, now: now, onSort: onSort, scopedCount: scopedCount, sort: sort, sorted: sorted, view: view}) {
6095
4599
  const columnStyle = useWorkColumnStyle({
6096
4600
  boardMode: boardMode,
@@ -6305,10 +4809,9 @@ const RunsTab = memo(function({addressed: addressed, filterSlot: filterSlot, for
6305
4809
  scoped: scoped,
6306
4810
  view: view
6307
4811
  }), taskRows = useMemo(() => forMeIdentity === void 0 ? [] : forMeTaskRowsOf({
6308
- now: now,
6309
4812
  rows: filtered,
6310
4813
  who: forMeIdentity
6311
- }), [ filtered, forMeIdentity, now ]), shownAttention = useMemo(() => runAttentionCounts(filtered), [ filtered ]), documents = useMemo(() => filtered.flatMap(row => row.document === void 0 ? [] : [ row.document ]), [ filtered ]), titles = useDocPreviewTitles(documents), sortedTasks = useMemo(() => sortForMeRows({
4814
+ }), [ filtered, forMeIdentity ]), shownAttention = useMemo(() => runAttentionCounts(filtered), [ filtered ]), documents = useMemo(() => filtered.flatMap(row => row.document === void 0 ? [] : [ row.document ]), [ filtered ]), titles = useDocPreviewTitles(documents), sortedTasks = useMemo(() => sortForMeRows({
6312
4815
  rows: taskRows,
6313
4816
  sort: forMeSort,
6314
4817
  titles: titles.titles