@sanity/workflow-studio-plugin 0.32.0 → 0.33.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,25 @@ 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, MenuButton, Menu, MenuGroup, MenuItem, MenuDivider, TextInput, Checkbox, Popover, KBD, TabPanel } from "@sanity/ui";
12
12
 
13
13
  import { useWorkflowTelemetry } from "@sanity/workflow-react";
14
14
 
15
- import { useMemo, useCallback, useState, useLayoutEffect, useEffect, useRef, memo, Fragment as Fragment$1, Activity } from "react";
15
+ import { useState, useEffect, useMemo, useRef, useLayoutEffect, useCallback, Fragment as Fragment$1, memo, Activity } from "react";
16
16
 
17
17
  import { StateLink, useRouter } from "sanity/router";
18
18
 
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";
19
+ 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
20
 
21
21
  import { TransferIcon } from "@sanity/icons/Transfer";
22
22
 
23
23
  import { WarningOutlineIcon } from "@sanity/icons/WarningOutline";
24
24
 
25
- import { useSchema, useDocumentPreviewStore, usePerspective, useClient } from "sanity";
26
-
27
- import { assignmentMatch, MemberAvatar, roleMemberCount, roleLabel, memberRoleFor, memberCountLabel, RoleAvatar, roleLabelFor, AssigneeStack } from "@sanity/workflow-components";
25
+ import { assignmentMatch, _formatShortDateTime, AgoStamp, _HoverHint, RoleAvatar, MemberAvatar, roleLabelFor, AssigneeStack } from "@sanity/workflow-components";
28
26
 
29
- import { entryDocRefs, toBareId, findOpenStageEntry, findStageNode, deriveWorkflowAutonomy, deriveExecutorClassification, terminalState, openActivityAssignments, assignmentState, activeAssignmentMembers, startKindOf, isSubjectEntry, isInputSourced, latestDeployedDefinitions, isTerminalStage, isStartableDefinition } from "@sanity/workflow-engine";
27
+ import { useSchema, useDocumentPreviewStore, usePerspective, useClient } from "sanity";
30
28
 
31
- import { useVirtualizer } from "@tanstack/react-virtual";
29
+ import { activeAssignmentMembers, terminalState, startKindOf, isSubjectEntry, isInputSourced, latestDeployedDefinitions, isTerminalStage, findOpenStageEntry, isStartableDefinition } from "@sanity/workflow-engine";
32
30
 
33
31
  import { useWorkflowInstancePreviews } from "@sanity/workflow-studio";
34
32
 
@@ -42,13 +40,7 @@ import { ExpandIcon } from "@sanity/icons/Expand";
42
40
 
43
41
  import { useReducedMotion, motion, useSpring, useMotionValueEvent } from "motion/react";
44
42
 
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";
43
+ import { useVirtualizer } from "@tanstack/react-virtual";
52
44
 
53
45
  import { createPortal } from "react-dom";
54
46
 
@@ -56,6 +48,8 @@ import { styled } from "styled-components";
56
48
 
57
49
  import { isReferenceSchemaType } from "@sanity/types";
58
50
 
51
+ import { UserIcon } from "@sanity/icons/User";
52
+
59
53
  import { AddIcon } from "@sanity/icons/Add";
60
54
 
61
55
  import { CheckmarkIcon } from "@sanity/icons/Checkmark";
@@ -76,400 +70,6 @@ function MutedNote({text: text}) {
76
70
  });
77
71
  }
78
72
 
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
73
  function clausePolarity(operator) {
474
74
  return operator === "isNot" || operator === "isNoneOf" ? "isNot" : "is";
475
75
  }
@@ -843,7 +443,7 @@ function deployedPhrase(definition) {
843
443
  const deployedAt = deployedAtOf(definition);
844
444
  if (deployedAt === void 0) return `v${definition.version}`;
845
445
  const ago = formatTimeAgo(deployedAt);
846
- return ago === "" ? formatShortDateTime(deployedAt) : `${formatShortDateTime(deployedAt)} (${ago})`;
446
+ return ago === "" ? _formatShortDateTime(deployedAt) : `${_formatShortDateTime(deployedAt)} (${ago})`;
847
447
  }
848
448
 
849
449
  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 +461,6 @@ function TabStatusRow({children: children}) {
861
461
  });
862
462
  }
863
463
 
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
464
  const logged = /* @__PURE__ */ new WeakSet;
1066
465
 
1067
466
  function logReadFailure(what, error) {
@@ -1259,7 +658,7 @@ function UndeployedWorkflows({notices: notices}) {
1259
658
  });
1260
659
  }
1261
660
 
1262
- const COLUMNS$1 = [ {
661
+ const COLUMNS = [ {
1263
662
  key: "workflow",
1264
663
  label: "Workflow"
1265
664
  }, {
@@ -1299,7 +698,7 @@ function DefinitionsTable({countKnown: countKnown, now: now, onOpenWorkflow: onO
1299
698
  children: [
1300
699
  /* @__PURE__ */ jsx("thead", {
1301
700
  children: /* @__PURE__ */ jsxs("tr", {
1302
- children: [ COLUMNS$1.map(column => /* @__PURE__ */ jsx("th", {
701
+ children: [ COLUMNS.map(column => /* @__PURE__ */ jsx("th", {
1303
702
  style: {
1304
703
  ...head,
1305
704
  ...column.width === void 0 ? {} : {
@@ -1476,7 +875,7 @@ function useDocPreviewTitles(documents) {
1476
875
  }, evaluate = () => {
1477
876
  for (const {doc: doc, bareId: bareId} of localDocs) {
1478
877
  const probe = actualTypes.read(bareId);
1479
- if (probe === null) {
878
+ if (probe === null || probe === UNREADABLE_DOCUMENT) {
1480
879
  dropPreview(doc.id), resolved.add(doc.id);
1481
880
  continue;
1482
881
  }
@@ -1554,86 +953,18 @@ function outsiderIds(args) {
1554
953
  return [ ...new Set(candidates.filter(id => !memberIds.has(id))) ];
1555
954
  }
1556
955
 
1557
- function forMeRowId(instanceId, activityName) {
1558
- return `${instanceId}\t${activityName}`;
1559
- }
1560
-
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
- }));
956
+ function documentTitleKey(row, titles) {
957
+ return row.document === void 0 ? "" : titles.get(row.document.id) ?? "";
1587
958
  }
1588
959
 
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));
1591
- 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
- };
960
+ function namedRowComparator(key, titles) {
961
+ return key === "document" ? (a, b) => documentTitleKey(a, titles).localeCompare(documentTitleKey(b, titles)) : (a, b) => a.workflowTitle.localeCompare(b.workflowTitle);
1595
962
  }
1596
963
 
1597
- function forMeSectionsOf(rows) {
964
+ function defaultForMeSort() {
1598
965
  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"
966
+ dir: "asc",
967
+ key: "due"
1637
968
  };
1638
969
  }
1639
970
 
@@ -1664,17 +995,11 @@ function forMeCompare(args) {
1664
995
  return (a, b) => dir * named(a, b);
1665
996
  }
1666
997
 
1667
- function documentTitleKey$1(row, titles) {
1668
- return row.document === void 0 ? "" : titles.get(row.document.id) ?? "";
1669
- }
1670
-
1671
998
  function namedCompare(key, titles) {
1672
999
  switch (key) {
1673
1000
  case "document":
1674
- return (a, b) => documentTitleKey$1(a, titles).localeCompare(documentTitleKey$1(b, titles));
1675
-
1676
1001
  case "workflow":
1677
- return (a, b) => a.workflowTitle.localeCompare(b.workflowTitle);
1002
+ return namedRowComparator(key, titles);
1678
1003
 
1679
1004
  default:
1680
1005
  return (a, b) => a.title.localeCompare(b.title);
@@ -1922,7 +1247,7 @@ function PanelResizeHandle({enabled: enabled, onClose: onClose, onCommit: onComm
1922
1247
  top: 0
1923
1248
  }
1924
1249
  }),
1925
- /* @__PURE__ */ jsx(HoverHint, {
1250
+ /* @__PURE__ */ jsx(_HoverHint, {
1926
1251
  anchor: anchor,
1927
1252
  disabled: !enabled || dragging,
1928
1253
  open: pointed,
@@ -2432,567 +1757,96 @@ function ForMeDetailPanel({activityName: activityName, instanceId: instanceId, o
2432
1757
  });
2433
1758
  }
2434
1759
 
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
- },
1760
+ function ForMeTables({loading: loading, now: now, onNavigateKey: onNavigateKey, onSelect: onSelect, onSort: onSort, selectedId: selectedId, selectedRef: selectedRef, sort: sort, sections: sections}) {
1761
+ return loading ? /* @__PURE__ */ jsxs(Fragment, {
2600
1762
  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
- })
1763
+ /* @__PURE__ */ jsx(LoadingRow, {
1764
+ label: "Loading…",
1765
+ padding: 2
1766
+ }), selectedId === void 0 ? null : /* @__PURE__ */ jsx(LoadingTablePlaceholder, {
1767
+ children: /* @__PURE__ */ jsx(ForMeTable, {
1768
+ now: now,
1769
+ onNavigateKey: onNavigateKey,
1770
+ onSelect: onSelect,
1771
+ onSort: onSort,
1772
+ rows: [],
1773
+ selectedId: void 0,
1774
+ selectedRef: selectedRef,
1775
+ sort: sort
2638
1776
  })
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,
1777
+ }) ]
1778
+ }) : sections.assignedToUser.length === 0 && sections.assignedToRoles.length === 0 ? /* @__PURE__ */ jsx(ForMeEmptyState, {}) : /* @__PURE__ */ jsxs(Stack, {
1779
+ gap: 6,
2649
1780
  children: [
2650
- /* @__PURE__ */ jsx(OverlineHeading, {
2651
- children: "Tasks in this stage"
1781
+ /* @__PURE__ */ jsx(ForMeSection, {
1782
+ description: /* @__PURE__ */ jsx(ForMeSectionCount, {
1783
+ rows: sections.assignedToUser
1784
+ }),
1785
+ now: now,
1786
+ onNavigateKey: onNavigateKey,
1787
+ onSelect: onSelect,
1788
+ onSort: onSort,
1789
+ rows: sections.assignedToUser,
1790
+ selectedId: selectedId,
1791
+ selectedRef: selectedRef,
1792
+ sort: sort,
1793
+ title: FOR_ME_SECTION_COPY.assignedTitle
2652
1794
  }),
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))
1795
+ /* @__PURE__ */ jsx(ForMeSection, {
1796
+ description: FOR_ME_SECTION_COPY.roleDescription,
1797
+ now: now,
1798
+ onNavigateKey: onNavigateKey,
1799
+ onSelect: onSelect,
1800
+ onSort: onSort,
1801
+ rows: sections.assignedToRoles,
1802
+ selectedId: selectedId,
1803
+ selectedRef: selectedRef,
1804
+ sort: sort,
1805
+ title: FOR_ME_SECTION_COPY.roleTitle
2660
1806
  }) ]
2661
1807
  });
2662
1808
  }
2663
1809
 
2664
- function TaskCardRow({displayById: displayById, now: now, task: task}) {
2665
- const mark = taskAssignmentMarkOf(task.assignees);
2666
- /* @__PURE__ */
2667
- return jsxs(Stack, {
1810
+ function ForMeSection({description: description, now: now, onNavigateKey: onNavigateKey, onSelect: onSelect, onSort: onSort, rows: rows, selectedId: selectedId, selectedRef: selectedRef, sort: sort, title: title}) {
1811
+ return rows.length === 0 ? null : /* @__PURE__ */ jsxs(Stack, {
2668
1812
  gap: 3,
2669
1813
  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
- }) ]
1814
+ /* @__PURE__ */ jsx(ForMeSectionHeading, {
1815
+ description: description,
1816
+ title: title
2689
1817
  }),
2690
- /* @__PURE__ */ jsx(AssignmentLine, {
2691
- displayById: displayById,
2692
- mark: mark,
1818
+ /* @__PURE__ */ jsx(ForMeTable, {
2693
1819
  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"
1820
+ onNavigateKey: onNavigateKey,
1821
+ onSelect: onSelect,
1822
+ onSort: onSort,
1823
+ rows: rows,
1824
+ selectedId: selectedId,
1825
+ selectedRef: selectedRef,
1826
+ sort: sort
2710
1827
  }) ]
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
1828
  });
2732
1829
  }
2733
1830
 
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)));
1831
+ function ForMeSectionCount({rows: rows}) {
1832
+ const summary = forMeSummaryOf(rows);
2740
1833
  /* @__PURE__ */
2741
1834
  return jsxs(Flex, {
2742
1835
  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,
1836
+ gap: 1,
2925
1837
  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
- })
1838
+ /* @__PURE__ */ jsx(Text, {
1839
+ size: 1,
1840
+ weight: "semibold",
1841
+ children: summary.lead
1842
+ }),
1843
+ /* @__PURE__ */ jsx(Text, {
1844
+ muted: !0,
1845
+ size: 1,
1846
+ children: summary.subjects
2993
1847
  }) ]
2994
1848
  });
2995
- });
1849
+ }
2996
1850
 
2997
1851
  function AbortWorkflowSection({entry: entry}) {
2998
1852
  const [aborting, setAborting] = useState(!1);
@@ -3270,7 +2124,7 @@ function ForMeWorkArea({previews: previews, loading: loading, model: model, now:
3270
2124
  loading: loading,
3271
2125
  previews: previews,
3272
2126
  resetKey: `${sort.dir}:${sort.key}`,
3273
- children: /* @__PURE__ */ jsx(ForMeBody, {
2127
+ children: /* @__PURE__ */ jsx(ForMeTables, {
3274
2128
  loading: loading,
3275
2129
  now: now,
3276
2130
  onNavigateKey: keyboardNavigation.onKeyDown,
@@ -3295,97 +2149,6 @@ function ForMeWorkArea({previews: previews, loading: loading, model: model, now:
3295
2149
  });
3296
2150
  }
3297
2151
 
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
2152
  function defaultRunSort(scope) {
3390
2153
  return scope === "closed" ? {
3391
2154
  key: "ended",
@@ -3411,17 +2174,11 @@ function sortRunRows(args) {
3411
2174
  return [ ...rows ].sort((a, b) => dir * primary(a, b) || tiebreak(a, b));
3412
2175
  }
3413
2176
 
3414
- function documentTitleKey(row, titles) {
3415
- return row.document === void 0 ? "" : titles.get(row.document.id) ?? "";
3416
- }
3417
-
3418
2177
  function comparatorFor(key, titles) {
3419
2178
  switch (key) {
3420
2179
  case "document":
3421
- return (a, b) => documentTitleKey(a, titles).localeCompare(documentTitleKey(b, titles));
3422
-
3423
2180
  case "workflow":
3424
- return (a, b) => a.workflowTitle.localeCompare(b.workflowTitle);
2181
+ return namedRowComparator(key, titles);
3425
2182
 
3426
2183
  case "stage":
3427
2184
  return (a, b) => a.stageTitle.localeCompare(b.stageTitle);
@@ -3455,7 +2212,7 @@ function cardFacts(args) {
3455
2212
  now: args.now,
3456
2213
  preview: preview
3457
2214
  }),
3458
- blocked: blockedRunDetail({
2215
+ blocked: settled ? void 0 : blockedRunDetail({
3459
2216
  definition: args.definition,
3460
2217
  preview: preview
3461
2218
  }),
@@ -3814,9 +2571,9 @@ function boardDocuments(board) {
3814
2571
  const CARD_RADIUS = 3;
3815
2572
 
3816
2573
  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);
2574
+ 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
2575
  /* @__PURE__ */
3819
- return jsx(Card, {
2576
+ return jsxs(Card, {
3820
2577
  "aria-pressed": selected,
3821
2578
  as: "button",
3822
2579
  onClick: event => {
@@ -3830,18 +2587,32 @@ function BoardCard({card: card, wiring: wiring}) {
3830
2587
  border: `1px solid ${color.border}`,
3831
2588
  display: "flex",
3832
2589
  flexDirection: "column",
2590
+ position: "relative",
3833
2591
  textAlign: "left",
3834
2592
  width: "100%"
3835
2593
  },
3836
2594
  ...selected ? {
3837
2595
  ref: selectedRef
3838
2596
  } : {},
3839
- children: /* @__PURE__ */ jsxs(Stack, {
2597
+ children: [ held === void 0 || blocked === void 0 ? null : /* @__PURE__ */ jsx(Box, {
2598
+ style: {
2599
+ position: "absolute",
2600
+ right: faceInset,
2601
+ top: faceInset
2602
+ },
2603
+ children: /* @__PURE__ */ jsx(AttentionMark, {
2604
+ detail: blocked,
2605
+ now: now,
2606
+ tasks: held.tasks
2607
+ })
2608
+ }),
2609
+ /* @__PURE__ */ jsxs(Stack, {
3840
2610
  gap: 2,
3841
2611
  children: [
3842
2612
  /* @__PURE__ */ jsx(Box, {
3843
2613
  style: {
3844
2614
  minWidth: 0,
2615
+ paddingRight: blocked === void 0 ? void 0 : markClearance,
3845
2616
  ...card.face.kind === "document" ? {
3846
2617
  margin: `${-faceInset}px 0 ${-faceInset}px ${-faceInset}px`
3847
2618
  } : {}
@@ -3859,13 +2630,13 @@ function BoardCard({card: card, wiring: wiring}) {
3859
2630
  facts: held,
3860
2631
  now: now
3861
2632
  }) ]
3862
- })
2633
+ }) ]
3863
2634
  });
3864
2635
  }
3865
2636
 
3866
2637
  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, {
2638
+ const markOverhang = -useCapTrimFor(useTextIconSize());
2639
+ return facts.settled || facts.tasks.length === 0 && facts.overdueDetail === void 0 ? null : /* @__PURE__ */ jsx(Box, {
3869
2640
  padding: 1,
3870
2641
  children: /* @__PURE__ */ jsxs(Flex, {
3871
2642
  align: "center",
@@ -3874,8 +2645,7 @@ function CardMetrics({facts: facts, now: now}) {
3874
2645
  /* @__PURE__ */ jsx(StageTaskGroups, {
3875
2646
  now: now,
3876
2647
  tasks: facts.tasks
3877
- }),
3878
- /* @__PURE__ */ jsxs(Flex, {
2648
+ }), facts.overdueDetail === void 0 ? null : /* @__PURE__ */ jsx(Flex, {
3879
2649
  align: "center",
3880
2650
  flex: 1,
3881
2651
  gap: 3,
@@ -3883,15 +2653,11 @@ function CardMetrics({facts: facts, now: now}) {
3883
2653
  style: {
3884
2654
  paddingRight: markOverhang
3885
2655
  },
3886
- children: [ facts.overdueDetail === void 0 ? null : /* @__PURE__ */ jsx(AttentionMark, {
2656
+ children: /* @__PURE__ */ jsx(AttentionMark, {
3887
2657
  detail: facts.overdueDetail,
3888
2658
  now: now,
3889
2659
  tasks: facts.tasks
3890
- }), facts.blocked === void 0 ? null : /* @__PURE__ */ jsx(AttentionMark, {
3891
- detail: facts.blocked,
3892
- now: now,
3893
- tasks: facts.tasks
3894
- }) ]
2660
+ })
3895
2661
  }) ]
3896
2662
  })
3897
2663
  });
@@ -4614,7 +3380,7 @@ function Segment({active: active, joined: joined, mode: mode, onPick: onPick, op
4614
3380
  tone: tone
4615
3381
  }
4616
3382
  });
4617
- return option.tooltip === void 0 ? button : /* @__PURE__ */ jsx(HoverHint, {
3383
+ return option.tooltip === void 0 ? button : /* @__PURE__ */ jsx(_HoverHint, {
4618
3384
  text: option.tooltip,
4619
3385
  children: button
4620
3386
  });
@@ -5825,272 +4591,6 @@ function walkIdOf(view) {
5825
4591
  if (view.run !== void 0) return view.task === void 0 ? view.run : forMeRowId(view.run, view.task);
5826
4592
  }
5827
4593
 
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
4594
  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
4595
  const columnStyle = useWorkColumnStyle({
6096
4596
  boardMode: boardMode,
@@ -6305,10 +4805,9 @@ const RunsTab = memo(function({addressed: addressed, filterSlot: filterSlot, for
6305
4805
  scoped: scoped,
6306
4806
  view: view
6307
4807
  }), taskRows = useMemo(() => forMeIdentity === void 0 ? [] : forMeTaskRowsOf({
6308
- now: now,
6309
4808
  rows: filtered,
6310
4809
  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({
4810
+ }), [ 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
4811
  rows: taskRows,
6313
4812
  sort: forMeSort,
6314
4813
  titles: titles.titles