@sanity/workflow-studio-plugin 0.23.0 → 0.24.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +136 -0
- package/README.md +11 -4
- package/dist/_chunks-cjs/index.cjs +1041 -439
- package/dist/_chunks-cjs/workflows-tool-root.cjs +2016 -664
- package/dist/_chunks-es/index.js +998 -440
- package/dist/_chunks-es/workflows-tool-root.js +2056 -692
- package/package.json +12 -12
|
@@ -1,84 +1,1306 @@
|
|
|
1
1
|
import { jsx, jsxs, Fragment } from "react/jsx-runtime";
|
|
2
2
|
|
|
3
|
-
import { Box, Text, Flex, Stack,
|
|
3
|
+
import { Box, Text, Card, Flex, Stack, MenuButton, Menu, MenuItem, Button, Badge, Dialog, TextInput, useTheme_v2, TabPanel } from "@sanity/ui";
|
|
4
4
|
|
|
5
|
-
import { useWorkflowTelemetry
|
|
5
|
+
import { useWorkflowTelemetry } from "@sanity/workflow-react";
|
|
6
6
|
|
|
7
|
-
import { useState, useEffect,
|
|
7
|
+
import { useMemo, useSyncExternalStore, useCallback, useState, useEffect, useRef } from "react";
|
|
8
8
|
|
|
9
9
|
import { useRouter } from "sanity/router";
|
|
10
10
|
|
|
11
|
-
import {
|
|
11
|
+
import { createSubscribers, useWorkflowContext, readDeployedDefinitions, describeError, useDelayedFlag, instanceTitle, definitionSnapshotOf, stageTitle, DocPreviewLink, NOTICE_PADDING, chipPadding, CountedLabel, useSpaceToken, useRadiusToken, HoverHint, definitionFingerprint, CollapsibleBand, gdrLocality, openableSchemaType, WORKFLOW_API_VERSION, WorkflowTitleSeedDrifted, WorkflowBoardLayoutChanged, UnreadableDocsNote, LogEventOnMount, WorkflowBoardWorkflowSelected, LoadingRow, EmptyState, mappingIssueDetail, formatTimeAgo, formatShortDateTime, namesNoDeployedDefinition, SpinnerSlot, WorkflowDefinitionDetailViewed, useContainerToken, MetaRow, CautionNote, useBadgeCapTrim, TOAST_ID, useDefinition, useWorkflowToast, isLiveEntry, UserAvatar, formatShortAgo, formatDateTime, useAvatarSize, HintedMenuButton, useUserDisplay, useWorkflowInstanceEntry, useLogEventOnMount, WorkflowInstanceDetailViewed, InvalidDocNotice, openActivityGone, isEvaluationStale, InstanceSnapshotBody, ActivityDetailDialog, instanceBreadcrumb, DismissablePopover, findActivity, stateByActivity, findActivityNode, rowDateControlState, rowAssignControlState, isActivityAssignedTo, assigneeUserIdsOf, isOpenActivityStatus, isDateFieldKind, committedRowFace, activityRowProps, formatDate, parseStoredDateValue, useUserDisplays, useProjectMembers, WorkflowTaskFiltersApplied, DocRefFace, useEditField, useSaveField, dateControlValue, stopRowMouseDown, stopRowClick, dateControlKind, parseDateFieldValue, hasTimeOfDay, serializeDateFieldValue, LinkChip, BreadcrumbTail, StageFace, TrailingHairline, StaleLock, ActivityRow, ForMeEmptyState, pathSegmentTab, TabSwitch, WorkflowToolOpened, useAssignmentIdentity } from "./index.js";
|
|
12
|
+
|
|
13
|
+
import { SearchIcon } from "@sanity/icons/Search";
|
|
14
|
+
|
|
15
|
+
import { latestDeployedDefinitions, entryDocRefs, terminalState, startKindOf, isSubjectEntry, isInputSourced, isStartableDefinition, toBareId, findOpenStageEntry } from "@sanity/workflow-engine";
|
|
16
|
+
|
|
17
|
+
import { ChevronDownIcon } from "@sanity/icons/ChevronDown";
|
|
18
|
+
|
|
19
|
+
import { InlineIcon } from "@sanity/icons/Inline";
|
|
20
|
+
|
|
21
|
+
import { StackCompactIcon } from "@sanity/icons/StackCompact";
|
|
22
|
+
|
|
23
|
+
import { createPortal } from "react-dom";
|
|
24
|
+
|
|
25
|
+
import { isReferenceSchemaType } from "@sanity/types";
|
|
26
|
+
|
|
27
|
+
import { useDocumentPreviewStore, useSchema, usePerspective, useClient } from "sanity";
|
|
28
|
+
|
|
29
|
+
import { useWorkflowInstances } from "@sanity/workflow-studio";
|
|
30
|
+
|
|
31
|
+
import { WarningOutlineIcon } from "@sanity/icons/WarningOutline";
|
|
12
32
|
|
|
13
33
|
import { WorkflowDiagram } from "@sanity/workflow-diagram";
|
|
14
34
|
|
|
15
|
-
import {
|
|
35
|
+
import { ArrowLeftIcon } from "@sanity/icons/ArrowLeft";
|
|
36
|
+
|
|
37
|
+
import { InfoOutlineIcon } from "@sanity/icons/InfoOutline";
|
|
38
|
+
|
|
39
|
+
import { TransferIcon } from "@sanity/icons/Transfer";
|
|
40
|
+
|
|
41
|
+
import pluralize from "pluralize-esm";
|
|
42
|
+
|
|
43
|
+
import { ClockIcon } from "@sanity/icons/Clock";
|
|
44
|
+
|
|
45
|
+
import { CogIcon } from "@sanity/icons/Cog";
|
|
46
|
+
|
|
47
|
+
import { EllipsisHorizontalIcon } from "@sanity/icons/EllipsisHorizontal";
|
|
48
|
+
|
|
49
|
+
import { AddIcon } from "@sanity/icons/Add";
|
|
50
|
+
|
|
51
|
+
import { CheckmarkIcon } from "@sanity/icons/Checkmark";
|
|
52
|
+
|
|
53
|
+
import { CloseIcon } from "@sanity/icons/Close";
|
|
54
|
+
|
|
55
|
+
import { FilterIcon } from "@sanity/icons/Filter";
|
|
56
|
+
|
|
57
|
+
import { MemberAvatar, DatePicker, ClearableDatePicker } from "@sanity/workflow-components";
|
|
58
|
+
|
|
59
|
+
import { endOfDay } from "date-fns/endOfDay";
|
|
60
|
+
|
|
61
|
+
import { CalendarIcon } from "@sanity/icons/Calendar";
|
|
62
|
+
|
|
63
|
+
function MutedNote({text: text}) {
|
|
64
|
+
/* @__PURE__ */
|
|
65
|
+
return jsx(Box, {
|
|
66
|
+
paddingY: 3,
|
|
67
|
+
children: /* @__PURE__ */ jsx(Text, {
|
|
68
|
+
muted: !0,
|
|
69
|
+
size: 1,
|
|
70
|
+
children: text
|
|
71
|
+
})
|
|
72
|
+
});
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
function TabStatusRow({children: children}) {
|
|
76
|
+
/* @__PURE__ */
|
|
77
|
+
return jsx(Box, {
|
|
78
|
+
paddingLeft: 2,
|
|
79
|
+
paddingY: 3,
|
|
80
|
+
children: children
|
|
81
|
+
});
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
const TOOL_PANEL_PADDING = 3, UNREADABLE = {
|
|
85
|
+
readable: !1,
|
|
86
|
+
raw: void 0
|
|
87
|
+
};
|
|
88
|
+
|
|
89
|
+
function defaultStorage() {
|
|
90
|
+
try {
|
|
91
|
+
return globalThis.localStorage;
|
|
92
|
+
} catch {
|
|
93
|
+
return;
|
|
94
|
+
}
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
function readItem(storage, key) {
|
|
98
|
+
if (!storage) return UNREADABLE;
|
|
99
|
+
try {
|
|
100
|
+
const raw = storage.getItem(key);
|
|
101
|
+
return {
|
|
102
|
+
readable: !0,
|
|
103
|
+
raw: raw === null ? void 0 : raw
|
|
104
|
+
};
|
|
105
|
+
} catch {
|
|
106
|
+
return UNREADABLE;
|
|
107
|
+
}
|
|
108
|
+
}
|
|
109
|
+
|
|
110
|
+
function writeItem(args) {
|
|
111
|
+
if (!args.storage) return !1;
|
|
112
|
+
try {
|
|
113
|
+
return args.storage.setItem(args.key, args.value), !0;
|
|
114
|
+
} catch {
|
|
115
|
+
return !1;
|
|
116
|
+
}
|
|
117
|
+
}
|
|
118
|
+
|
|
119
|
+
const BAND_DEFAULT_OPEN = !0, UNGROUPED_BAND_KEY = "section:no-document", PAYLOAD_VERSION = 2, MAX_ENTRIES = 200;
|
|
120
|
+
|
|
121
|
+
function bandStateStorageKey(scope) {
|
|
122
|
+
return `sanity.workflows.tool.bands:${scope}`;
|
|
123
|
+
}
|
|
124
|
+
|
|
125
|
+
function isRecord(value) {
|
|
126
|
+
return typeof value == "object" && value !== null && !Array.isArray(value);
|
|
127
|
+
}
|
|
128
|
+
|
|
129
|
+
function bandEntryOf(value) {
|
|
130
|
+
if (!isRecord(value)) return;
|
|
131
|
+
const {open: open, touched: touched} = value;
|
|
132
|
+
if (!(typeof open != "boolean" || typeof touched != "number") && Number.isFinite(touched)) return {
|
|
133
|
+
open: open,
|
|
134
|
+
touched: touched
|
|
135
|
+
};
|
|
136
|
+
}
|
|
137
|
+
|
|
138
|
+
function parsePayload(raw) {
|
|
139
|
+
try {
|
|
140
|
+
const parsed = JSON.parse(raw);
|
|
141
|
+
if (!isRecord(parsed) || parsed.version !== PAYLOAD_VERSION || !isRecord(parsed.bands)) return;
|
|
142
|
+
const entries = [];
|
|
143
|
+
for (const [key, value] of Object.entries(parsed.bands)) {
|
|
144
|
+
const entry = bandEntryOf(value);
|
|
145
|
+
if (entry === void 0) return;
|
|
146
|
+
entries.push([ key, entry ]);
|
|
147
|
+
}
|
|
148
|
+
return Object.fromEntries(entries);
|
|
149
|
+
} catch {
|
|
150
|
+
return;
|
|
151
|
+
}
|
|
152
|
+
}
|
|
153
|
+
|
|
154
|
+
function readStored(storage, storageKey) {
|
|
155
|
+
const {readable: readable, raw: raw} = readItem(storage, storageKey);
|
|
156
|
+
if (!readable) return {
|
|
157
|
+
entries: void 0,
|
|
158
|
+
corrupt: !1
|
|
159
|
+
};
|
|
160
|
+
if (raw === void 0) return {
|
|
161
|
+
entries: {},
|
|
162
|
+
corrupt: !1
|
|
163
|
+
};
|
|
164
|
+
const entries = parsePayload(raw);
|
|
165
|
+
return {
|
|
166
|
+
entries: entries,
|
|
167
|
+
corrupt: entries === void 0
|
|
168
|
+
};
|
|
169
|
+
}
|
|
170
|
+
|
|
171
|
+
function writeStored(args) {
|
|
172
|
+
return writeItem({
|
|
173
|
+
storage: args.storage,
|
|
174
|
+
key: args.storageKey,
|
|
175
|
+
value: JSON.stringify({
|
|
176
|
+
version: PAYLOAD_VERSION,
|
|
177
|
+
bands: args.entries
|
|
178
|
+
})
|
|
179
|
+
});
|
|
180
|
+
}
|
|
181
|
+
|
|
182
|
+
function baseEntries(args) {
|
|
183
|
+
return args.stored === void 0 ? args.held : args.unpersisted ? mergeByTouched(args.stored, args.held) : args.stored;
|
|
184
|
+
}
|
|
185
|
+
|
|
186
|
+
function mergeByTouched(stored, held) {
|
|
187
|
+
const merged = {
|
|
188
|
+
...stored
|
|
189
|
+
};
|
|
190
|
+
for (const [key, entry] of Object.entries(held)) {
|
|
191
|
+
const persisted = merged[key];
|
|
192
|
+
(persisted === void 0 || entry.touched >= persisted.touched) && (merged[key] = entry);
|
|
193
|
+
}
|
|
194
|
+
return merged;
|
|
195
|
+
}
|
|
196
|
+
|
|
197
|
+
function prune(entries) {
|
|
198
|
+
const held = Object.entries(entries);
|
|
199
|
+
return held.length <= MAX_ENTRIES ? entries : Object.fromEntries(held.sort(([, a], [, b]) => b.touched - a.touched).slice(0, MAX_ENTRIES));
|
|
200
|
+
}
|
|
201
|
+
|
|
202
|
+
function togglesOf(entries) {
|
|
203
|
+
return new Map(Object.entries(entries).map(([key, entry]) => [ key, entry.open ]));
|
|
204
|
+
}
|
|
205
|
+
|
|
206
|
+
function createBandStateStore(args) {
|
|
207
|
+
const storage = args.storage ?? defaultStorage(), initial = readStored(storage, args.storageKey);
|
|
208
|
+
initial.corrupt && writeStored({
|
|
209
|
+
storage: storage,
|
|
210
|
+
storageKey: args.storageKey,
|
|
211
|
+
entries: {}
|
|
212
|
+
});
|
|
213
|
+
let held = initial.entries ?? {}, toggles = togglesOf(held);
|
|
214
|
+
const subscribers = createSubscribers();
|
|
215
|
+
let unpersisted = !1;
|
|
216
|
+
return {
|
|
217
|
+
subscribe: subscribers.subscribe,
|
|
218
|
+
read: () => toggles,
|
|
219
|
+
setOpen(key, open) {
|
|
220
|
+
const stored = readStored(storage, args.storageKey).entries, base = baseEntries({
|
|
221
|
+
stored: stored,
|
|
222
|
+
held: held,
|
|
223
|
+
unpersisted: unpersisted
|
|
224
|
+
});
|
|
225
|
+
held = prune({
|
|
226
|
+
...base,
|
|
227
|
+
[key]: {
|
|
228
|
+
open: open,
|
|
229
|
+
touched: Date.now()
|
|
230
|
+
}
|
|
231
|
+
}), toggles = togglesOf(held), unpersisted = !writeStored({
|
|
232
|
+
storage: storage,
|
|
233
|
+
storageKey: args.storageKey,
|
|
234
|
+
entries: held
|
|
235
|
+
}), subscribers.notify();
|
|
236
|
+
}
|
|
237
|
+
};
|
|
238
|
+
}
|
|
239
|
+
|
|
240
|
+
function useBandOpenState(args) {
|
|
241
|
+
const {segment: segment, scope: scope} = args, store = useMemo(() => createBandStateStore({
|
|
242
|
+
storageKey: bandStateStorageKey(scope)
|
|
243
|
+
}), [ scope ]);
|
|
244
|
+
return useMemo(() => ({
|
|
245
|
+
segment: segment,
|
|
246
|
+
store: store
|
|
247
|
+
}), [ segment, store ]);
|
|
248
|
+
}
|
|
249
|
+
|
|
250
|
+
function openOf(store, qualified) {
|
|
251
|
+
return store.read().get(qualified) ?? BAND_DEFAULT_OPEN;
|
|
252
|
+
}
|
|
253
|
+
|
|
254
|
+
function useBandOpen(bands, key) {
|
|
255
|
+
const {segment: segment, store: store} = bands, qualified = `${segment}/${key}`;
|
|
256
|
+
return {
|
|
257
|
+
open: useSyncExternalStore(store.subscribe, useCallback(() => openOf(store, qualified), [ store, qualified ])),
|
|
258
|
+
toggle: () => store.setOpen(qualified, !openOf(store, qualified))
|
|
259
|
+
};
|
|
260
|
+
}
|
|
261
|
+
|
|
262
|
+
const lastRead = /* @__PURE__ */ new WeakMap, issuedReads = /* @__PURE__ */ new WeakMap;
|
|
263
|
+
|
|
264
|
+
function useDeployedDefinitions() {
|
|
265
|
+
const {engine: engine} = useWorkflowContext(), [definitions, setDefinitions] = useState(() => lastRead.get(engine)?.rows), [error, setError] = useState(void 0);
|
|
266
|
+
return useEffect(() => {
|
|
267
|
+
let cancelled = !1;
|
|
268
|
+
setDefinitions(lastRead.get(engine)?.rows), setError(void 0);
|
|
269
|
+
const seq = (issuedReads.get(engine) ?? 0) + 1;
|
|
270
|
+
return issuedReads.set(engine, seq), (async () => {
|
|
271
|
+
const rows = await readDeployedDefinitions(engine), latest = latestDeployedDefinitions(rows), held = lastRead.get(engine);
|
|
272
|
+
(held === void 0 || seq > held.seq) && lastRead.set(engine, {
|
|
273
|
+
seq: seq,
|
|
274
|
+
rows: latest
|
|
275
|
+
}), cancelled || (setDefinitions(latest), setError(void 0));
|
|
276
|
+
})().catch(err => {
|
|
277
|
+
cancelled || setError(describeError(err));
|
|
278
|
+
}), () => {
|
|
279
|
+
cancelled = !0;
|
|
280
|
+
};
|
|
281
|
+
}, [ engine ]), {
|
|
282
|
+
definitions: definitions,
|
|
283
|
+
error: error
|
|
284
|
+
};
|
|
285
|
+
}
|
|
286
|
+
|
|
287
|
+
const REVEAL_MAX_WAIT_MS = 2e3;
|
|
288
|
+
|
|
289
|
+
function useRevealGate(args) {
|
|
290
|
+
const {loading: loading, ready: ready} = args, settled = !loading && ready, expired = useDelayedFlag(!loading && !ready, REVEAL_MAX_WAIT_MS), [revealed, setRevealed] = useState(!1);
|
|
291
|
+
return useEffect(() => {
|
|
292
|
+
!revealed && (settled || expired) && setRevealed(!0);
|
|
293
|
+
}, [ expired, revealed, settled ]), revealed || settled || expired;
|
|
294
|
+
}
|
|
295
|
+
|
|
296
|
+
function documentRefsOf(instance) {
|
|
297
|
+
const seen = /* @__PURE__ */ new Map;
|
|
298
|
+
for (const ref of entryDocRefs(instance.fields)) seen.has(ref.id) || seen.set(ref.id, ref);
|
|
299
|
+
return [ ...seen.values() ];
|
|
300
|
+
}
|
|
301
|
+
|
|
302
|
+
function byTitleThenName(a, b) {
|
|
303
|
+
return a.title.localeCompare(b.title) || a.name.localeCompare(b.name);
|
|
304
|
+
}
|
|
305
|
+
|
|
306
|
+
function byResolvedTitle(titleOf, keyOf) {
|
|
307
|
+
return (a, b) => {
|
|
308
|
+
const aTitle = titleOf(a), bTitle = titleOf(b);
|
|
309
|
+
return aTitle !== void 0 && bTitle !== void 0 ? aTitle.localeCompare(bTitle) || keyOf(a).localeCompare(keyOf(b)) : aTitle !== void 0 ? -1 : bTitle !== void 0 ? 1 : keyOf(a).localeCompare(keyOf(b));
|
|
310
|
+
};
|
|
311
|
+
}
|
|
312
|
+
|
|
313
|
+
const BOARD_EMPTY_STAGE_NOTE = "No items";
|
|
314
|
+
|
|
315
|
+
function faceOf(instance) {
|
|
316
|
+
const document = documentRefsOf(instance)[0];
|
|
317
|
+
return document ? {
|
|
318
|
+
kind: "document",
|
|
319
|
+
document: document
|
|
320
|
+
} : {
|
|
321
|
+
kind: "instance",
|
|
322
|
+
title: instanceTitle(instance, definitionSnapshotOf(instance))
|
|
323
|
+
};
|
|
324
|
+
}
|
|
325
|
+
|
|
326
|
+
function boardRuns(instances) {
|
|
327
|
+
return instances.filter(instance => terminalState(instance) !== "aborted");
|
|
328
|
+
}
|
|
329
|
+
|
|
330
|
+
function groupsOf(args) {
|
|
331
|
+
const declared = args.definition.stages.map(stage => stage.name), retired = [ ...args.byStage.keys() ].filter(stage => !declared.includes(stage)).sort();
|
|
332
|
+
return [ ...declared, ...retired ].map(stage => ({
|
|
333
|
+
stage: stage,
|
|
334
|
+
title: stageTitle(args.definition, stage),
|
|
335
|
+
cards: args.byStage.get(stage) ?? [],
|
|
336
|
+
retired: !declared.includes(stage)
|
|
337
|
+
}));
|
|
338
|
+
}
|
|
339
|
+
|
|
340
|
+
function deriveBoard(args) {
|
|
341
|
+
const byStage = /* @__PURE__ */ new Map;
|
|
342
|
+
for (const instance of boardRuns(args.instances)) {
|
|
343
|
+
const card = {
|
|
344
|
+
instanceId: instance._id,
|
|
345
|
+
face: faceOf(instance)
|
|
346
|
+
}, held = byStage.get(instance.currentStage);
|
|
347
|
+
held ? held.push(card) : byStage.set(instance.currentStage, [ card ]);
|
|
348
|
+
}
|
|
349
|
+
return {
|
|
350
|
+
groups: groupsOf({
|
|
351
|
+
definition: args.definition,
|
|
352
|
+
byStage: byStage
|
|
353
|
+
})
|
|
354
|
+
};
|
|
355
|
+
}
|
|
356
|
+
|
|
357
|
+
function orderBoardByPreviewTitle(board, titles) {
|
|
358
|
+
const compare = byResolvedTitle(card => card.face.kind === "instance" ? card.face.title : titles.get(card.face.document.id), card => card.instanceId);
|
|
359
|
+
return {
|
|
360
|
+
groups: board.groups.map(group => ({
|
|
361
|
+
...group,
|
|
362
|
+
cards: [ ...group.cards ].sort(compare)
|
|
363
|
+
}))
|
|
364
|
+
};
|
|
365
|
+
}
|
|
366
|
+
|
|
367
|
+
function boardDocuments(board) {
|
|
368
|
+
return board.groups.flatMap(group => group.cards.flatMap(card => card.face.kind === "document" ? [ card.face.document ] : []));
|
|
369
|
+
}
|
|
370
|
+
|
|
371
|
+
function BoardCard({card: card, size: size}) {
|
|
372
|
+
return size === "slim" ? card.face.kind === "instance" ? /* @__PURE__ */ jsx(InstanceFace, {
|
|
373
|
+
size: size,
|
|
374
|
+
title: card.face.title
|
|
375
|
+
}) : /* @__PURE__ */ jsx(DocPreviewLink, {
|
|
376
|
+
gdr: card.face.document,
|
|
377
|
+
layout: "row",
|
|
378
|
+
source: "board-card"
|
|
379
|
+
}) : /* @__PURE__ */ jsx(Card, {
|
|
380
|
+
border: !0,
|
|
381
|
+
radius: 3,
|
|
382
|
+
children: card.face.kind === "instance" ? /* @__PURE__ */ jsx(InstanceFace, {
|
|
383
|
+
size: size,
|
|
384
|
+
title: card.face.title
|
|
385
|
+
}) : /* @__PURE__ */ jsx(DocPreviewLink, {
|
|
386
|
+
gdr: card.face.document,
|
|
387
|
+
layout: "bare",
|
|
388
|
+
source: "board-card"
|
|
389
|
+
})
|
|
390
|
+
});
|
|
391
|
+
}
|
|
392
|
+
|
|
393
|
+
function InstanceFace({size: size, title: title}) {
|
|
394
|
+
const fill = size === "slim";
|
|
395
|
+
/* @__PURE__ */
|
|
396
|
+
return jsx(Box, {
|
|
397
|
+
padding: fill ? chipPadding(!0) : NOTICE_PADDING,
|
|
398
|
+
style: fill ? {
|
|
399
|
+
width: "100%"
|
|
400
|
+
} : {},
|
|
401
|
+
children: /* @__PURE__ */ jsx(Text, {
|
|
402
|
+
size: 1,
|
|
403
|
+
textOverflow: "ellipsis",
|
|
404
|
+
weight: "medium",
|
|
405
|
+
children: title
|
|
406
|
+
})
|
|
407
|
+
});
|
|
408
|
+
}
|
|
409
|
+
|
|
410
|
+
function StageGroupHeading({group: group}) {
|
|
411
|
+
/* @__PURE__ */
|
|
412
|
+
return jsxs(Flex, {
|
|
413
|
+
align: "center",
|
|
414
|
+
gap: 2,
|
|
415
|
+
children: [
|
|
416
|
+
/* @__PURE__ */ jsx(CountedLabel, {
|
|
417
|
+
count: group.cards.length,
|
|
418
|
+
label: /* @__PURE__ */ jsx(Text, {
|
|
419
|
+
size: 1,
|
|
420
|
+
weight: "medium",
|
|
421
|
+
children: group.title
|
|
422
|
+
})
|
|
423
|
+
}), group.retired ?
|
|
424
|
+
/* @__PURE__ */ jsx(Text, {
|
|
425
|
+
muted: !0,
|
|
426
|
+
size: 1,
|
|
427
|
+
children: "No longer in this workflow"
|
|
428
|
+
}) : null ]
|
|
429
|
+
});
|
|
430
|
+
}
|
|
431
|
+
|
|
432
|
+
const COLUMN_WIDTH = 320, PANEL_FADE = "linear-gradient(to bottom, rgb(0 0 0) 50%, rgb(0 0 0 / 0) 75%)";
|
|
433
|
+
|
|
434
|
+
function StageColumn({group: group}) {
|
|
435
|
+
/* @__PURE__ */
|
|
436
|
+
return jsxs(Box, {
|
|
437
|
+
flex: "none",
|
|
438
|
+
style: {
|
|
439
|
+
display: "flex",
|
|
440
|
+
flexDirection: "column",
|
|
441
|
+
position: "relative",
|
|
442
|
+
width: COLUMN_WIDTH
|
|
443
|
+
},
|
|
444
|
+
children: [
|
|
445
|
+
/* @__PURE__ */ jsx(Card, {
|
|
446
|
+
"aria-hidden": !0,
|
|
447
|
+
radius: 3,
|
|
448
|
+
style: {
|
|
449
|
+
inset: 0,
|
|
450
|
+
maskImage: PANEL_FADE,
|
|
451
|
+
position: "absolute",
|
|
452
|
+
WebkitMaskImage: PANEL_FADE
|
|
453
|
+
},
|
|
454
|
+
tone: "transparent"
|
|
455
|
+
}),
|
|
456
|
+
/* @__PURE__ */ jsx(Box, {
|
|
457
|
+
flex: "none",
|
|
458
|
+
paddingX: 3,
|
|
459
|
+
paddingY: 4,
|
|
460
|
+
style: {
|
|
461
|
+
position: "relative"
|
|
462
|
+
},
|
|
463
|
+
children: /* @__PURE__ */ jsx(StageGroupHeading, {
|
|
464
|
+
group: group
|
|
465
|
+
})
|
|
466
|
+
}), group.cards.length === 0 ?
|
|
467
|
+
/* @__PURE__ */ jsx(Flex, {
|
|
468
|
+
align: "center",
|
|
469
|
+
flex: 1,
|
|
470
|
+
justify: "center",
|
|
471
|
+
padding: 2,
|
|
472
|
+
style: {
|
|
473
|
+
position: "relative"
|
|
474
|
+
},
|
|
475
|
+
children: /* @__PURE__ */ jsx(Text, {
|
|
476
|
+
muted: !0,
|
|
477
|
+
size: 1,
|
|
478
|
+
children: BOARD_EMPTY_STAGE_NOTE
|
|
479
|
+
})
|
|
480
|
+
}) :
|
|
481
|
+
/* @__PURE__ */ jsx(Box, {
|
|
482
|
+
flex: 1,
|
|
483
|
+
overflow: "auto",
|
|
484
|
+
paddingBottom: 2,
|
|
485
|
+
paddingX: 2,
|
|
486
|
+
style: {
|
|
487
|
+
minHeight: 0,
|
|
488
|
+
position: "relative"
|
|
489
|
+
},
|
|
490
|
+
children: /* @__PURE__ */ jsx(Stack, {
|
|
491
|
+
gap: 1,
|
|
492
|
+
children: group.cards.map(card => /* @__PURE__ */ jsx(BoardCard, {
|
|
493
|
+
card: card,
|
|
494
|
+
size: "block"
|
|
495
|
+
}, card.instanceId))
|
|
496
|
+
})
|
|
497
|
+
}) ]
|
|
498
|
+
});
|
|
499
|
+
}
|
|
500
|
+
|
|
501
|
+
function StageGroups({board: board}) {
|
|
502
|
+
const topGap = useSpaceToken(TOOL_PANEL_PADDING);
|
|
503
|
+
/* @__PURE__ */
|
|
504
|
+
return jsx(Box, {
|
|
505
|
+
flex: 1,
|
|
506
|
+
style: {
|
|
507
|
+
minHeight: 0,
|
|
508
|
+
position: "relative"
|
|
509
|
+
},
|
|
510
|
+
children: /* @__PURE__ */ jsx(Box, {
|
|
511
|
+
style: {
|
|
512
|
+
bottom: 0,
|
|
513
|
+
left: 0,
|
|
514
|
+
overflowX: "auto",
|
|
515
|
+
overflowY: "hidden",
|
|
516
|
+
position: "absolute",
|
|
517
|
+
right: 0,
|
|
518
|
+
top: topGap
|
|
519
|
+
},
|
|
520
|
+
children: /* @__PURE__ */ jsx(Flex, {
|
|
521
|
+
align: "stretch",
|
|
522
|
+
gap: 2,
|
|
523
|
+
paddingX: TOOL_PANEL_PADDING,
|
|
524
|
+
style: {
|
|
525
|
+
boxSizing: "border-box",
|
|
526
|
+
height: "100%",
|
|
527
|
+
width: "max-content"
|
|
528
|
+
},
|
|
529
|
+
children: board.groups.map(group => /* @__PURE__ */ jsx(StageColumn, {
|
|
530
|
+
group: group
|
|
531
|
+
}, group.stage))
|
|
532
|
+
})
|
|
533
|
+
})
|
|
534
|
+
});
|
|
535
|
+
}
|
|
536
|
+
|
|
537
|
+
function isPlainClick(event) {
|
|
538
|
+
return !event.altKey && !event.ctrlKey && !event.metaKey && !event.shiftKey;
|
|
539
|
+
}
|
|
540
|
+
|
|
541
|
+
const BOARD_LAYOUTS = [ "columns", "stack" ], BOARD_DEFAULT_LAYOUT = "columns";
|
|
542
|
+
|
|
543
|
+
function boardLayoutStorageKey(scope) {
|
|
544
|
+
return `sanity.workflows.tool.board-layout:${scope}`;
|
|
545
|
+
}
|
|
546
|
+
|
|
547
|
+
function layoutOf(raw) {
|
|
548
|
+
return BOARD_LAYOUTS.find(layout => layout === raw) ?? BOARD_DEFAULT_LAYOUT;
|
|
549
|
+
}
|
|
550
|
+
|
|
551
|
+
function createBoardLayoutStore(args) {
|
|
552
|
+
const storage = args.storage ?? defaultStorage();
|
|
553
|
+
return {
|
|
554
|
+
read: () => layoutOf(readItem(storage, args.storageKey).raw),
|
|
555
|
+
set(layout) {
|
|
556
|
+
return writeItem({
|
|
557
|
+
storage: storage,
|
|
558
|
+
key: args.storageKey,
|
|
559
|
+
value: layout
|
|
560
|
+
}), layout;
|
|
561
|
+
}
|
|
562
|
+
};
|
|
563
|
+
}
|
|
564
|
+
|
|
565
|
+
const PICKER_RADIUS = 3;
|
|
566
|
+
|
|
567
|
+
function pickerLabel(face) {
|
|
568
|
+
return face.kind === "named" ? face.title : face.kind === "loading" ? "Loading" : "Select a workflow";
|
|
569
|
+
}
|
|
570
|
+
|
|
571
|
+
function WorkflowPicker({face: face, onSelect: onSelect, options: options}) {
|
|
572
|
+
const empty = options.length === 0, innerRadius = useRadiusToken(PICKER_RADIUS) - 1;
|
|
573
|
+
/* @__PURE__ */
|
|
574
|
+
return jsx(Card, {
|
|
575
|
+
border: !0,
|
|
576
|
+
radius: PICKER_RADIUS,
|
|
577
|
+
children: /* @__PURE__ */ jsxs(Flex, {
|
|
578
|
+
align: "center",
|
|
579
|
+
children: [
|
|
580
|
+
/* @__PURE__ */ jsx(Box, {
|
|
581
|
+
paddingLeft: 2,
|
|
582
|
+
paddingRight: 2,
|
|
583
|
+
children: /* @__PURE__ */ jsx(Text, {
|
|
584
|
+
muted: !0,
|
|
585
|
+
size: 1,
|
|
586
|
+
children: "Workflow"
|
|
587
|
+
})
|
|
588
|
+
}),
|
|
589
|
+
/* @__PURE__ */ jsx(MenuButton, {
|
|
590
|
+
button: /* @__PURE__ */ jsx(Button, {
|
|
591
|
+
fontSize: 1,
|
|
592
|
+
gap: 2,
|
|
593
|
+
iconRight: ChevronDownIcon,
|
|
594
|
+
mode: "bleed",
|
|
595
|
+
disabled: empty,
|
|
596
|
+
padding: 2,
|
|
597
|
+
radius: 0,
|
|
598
|
+
style: {
|
|
599
|
+
borderRadius: `0 ${innerRadius}px ${innerRadius}px 0`
|
|
600
|
+
},
|
|
601
|
+
text: pickerLabel(face)
|
|
602
|
+
}),
|
|
603
|
+
id: "workflows-board-picker",
|
|
604
|
+
menu: /* @__PURE__ */ jsx(Menu, {
|
|
605
|
+
children: options.map(option => /* @__PURE__ */ jsx(MenuItem, {
|
|
606
|
+
fontSize: 1,
|
|
607
|
+
onClick: () => onSelect(option.name),
|
|
608
|
+
pressed: face.kind === "named" && option.name === face.name,
|
|
609
|
+
text: option.title
|
|
610
|
+
}, option.name))
|
|
611
|
+
}),
|
|
612
|
+
popover: {
|
|
613
|
+
constrainSize: !0,
|
|
614
|
+
fallbackPlacements: [ "top-start" ],
|
|
615
|
+
placement: "bottom-start",
|
|
616
|
+
portal: !0
|
|
617
|
+
}
|
|
618
|
+
}) ]
|
|
619
|
+
})
|
|
620
|
+
});
|
|
621
|
+
}
|
|
622
|
+
|
|
623
|
+
const LAYOUT_LABELS = {
|
|
624
|
+
columns: {
|
|
625
|
+
icon: InlineIcon,
|
|
626
|
+
label: "Show as boards"
|
|
627
|
+
},
|
|
628
|
+
stack: {
|
|
629
|
+
icon: StackCompactIcon,
|
|
630
|
+
label: "Show as list"
|
|
631
|
+
}
|
|
632
|
+
};
|
|
633
|
+
|
|
634
|
+
function LayoutToggle({layout: layout, onChange: onChange}) {
|
|
635
|
+
/* @__PURE__ */
|
|
636
|
+
return jsx(Flex, {
|
|
637
|
+
align: "center",
|
|
638
|
+
gap: 1,
|
|
639
|
+
children: BOARD_LAYOUTS.map(value => {
|
|
640
|
+
const {icon: icon, label: label} = LAYOUT_LABELS[value];
|
|
641
|
+
/* @__PURE__ */
|
|
642
|
+
return jsx(HoverHint, {
|
|
643
|
+
text: label,
|
|
644
|
+
children: /* @__PURE__ */ jsx(Button, {
|
|
645
|
+
"aria-label": label,
|
|
646
|
+
"aria-pressed": value === layout,
|
|
647
|
+
fontSize: 1,
|
|
648
|
+
icon: icon,
|
|
649
|
+
mode: "bleed",
|
|
650
|
+
onClick: () => onChange(value),
|
|
651
|
+
padding: 2,
|
|
652
|
+
selected: value === layout
|
|
653
|
+
})
|
|
654
|
+
}, value);
|
|
655
|
+
})
|
|
656
|
+
});
|
|
657
|
+
}
|
|
658
|
+
|
|
659
|
+
function DefinitionLink({name: name, onOpen: onOpen}) {
|
|
660
|
+
const {resolvePathFromState: resolvePathFromState} = useRouter();
|
|
661
|
+
/* @__PURE__ */
|
|
662
|
+
return jsx(Button, {
|
|
663
|
+
as: "a",
|
|
664
|
+
fontSize: 1,
|
|
665
|
+
href: resolvePathFromState({
|
|
666
|
+
definitionName: name
|
|
667
|
+
}),
|
|
668
|
+
mode: "bleed",
|
|
669
|
+
onClick: event => {
|
|
670
|
+
isPlainClick(event) && (event.preventDefault(), onOpen(name));
|
|
671
|
+
},
|
|
672
|
+
padding: 2,
|
|
673
|
+
text: "View definition"
|
|
674
|
+
});
|
|
675
|
+
}
|
|
676
|
+
|
|
677
|
+
function BoardControlsPortal({definitionName: definitionName, layout: layout, onChangeLayout: onChangeLayout, face: face, onOpenDefinition: onOpenDefinition, onSelectWorkflow: onSelectWorkflow, options: options, slot: slot}) {
|
|
678
|
+
return slot ? createPortal(
|
|
679
|
+
/* @__PURE__ */ jsxs(Flex, {
|
|
680
|
+
align: "center",
|
|
681
|
+
gap: 2,
|
|
682
|
+
children: [
|
|
683
|
+
/* @__PURE__ */ jsx(WorkflowPicker, {
|
|
684
|
+
face: face,
|
|
685
|
+
onSelect: onSelectWorkflow,
|
|
686
|
+
options: options
|
|
687
|
+
}), definitionName === void 0 ? null : /* @__PURE__ */ jsx(DefinitionLink, {
|
|
688
|
+
name: definitionName,
|
|
689
|
+
onOpen: onOpenDefinition
|
|
690
|
+
}),
|
|
691
|
+
/* @__PURE__ */ jsx(Box, {
|
|
692
|
+
flex: 1
|
|
693
|
+
}),
|
|
694
|
+
/* @__PURE__ */ jsx(LayoutToggle, {
|
|
695
|
+
layout: layout,
|
|
696
|
+
onChange: onChangeLayout
|
|
697
|
+
}) ]
|
|
698
|
+
}), slot) : null;
|
|
699
|
+
}
|
|
700
|
+
|
|
701
|
+
function boardWorkflowOptions(definitions) {
|
|
702
|
+
return definitions.map(definition => ({
|
|
703
|
+
name: definition.name,
|
|
704
|
+
title: definition.title
|
|
705
|
+
})).sort(byTitleThenName);
|
|
706
|
+
}
|
|
707
|
+
|
|
708
|
+
function boardLandingName(selection) {
|
|
709
|
+
if (!(selection.kind !== "resolved" || selection.via !== "default")) return selection.definition.name;
|
|
710
|
+
}
|
|
711
|
+
|
|
712
|
+
function boardPickerFace(args) {
|
|
713
|
+
const {selection: selection, routeName: routeName} = args;
|
|
714
|
+
if (selection.kind === "resolved") {
|
|
715
|
+
const {name: name, title: title} = selection.definition;
|
|
716
|
+
return {
|
|
717
|
+
kind: "named",
|
|
718
|
+
name: name,
|
|
719
|
+
title: title
|
|
720
|
+
};
|
|
721
|
+
}
|
|
722
|
+
return selection.kind === "loading" && routeName !== void 0 ? {
|
|
723
|
+
kind: "loading"
|
|
724
|
+
} : {
|
|
725
|
+
kind: "none"
|
|
726
|
+
};
|
|
727
|
+
}
|
|
728
|
+
|
|
729
|
+
function boardSelectedPayload(selection) {
|
|
730
|
+
if (selection.kind === "resolved") return {
|
|
731
|
+
via: selection.via,
|
|
732
|
+
...definitionFingerprint(selection.definition)
|
|
733
|
+
};
|
|
734
|
+
}
|
|
735
|
+
|
|
736
|
+
function resolveBoardSelection(args) {
|
|
737
|
+
const {definitions: definitions, routeName: routeName} = args;
|
|
738
|
+
if (definitions === void 0) return {
|
|
739
|
+
kind: "loading"
|
|
740
|
+
};
|
|
741
|
+
if (routeName !== void 0) {
|
|
742
|
+
const named = definitions.find(definition => definition.name === routeName);
|
|
743
|
+
return named ? {
|
|
744
|
+
kind: "resolved",
|
|
745
|
+
definition: named,
|
|
746
|
+
via: "address"
|
|
747
|
+
} : {
|
|
748
|
+
kind: "unknown",
|
|
749
|
+
name: routeName
|
|
750
|
+
};
|
|
751
|
+
}
|
|
752
|
+
const [landing] = [ ...definitions ].sort(byTitleThenName);
|
|
753
|
+
return landing ? {
|
|
754
|
+
kind: "resolved",
|
|
755
|
+
definition: landing,
|
|
756
|
+
via: "default"
|
|
757
|
+
} : {
|
|
758
|
+
kind: "empty"
|
|
759
|
+
};
|
|
760
|
+
}
|
|
761
|
+
|
|
762
|
+
function StageBand({bands: bands, group: group}) {
|
|
763
|
+
const {open: open, toggle: toggle} = useBandOpen(bands, group.stage);
|
|
764
|
+
/* @__PURE__ */
|
|
765
|
+
return jsx(CollapsibleBand, {
|
|
766
|
+
background: !0,
|
|
767
|
+
onToggle: toggle,
|
|
768
|
+
open: open,
|
|
769
|
+
sticky: !0,
|
|
770
|
+
title: group.title,
|
|
771
|
+
header: /* @__PURE__ */ jsx(StageGroupHeading, {
|
|
772
|
+
group: group
|
|
773
|
+
}),
|
|
774
|
+
children: /* @__PURE__ */ jsx(Stack, {
|
|
775
|
+
gap: 1,
|
|
776
|
+
paddingLeft: 5,
|
|
777
|
+
children: group.cards.length === 0 ?
|
|
778
|
+
/* @__PURE__ */ jsx(Box, {
|
|
779
|
+
padding: 3,
|
|
780
|
+
children: /* @__PURE__ */ jsx(Text, {
|
|
781
|
+
muted: !0,
|
|
782
|
+
size: 1,
|
|
783
|
+
children: BOARD_EMPTY_STAGE_NOTE
|
|
784
|
+
})
|
|
785
|
+
}) : group.cards.map(card => /* @__PURE__ */ jsx(BoardCard, {
|
|
786
|
+
card: card,
|
|
787
|
+
size: "slim"
|
|
788
|
+
}, card.instanceId))
|
|
789
|
+
})
|
|
790
|
+
});
|
|
791
|
+
}
|
|
792
|
+
|
|
793
|
+
function BoardStack({bands: bands, board: board}) {
|
|
794
|
+
/* @__PURE__ */
|
|
795
|
+
return jsx(Stack, {
|
|
796
|
+
gap: 1,
|
|
797
|
+
paddingBottom: 4,
|
|
798
|
+
paddingTop: 3,
|
|
799
|
+
paddingX: TOOL_PANEL_PADDING,
|
|
800
|
+
children: board.groups.map(group => /* @__PURE__ */ jsx(StageBand, {
|
|
801
|
+
bands: bands,
|
|
802
|
+
group: group
|
|
803
|
+
}, group.stage))
|
|
804
|
+
});
|
|
805
|
+
}
|
|
806
|
+
|
|
807
|
+
const ALIAS_PREFIX = "__seed_", MAX_PATH_DEPTH = 3, IDENTIFIER = /^[A-Za-z_][A-Za-z0-9_]*$/;
|
|
808
|
+
|
|
809
|
+
function previewSelectOf(schemaType) {
|
|
810
|
+
const select = schemaType.preview?.select;
|
|
811
|
+
if (!(select === void 0 || Object.keys(select).length === 0)) return select;
|
|
812
|
+
}
|
|
813
|
+
|
|
814
|
+
function fieldTypeOf(parent, name) {
|
|
815
|
+
if (!(!("fields" in parent) || !Array.isArray(parent.fields))) return parent.fields.find(field => field.name === name)?.type;
|
|
816
|
+
}
|
|
817
|
+
|
|
818
|
+
function stepOf(args) {
|
|
819
|
+
const {parent: parent, segment: segment, terminal: terminal} = args, fieldType = fieldTypeOf(parent, segment);
|
|
820
|
+
if (fieldType !== void 0) {
|
|
821
|
+
if (terminal) return {
|
|
822
|
+
part: segment,
|
|
823
|
+
next: fieldType
|
|
824
|
+
};
|
|
825
|
+
if (isReferenceSchemaType(fieldType)) {
|
|
826
|
+
const target = fieldType.to.length === 1 ? fieldType.to[0] : void 0;
|
|
827
|
+
return target === void 0 ? void 0 : {
|
|
828
|
+
part: `${segment}->`,
|
|
829
|
+
next: target
|
|
830
|
+
};
|
|
831
|
+
}
|
|
832
|
+
return {
|
|
833
|
+
part: `${segment}.`,
|
|
834
|
+
next: fieldType
|
|
835
|
+
};
|
|
836
|
+
}
|
|
837
|
+
}
|
|
838
|
+
|
|
839
|
+
function compilePath(root, path) {
|
|
840
|
+
const segments = path.split(".");
|
|
841
|
+
if (segments.length > MAX_PATH_DEPTH || segments.some(s => !IDENTIFIER.test(s))) return;
|
|
842
|
+
let parent = root;
|
|
843
|
+
const parts = [];
|
|
844
|
+
for (const [index, segment] of segments.entries()) {
|
|
845
|
+
const step = stepOf({
|
|
846
|
+
parent: parent,
|
|
847
|
+
segment: segment,
|
|
848
|
+
terminal: index === segments.length - 1
|
|
849
|
+
});
|
|
850
|
+
if (step === void 0) return;
|
|
851
|
+
parts.push(step.part), parent = step.next;
|
|
852
|
+
}
|
|
853
|
+
return parts.join("");
|
|
854
|
+
}
|
|
855
|
+
|
|
856
|
+
function selectArmOf(schemaType) {
|
|
857
|
+
const select = previewSelectOf(schemaType);
|
|
858
|
+
if (select === void 0) return;
|
|
859
|
+
const entries = [];
|
|
860
|
+
for (const [key, path] of Object.entries(select)) {
|
|
861
|
+
const compiled = compilePath(schemaType, path);
|
|
862
|
+
if (compiled === void 0) return;
|
|
863
|
+
entries.push(`${JSON.stringify(ALIAS_PREFIX + key)}: ${compiled}`);
|
|
864
|
+
}
|
|
865
|
+
return `_type == ${JSON.stringify(schemaType.name)} => {${entries.join(", ")}}`;
|
|
866
|
+
}
|
|
867
|
+
|
|
868
|
+
function planTitleSeed(types) {
|
|
869
|
+
const seedable = /* @__PURE__ */ new Map, arms = [];
|
|
870
|
+
for (const type of types) {
|
|
871
|
+
const arm = selectArmOf(type);
|
|
872
|
+
arm !== void 0 && (seedable.set(type.name, type), arms.push(arm));
|
|
873
|
+
}
|
|
874
|
+
return {
|
|
875
|
+
query: `*[_id in $ids]{_id, _type${arms.length > 0 ? `, ...select(${arms.join(", ")})` : ""}}`,
|
|
876
|
+
seedable: seedable
|
|
877
|
+
};
|
|
878
|
+
}
|
|
16
879
|
|
|
17
|
-
|
|
880
|
+
function isSeedRow(value) {
|
|
881
|
+
if (typeof value != "object" || value === null) return !1;
|
|
882
|
+
const row = value;
|
|
883
|
+
return typeof row._id == "string" && typeof row._type == "string";
|
|
884
|
+
}
|
|
18
885
|
|
|
19
|
-
|
|
886
|
+
function seededTitleOf(row, schemaType) {
|
|
887
|
+
const select = previewSelectOf(schemaType);
|
|
888
|
+
if (select === void 0) return;
|
|
889
|
+
const selected = {};
|
|
890
|
+
for (const key of Object.keys(select)) selected[key] = row[ALIAS_PREFIX + key];
|
|
891
|
+
const prepare = schemaType.preview?.prepare;
|
|
892
|
+
let title;
|
|
893
|
+
if (prepare === void 0) title = selected.title; else try {
|
|
894
|
+
title = prepare(selected).title;
|
|
895
|
+
} catch (err) {
|
|
896
|
+
console.error(`[workflow-studio-plugin] preview prepare for "${schemaType.name}" failed on seed:`, err);
|
|
897
|
+
return;
|
|
898
|
+
}
|
|
899
|
+
return typeof title == "string" ? title : void 0;
|
|
900
|
+
}
|
|
20
901
|
|
|
21
|
-
|
|
902
|
+
function seedFromRows(args) {
|
|
903
|
+
const rows = args.rows.filter(isSeedRow), byBareId = new Map(rows.map(row => [ row._id, row ])), types = new Map(rows.map(row => [ row._id, row._type ])), titles = /* @__PURE__ */ new Map, resolved = /* @__PURE__ */ new Set;
|
|
904
|
+
for (const {gdrId: gdrId, bareId: bareId} of args.docs) {
|
|
905
|
+
const row = byBareId.get(bareId);
|
|
906
|
+
if (row === void 0) continue;
|
|
907
|
+
const schemaType = args.seedable.get(row._type);
|
|
908
|
+
if (schemaType === void 0) continue;
|
|
909
|
+
resolved.add(gdrId);
|
|
910
|
+
const title = seededTitleOf(row, schemaType);
|
|
911
|
+
title !== void 0 && titles.set(gdrId, title);
|
|
912
|
+
}
|
|
913
|
+
return {
|
|
914
|
+
types: types,
|
|
915
|
+
titles: {
|
|
916
|
+
titles: titles,
|
|
917
|
+
resolved: resolved
|
|
918
|
+
}
|
|
919
|
+
};
|
|
920
|
+
}
|
|
22
921
|
|
|
23
|
-
|
|
922
|
+
function titleDrift(seed, live) {
|
|
923
|
+
const drifted = [];
|
|
924
|
+
for (const gdrId of seed.resolved) {
|
|
925
|
+
if (!live.resolved.has(gdrId)) continue;
|
|
926
|
+
const seeded = seed.titles.get(gdrId), observed = live.titles.get(gdrId);
|
|
927
|
+
seeded !== observed && drifted.push({
|
|
928
|
+
gdrId: gdrId,
|
|
929
|
+
seeded: seeded,
|
|
930
|
+
observed: observed
|
|
931
|
+
});
|
|
932
|
+
}
|
|
933
|
+
return drifted;
|
|
934
|
+
}
|
|
24
935
|
|
|
25
|
-
|
|
936
|
+
function mergeSeededTitles(live, seed) {
|
|
937
|
+
if (seed.resolved.size === 0) return live;
|
|
938
|
+
const titles = new Map(live.titles), resolved = new Set(live.resolved);
|
|
939
|
+
for (const gdrId of seed.resolved) {
|
|
940
|
+
if (live.resolved.has(gdrId)) continue;
|
|
941
|
+
resolved.add(gdrId);
|
|
942
|
+
const title = seed.titles.get(gdrId);
|
|
943
|
+
title !== void 0 && titles.set(gdrId, title);
|
|
944
|
+
}
|
|
945
|
+
return {
|
|
946
|
+
titles: titles,
|
|
947
|
+
resolved: resolved
|
|
948
|
+
};
|
|
949
|
+
}
|
|
26
950
|
|
|
27
|
-
|
|
951
|
+
const NO_TITLES = {
|
|
952
|
+
titles: /* @__PURE__ */ new Map,
|
|
953
|
+
resolved: /* @__PURE__ */ new Set
|
|
954
|
+
};
|
|
28
955
|
|
|
29
|
-
|
|
956
|
+
function useDocPreviewTitles(documents) {
|
|
957
|
+
const previewStore = useDocumentPreviewStore(), schema = useSchema(), {perspectiveStack: perspectiveStack} = usePerspective(), {actualTypes: actualTypes, binding: binding} = useWorkflowContext(), [state, setState] = useState(NO_TITLES), key = documents.map(doc => doc.id).join("|");
|
|
958
|
+
return useEffect(() => {
|
|
959
|
+
const titles = /* @__PURE__ */ new Map, resolved = /* @__PURE__ */ new Set, previews = /* @__PURE__ */ new Map, publish = () => setState({
|
|
960
|
+
titles: new Map(titles),
|
|
961
|
+
resolved: new Set(resolved)
|
|
962
|
+
}), localDocs = documents.flatMap(doc => {
|
|
963
|
+
const {parsed: parsed, local: local} = gdrLocality(doc.id, binding.contentResource);
|
|
964
|
+
return !parsed || !local ? (resolved.add(doc.id), []) : [ {
|
|
965
|
+
doc: doc,
|
|
966
|
+
bareId: parsed.documentId
|
|
967
|
+
} ];
|
|
968
|
+
}), untracks = localDocs.map(({bareId: bareId}) => actualTypes.track(bareId)), dropPreview = docId => {
|
|
969
|
+
previews.get(docId)?.unsubscribe(), previews.delete(docId), titles.delete(docId);
|
|
970
|
+
}, observe = ({docId: docId, bareId: bareId, typeName: typeName}) => {
|
|
971
|
+
const schemaType = openableSchemaType(schema, typeName);
|
|
972
|
+
if (!schemaType) return !1;
|
|
973
|
+
if (previews.get(docId)?.typeName === typeName) return !0;
|
|
974
|
+
dropPreview(docId), resolved.delete(docId);
|
|
975
|
+
const subscription = previewStore.observeForPreview({
|
|
976
|
+
_id: bareId,
|
|
977
|
+
_type: schemaType.name
|
|
978
|
+
}, schemaType, {
|
|
979
|
+
perspective: perspectiveStack
|
|
980
|
+
}).subscribe({
|
|
981
|
+
next: event => {
|
|
982
|
+
resolved.add(docId);
|
|
983
|
+
const title = event.snapshot?.title;
|
|
984
|
+
typeof title == "string" ? titles.set(docId, title) : titles.delete(docId), publish();
|
|
985
|
+
},
|
|
986
|
+
error: err => {
|
|
987
|
+
console.error(`[workflow-studio-plugin] preview for "${docId}" failed:`, err), resolved.add(docId),
|
|
988
|
+
publish();
|
|
989
|
+
}
|
|
990
|
+
});
|
|
991
|
+
return previews.set(docId, {
|
|
992
|
+
typeName: typeName,
|
|
993
|
+
unsubscribe: () => subscription.unsubscribe()
|
|
994
|
+
}), !0;
|
|
995
|
+
}, evaluate = () => {
|
|
996
|
+
for (const {doc: doc, bareId: bareId} of localDocs) {
|
|
997
|
+
const probe = actualTypes.read(bareId);
|
|
998
|
+
if (probe === null) {
|
|
999
|
+
dropPreview(doc.id), resolved.add(doc.id);
|
|
1000
|
+
continue;
|
|
1001
|
+
}
|
|
1002
|
+
!observe({
|
|
1003
|
+
docId: doc.id,
|
|
1004
|
+
bareId: bareId,
|
|
1005
|
+
typeName: probe ?? doc.type
|
|
1006
|
+
}) && typeof probe == "string" && (dropPreview(doc.id), resolved.add(doc.id));
|
|
1007
|
+
}
|
|
1008
|
+
publish();
|
|
1009
|
+
}, unsubscribeProbes = actualTypes.subscribe(evaluate);
|
|
1010
|
+
return evaluate(), () => {
|
|
1011
|
+
unsubscribeProbes(), untracks.forEach(untrack => untrack()), previews.forEach(preview => preview.unsubscribe());
|
|
1012
|
+
};
|
|
1013
|
+
}, [ key, previewStore, schema, actualTypes, binding.contentResource.id, perspectiveStack.join("|") ]),
|
|
1014
|
+
state;
|
|
1015
|
+
}
|
|
30
1016
|
|
|
31
|
-
|
|
1017
|
+
function usePreviewSeed(documents) {
|
|
1018
|
+
const client = useClient({
|
|
1019
|
+
apiVersion: WORKFLOW_API_VERSION
|
|
1020
|
+
}), schema = useSchema(), {perspectiveStack: perspectiveStack} = usePerspective(), {actualTypes: actualTypes, binding: binding} = useWorkflowContext(), [seed, setSeed] = useState(NO_TITLES), docs = useMemo(() => documents.flatMap(doc => {
|
|
1021
|
+
const {parsed: parsed, local: local} = gdrLocality(doc.id, binding.contentResource);
|
|
1022
|
+
return parsed === void 0 || !local ? [] : [ {
|
|
1023
|
+
gdrId: doc.id,
|
|
1024
|
+
bareId: parsed.documentId
|
|
1025
|
+
} ];
|
|
1026
|
+
}), [ documents, binding.contentResource ]), key = docs.map(doc => doc.gdrId).join("|");
|
|
1027
|
+
return useEffect(() => {
|
|
1028
|
+
if (setSeed(NO_TITLES), key === "") return;
|
|
1029
|
+
const plan = planTitleSeed(schema.getTypeNames().flatMap(name => openableSchemaType(schema, name) ?? []));
|
|
1030
|
+
let cancelled = !1;
|
|
1031
|
+
return client.fetch(plan.query, {
|
|
1032
|
+
ids: docs.map(doc => doc.bareId)
|
|
1033
|
+
}, {
|
|
1034
|
+
tag: "workflows.preview-seed",
|
|
1035
|
+
...perspectiveStack.length > 0 ? {
|
|
1036
|
+
perspective: [ ...perspectiveStack ]
|
|
1037
|
+
} : {}
|
|
1038
|
+
}).then(rows => {
|
|
1039
|
+
if (cancelled) return;
|
|
1040
|
+
const result = seedFromRows({
|
|
1041
|
+
rows: rows,
|
|
1042
|
+
docs: docs,
|
|
1043
|
+
seedable: plan.seedable
|
|
1044
|
+
});
|
|
1045
|
+
actualTypes.seed(result.types), setSeed(result.titles);
|
|
1046
|
+
}).catch(err => {
|
|
1047
|
+
cancelled || console.error("[workflow-studio-plugin] preview seed failed:", err);
|
|
1048
|
+
}), () => {
|
|
1049
|
+
cancelled = !0;
|
|
1050
|
+
};
|
|
1051
|
+
}, [ key, client, schema, actualTypes, binding.contentResource.id, perspectiveStack.join("|") ]),
|
|
1052
|
+
seed;
|
|
1053
|
+
}
|
|
32
1054
|
|
|
33
|
-
|
|
1055
|
+
function useSeededTitles(args) {
|
|
1056
|
+
const {ordering: ordering, warm: warm} = args, seed = usePreviewSeed(warm), live = useDocPreviewTitles(ordering), telemetry = useWorkflowTelemetry(), warned = useRef(/* @__PURE__ */ new Set);
|
|
1057
|
+
return useEffect(() => {
|
|
1058
|
+
const fresh = titleDrift(seed, live).filter(drift => !warned.current.has(drift.gdrId));
|
|
1059
|
+
if (fresh.length !== 0) {
|
|
1060
|
+
warned.current.size === 0 && telemetry.log(WorkflowTitleSeedDrifted, {
|
|
1061
|
+
driftCount: fresh.length
|
|
1062
|
+
});
|
|
1063
|
+
for (const drift of fresh) warned.current.add(drift.gdrId), console.warn(`[workflow-studio-plugin] seeded preview title for "${drift.gdrId}" diverged from the live pipeline — the seed projection or prepare mirroring is drifting from Studio preview resolution`);
|
|
1064
|
+
}
|
|
1065
|
+
}, [ seed, live, telemetry ]), useMemo(() => {
|
|
1066
|
+
const merged = mergeSeededTitles(live, seed);
|
|
1067
|
+
return {
|
|
1068
|
+
...merged,
|
|
1069
|
+
ready: ordering.every(doc => merged.resolved.has(doc.id))
|
|
1070
|
+
};
|
|
1071
|
+
}, [ ordering, live, seed ]);
|
|
1072
|
+
}
|
|
34
1073
|
|
|
35
|
-
|
|
1074
|
+
function useGroupTitles(groups) {
|
|
1075
|
+
const ordering = useMemo(() => groups.withDocuments.map(group => group.document), [ groups ]), warm = useMemo(() => groups.withDocuments.flatMap(group => group.documents), [ groups ]);
|
|
1076
|
+
return useSeededTitles({
|
|
1077
|
+
ordering: ordering,
|
|
1078
|
+
warm: warm
|
|
1079
|
+
});
|
|
1080
|
+
}
|
|
36
1081
|
|
|
37
|
-
|
|
1082
|
+
const NO_DOCUMENTS = [];
|
|
38
1083
|
|
|
39
|
-
|
|
1084
|
+
function useBoard(args) {
|
|
1085
|
+
const {definition: definition, instances: instances} = args, derived = useMemo(() => definition ? deriveBoard({
|
|
1086
|
+
instances: instances,
|
|
1087
|
+
definition: definition
|
|
1088
|
+
}) : void 0, [ definition, instances ]), documents = useMemo(() => derived ? boardDocuments(derived) : NO_DOCUMENTS, [ derived ]), {titles: titles, ready: ready} = useSeededTitles({
|
|
1089
|
+
ordering: documents,
|
|
1090
|
+
warm: documents
|
|
1091
|
+
}), board = useMemo(() => derived ? orderBoardByPreviewTitle(derived, titles) : void 0, [ derived, titles ]);
|
|
1092
|
+
return useMemo(() => ({
|
|
1093
|
+
board: board,
|
|
1094
|
+
ready: ready
|
|
1095
|
+
}), [ board, ready ]);
|
|
1096
|
+
}
|
|
40
1097
|
|
|
41
|
-
|
|
1098
|
+
const INSTANCE_CAP = 200;
|
|
42
1099
|
|
|
43
|
-
|
|
1100
|
+
function useCappedInstances(filter) {
|
|
1101
|
+
const {engine: engine} = useWorkflowContext(), capped = useMemo(() => ({
|
|
1102
|
+
...filter,
|
|
1103
|
+
limit: INSTANCE_CAP
|
|
1104
|
+
}), [ filter ]), {instances: instances, loading: loading, unreadable: unreadable} = useWorkflowInstances({
|
|
1105
|
+
engine: engine,
|
|
1106
|
+
filter: capped
|
|
1107
|
+
});
|
|
1108
|
+
return useMemo(() => {
|
|
1109
|
+
const rows = instances ?? [];
|
|
1110
|
+
return {
|
|
1111
|
+
rows: rows,
|
|
1112
|
+
truncated: rows.length + unreadable.length === INSTANCE_CAP,
|
|
1113
|
+
loading: loading,
|
|
1114
|
+
unreadable: unreadable
|
|
1115
|
+
};
|
|
1116
|
+
}, [ instances, loading, unreadable ]);
|
|
1117
|
+
}
|
|
44
1118
|
|
|
45
|
-
|
|
1119
|
+
const BOARD_CAP_NOTE = `Showing the latest ${INSTANCE_CAP} workflows — older ones aren’t on the board.`, NOTHING = {
|
|
1120
|
+
ids: []
|
|
1121
|
+
};
|
|
46
1122
|
|
|
47
|
-
|
|
1123
|
+
function useBoardInstances(definitionName) {
|
|
1124
|
+
const filter = useMemo(() => definitionName === void 0 ? NOTHING : {
|
|
1125
|
+
definition: definitionName,
|
|
1126
|
+
includeCompleted: !0
|
|
1127
|
+
}, [ definitionName ]);
|
|
1128
|
+
return useCappedInstances(filter);
|
|
1129
|
+
}
|
|
48
1130
|
|
|
49
|
-
|
|
1131
|
+
function useBoardLayout(scope) {
|
|
1132
|
+
const store = useMemo(() => createBoardLayoutStore({
|
|
1133
|
+
storageKey: boardLayoutStorageKey(scope)
|
|
1134
|
+
}), [ scope ]), [held, setHeld] = useState(() => ({
|
|
1135
|
+
store: store,
|
|
1136
|
+
layout: store.read()
|
|
1137
|
+
}));
|
|
1138
|
+
return held.store !== store && setHeld({
|
|
1139
|
+
store: store,
|
|
1140
|
+
layout: store.read()
|
|
1141
|
+
}), {
|
|
1142
|
+
layout: held.layout,
|
|
1143
|
+
setLayout: layout => setHeld({
|
|
1144
|
+
store: store,
|
|
1145
|
+
layout: store.set(layout)
|
|
1146
|
+
})
|
|
1147
|
+
};
|
|
1148
|
+
}
|
|
50
1149
|
|
|
51
|
-
function
|
|
1150
|
+
function DocumentsTab({filterSlot: filterSlot, onOpenDefinition: onOpenDefinition, onSelectWorkflow: onSelectWorkflow, routeDefinition: routeDefinition}) {
|
|
1151
|
+
const {binding: binding} = useWorkflowContext(), telemetry = useWorkflowTelemetry(), {definitions: definitions, error: error} = useDeployedDefinitions(), {layout: layout, setLayout: setLayout} = useBoardLayout(binding.engineResource.id), bands = useBandOpenState({
|
|
1152
|
+
segment: "documents",
|
|
1153
|
+
scope: binding.engineResource.id
|
|
1154
|
+
}), selection = resolveBoardSelection({
|
|
1155
|
+
definitions: definitions,
|
|
1156
|
+
routeName: routeDefinition
|
|
1157
|
+
}), selected = selection.kind === "resolved" ? selection.definition : void 0, instances = useBoardInstances(selected?.name), {board: board, ready: ready} = useBoard({
|
|
1158
|
+
definition: selected,
|
|
1159
|
+
instances: instances.rows
|
|
1160
|
+
}), revealed = useRevealGate({
|
|
1161
|
+
loading: instances.loading,
|
|
1162
|
+
ready: ready
|
|
1163
|
+
}), landing = boardLandingName(selection);
|
|
1164
|
+
useEffect(() => {
|
|
1165
|
+
landing !== void 0 && onSelectWorkflow(landing, {
|
|
1166
|
+
replace: !0
|
|
1167
|
+
});
|
|
1168
|
+
}, [ landing, onSelectWorkflow ]);
|
|
1169
|
+
const selectedPayload = boardSelectedPayload(selection);
|
|
52
1170
|
/* @__PURE__ */
|
|
53
|
-
return
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
1171
|
+
return jsxs(Flex, {
|
|
1172
|
+
direction: "column",
|
|
1173
|
+
flex: 1,
|
|
1174
|
+
style: {
|
|
1175
|
+
minHeight: 0
|
|
1176
|
+
},
|
|
1177
|
+
children: [
|
|
1178
|
+
/* @__PURE__ */ jsx(BoardControlsPortal, {
|
|
1179
|
+
definitionName: selected?.name,
|
|
1180
|
+
layout: layout,
|
|
1181
|
+
onOpenDefinition: onOpenDefinition,
|
|
1182
|
+
onChangeLayout: next => {
|
|
1183
|
+
next !== layout && (telemetry.log(WorkflowBoardLayoutChanged, {
|
|
1184
|
+
layout: next
|
|
1185
|
+
}), setLayout(next));
|
|
1186
|
+
},
|
|
1187
|
+
onSelectWorkflow: onSelectWorkflow,
|
|
1188
|
+
options: boardWorkflowOptions(definitions ?? []),
|
|
1189
|
+
face: boardPickerFace({
|
|
1190
|
+
selection: selection,
|
|
1191
|
+
routeName: routeDefinition
|
|
1192
|
+
}),
|
|
1193
|
+
slot: filterSlot
|
|
1194
|
+
}),
|
|
1195
|
+
/* @__PURE__ */ jsxs(Flex, {
|
|
1196
|
+
direction: "column",
|
|
1197
|
+
flex: 1,
|
|
1198
|
+
gap: 2,
|
|
1199
|
+
style: {
|
|
1200
|
+
minHeight: 0
|
|
1201
|
+
},
|
|
1202
|
+
children: [ instances.unreadable.length === 0 ? null : /* @__PURE__ */ jsx(Box, {
|
|
1203
|
+
paddingX: TOOL_PANEL_PADDING,
|
|
1204
|
+
children: /* @__PURE__ */ jsx(UnreadableDocsNote, {
|
|
1205
|
+
unreadable: instances.unreadable
|
|
1206
|
+
})
|
|
1207
|
+
}),
|
|
1208
|
+
/* @__PURE__ */ jsx(BoardBody, {
|
|
1209
|
+
bands: bands,
|
|
1210
|
+
board: board,
|
|
1211
|
+
error: error,
|
|
1212
|
+
layout: layout,
|
|
1213
|
+
loading: !revealed,
|
|
1214
|
+
selection: selection
|
|
1215
|
+
}), instances.truncated ? /* @__PURE__ */ jsx(Box, {
|
|
1216
|
+
paddingX: TOOL_PANEL_PADDING,
|
|
1217
|
+
children: /* @__PURE__ */ jsx(MutedNote, {
|
|
1218
|
+
text: BOARD_CAP_NOTE
|
|
1219
|
+
})
|
|
1220
|
+
}) : null ]
|
|
1221
|
+
}), selectedPayload === void 0 ? null :
|
|
1222
|
+
/* @__PURE__ */ jsx(LogEventOnMount, {
|
|
1223
|
+
data: selectedPayload,
|
|
1224
|
+
event: WorkflowBoardWorkflowSelected
|
|
1225
|
+
}, selected?.name) ]
|
|
1226
|
+
});
|
|
1227
|
+
}
|
|
1228
|
+
|
|
1229
|
+
function BoardBody({bands: bands, board: board, error: error, layout: layout, loading: loading, selection: selection}) {
|
|
1230
|
+
return error !== void 0 ? /* @__PURE__ */ jsx(StatusBox, {
|
|
1231
|
+
children: /* @__PURE__ */ jsx(MutedNote, {
|
|
1232
|
+
text: `Could not load the deployed workflows: ${error}`
|
|
1233
|
+
})
|
|
1234
|
+
}) : selection.kind === "loading" ? /* @__PURE__ */ jsx(StatusBox, {
|
|
1235
|
+
children: /* @__PURE__ */ jsx(TabStatusRow, {
|
|
1236
|
+
children: /* @__PURE__ */ jsx(LoadingRow, {
|
|
1237
|
+
label: "Loading workflows…"
|
|
1238
|
+
})
|
|
1239
|
+
})
|
|
1240
|
+
}) : selection.kind === "empty" ? /* @__PURE__ */ jsx(StatusBox, {
|
|
1241
|
+
children: /* @__PURE__ */ jsx(EmptyState, {
|
|
1242
|
+
description: "Deploy a workflow to see its documents here",
|
|
1243
|
+
icon: /* @__PURE__ */ jsx(SearchIcon, {}),
|
|
1244
|
+
title: "No workflows deployed"
|
|
1245
|
+
})
|
|
1246
|
+
}) : selection.kind === "unknown" ? /* @__PURE__ */ jsx(StatusBox, {
|
|
1247
|
+
children: /* @__PURE__ */ jsx(EmptyState, {
|
|
1248
|
+
description: `No deployed workflow is named “${selection.name}” — pick one above`,
|
|
1249
|
+
icon: /* @__PURE__ */ jsx(SearchIcon, {}),
|
|
1250
|
+
title: "Workflow not found"
|
|
1251
|
+
})
|
|
1252
|
+
}) : loading || board === void 0 ? /* @__PURE__ */ jsx(StatusBox, {
|
|
1253
|
+
children: /* @__PURE__ */ jsx(TabStatusRow, {
|
|
1254
|
+
children: /* @__PURE__ */ jsx(LoadingRow, {
|
|
1255
|
+
label: "Loading documents…"
|
|
1256
|
+
})
|
|
59
1257
|
})
|
|
1258
|
+
}) : layout === "stack" ? /* @__PURE__ */ jsx(BoardStack, {
|
|
1259
|
+
bands: bands,
|
|
1260
|
+
board: board
|
|
1261
|
+
}) : /* @__PURE__ */ jsx(StageGroups, {
|
|
1262
|
+
board: board
|
|
1263
|
+
});
|
|
1264
|
+
}
|
|
1265
|
+
|
|
1266
|
+
function StatusBox({children: children}) {
|
|
1267
|
+
/* @__PURE__ */
|
|
1268
|
+
return jsx(Flex, {
|
|
1269
|
+
direction: "column",
|
|
1270
|
+
flex: 1,
|
|
1271
|
+
paddingX: TOOL_PANEL_PADDING,
|
|
1272
|
+
children: children
|
|
60
1273
|
});
|
|
61
1274
|
}
|
|
62
1275
|
|
|
63
1276
|
function definitionCatalog(args) {
|
|
1277
|
+
const rejected = [ ...args.issues.values() ];
|
|
64
1278
|
return args.definitions.map(definition => ({
|
|
65
1279
|
name: definition.name,
|
|
66
1280
|
title: definition.title ?? definition.name,
|
|
67
1281
|
description: definition.description,
|
|
68
1282
|
activeCount: args.inFlight.filter(instance => instance.definition === definition.name).length,
|
|
69
|
-
docTypes: [ ...new Set(args.mappings.filter(mapping => mapping.definition === definition.name).map(mapping => mapping.docType)) ]
|
|
70
|
-
|
|
1283
|
+
docTypes: [ ...new Set(args.mappings.filter(mapping => mapping.definition === definition.name).map(mapping => mapping.docType)) ],
|
|
1284
|
+
brokenBindings: rejected.filter(issue => issue.definition === definition.name && issue.version === definition.version).map(issue => ({
|
|
1285
|
+
docType: issue.docType,
|
|
1286
|
+
detail: mappingIssueDetail(issue)
|
|
1287
|
+
})).sort((a, b) => a.docType.localeCompare(b.docType))
|
|
1288
|
+
})).sort(byTitleThenName);
|
|
1289
|
+
}
|
|
1290
|
+
|
|
1291
|
+
function undeployedWorkflowNotices(args) {
|
|
1292
|
+
return [ ...args.issues.values() ].filter(namesNoDeployedDefinition).sort((a, b) => a.definition.localeCompare(b.definition) || a.docType.localeCompare(b.docType)).map(issue => `“${issue.definition}” is set up to run on ${args.titleOf(issue.docType) ?? issue.docType} documents, but no deployed workflow has that name`);
|
|
71
1293
|
}
|
|
72
1294
|
|
|
73
1295
|
function docTypeLabels(docTypes, titleOf) {
|
|
74
1296
|
return docTypes.map(name => ({
|
|
75
1297
|
name: name,
|
|
76
1298
|
title: titleOf(name) ?? name
|
|
77
|
-
})).sort(
|
|
1299
|
+
})).sort(byTitleThenName);
|
|
78
1300
|
}
|
|
79
1301
|
|
|
80
1302
|
function startPhrase(definition) {
|
|
81
|
-
if (definition.lifecycle === "child") return "
|
|
1303
|
+
if (definition.lifecycle === "child") return "Started by a parent workflow";
|
|
82
1304
|
if (startKindOf(definition) === "autonomous") return "Starts automatically";
|
|
83
1305
|
const subject = (definition.fields ?? []).find(isSubjectEntry);
|
|
84
1306
|
return subject !== void 0 && isInputSourced(subject) ? "Started manually, from a document" : "Started manually";
|
|
@@ -88,6 +1310,37 @@ function deployedAtOf(definition) {
|
|
|
88
1310
|
return typeof definition._updatedAt == "string" ? definition._updatedAt : void 0;
|
|
89
1311
|
}
|
|
90
1312
|
|
|
1313
|
+
function deployedPhrase(definition) {
|
|
1314
|
+
const deployedAt = deployedAtOf(definition);
|
|
1315
|
+
if (deployedAt === void 0) return `v${definition.version}`;
|
|
1316
|
+
const ago = formatTimeAgo(deployedAt);
|
|
1317
|
+
return ago === "" ? formatShortDateTime(deployedAt) : `${formatShortDateTime(deployedAt)} (${ago})`;
|
|
1318
|
+
}
|
|
1319
|
+
|
|
1320
|
+
function DetailNotFound({back: back, message: message}) {
|
|
1321
|
+
/* @__PURE__ */
|
|
1322
|
+
return jsxs(Stack, {
|
|
1323
|
+
gap: 4,
|
|
1324
|
+
children: [
|
|
1325
|
+
/* @__PURE__ */ jsx(Text, {
|
|
1326
|
+
muted: !0,
|
|
1327
|
+
size: 1,
|
|
1328
|
+
children: message
|
|
1329
|
+
}),
|
|
1330
|
+
/* @__PURE__ */ jsx(Flex, {
|
|
1331
|
+
children: /* @__PURE__ */ jsx(Button, {
|
|
1332
|
+
fontSize: 1,
|
|
1333
|
+
gap: 2,
|
|
1334
|
+
icon: ArrowLeftIcon,
|
|
1335
|
+
mode: "ghost",
|
|
1336
|
+
onClick: back.go,
|
|
1337
|
+
padding: 2,
|
|
1338
|
+
text: back.label
|
|
1339
|
+
})
|
|
1340
|
+
}) ]
|
|
1341
|
+
});
|
|
1342
|
+
}
|
|
1343
|
+
|
|
91
1344
|
function DetailTitle({busy: busy = !1, documentGdr: documentGdr, title: title}) {
|
|
92
1345
|
const chipPullback = -useSpaceToken(1);
|
|
93
1346
|
/* @__PURE__ */
|
|
@@ -122,7 +1375,8 @@ function DetailTitle({busy: busy = !1, documentGdr: documentGdr, title: title})
|
|
|
122
1375
|
},
|
|
123
1376
|
children: /* @__PURE__ */ jsx(DocPreviewLink, {
|
|
124
1377
|
gdr: documentGdr,
|
|
125
|
-
layout: "inline"
|
|
1378
|
+
layout: "inline",
|
|
1379
|
+
source: "detail-title"
|
|
126
1380
|
})
|
|
127
1381
|
}) ]
|
|
128
1382
|
}),
|
|
@@ -132,46 +1386,59 @@ function DetailTitle({busy: busy = !1, documentGdr: documentGdr, title: title})
|
|
|
132
1386
|
});
|
|
133
1387
|
}
|
|
134
1388
|
|
|
135
|
-
const
|
|
1389
|
+
const INSTANCE_CAP_COUNT_NOTE = `Counts from the latest ${INSTANCE_CAP} workflows — older ones aren’t counted.`, NEWEST_INSTANCES = {
|
|
1390
|
+
includeCompleted: !0
|
|
1391
|
+
};
|
|
136
1392
|
|
|
137
|
-
function
|
|
138
|
-
const {
|
|
139
|
-
return
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
seq: seq,
|
|
147
|
-
rows: latest
|
|
148
|
-
}), cancelled || (setDefinitions(latest), setError(void 0));
|
|
149
|
-
})().catch(err => {
|
|
150
|
-
cancelled || setError(describeError(err));
|
|
151
|
-
}), () => {
|
|
152
|
-
cancelled = !0;
|
|
153
|
-
};
|
|
154
|
-
}, [ engine ]), {
|
|
155
|
-
definitions: definitions,
|
|
156
|
-
error: error
|
|
157
|
-
};
|
|
1393
|
+
function useToolInstances() {
|
|
1394
|
+
const {rows: rows, truncated: truncated, loading: loading, unreadable: unreadable} = useCappedInstances(NEWEST_INSTANCES);
|
|
1395
|
+
return useMemo(() => ({
|
|
1396
|
+
inFlight: rows.filter(instance => terminalState(instance) === "in-flight"),
|
|
1397
|
+
settled: rows.filter(instance => terminalState(instance) !== "in-flight"),
|
|
1398
|
+
truncated: truncated,
|
|
1399
|
+
loading: loading,
|
|
1400
|
+
unreadable: unreadable
|
|
1401
|
+
}), [ rows, truncated, loading, unreadable ]);
|
|
158
1402
|
}
|
|
159
1403
|
|
|
160
|
-
function DefinitionDetail({definitionName: definitionName}) {
|
|
161
|
-
const {definitions: definitions, error: error} = useDeployedDefinitions(),
|
|
162
|
-
|
|
163
|
-
|
|
1404
|
+
function DefinitionDetail({definitionName: definitionName, backToList: backToList}) {
|
|
1405
|
+
const {definitions: definitions, error: error} = useDeployedDefinitions(), definition = definitions?.find(row => row.name === definitionName), loading = definitions === void 0 && error === void 0, viewed = loading || error !== void 0 ? null : /* @__PURE__ */ jsx(LogEventOnMount, {
|
|
1406
|
+
data: {
|
|
1407
|
+
found: definition !== void 0,
|
|
1408
|
+
...definitionFingerprint(definition)
|
|
1409
|
+
},
|
|
1410
|
+
event: WorkflowDefinitionDetailViewed
|
|
1411
|
+
});
|
|
1412
|
+
return !loading && error === void 0 && definition === void 0 ? /* @__PURE__ */ jsxs(Box, {
|
|
1413
|
+
paddingX: 3,
|
|
1414
|
+
children: [ viewed,
|
|
1415
|
+
/* @__PURE__ */ jsx(TabStatusRow, {
|
|
1416
|
+
children: /* @__PURE__ */ jsx(DetailNotFound, {
|
|
1417
|
+
back: backToList,
|
|
1418
|
+
message: /* @__PURE__ */ jsxs(Fragment, {
|
|
1419
|
+
children: [ "Unable to find a definition with name “",
|
|
1420
|
+
/* @__PURE__ */ jsx("strong", {
|
|
1421
|
+
children: definitionName
|
|
1422
|
+
}), "”." ]
|
|
1423
|
+
})
|
|
1424
|
+
})
|
|
1425
|
+
}) ]
|
|
1426
|
+
}) : /* @__PURE__ */ jsxs(Flex, {
|
|
164
1427
|
direction: "column",
|
|
165
1428
|
height: "fill",
|
|
166
1429
|
overflow: "hidden",
|
|
167
|
-
children: [
|
|
1430
|
+
children: [ viewed,
|
|
168
1431
|
/* @__PURE__ */ jsx(Box, {
|
|
169
1432
|
flex: "none",
|
|
170
1433
|
paddingBottom: 2,
|
|
171
1434
|
paddingTop: 3,
|
|
172
1435
|
paddingX: 3,
|
|
173
|
-
children: /* @__PURE__ */ jsx(
|
|
174
|
-
|
|
1436
|
+
children: loading ? /* @__PURE__ */ jsx(Box, {
|
|
1437
|
+
paddingLeft: 2,
|
|
1438
|
+
children: /* @__PURE__ */ jsx(LoadingRow, {
|
|
1439
|
+
label: "Loading definition…"
|
|
1440
|
+
})
|
|
1441
|
+
}) : /* @__PURE__ */ jsx(DetailTitle, {
|
|
175
1442
|
title: definition?.title ?? definitionName
|
|
176
1443
|
})
|
|
177
1444
|
}),
|
|
@@ -179,125 +1446,176 @@ function DefinitionDetail({definitionName: definitionName}) {
|
|
|
179
1446
|
flex: 1,
|
|
180
1447
|
overflow: "auto",
|
|
181
1448
|
paddingX: 3,
|
|
182
|
-
children: /* @__PURE__ */ jsx(
|
|
1449
|
+
children: /* @__PURE__ */ jsx(Flex, {
|
|
1450
|
+
direction: "column",
|
|
183
1451
|
paddingBottom: 5,
|
|
184
1452
|
paddingLeft: 2,
|
|
185
|
-
paddingTop:
|
|
1453
|
+
paddingTop: 4,
|
|
186
1454
|
style: {
|
|
187
|
-
|
|
1455
|
+
boxSizing: "border-box",
|
|
1456
|
+
minHeight: "100%"
|
|
188
1457
|
},
|
|
189
1458
|
children: /* @__PURE__ */ jsx(DefinitionBody, {
|
|
190
1459
|
definition: definition,
|
|
191
|
-
error: error
|
|
192
|
-
loaded: definitions !== void 0
|
|
1460
|
+
error: error
|
|
193
1461
|
})
|
|
194
1462
|
})
|
|
195
1463
|
}) ]
|
|
196
1464
|
});
|
|
197
1465
|
}
|
|
198
1466
|
|
|
199
|
-
function DefinitionBody({definition: definition, error: error
|
|
1467
|
+
function DefinitionBody({definition: definition, error: error}) {
|
|
200
1468
|
return error !== void 0 ? /* @__PURE__ */ jsx(MutedNote, {
|
|
201
1469
|
text: `Could not load the deployed workflows: ${error}`
|
|
202
|
-
}) :
|
|
203
|
-
text: "No deployed workflow definition with this name — it may have been retracted."
|
|
204
|
-
}) : /* @__PURE__ */ jsx(DefinitionFacts, {
|
|
1470
|
+
}) : definition === void 0 ? null : /* @__PURE__ */ jsx(DefinitionFacts, {
|
|
205
1471
|
definition: definition
|
|
206
|
-
})
|
|
207
|
-
|
|
1472
|
+
});
|
|
1473
|
+
}
|
|
1474
|
+
|
|
1475
|
+
function SetupIssues({bindings: bindings}) {
|
|
1476
|
+
const schema = useSchema();
|
|
1477
|
+
return bindings.length === 0 ? null : /* @__PURE__ */ jsx(Card, {
|
|
1478
|
+
padding: 3,
|
|
1479
|
+
radius: 3,
|
|
1480
|
+
tone: "caution",
|
|
1481
|
+
children: /* @__PURE__ */ jsxs(Flex, {
|
|
1482
|
+
align: "flex-start",
|
|
1483
|
+
gap: 3,
|
|
1484
|
+
children: [
|
|
1485
|
+
/* @__PURE__ */ jsx(Text, {
|
|
1486
|
+
size: 1,
|
|
1487
|
+
children: /* @__PURE__ */ jsx(WarningOutlineIcon, {})
|
|
1488
|
+
}),
|
|
1489
|
+
/* @__PURE__ */ jsxs(Stack, {
|
|
1490
|
+
flex: 1,
|
|
1491
|
+
gap: 3,
|
|
1492
|
+
children: [
|
|
1493
|
+
/* @__PURE__ */ jsx(Text, {
|
|
1494
|
+
size: 1,
|
|
1495
|
+
weight: "semibold",
|
|
1496
|
+
children: "Setup issue"
|
|
1497
|
+
}), bindings.map(binding => /* @__PURE__ */ jsx(Text, {
|
|
1498
|
+
size: 1,
|
|
1499
|
+
children: `${schema.get(binding.docType)?.title ?? binding.docType}: ${binding.detail}.`
|
|
1500
|
+
}, binding.docType)),
|
|
1501
|
+
/* @__PURE__ */ jsx(Text, {
|
|
1502
|
+
muted: !0,
|
|
1503
|
+
size: 1,
|
|
1504
|
+
children: "Editors see this workflow disabled on these document types until a developer fixes it."
|
|
1505
|
+
}) ]
|
|
1506
|
+
}) ]
|
|
1507
|
+
})
|
|
208
1508
|
});
|
|
209
1509
|
}
|
|
210
1510
|
|
|
211
1511
|
function DefinitionFacts({definition: definition}) {
|
|
212
|
-
const {
|
|
1512
|
+
const {mappingIssues: mappingIssues, mappings: mappings} = useWorkflowContext(), schema = useSchema(), instances = useToolInstances(), snapshotWidth = useContainerToken(2), [row] = definitionCatalog({
|
|
213
1513
|
definitions: [ definition ],
|
|
214
1514
|
mappings: mappings,
|
|
215
|
-
inFlight:
|
|
1515
|
+
inFlight: instances.inFlight,
|
|
1516
|
+
issues: mappingIssues
|
|
216
1517
|
}), runsOn = docTypeLabels(row?.docTypes ?? [], name => schema.get(name)?.title).map(docType => docType.title);
|
|
217
1518
|
/* @__PURE__ */
|
|
218
|
-
return jsxs(
|
|
1519
|
+
return jsxs(Flex, {
|
|
1520
|
+
direction: "column",
|
|
1521
|
+
flex: 1,
|
|
219
1522
|
gap: 4,
|
|
220
|
-
children: [
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
size: 1,
|
|
225
|
-
children: [ deployedAt === void 0 ? `v${definition.version}` : formatDate(deployedAt), " ·", " ", binding.tag ]
|
|
226
|
-
})
|
|
227
|
-
}),
|
|
228
|
-
/* @__PURE__ */ jsx(MetaRow, {
|
|
229
|
-
label: "Trigger",
|
|
230
|
-
children: /* @__PURE__ */ jsx(Text, {
|
|
231
|
-
size: 1,
|
|
232
|
-
children: startPhrase(definition)
|
|
1523
|
+
children: [ row === void 0 || row.brokenBindings.length === 0 ? null : /* @__PURE__ */ jsx(Box, {
|
|
1524
|
+
flex: "none",
|
|
1525
|
+
children: /* @__PURE__ */ jsx(SetupIssues, {
|
|
1526
|
+
bindings: row.brokenBindings
|
|
233
1527
|
})
|
|
234
1528
|
}),
|
|
235
|
-
/* @__PURE__ */ jsx(
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
|
|
241
|
-
|
|
242
|
-
|
|
243
|
-
|
|
1529
|
+
/* @__PURE__ */ jsx(Box, {
|
|
1530
|
+
flex: "none",
|
|
1531
|
+
style: {
|
|
1532
|
+
maxWidth: snapshotWidth
|
|
1533
|
+
},
|
|
1534
|
+
children: /* @__PURE__ */ jsxs(Stack, {
|
|
1535
|
+
gap: 4,
|
|
1536
|
+
children: [
|
|
1537
|
+
/* @__PURE__ */ jsx(MetaRow, {
|
|
1538
|
+
label: "Deployed",
|
|
1539
|
+
children: /* @__PURE__ */ jsx(Text, {
|
|
1540
|
+
size: 1,
|
|
1541
|
+
children: deployedPhrase(definition)
|
|
1542
|
+
})
|
|
1543
|
+
}),
|
|
1544
|
+
/* @__PURE__ */ jsx(MetaRow, {
|
|
1545
|
+
label: "Active instances",
|
|
1546
|
+
children: instances.loading ? /* @__PURE__ */ jsx(Text, {
|
|
1547
|
+
muted: !0,
|
|
1548
|
+
size: 1,
|
|
1549
|
+
children: "—"
|
|
1550
|
+
}) : /* @__PURE__ */ jsxs(Stack, {
|
|
1551
|
+
gap: 2,
|
|
1552
|
+
children: [
|
|
1553
|
+
/* @__PURE__ */ jsx(Text, {
|
|
1554
|
+
size: 1,
|
|
1555
|
+
children: row?.activeCount ?? 0
|
|
1556
|
+
}), instances.truncated ? /* @__PURE__ */ jsx(Text, {
|
|
1557
|
+
muted: !0,
|
|
1558
|
+
size: 1,
|
|
1559
|
+
children: INSTANCE_CAP_COUNT_NOTE
|
|
1560
|
+
}) : null ]
|
|
1561
|
+
})
|
|
1562
|
+
}),
|
|
1563
|
+
/* @__PURE__ */ jsx(MetaRow, {
|
|
1564
|
+
label: "Trigger",
|
|
1565
|
+
children: /* @__PURE__ */ jsx(Text, {
|
|
1566
|
+
size: 1,
|
|
1567
|
+
children: startPhrase(definition)
|
|
1568
|
+
})
|
|
1569
|
+
}),
|
|
1570
|
+
/* @__PURE__ */ jsx(MetaRow, {
|
|
1571
|
+
label: "Document types",
|
|
1572
|
+
children: runsOn.length === 0 ? /* @__PURE__ */ jsx(Text, {
|
|
1573
|
+
muted: !0,
|
|
1574
|
+
size: 1,
|
|
1575
|
+
children: "No document types in this Studio"
|
|
1576
|
+
}) : /* @__PURE__ */ jsx(Text, {
|
|
1577
|
+
size: 1,
|
|
1578
|
+
children: runsOn.join(", ")
|
|
1579
|
+
})
|
|
1580
|
+
}),
|
|
1581
|
+
/* @__PURE__ */ jsx(MetaRow, {
|
|
1582
|
+
label: "Description",
|
|
1583
|
+
children: definition.description === void 0 ? /* @__PURE__ */ jsx(Text, {
|
|
1584
|
+
muted: !0,
|
|
1585
|
+
size: 1,
|
|
1586
|
+
children: /* @__PURE__ */ jsx("em", {
|
|
1587
|
+
children: "No description"
|
|
1588
|
+
})
|
|
1589
|
+
}) : /* @__PURE__ */ jsx(Text, {
|
|
1590
|
+
size: 1,
|
|
1591
|
+
style: {
|
|
1592
|
+
whiteSpace: "pre-wrap"
|
|
1593
|
+
},
|
|
1594
|
+
children: definition.description
|
|
1595
|
+
})
|
|
1596
|
+
}) ]
|
|
244
1597
|
})
|
|
245
1598
|
}),
|
|
246
|
-
/* @__PURE__ */ jsx(
|
|
247
|
-
|
|
248
|
-
|
|
249
|
-
|
|
250
|
-
|
|
251
|
-
|
|
252
|
-
|
|
1599
|
+
/* @__PURE__ */ jsx(Flex, {
|
|
1600
|
+
direction: "column",
|
|
1601
|
+
flex: 1,
|
|
1602
|
+
style: {
|
|
1603
|
+
minHeight: 340
|
|
1604
|
+
},
|
|
1605
|
+
children: /* @__PURE__ */ jsx(MetaRow, {
|
|
1606
|
+
fillHeight: !0,
|
|
1607
|
+
label: "Stages",
|
|
1608
|
+
children: /* @__PURE__ */ jsx(WorkflowDiagram, {
|
|
1609
|
+
definition: definition,
|
|
1610
|
+
explain: !0,
|
|
1611
|
+
fill: !0,
|
|
1612
|
+
height: "100%"
|
|
253
1613
|
})
|
|
254
|
-
}) : /* @__PURE__ */ jsx(Text, {
|
|
255
|
-
size: 1,
|
|
256
|
-
style: {
|
|
257
|
-
whiteSpace: "pre-wrap"
|
|
258
|
-
},
|
|
259
|
-
children: definition.description
|
|
260
1614
|
})
|
|
261
|
-
}),
|
|
262
|
-
/* @__PURE__ */ jsx(WorkflowDiagram, {
|
|
263
|
-
definition: definition,
|
|
264
|
-
explain: !0,
|
|
265
|
-
height: 340
|
|
266
1615
|
}) ]
|
|
267
1616
|
});
|
|
268
1617
|
}
|
|
269
1618
|
|
|
270
|
-
function TabStatusRow({children: children}) {
|
|
271
|
-
/* @__PURE__ */
|
|
272
|
-
return jsx(Box, {
|
|
273
|
-
paddingLeft: 2,
|
|
274
|
-
paddingY: 3,
|
|
275
|
-
children: children
|
|
276
|
-
});
|
|
277
|
-
}
|
|
278
|
-
|
|
279
|
-
const INSTANCE_CAP = 200, NEWEST_INSTANCES = {
|
|
280
|
-
includeCompleted: !0,
|
|
281
|
-
limit: INSTANCE_CAP
|
|
282
|
-
};
|
|
283
|
-
|
|
284
|
-
function useToolInstances() {
|
|
285
|
-
const {engine: engine} = useWorkflowContext(), {instances: instances, loading: loading, unreadable: unreadable} = useWorkflowInstances({
|
|
286
|
-
engine: engine,
|
|
287
|
-
filter: NEWEST_INSTANCES
|
|
288
|
-
});
|
|
289
|
-
return useMemo(() => {
|
|
290
|
-
const rows = instances ?? [];
|
|
291
|
-
return {
|
|
292
|
-
inFlight: rows.filter(instance => terminalState(instance) === "in-flight"),
|
|
293
|
-
settled: rows.filter(instance => terminalState(instance) !== "in-flight"),
|
|
294
|
-
truncated: rows.length + unreadable.length === INSTANCE_CAP,
|
|
295
|
-
loading: loading,
|
|
296
|
-
unreadable: unreadable
|
|
297
|
-
};
|
|
298
|
-
}, [ instances, loading, unreadable ]);
|
|
299
|
-
}
|
|
300
|
-
|
|
301
1619
|
const MAX_VISIBLE_DOC_TYPES = 4, COLUMNS = {
|
|
302
1620
|
definition: 6,
|
|
303
1621
|
instances: 2,
|
|
@@ -314,7 +1632,12 @@ function Col({flex: flex, children: children}) {
|
|
|
314
1632
|
}
|
|
315
1633
|
|
|
316
1634
|
function DefinitionsTab({onOpenDefinition: onOpenDefinition}) {
|
|
317
|
-
const {definitions: definitions, error: error} = useDeployedDefinitions(), {mappings: mappings} = useWorkflowContext(), instances = useToolInstances()
|
|
1635
|
+
const {definitions: definitions, error: error} = useDeployedDefinitions(), {mappingIssues: mappingIssues, mappings: mappings} = useWorkflowContext(), schema = useSchema(), instances = useToolInstances(), undeployed = /* @__PURE__ */ jsx(UndeployedWorkflows, {
|
|
1636
|
+
notices: undeployedWorkflowNotices({
|
|
1637
|
+
issues: mappingIssues,
|
|
1638
|
+
titleOf: name => schema.get(name)?.title
|
|
1639
|
+
})
|
|
1640
|
+
});
|
|
318
1641
|
if (error !== void 0) /* @__PURE__ */
|
|
319
1642
|
return jsx(TabStatusRow, {
|
|
320
1643
|
children: /* @__PURE__ */ jsx(Text, {
|
|
@@ -330,25 +1653,32 @@ function DefinitionsTab({onOpenDefinition: onOpenDefinition}) {
|
|
|
330
1653
|
})
|
|
331
1654
|
});
|
|
332
1655
|
if (definitions.length === 0) /* @__PURE__ */
|
|
333
|
-
return
|
|
334
|
-
|
|
335
|
-
|
|
336
|
-
|
|
337
|
-
|
|
338
|
-
|
|
1656
|
+
return jsxs(Flex, {
|
|
1657
|
+
direction: "column",
|
|
1658
|
+
flex: 1,
|
|
1659
|
+
gap: 3,
|
|
1660
|
+
paddingBottom: 4,
|
|
1661
|
+
paddingTop: 3,
|
|
1662
|
+
children: [ undeployed,
|
|
1663
|
+
/* @__PURE__ */ jsx(EmptyState, {
|
|
1664
|
+
description: "Workflow definitions deployed to this project will appear here",
|
|
1665
|
+
icon: /* @__PURE__ */ jsx(TransferIcon, {}),
|
|
1666
|
+
title: "No definitions deployed"
|
|
1667
|
+
}) ]
|
|
339
1668
|
});
|
|
340
1669
|
const rows = definitionCatalog({
|
|
341
1670
|
definitions: definitions,
|
|
342
1671
|
mappings: mappings,
|
|
343
|
-
inFlight: instances.inFlight
|
|
1672
|
+
inFlight: instances.inFlight,
|
|
1673
|
+
issues: mappingIssues
|
|
344
1674
|
}), active = rows.reduce((sum, row) => sum + row.activeCount, 0);
|
|
345
1675
|
/* @__PURE__ */
|
|
346
1676
|
return jsxs(Stack, {
|
|
347
1677
|
gap: 3,
|
|
348
1678
|
paddingBottom: 4,
|
|
349
|
-
|
|
1679
|
+
paddingTop: 3,
|
|
1680
|
+
children: [ undeployed,
|
|
350
1681
|
/* @__PURE__ */ jsx(Box, {
|
|
351
|
-
paddingTop: 3,
|
|
352
1682
|
paddingX: 2,
|
|
353
1683
|
children: /* @__PURE__ */ jsxs(Flex, {
|
|
354
1684
|
align: "center",
|
|
@@ -435,7 +1765,7 @@ function DefinitionsTab({onOpenDefinition: onOpenDefinition}) {
|
|
|
435
1765
|
}, row.name))
|
|
436
1766
|
}) ]
|
|
437
1767
|
}), instances.truncated ? /* @__PURE__ */ jsx(MutedNote, {
|
|
438
|
-
text:
|
|
1768
|
+
text: INSTANCE_CAP_COUNT_NOTE
|
|
439
1769
|
}) : null ]
|
|
440
1770
|
});
|
|
441
1771
|
}
|
|
@@ -444,88 +1774,277 @@ function activeSummary(active) {
|
|
|
444
1774
|
return `${pluralize("active instance", active, !0)}`;
|
|
445
1775
|
}
|
|
446
1776
|
|
|
1777
|
+
const ROW_ISSUES_HINT = "This definition has issues";
|
|
1778
|
+
|
|
1779
|
+
function UndeployedWorkflows({notices: notices}) {
|
|
1780
|
+
return notices.length === 0 ? null :
|
|
1781
|
+
/* @__PURE__ */ jsx(Stack, {
|
|
1782
|
+
gap: 2,
|
|
1783
|
+
paddingBottom: 1,
|
|
1784
|
+
children: notices.map(notice => /* @__PURE__ */ jsx(CautionNote, {
|
|
1785
|
+
label: notice
|
|
1786
|
+
}, notice))
|
|
1787
|
+
});
|
|
1788
|
+
}
|
|
1789
|
+
|
|
447
1790
|
function DefinitionRow({countPending: countPending, onOpen: onOpen, row: row}) {
|
|
448
|
-
/* @__PURE__ */
|
|
449
|
-
return jsx(Card, {
|
|
1791
|
+
const flagged = row.brokenBindings.length > 0, card = /* @__PURE__ */ jsx(Card, {
|
|
450
1792
|
as: "button",
|
|
451
1793
|
onClick: onOpen,
|
|
452
1794
|
paddingX: 2,
|
|
453
1795
|
paddingY: 3,
|
|
454
1796
|
radius: 2,
|
|
455
1797
|
style: {
|
|
456
|
-
textAlign: "left"
|
|
1798
|
+
textAlign: "left",
|
|
1799
|
+
width: "100%"
|
|
457
1800
|
},
|
|
1801
|
+
...flagged ? {
|
|
1802
|
+
tone: "caution"
|
|
1803
|
+
} : {},
|
|
458
1804
|
children: /* @__PURE__ */ jsxs(Flex, {
|
|
459
1805
|
align: "flex-start",
|
|
460
1806
|
gap: 4,
|
|
461
1807
|
children: [
|
|
462
1808
|
/* @__PURE__ */ jsx(Col, {
|
|
463
1809
|
flex: COLUMNS.definition,
|
|
464
|
-
children: /* @__PURE__ */ jsxs(
|
|
1810
|
+
children: /* @__PURE__ */ jsxs(Flex, {
|
|
1811
|
+
align: "flex-start",
|
|
1812
|
+
gap: 3,
|
|
1813
|
+
paddingLeft: flagged ? 1 : 0,
|
|
1814
|
+
children: [ flagged ? /* @__PURE__ */ jsx(Text, {
|
|
1815
|
+
size: 1,
|
|
1816
|
+
children: /* @__PURE__ */ jsx(WarningOutlineIcon, {})
|
|
1817
|
+
}) : null,
|
|
1818
|
+
/* @__PURE__ */ jsxs(Stack, {
|
|
1819
|
+
flex: 1,
|
|
1820
|
+
gap: 3,
|
|
1821
|
+
style: {
|
|
1822
|
+
minWidth: 0
|
|
1823
|
+
},
|
|
1824
|
+
children: [
|
|
1825
|
+
/* @__PURE__ */ jsx(Text, {
|
|
1826
|
+
size: 1,
|
|
1827
|
+
weight: "semibold",
|
|
1828
|
+
children: row.title
|
|
1829
|
+
}), row.description === void 0 ? /* @__PURE__ */ jsx(Text, {
|
|
1830
|
+
muted: !0,
|
|
1831
|
+
size: 1,
|
|
1832
|
+
children: /* @__PURE__ */ jsx("em", {
|
|
1833
|
+
children: "No description"
|
|
1834
|
+
})
|
|
1835
|
+
}) : /* @__PURE__ */ jsx(Text, {
|
|
1836
|
+
muted: !0,
|
|
1837
|
+
size: 1,
|
|
1838
|
+
children: row.description
|
|
1839
|
+
}) ]
|
|
1840
|
+
}) ]
|
|
1841
|
+
})
|
|
1842
|
+
}),
|
|
1843
|
+
/* @__PURE__ */ jsx(Col, {
|
|
1844
|
+
flex: COLUMNS.instances,
|
|
1845
|
+
children: /* @__PURE__ */ jsx(Text, {
|
|
1846
|
+
muted: !0,
|
|
1847
|
+
size: 1,
|
|
1848
|
+
children: countPending ? "—" : `${row.activeCount} active`
|
|
1849
|
+
})
|
|
1850
|
+
}),
|
|
1851
|
+
/* @__PURE__ */ jsx(Col, {
|
|
1852
|
+
flex: COLUMNS.docTypes,
|
|
1853
|
+
children: /* @__PURE__ */ jsx(DocTypeChips, {
|
|
1854
|
+
docTypes: row.docTypes
|
|
1855
|
+
})
|
|
1856
|
+
}) ]
|
|
1857
|
+
})
|
|
1858
|
+
});
|
|
1859
|
+
return flagged ? /* @__PURE__ */ jsx(HoverHint, {
|
|
1860
|
+
fill: !0,
|
|
1861
|
+
text: ROW_ISSUES_HINT,
|
|
1862
|
+
children: card
|
|
1863
|
+
}) : card;
|
|
1864
|
+
}
|
|
1865
|
+
|
|
1866
|
+
function DocTypeChips({docTypes: docTypes}) {
|
|
1867
|
+
const schema = useSchema(), badgeTrim = useBadgeCapTrim();
|
|
1868
|
+
if (docTypes.length === 0) /* @__PURE__ */
|
|
1869
|
+
return jsx(Text, {
|
|
1870
|
+
muted: !0,
|
|
1871
|
+
size: 1,
|
|
1872
|
+
children: "—"
|
|
1873
|
+
});
|
|
1874
|
+
const labels = docTypeLabels(docTypes, name => schema.get(name)?.title), shown = labels.slice(0, MAX_VISIBLE_DOC_TYPES), overflow = labels.length - shown.length;
|
|
1875
|
+
/* @__PURE__ */
|
|
1876
|
+
return jsxs(Flex, {
|
|
1877
|
+
align: "center",
|
|
1878
|
+
gap: 2,
|
|
1879
|
+
style: badgeTrim,
|
|
1880
|
+
wrap: "wrap",
|
|
1881
|
+
children: [ shown.map(docType =>
|
|
1882
|
+
/* @__PURE__ */ jsx(Badge, {
|
|
1883
|
+
fontSize: 1,
|
|
1884
|
+
style: {
|
|
1885
|
+
minWidth: 0
|
|
1886
|
+
},
|
|
1887
|
+
children: /* @__PURE__ */ jsx("span", {
|
|
1888
|
+
style: {
|
|
1889
|
+
display: "block",
|
|
1890
|
+
overflow: "hidden",
|
|
1891
|
+
textOverflow: "ellipsis",
|
|
1892
|
+
whiteSpace: "nowrap"
|
|
1893
|
+
},
|
|
1894
|
+
children: docType.title
|
|
1895
|
+
})
|
|
1896
|
+
}, docType.name)), overflow > 0 ? /* @__PURE__ */ jsxs(Text, {
|
|
1897
|
+
muted: !0,
|
|
1898
|
+
size: 1,
|
|
1899
|
+
children: [ "+", overflow, " more" ]
|
|
1900
|
+
}) : null ]
|
|
1901
|
+
});
|
|
1902
|
+
}
|
|
1903
|
+
|
|
1904
|
+
function normalizeAbortReason(raw) {
|
|
1905
|
+
const trimmed = raw.trim();
|
|
1906
|
+
return trimmed === "" ? void 0 : trimmed;
|
|
1907
|
+
}
|
|
1908
|
+
|
|
1909
|
+
function abortedToast(title) {
|
|
1910
|
+
return {
|
|
1911
|
+
id: TOAST_ID.abort,
|
|
1912
|
+
status: "info",
|
|
1913
|
+
title: `Aborted “${title}”`
|
|
1914
|
+
};
|
|
1915
|
+
}
|
|
1916
|
+
|
|
1917
|
+
function abortAlreadySettledToast(title) {
|
|
1918
|
+
return {
|
|
1919
|
+
id: TOAST_ID.abort,
|
|
1920
|
+
status: "info",
|
|
1921
|
+
title: `“${title}” had already finished`,
|
|
1922
|
+
description: "Nothing was aborted — the workflow reached a terminal state first."
|
|
1923
|
+
};
|
|
1924
|
+
}
|
|
1925
|
+
|
|
1926
|
+
function abortUnconfirmedToast(args) {
|
|
1927
|
+
return {
|
|
1928
|
+
id: TOAST_ID.abort,
|
|
1929
|
+
status: "warning",
|
|
1930
|
+
title: `Couldn’t confirm “${args.title}” was aborted`,
|
|
1931
|
+
description: `${describeError(args.err)} — the abort may still have committed, so check the workflow’s state before trying again.`
|
|
1932
|
+
};
|
|
1933
|
+
}
|
|
1934
|
+
|
|
1935
|
+
function AbortWorkflowDialog({entry: entry, onClose: onClose}) {
|
|
1936
|
+
const {engine: engine} = useWorkflowContext(), definition = useDefinition(entry), toast = useWorkflowToast(), [typedReason, setTypedReason] = useState(""), [pending, setPending] = useState(!1), {instance: instance} = entry, title = instanceTitle(instance, definition), reason = normalizeAbortReason(typedReason), reasonInputId = `abort-workflow-reason-${instance._id}`, confirm = async () => {
|
|
1937
|
+
if (reason !== void 0) {
|
|
1938
|
+
setPending(!0);
|
|
1939
|
+
try {
|
|
1940
|
+
const {changed: changed} = await engine.abortInstance({
|
|
1941
|
+
instanceId: instance._id,
|
|
1942
|
+
reason: reason
|
|
1943
|
+
});
|
|
1944
|
+
toast.push(changed ? abortedToast(title) : abortAlreadySettledToast(title)), onClose();
|
|
1945
|
+
} catch (err) {
|
|
1946
|
+
toast.push(abortUnconfirmedToast({
|
|
1947
|
+
title: title,
|
|
1948
|
+
err: err
|
|
1949
|
+
})), setPending(!1);
|
|
1950
|
+
}
|
|
1951
|
+
}
|
|
1952
|
+
};
|
|
1953
|
+
/* @__PURE__ */
|
|
1954
|
+
return jsx(Dialog, {
|
|
1955
|
+
footer: /* @__PURE__ */ jsx(Box, {
|
|
1956
|
+
padding: 3,
|
|
1957
|
+
children: /* @__PURE__ */ jsxs(Flex, {
|
|
1958
|
+
gap: 2,
|
|
1959
|
+
justify: "flex-end",
|
|
1960
|
+
children: [
|
|
1961
|
+
/* @__PURE__ */ jsx(Button, {
|
|
1962
|
+
disabled: pending,
|
|
1963
|
+
fontSize: 1,
|
|
1964
|
+
mode: "bleed",
|
|
1965
|
+
onClick: onClose,
|
|
1966
|
+
padding: 2,
|
|
1967
|
+
text: "Cancel"
|
|
1968
|
+
}),
|
|
1969
|
+
/* @__PURE__ */ jsx(Button, {
|
|
1970
|
+
disabled: reason === void 0,
|
|
1971
|
+
fontSize: 1,
|
|
1972
|
+
loading: pending,
|
|
1973
|
+
onClick: () => {
|
|
1974
|
+
confirm();
|
|
1975
|
+
},
|
|
1976
|
+
padding: 2,
|
|
1977
|
+
text: "Abort workflow",
|
|
1978
|
+
tone: "critical"
|
|
1979
|
+
}) ]
|
|
1980
|
+
})
|
|
1981
|
+
}),
|
|
1982
|
+
header: "Abort workflow",
|
|
1983
|
+
id: `abort-workflow-${instance._id}`,
|
|
1984
|
+
onClose: () => {
|
|
1985
|
+
pending || onClose();
|
|
1986
|
+
},
|
|
1987
|
+
width: 0,
|
|
1988
|
+
children: /* @__PURE__ */ jsx(Box, {
|
|
1989
|
+
padding: 4,
|
|
1990
|
+
children: /* @__PURE__ */ jsxs(Stack, {
|
|
1991
|
+
gap: 5,
|
|
1992
|
+
children: [
|
|
1993
|
+
/* @__PURE__ */ jsxs(Text, {
|
|
1994
|
+
size: 1,
|
|
1995
|
+
children: [ "Abort the ",
|
|
1996
|
+
/* @__PURE__ */ jsx("strong", {
|
|
1997
|
+
children: title
|
|
1998
|
+
}), " workflow? This cannot be undone." ]
|
|
1999
|
+
}),
|
|
2000
|
+
/* @__PURE__ */ jsxs(Stack, {
|
|
465
2001
|
gap: 3,
|
|
466
|
-
style: {
|
|
467
|
-
minWidth: 0
|
|
468
|
-
},
|
|
469
2002
|
children: [
|
|
470
2003
|
/* @__PURE__ */ jsx(Text, {
|
|
2004
|
+
as: "label",
|
|
2005
|
+
htmlFor: reasonInputId,
|
|
471
2006
|
size: 1,
|
|
472
|
-
weight: "
|
|
473
|
-
children:
|
|
474
|
-
}),
|
|
475
|
-
|
|
476
|
-
|
|
477
|
-
|
|
478
|
-
|
|
479
|
-
|
|
480
|
-
|
|
481
|
-
|
|
482
|
-
size: 1,
|
|
483
|
-
children: row.description
|
|
2007
|
+
weight: "medium",
|
|
2008
|
+
children: "Reason"
|
|
2009
|
+
}),
|
|
2010
|
+
/* @__PURE__ */ jsx(TextInput, {
|
|
2011
|
+
autoFocus: !0,
|
|
2012
|
+
fontSize: 1,
|
|
2013
|
+
id: reasonInputId,
|
|
2014
|
+
onChange: event => setTypedReason(event.currentTarget.value),
|
|
2015
|
+
placeholder: "Why is this workflow being stopped?",
|
|
2016
|
+
value: typedReason
|
|
484
2017
|
}) ]
|
|
485
|
-
})
|
|
486
|
-
})
|
|
487
|
-
/* @__PURE__ */ jsx(Col, {
|
|
488
|
-
flex: COLUMNS.instances,
|
|
489
|
-
children: /* @__PURE__ */ jsx(Text, {
|
|
490
|
-
muted: !0,
|
|
491
|
-
size: 1,
|
|
492
|
-
children: countPending ? "—" : `${row.activeCount} active`
|
|
493
|
-
})
|
|
494
|
-
}),
|
|
495
|
-
/* @__PURE__ */ jsx(Col, {
|
|
496
|
-
flex: COLUMNS.docTypes,
|
|
497
|
-
children: /* @__PURE__ */ jsx(DocTypeChips, {
|
|
498
|
-
docTypes: row.docTypes
|
|
499
|
-
})
|
|
500
|
-
}) ]
|
|
2018
|
+
}) ]
|
|
2019
|
+
})
|
|
501
2020
|
})
|
|
502
2021
|
});
|
|
503
2022
|
}
|
|
504
2023
|
|
|
505
|
-
function
|
|
506
|
-
const
|
|
507
|
-
|
|
508
|
-
|
|
509
|
-
|
|
510
|
-
|
|
511
|
-
children: "—"
|
|
512
|
-
});
|
|
513
|
-
const labels = docTypeLabels(docTypes, name => schema.get(name)?.title), shown = labels.slice(0, MAX_VISIBLE_DOC_TYPES), overflow = labels.length - shown.length;
|
|
514
|
-
/* @__PURE__ */
|
|
515
|
-
return jsxs(Flex, {
|
|
516
|
-
align: "center",
|
|
517
|
-
gap: 2,
|
|
518
|
-
style: badgeTrim,
|
|
519
|
-
wrap: "wrap",
|
|
520
|
-
children: [ shown.map(docType => /* @__PURE__ */ jsx(Badge, {
|
|
521
|
-
fontSize: 1,
|
|
522
|
-
children: docType.title
|
|
523
|
-
}, docType.name)), overflow > 0 ? /* @__PURE__ */ jsxs(Text, {
|
|
524
|
-
muted: !0,
|
|
2024
|
+
function AbortWorkflowSection({entry: entry}) {
|
|
2025
|
+
const [aborting, setAborting] = useState(!1);
|
|
2026
|
+
return isLiveEntry(entry) ? /* @__PURE__ */ jsxs(Stack, {
|
|
2027
|
+
gap: 4,
|
|
2028
|
+
children: [
|
|
2029
|
+
/* @__PURE__ */ jsx(Text, {
|
|
525
2030
|
size: 1,
|
|
526
|
-
|
|
2031
|
+
weight: "semibold",
|
|
2032
|
+
children: "Manage workflow"
|
|
2033
|
+
}),
|
|
2034
|
+
/* @__PURE__ */ jsx(Flex, {
|
|
2035
|
+
children: /* @__PURE__ */ jsx(Button, {
|
|
2036
|
+
fontSize: 1,
|
|
2037
|
+
mode: "ghost",
|
|
2038
|
+
onClick: () => setAborting(!0),
|
|
2039
|
+
padding: 2,
|
|
2040
|
+
text: "Abort workflow…",
|
|
2041
|
+
tone: "critical"
|
|
2042
|
+
})
|
|
2043
|
+
}), aborting ? /* @__PURE__ */ jsx(AbortWorkflowDialog, {
|
|
2044
|
+
entry: entry,
|
|
2045
|
+
onClose: () => setAborting(!1)
|
|
527
2046
|
}) : null ]
|
|
528
|
-
});
|
|
2047
|
+
}) : null;
|
|
529
2048
|
}
|
|
530
2049
|
|
|
531
2050
|
function makeTitleResolver(definition) {
|
|
@@ -600,19 +2119,21 @@ function historyLine(h, titles) {
|
|
|
600
2119
|
}
|
|
601
2120
|
|
|
602
2121
|
function PendingEffectRows({instance: instance, now: now}) {
|
|
603
|
-
const {drainEffectsFor: drainEffectsFor, completeEffectFor: completeEffectFor, effectHandlers: effectHandlers} = useWorkflowContext(), toast =
|
|
2122
|
+
const {drainEffectsFor: drainEffectsFor, completeEffectFor: completeEffectFor, effectHandlers: effectHandlers} = useWorkflowContext(), toast = useWorkflowToast(), [busy, setBusy] = useState(!1), pending = instance.pendingEffects ?? [];
|
|
604
2123
|
if (pending.length === 0) return null;
|
|
605
2124
|
const runRegistered = async () => {
|
|
606
2125
|
setBusy(!0);
|
|
607
2126
|
try {
|
|
608
2127
|
await drainEffectsFor(instance._id), toast.push({
|
|
609
|
-
|
|
610
|
-
|
|
2128
|
+
id: TOAST_ID.effectsDrain,
|
|
2129
|
+
status: "info",
|
|
2130
|
+
title: "Ran the registered handlers"
|
|
611
2131
|
});
|
|
612
2132
|
} catch (err) {
|
|
613
2133
|
toast.push({
|
|
2134
|
+
id: TOAST_ID.effectsDrain,
|
|
614
2135
|
status: "error",
|
|
615
|
-
title: "
|
|
2136
|
+
title: "Failed to run pending effects",
|
|
616
2137
|
description: describeError(err)
|
|
617
2138
|
});
|
|
618
2139
|
} finally {
|
|
@@ -626,13 +2147,15 @@ function PendingEffectRows({instance: instance, now: now}) {
|
|
|
626
2147
|
status: status,
|
|
627
2148
|
detail: "Resolved in Studio"
|
|
628
2149
|
}), toast.push({
|
|
629
|
-
|
|
630
|
-
|
|
2150
|
+
id: TOAST_ID.effectResolve,
|
|
2151
|
+
status: "info",
|
|
2152
|
+
title: `Effect marked as ${status}`
|
|
631
2153
|
});
|
|
632
2154
|
} catch (err) {
|
|
633
2155
|
toast.push({
|
|
2156
|
+
id: TOAST_ID.effectResolve,
|
|
634
2157
|
status: "error",
|
|
635
|
-
title: "
|
|
2158
|
+
title: "Failed to resolve the effect",
|
|
636
2159
|
description: describeError(err)
|
|
637
2160
|
});
|
|
638
2161
|
} finally {
|
|
@@ -862,13 +2385,7 @@ function FeedGlyph({hint: hint, icon: icon}) {
|
|
|
862
2385
|
});
|
|
863
2386
|
}
|
|
864
2387
|
|
|
865
|
-
function
|
|
866
|
-
const seen = /* @__PURE__ */ new Map;
|
|
867
|
-
for (const ref of entryDocRefs(instance.fields)) seen.has(ref.id) || seen.set(ref.id, ref);
|
|
868
|
-
return [ ...seen.values() ];
|
|
869
|
-
}
|
|
870
|
-
|
|
871
|
-
function WorkflowInstanceDetail({instanceId: instanceId, onBack: onBack}) {
|
|
2388
|
+
function WorkflowInstanceDetail({instanceId: instanceId, backToList: backToList}) {
|
|
872
2389
|
const entry = useWorkflowInstanceEntry(instanceId);
|
|
873
2390
|
useLogEventOnMount(WorkflowInstanceDetailViewed, {
|
|
874
2391
|
instanceId: instanceId
|
|
@@ -887,9 +2404,14 @@ function WorkflowInstanceDetail({instanceId: instanceId, onBack: onBack}) {
|
|
|
887
2404
|
}) : /* @__PURE__ */ jsx(Box, {
|
|
888
2405
|
paddingX: 3,
|
|
889
2406
|
children: /* @__PURE__ */ jsx(TabStatusRow, {
|
|
890
|
-
children: graceOver ? /* @__PURE__ */ jsx(
|
|
891
|
-
|
|
892
|
-
|
|
2407
|
+
children: graceOver ? /* @__PURE__ */ jsx(DetailNotFound, {
|
|
2408
|
+
back: backToList,
|
|
2409
|
+
message: /* @__PURE__ */ jsxs(Fragment, {
|
|
2410
|
+
children: [ "Unable to find workflow with id “",
|
|
2411
|
+
/* @__PURE__ */ jsx("strong", {
|
|
2412
|
+
children: instanceId
|
|
2413
|
+
}), "”." ]
|
|
2414
|
+
})
|
|
893
2415
|
}) : /* @__PURE__ */ jsx(LoadingRow, {
|
|
894
2416
|
label: "Loading workflow…"
|
|
895
2417
|
})
|
|
@@ -897,29 +2419,6 @@ function WorkflowInstanceDetail({instanceId: instanceId, onBack: onBack}) {
|
|
|
897
2419
|
});
|
|
898
2420
|
}
|
|
899
2421
|
|
|
900
|
-
function NotFound({id: id, onBack: onBack}) {
|
|
901
|
-
/* @__PURE__ */
|
|
902
|
-
return jsxs(Stack, {
|
|
903
|
-
gap: 4,
|
|
904
|
-
children: [
|
|
905
|
-
/* @__PURE__ */ jsxs(Text, {
|
|
906
|
-
muted: !0,
|
|
907
|
-
size: 1,
|
|
908
|
-
children: [ "No workflow with id “", id, "” — it may have been deleted." ]
|
|
909
|
-
}),
|
|
910
|
-
/* @__PURE__ */ jsx(Flex, {
|
|
911
|
-
children: /* @__PURE__ */ jsx(Button, {
|
|
912
|
-
fontSize: 1,
|
|
913
|
-
icon: ArrowLeftIcon,
|
|
914
|
-
mode: "ghost",
|
|
915
|
-
onClick: onBack,
|
|
916
|
-
padding: 2,
|
|
917
|
-
text: "Back to workflows"
|
|
918
|
-
})
|
|
919
|
-
}) ]
|
|
920
|
-
});
|
|
921
|
-
}
|
|
922
|
-
|
|
923
2422
|
function InstanceDetailPanel({entry: entry}) {
|
|
924
2423
|
const definition = useDefinition(entry), snapshotWidth = useContainerToken(2), [openActivity, setOpenActivity] = useState(null), {instance: instance, ready: ready} = entry;
|
|
925
2424
|
return useEffect(() => {
|
|
@@ -962,7 +2461,11 @@ function InstanceDetailPanel({entry: entry}) {
|
|
|
962
2461
|
onOpenActivity: name => setOpenActivity({
|
|
963
2462
|
stage: instance.currentStage,
|
|
964
2463
|
activityName: name
|
|
965
|
-
})
|
|
2464
|
+
}),
|
|
2465
|
+
surface: "tool-instance-detail"
|
|
2466
|
+
}),
|
|
2467
|
+
/* @__PURE__ */ jsx(AbortWorkflowSection, {
|
|
2468
|
+
entry: entry
|
|
966
2469
|
}),
|
|
967
2470
|
/* @__PURE__ */ jsxs(Stack, {
|
|
968
2471
|
gap: 4,
|
|
@@ -1066,217 +2569,76 @@ function DefinitionPickerPanel({onPick: onPick}) {
|
|
|
1066
2569
|
overflowY: "auto"
|
|
1067
2570
|
},
|
|
1068
2571
|
children: visible.map(definition => /* @__PURE__ */ jsx(Card, {
|
|
1069
|
-
as: "button",
|
|
1070
|
-
onClick: () => onPick(definition),
|
|
1071
|
-
padding: 3,
|
|
1072
|
-
radius: 2,
|
|
1073
|
-
style: {
|
|
1074
|
-
cursor: "pointer",
|
|
1075
|
-
textAlign: "left"
|
|
1076
|
-
},
|
|
1077
|
-
children: /* @__PURE__ */ jsxs(Stack, {
|
|
1078
|
-
gap: 2,
|
|
1079
|
-
children: [
|
|
1080
|
-
/* @__PURE__ */ jsx(Text, {
|
|
1081
|
-
size: 1,
|
|
1082
|
-
weight: "medium",
|
|
1083
|
-
children: definition.title
|
|
1084
|
-
}), definition.description ? /* @__PURE__ */ jsx(Text, {
|
|
1085
|
-
muted: !0,
|
|
1086
|
-
size: 1,
|
|
1087
|
-
textOverflow: "ellipsis",
|
|
1088
|
-
children: definition.description
|
|
1089
|
-
}) : null ]
|
|
1090
|
-
})
|
|
1091
|
-
}, definition.name))
|
|
1092
|
-
}) ]
|
|
1093
|
-
})
|
|
1094
|
-
});
|
|
1095
|
-
}
|
|
1096
|
-
|
|
1097
|
-
function ToolActivityDialog({target: target, onClose: onClose}) {
|
|
1098
|
-
const entry = useWorkflowInstanceEntry(target.instanceId), definition = useDefinition(entry), resolvedOnce = useRef(!1);
|
|
1099
|
-
return entry && (resolvedOnce.current = !0), useEffect(() => {
|
|
1100
|
-
resolvedOnce.current && openActivityGone({
|
|
1101
|
-
entry: entry,
|
|
1102
|
-
target: target
|
|
1103
|
-
}) && onClose();
|
|
1104
|
-
}, [ entry, target, onClose ]), entry?.invalid ? /* @__PURE__ */ jsx(Dialog, {
|
|
1105
|
-
header: "Workflow unavailable",
|
|
1106
|
-
id: "workflow-activity-detail",
|
|
1107
|
-
onClose: onClose,
|
|
1108
|
-
width: 1,
|
|
1109
|
-
children: /* @__PURE__ */ jsx(Box, {
|
|
1110
|
-
padding: 4,
|
|
1111
|
-
children: /* @__PURE__ */ jsx(InvalidDocNotice, {
|
|
1112
|
-
invalid: entry.invalid
|
|
1113
|
-
})
|
|
1114
|
-
})
|
|
1115
|
-
}) : entry?.evaluation ? /* @__PURE__ */ jsx(ActivityDetailDialog, {
|
|
1116
|
-
activityName: target.activityName,
|
|
1117
|
-
breadcrumb: instanceBreadcrumb(entry.instance, definition),
|
|
1118
|
-
definition: definition,
|
|
1119
|
-
document: documentRefsOf(entry.instance)[0],
|
|
1120
|
-
entry: entry,
|
|
1121
|
-
onClose: onClose,
|
|
1122
|
-
source: "tool-task-list"
|
|
1123
|
-
}) : /* @__PURE__ */ jsx(Dialog, {
|
|
1124
|
-
header: "Loading activity…",
|
|
1125
|
-
id: "workflow-activity-detail",
|
|
1126
|
-
onClose: onClose,
|
|
1127
|
-
width: 1,
|
|
1128
|
-
children: /* @__PURE__ */ jsx(Box, {
|
|
1129
|
-
padding: 4,
|
|
1130
|
-
children: /* @__PURE__ */ jsx(LoadingRow, {
|
|
1131
|
-
label: "Fetching the live workflow state…"
|
|
1132
|
-
})
|
|
1133
|
-
})
|
|
1134
|
-
});
|
|
1135
|
-
}
|
|
1136
|
-
|
|
1137
|
-
const GROUP_DEFAULT_OPEN = !0;
|
|
1138
|
-
|
|
1139
|
-
function instanceBandDefaultOpen(segment) {
|
|
1140
|
-
return segment === "for-me";
|
|
1141
|
-
}
|
|
1142
|
-
|
|
1143
|
-
const UNGROUPED_BAND_KEY = "section:no-document", PAYLOAD_VERSION = 1, MAX_ENTRIES = 200;
|
|
1144
|
-
|
|
1145
|
-
function bandStateStorageKey(scope) {
|
|
1146
|
-
return `sanity.workflows.tool.bands:${scope}`;
|
|
1147
|
-
}
|
|
1148
|
-
|
|
1149
|
-
function isRecord(value) {
|
|
1150
|
-
return typeof value == "object" && value !== null && !Array.isArray(value);
|
|
1151
|
-
}
|
|
1152
|
-
|
|
1153
|
-
function bandEntryOf(value) {
|
|
1154
|
-
if (!isRecord(value)) return;
|
|
1155
|
-
const {open: open, touched: touched} = value;
|
|
1156
|
-
if (!(typeof open != "boolean" || typeof touched != "number") && Number.isFinite(touched)) return {
|
|
1157
|
-
open: open,
|
|
1158
|
-
touched: touched
|
|
1159
|
-
};
|
|
1160
|
-
}
|
|
1161
|
-
|
|
1162
|
-
function parsePayload(raw) {
|
|
1163
|
-
try {
|
|
1164
|
-
const parsed = JSON.parse(raw);
|
|
1165
|
-
if (!isRecord(parsed) || parsed.version !== PAYLOAD_VERSION || !isRecord(parsed.bands)) return;
|
|
1166
|
-
const entries = [];
|
|
1167
|
-
for (const [key, value] of Object.entries(parsed.bands)) {
|
|
1168
|
-
const entry = bandEntryOf(value);
|
|
1169
|
-
if (entry === void 0) return;
|
|
1170
|
-
entries.push([ key, entry ]);
|
|
1171
|
-
}
|
|
1172
|
-
return Object.fromEntries(entries);
|
|
1173
|
-
} catch {
|
|
1174
|
-
return;
|
|
1175
|
-
}
|
|
1176
|
-
}
|
|
1177
|
-
|
|
1178
|
-
function readStored(storage, storageKey) {
|
|
1179
|
-
if (!storage) return {
|
|
1180
|
-
entries: void 0,
|
|
1181
|
-
corrupt: !1
|
|
1182
|
-
};
|
|
1183
|
-
let raw;
|
|
1184
|
-
try {
|
|
1185
|
-
raw = storage.getItem(storageKey);
|
|
1186
|
-
} catch {
|
|
1187
|
-
return {
|
|
1188
|
-
entries: void 0,
|
|
1189
|
-
corrupt: !1
|
|
1190
|
-
};
|
|
1191
|
-
}
|
|
1192
|
-
if (raw === null) return {
|
|
1193
|
-
entries: {},
|
|
1194
|
-
corrupt: !1
|
|
1195
|
-
};
|
|
1196
|
-
const entries = parsePayload(raw);
|
|
1197
|
-
return {
|
|
1198
|
-
entries: entries,
|
|
1199
|
-
corrupt: entries === void 0
|
|
1200
|
-
};
|
|
1201
|
-
}
|
|
1202
|
-
|
|
1203
|
-
function writeStored(args) {
|
|
1204
|
-
if (!args.storage) return !1;
|
|
1205
|
-
try {
|
|
1206
|
-
return args.storage.setItem(args.storageKey, JSON.stringify({
|
|
1207
|
-
version: PAYLOAD_VERSION,
|
|
1208
|
-
bands: args.entries
|
|
1209
|
-
})), !0;
|
|
1210
|
-
} catch {
|
|
1211
|
-
return !1;
|
|
1212
|
-
}
|
|
1213
|
-
}
|
|
1214
|
-
|
|
1215
|
-
function baseEntries(args) {
|
|
1216
|
-
return args.stored === void 0 ? args.held : args.unpersisted ? mergeByTouched(args.stored, args.held) : args.stored;
|
|
1217
|
-
}
|
|
1218
|
-
|
|
1219
|
-
function mergeByTouched(stored, held) {
|
|
1220
|
-
const merged = {
|
|
1221
|
-
...stored
|
|
1222
|
-
};
|
|
1223
|
-
for (const [key, entry] of Object.entries(held)) {
|
|
1224
|
-
const persisted = merged[key];
|
|
1225
|
-
(persisted === void 0 || entry.touched >= persisted.touched) && (merged[key] = entry);
|
|
1226
|
-
}
|
|
1227
|
-
return merged;
|
|
1228
|
-
}
|
|
1229
|
-
|
|
1230
|
-
function prune(entries) {
|
|
1231
|
-
const held = Object.entries(entries);
|
|
1232
|
-
return held.length <= MAX_ENTRIES ? entries : Object.fromEntries(held.sort(([, a], [, b]) => b.touched - a.touched).slice(0, MAX_ENTRIES));
|
|
1233
|
-
}
|
|
1234
|
-
|
|
1235
|
-
function togglesOf(entries) {
|
|
1236
|
-
return new Map(Object.entries(entries).map(([key, entry]) => [ key, entry.open ]));
|
|
1237
|
-
}
|
|
1238
|
-
|
|
1239
|
-
function defaultStorage() {
|
|
1240
|
-
try {
|
|
1241
|
-
return globalThis.localStorage;
|
|
1242
|
-
} catch {
|
|
1243
|
-
return;
|
|
1244
|
-
}
|
|
2572
|
+
as: "button",
|
|
2573
|
+
onClick: () => onPick(definition),
|
|
2574
|
+
padding: 3,
|
|
2575
|
+
radius: 2,
|
|
2576
|
+
style: {
|
|
2577
|
+
cursor: "pointer",
|
|
2578
|
+
textAlign: "left"
|
|
2579
|
+
},
|
|
2580
|
+
children: /* @__PURE__ */ jsxs(Stack, {
|
|
2581
|
+
gap: 2,
|
|
2582
|
+
children: [
|
|
2583
|
+
/* @__PURE__ */ jsx(Text, {
|
|
2584
|
+
size: 1,
|
|
2585
|
+
weight: "medium",
|
|
2586
|
+
children: definition.title
|
|
2587
|
+
}), definition.description ? /* @__PURE__ */ jsx(Text, {
|
|
2588
|
+
muted: !0,
|
|
2589
|
+
size: 1,
|
|
2590
|
+
textOverflow: "ellipsis",
|
|
2591
|
+
children: definition.description
|
|
2592
|
+
}) : null ]
|
|
2593
|
+
})
|
|
2594
|
+
}, definition.name))
|
|
2595
|
+
}) ]
|
|
2596
|
+
})
|
|
2597
|
+
});
|
|
1245
2598
|
}
|
|
1246
2599
|
|
|
1247
|
-
function
|
|
1248
|
-
const
|
|
1249
|
-
|
|
1250
|
-
|
|
1251
|
-
|
|
1252
|
-
|
|
2600
|
+
function ToolActivityDialog({target: target, onClose: onClose}) {
|
|
2601
|
+
const entry = useWorkflowInstanceEntry(target.instanceId), definition = useDefinition(entry), resolvedOnce = useRef(!1);
|
|
2602
|
+
return entry && (resolvedOnce.current = !0), useEffect(() => {
|
|
2603
|
+
resolvedOnce.current && openActivityGone({
|
|
2604
|
+
entry: entry,
|
|
2605
|
+
target: target
|
|
2606
|
+
}) && onClose();
|
|
2607
|
+
}, [ entry, target, onClose ]), entry?.invalid ? /* @__PURE__ */ jsx(Dialog, {
|
|
2608
|
+
header: "Workflow unavailable",
|
|
2609
|
+
id: "workflow-activity-detail",
|
|
2610
|
+
onClose: onClose,
|
|
2611
|
+
width: 1,
|
|
2612
|
+
children: /* @__PURE__ */ jsx(Box, {
|
|
2613
|
+
padding: 4,
|
|
2614
|
+
children: /* @__PURE__ */ jsx(InvalidDocNotice, {
|
|
2615
|
+
invalid: entry.invalid
|
|
2616
|
+
})
|
|
2617
|
+
})
|
|
2618
|
+
}) : entry?.evaluation ? /* @__PURE__ */ jsx(ActivityDetailDialog, {
|
|
2619
|
+
activityName: target.activityName,
|
|
2620
|
+
breadcrumb: instanceBreadcrumb(entry.instance, definition),
|
|
2621
|
+
definition: definition,
|
|
2622
|
+
document: documentRefsOf(entry.instance)[0],
|
|
2623
|
+
entry: entry,
|
|
2624
|
+
onClose: onClose,
|
|
2625
|
+
source: "tool-task-list"
|
|
2626
|
+
}) : /* @__PURE__ */ jsx(Dialog, {
|
|
2627
|
+
header: "Loading activity…",
|
|
2628
|
+
id: "workflow-activity-detail",
|
|
2629
|
+
onClose: onClose,
|
|
2630
|
+
width: 1,
|
|
2631
|
+
children: /* @__PURE__ */ jsx(Box, {
|
|
2632
|
+
padding: 4,
|
|
2633
|
+
children: /* @__PURE__ */ jsx(LoadingRow, {
|
|
2634
|
+
label: "Fetching the live workflow state…"
|
|
2635
|
+
})
|
|
2636
|
+
})
|
|
1253
2637
|
});
|
|
1254
|
-
let held = initial.entries ?? {}, unpersisted = !1;
|
|
1255
|
-
return {
|
|
1256
|
-
read: () => togglesOf(held),
|
|
1257
|
-
setOpen(key, open) {
|
|
1258
|
-
const stored = readStored(storage, args.storageKey).entries, base = baseEntries({
|
|
1259
|
-
stored: stored,
|
|
1260
|
-
held: held,
|
|
1261
|
-
unpersisted: unpersisted
|
|
1262
|
-
});
|
|
1263
|
-
return held = prune({
|
|
1264
|
-
...base,
|
|
1265
|
-
[key]: {
|
|
1266
|
-
open: open,
|
|
1267
|
-
touched: Date.now()
|
|
1268
|
-
}
|
|
1269
|
-
}), unpersisted = !writeStored({
|
|
1270
|
-
storage: storage,
|
|
1271
|
-
storageKey: args.storageKey,
|
|
1272
|
-
entries: held
|
|
1273
|
-
}), togglesOf(held);
|
|
1274
|
-
}
|
|
1275
|
-
};
|
|
1276
2638
|
}
|
|
1277
2639
|
|
|
1278
2640
|
function datesOf(state) {
|
|
1279
|
-
return state.filter(entry => entry._type
|
|
2641
|
+
return state.filter(entry => isDateFieldKind(entry._type)).map(entry => entry.value).filter(value => typeof value == "string" && value !== "");
|
|
1280
2642
|
}
|
|
1281
2643
|
|
|
1282
2644
|
function spawnOrigins(instances) {
|
|
@@ -1377,10 +2739,7 @@ function deriveTaskGroups(args) {
|
|
|
1377
2739
|
}
|
|
1378
2740
|
|
|
1379
2741
|
function orderGroupsByPreviewTitle(groups, titles) {
|
|
1380
|
-
const withDocuments = [ ...groups.withDocuments ].sort((
|
|
1381
|
-
const aTitle = titles.get(a.document.id), bTitle = titles.get(b.document.id);
|
|
1382
|
-
return aTitle !== void 0 && bTitle !== void 0 ? aTitle.localeCompare(bTitle) || a.key.localeCompare(b.key) : aTitle !== void 0 ? -1 : bTitle !== void 0 ? 1 : a.key.localeCompare(b.key);
|
|
1383
|
-
});
|
|
2742
|
+
const withDocuments = [ ...groups.withDocuments ].sort(byResolvedTitle(group => titles.get(group.document.id), group => group.key));
|
|
1384
2743
|
return {
|
|
1385
2744
|
...groups,
|
|
1386
2745
|
withDocuments: withDocuments
|
|
@@ -1532,11 +2891,13 @@ function workflowTally(workflows) {
|
|
|
1532
2891
|
function settleToast(outcome) {
|
|
1533
2892
|
const total = outcome.settled + outcome.skipped.length + outcome.failures.length;
|
|
1534
2893
|
if (outcome.skipped.length === 0 && outcome.failures.length === 0) return {
|
|
1535
|
-
|
|
2894
|
+
id: TOAST_ID.orphanSettle,
|
|
2895
|
+
status: "info",
|
|
1536
2896
|
title: outcome.settled === 1 ? "Cleaned up 1 workflow" : `Cleaned up ${outcome.settled} workflows`
|
|
1537
2897
|
};
|
|
1538
2898
|
const lines = [ ...outcome.skipped.map(workflow => `${workflow.title}: its document exists again — left running`), ...outcome.failures.map(failure => `${failure.workflow.title}: ${failure.message}`) ];
|
|
1539
2899
|
return {
|
|
2900
|
+
id: TOAST_ID.orphanSettle,
|
|
1540
2901
|
status: "warning",
|
|
1541
2902
|
title: `Cleaned up ${outcome.settled} of ${total} workflows`,
|
|
1542
2903
|
description: lines.join(`\n`)
|
|
@@ -1545,9 +2906,10 @@ function settleToast(outcome) {
|
|
|
1545
2906
|
|
|
1546
2907
|
function recheckFailedToast(err) {
|
|
1547
2908
|
return {
|
|
2909
|
+
id: TOAST_ID.orphanSettle,
|
|
1548
2910
|
status: "error",
|
|
1549
|
-
title: "Nothing was cleaned up
|
|
1550
|
-
description: describeError(err)
|
|
2911
|
+
title: "Nothing was cleaned up",
|
|
2912
|
+
description: `The documents could not be re-checked: ${describeError(err)}`
|
|
1551
2913
|
};
|
|
1552
2914
|
}
|
|
1553
2915
|
|
|
@@ -1577,7 +2939,7 @@ function OrphanedWorkflowsNote({orphans: orphans}) {
|
|
|
1577
2939
|
function SettleOrphansDialog({workflows: workflows, onClose: onClose}) {
|
|
1578
2940
|
const {engine: engine} = useWorkflowContext(), client = useClient({
|
|
1579
2941
|
apiVersion: WORKFLOW_API_VERSION
|
|
1580
|
-
}), toast =
|
|
2942
|
+
}), toast = useWorkflowToast(), [pending, setPending] = useState(!1), confirm = async () => {
|
|
1581
2943
|
setPending(!0);
|
|
1582
2944
|
try {
|
|
1583
2945
|
const outcome = await settleOrphans({
|
|
@@ -1822,72 +3184,6 @@ function applyTaskFilters(args) {
|
|
|
1822
3184
|
});
|
|
1823
3185
|
}
|
|
1824
3186
|
|
|
1825
|
-
const NOTHING = {
|
|
1826
|
-
titles: /* @__PURE__ */ new Map,
|
|
1827
|
-
resolved: /* @__PURE__ */ new Set
|
|
1828
|
-
};
|
|
1829
|
-
|
|
1830
|
-
function useDocPreviewTitles(documents) {
|
|
1831
|
-
const previewStore = useDocumentPreviewStore(), schema = useSchema(), {perspectiveStack: perspectiveStack} = usePerspective(), {actualTypes: actualTypes, binding: binding} = useWorkflowContext(), [state, setState] = useState(NOTHING), key = documents.map(doc => doc.id).join("|");
|
|
1832
|
-
return useEffect(() => {
|
|
1833
|
-
const titles = /* @__PURE__ */ new Map, resolved = /* @__PURE__ */ new Set, previews = /* @__PURE__ */ new Map, publish = () => setState({
|
|
1834
|
-
titles: new Map(titles),
|
|
1835
|
-
resolved: new Set(resolved)
|
|
1836
|
-
}), localDocs = documents.flatMap(doc => {
|
|
1837
|
-
const {parsed: parsed, local: local} = gdrLocality(doc.id, binding.contentResource);
|
|
1838
|
-
return !parsed || !local ? (resolved.add(doc.id), []) : [ {
|
|
1839
|
-
doc: doc,
|
|
1840
|
-
bareId: parsed.documentId
|
|
1841
|
-
} ];
|
|
1842
|
-
}), untracks = localDocs.map(({bareId: bareId}) => actualTypes.track(bareId)), dropPreview = docId => {
|
|
1843
|
-
previews.get(docId)?.unsubscribe(), previews.delete(docId), titles.delete(docId);
|
|
1844
|
-
}, observe = ({docId: docId, bareId: bareId, typeName: typeName}) => {
|
|
1845
|
-
const schemaType = openableSchemaType(schema, typeName);
|
|
1846
|
-
if (!schemaType) return !1;
|
|
1847
|
-
if (previews.get(docId)?.typeName === typeName) return !0;
|
|
1848
|
-
dropPreview(docId), resolved.delete(docId);
|
|
1849
|
-
const subscription = previewStore.observeForPreview({
|
|
1850
|
-
_id: bareId,
|
|
1851
|
-
_type: schemaType.name
|
|
1852
|
-
}, schemaType, {
|
|
1853
|
-
perspective: perspectiveStack
|
|
1854
|
-
}).subscribe({
|
|
1855
|
-
next: event => {
|
|
1856
|
-
resolved.add(docId);
|
|
1857
|
-
const title = event.snapshot?.title;
|
|
1858
|
-
typeof title == "string" ? titles.set(docId, title) : titles.delete(docId), publish();
|
|
1859
|
-
},
|
|
1860
|
-
error: err => {
|
|
1861
|
-
console.error(`[workflow-studio-plugin] preview for "${docId}" failed:`, err), resolved.add(docId),
|
|
1862
|
-
publish();
|
|
1863
|
-
}
|
|
1864
|
-
});
|
|
1865
|
-
return previews.set(docId, {
|
|
1866
|
-
typeName: typeName,
|
|
1867
|
-
unsubscribe: () => subscription.unsubscribe()
|
|
1868
|
-
}), !0;
|
|
1869
|
-
}, evaluate = () => {
|
|
1870
|
-
for (const {doc: doc, bareId: bareId} of localDocs) {
|
|
1871
|
-
const probe = actualTypes.read(bareId);
|
|
1872
|
-
if (probe === null) {
|
|
1873
|
-
dropPreview(doc.id), resolved.add(doc.id);
|
|
1874
|
-
continue;
|
|
1875
|
-
}
|
|
1876
|
-
!observe({
|
|
1877
|
-
docId: doc.id,
|
|
1878
|
-
bareId: bareId,
|
|
1879
|
-
typeName: probe ?? doc.type
|
|
1880
|
-
}) && typeof probe == "string" && (dropPreview(doc.id), resolved.add(doc.id));
|
|
1881
|
-
}
|
|
1882
|
-
publish();
|
|
1883
|
-
}, unsubscribeProbes = actualTypes.subscribe(evaluate);
|
|
1884
|
-
return evaluate(), () => {
|
|
1885
|
-
unsubscribeProbes(), untracks.forEach(untrack => untrack()), previews.forEach(preview => preview.unsubscribe());
|
|
1886
|
-
};
|
|
1887
|
-
}, [ key, previewStore, schema, actualTypes, binding.contentResource.id, perspectiveStack.join("|") ]),
|
|
1888
|
-
state;
|
|
1889
|
-
}
|
|
1890
|
-
|
|
1891
3187
|
const HITS_CAP = 6;
|
|
1892
3188
|
|
|
1893
3189
|
function TaskFilterMenu({filters: filters, options: options, onChange: onChange}) {
|
|
@@ -2386,8 +3682,10 @@ function FilterRowPortal({filters: filters, onChange: onChange, options: options
|
|
|
2386
3682
|
}), slot) : null;
|
|
2387
3683
|
}
|
|
2388
3684
|
|
|
2389
|
-
function ActivityDateControl({instanceId: instanceId, state: state, dates: dates}) {
|
|
2390
|
-
const
|
|
3685
|
+
function ActivityDateControl({instanceId: instanceId, state: state, surface: surface, dates: dates}) {
|
|
3686
|
+
const editField = useEditField(surface), {save: save} = useSaveField({
|
|
3687
|
+
instanceId: instanceId
|
|
3688
|
+
}), [open, setOpen] = useState(!1), raw = dateControlValue({
|
|
2391
3689
|
state: state,
|
|
2392
3690
|
dates: dates
|
|
2393
3691
|
}), display = raw === void 0 ? null : /* @__PURE__ */ jsx(Text, {
|
|
@@ -2410,15 +3708,16 @@ function ActivityDateControl({instanceId: instanceId, state: state, dates: dates
|
|
|
2410
3708
|
})
|
|
2411
3709
|
});
|
|
2412
3710
|
const kind = dateControlKind(state), commit = (mode, value) => {
|
|
2413
|
-
state.kind === "editable" && save(() =>
|
|
2414
|
-
|
|
3711
|
+
state.kind === "editable" && save(() => editField({
|
|
3712
|
+
instanceId: instanceId,
|
|
3713
|
+
field: state.field,
|
|
2415
3714
|
...mode === "set" ? {
|
|
2416
3715
|
mode: mode,
|
|
2417
3716
|
value: value
|
|
2418
3717
|
} : {
|
|
2419
3718
|
mode: mode
|
|
2420
3719
|
}
|
|
2421
|
-
})
|
|
3720
|
+
}));
|
|
2422
3721
|
}, handleClick = e => {
|
|
2423
3722
|
e.stopPropagation(), setOpen(v => !v);
|
|
2424
3723
|
};
|
|
@@ -2435,9 +3734,9 @@ function ActivityDateControl({instanceId: instanceId, state: state, dates: dates
|
|
|
2435
3734
|
setOpen(!1), commit("unset");
|
|
2436
3735
|
},
|
|
2437
3736
|
onPick: next => {
|
|
2438
|
-
kind
|
|
3737
|
+
hasTimeOfDay(kind) || setOpen(!1), commit("set", serializeDateFieldValue(next, kind));
|
|
2439
3738
|
},
|
|
2440
|
-
selectTime: kind
|
|
3739
|
+
selectTime: hasTimeOfDay(kind),
|
|
2441
3740
|
value: parseDateFieldValue(state.field.value, kind)
|
|
2442
3741
|
})
|
|
2443
3742
|
}),
|
|
@@ -2501,7 +3800,8 @@ function RefChips({refs: refs, max: max = 2}) {
|
|
|
2501
3800
|
wrap: "wrap",
|
|
2502
3801
|
children: [ shown.map(ref => /* @__PURE__ */ jsx(DocPreviewLink, {
|
|
2503
3802
|
gdr: ref,
|
|
2504
|
-
layout: "inline"
|
|
3803
|
+
layout: "inline",
|
|
3804
|
+
source: "doc-ref-chip"
|
|
2505
3805
|
}, ref.id)), overflow > 0 ? /* @__PURE__ */ jsxs(Text, {
|
|
2506
3806
|
muted: !0,
|
|
2507
3807
|
size: 1,
|
|
@@ -2512,54 +3812,16 @@ function RefChips({refs: refs, max: max = 2}) {
|
|
|
2512
3812
|
|
|
2513
3813
|
const UNGROUPED_TITLE = "Workflows without Studio documents";
|
|
2514
3814
|
|
|
2515
|
-
function TaskGroupList({
|
|
3815
|
+
function TaskGroupList({groups: groups, ...wiring}) {
|
|
2516
3816
|
/* @__PURE__ */
|
|
2517
3817
|
return jsxs(Stack, {
|
|
2518
3818
|
gap: 1,
|
|
2519
|
-
children: [ groups.withDocuments.map(group => /* @__PURE__ */ jsx(
|
|
2520
|
-
|
|
2521
|
-
|
|
2522
|
-
|
|
2523
|
-
|
|
2524
|
-
|
|
2525
|
-
header: /* @__PURE__ */ jsx(Flex, {
|
|
2526
|
-
align: "center",
|
|
2527
|
-
flex: "none",
|
|
2528
|
-
style: {
|
|
2529
|
-
maxWidth: "60%"
|
|
2530
|
-
},
|
|
2531
|
-
children: /* @__PURE__ */ jsx(RefChips, {
|
|
2532
|
-
max: 2,
|
|
2533
|
-
refs: group.documents
|
|
2534
|
-
})
|
|
2535
|
-
}),
|
|
2536
|
-
children: /* @__PURE__ */ jsx(InstanceBands, {
|
|
2537
|
-
bands: bands,
|
|
2538
|
-
instanceDefaultOpen: instanceDefaultOpen,
|
|
2539
|
-
instances: group.instances,
|
|
2540
|
-
onOpenTask: onOpenTask,
|
|
2541
|
-
onOpenWorkflow: onOpenWorkflow,
|
|
2542
|
-
showTerminalActions: showTerminalActions
|
|
2543
|
-
})
|
|
2544
|
-
}, group.key)), groups.withoutDocuments.length > 0 ? /* @__PURE__ */ jsx(CollapsibleBand, {
|
|
2545
|
-
background: !0,
|
|
2546
|
-
onToggle: () => bands.toggle(UNGROUPED_BAND_KEY, GROUP_DEFAULT_OPEN),
|
|
2547
|
-
open: bands.isOpen(UNGROUPED_BAND_KEY, GROUP_DEFAULT_OPEN),
|
|
2548
|
-
sticky: !0,
|
|
2549
|
-
title: UNGROUPED_TITLE,
|
|
2550
|
-
header: /* @__PURE__ */ jsx(Text, {
|
|
2551
|
-
size: 1,
|
|
2552
|
-
weight: "semibold",
|
|
2553
|
-
children: UNGROUPED_TITLE
|
|
2554
|
-
}),
|
|
2555
|
-
children: /* @__PURE__ */ jsx(InstanceBands, {
|
|
2556
|
-
bands: bands,
|
|
2557
|
-
instanceDefaultOpen: instanceDefaultOpen,
|
|
2558
|
-
instances: groups.withoutDocuments,
|
|
2559
|
-
onOpenTask: onOpenTask,
|
|
2560
|
-
onOpenWorkflow: onOpenWorkflow,
|
|
2561
|
-
showTerminalActions: showTerminalActions
|
|
2562
|
-
})
|
|
3819
|
+
children: [ groups.withDocuments.map(group => /* @__PURE__ */ jsx(DocumentBand, {
|
|
3820
|
+
group: group,
|
|
3821
|
+
...wiring
|
|
3822
|
+
}, group.key)), groups.withoutDocuments.length > 0 ? /* @__PURE__ */ jsx(UngroupedBand, {
|
|
3823
|
+
instances: groups.withoutDocuments,
|
|
3824
|
+
...wiring
|
|
2563
3825
|
}) : null ]
|
|
2564
3826
|
});
|
|
2565
3827
|
}
|
|
@@ -2572,38 +3834,81 @@ function targetOf(row) {
|
|
|
2572
3834
|
};
|
|
2573
3835
|
}
|
|
2574
3836
|
|
|
2575
|
-
function
|
|
3837
|
+
function DocumentBand({group: group, ...wiring}) {
|
|
3838
|
+
const {open: open, toggle: toggle} = useBandOpen(wiring.bands, group.key);
|
|
3839
|
+
/* @__PURE__ */
|
|
3840
|
+
return jsx(CollapsibleBand, {
|
|
3841
|
+
background: !0,
|
|
3842
|
+
onToggle: toggle,
|
|
3843
|
+
open: open,
|
|
3844
|
+
sticky: !0,
|
|
3845
|
+
title: toBareId(group.document.id),
|
|
3846
|
+
header: /* @__PURE__ */ jsx(Flex, {
|
|
3847
|
+
align: "center",
|
|
3848
|
+
flex: "none",
|
|
3849
|
+
style: {
|
|
3850
|
+
maxWidth: "60%"
|
|
3851
|
+
},
|
|
3852
|
+
children: /* @__PURE__ */ jsx(RefChips, {
|
|
3853
|
+
max: 2,
|
|
3854
|
+
refs: group.documents
|
|
3855
|
+
})
|
|
3856
|
+
}),
|
|
3857
|
+
children: /* @__PURE__ */ jsx(InstanceBands, {
|
|
3858
|
+
instances: group.instances,
|
|
3859
|
+
...wiring
|
|
3860
|
+
})
|
|
3861
|
+
});
|
|
3862
|
+
}
|
|
3863
|
+
|
|
3864
|
+
function UngroupedBand({instances: instances, ...wiring}) {
|
|
3865
|
+
const {open: open, toggle: toggle} = useBandOpen(wiring.bands, UNGROUPED_BAND_KEY);
|
|
3866
|
+
/* @__PURE__ */
|
|
3867
|
+
return jsx(CollapsibleBand, {
|
|
3868
|
+
background: !0,
|
|
3869
|
+
onToggle: toggle,
|
|
3870
|
+
open: open,
|
|
3871
|
+
sticky: !0,
|
|
3872
|
+
title: UNGROUPED_TITLE,
|
|
3873
|
+
header: /* @__PURE__ */ jsx(Text, {
|
|
3874
|
+
size: 1,
|
|
3875
|
+
weight: "semibold",
|
|
3876
|
+
children: UNGROUPED_TITLE
|
|
3877
|
+
}),
|
|
3878
|
+
children: /* @__PURE__ */ jsx(InstanceBands, {
|
|
3879
|
+
instances: instances,
|
|
3880
|
+
...wiring
|
|
3881
|
+
})
|
|
3882
|
+
});
|
|
3883
|
+
}
|
|
3884
|
+
|
|
3885
|
+
function InstanceBands({instances: instances, ...wiring}) {
|
|
2576
3886
|
/* @__PURE__ */
|
|
2577
3887
|
return jsx(Stack, {
|
|
2578
3888
|
gap: 1,
|
|
2579
|
-
children: instances.map(
|
|
2580
|
-
|
|
2581
|
-
|
|
2582
|
-
|
|
2583
|
-
onOpenTask: onOpenTask,
|
|
2584
|
-
onOpenWorkflow: onOpenWorkflow,
|
|
2585
|
-
showTerminalActions: showTerminalActions
|
|
2586
|
-
}, band.instanceId))
|
|
3889
|
+
children: instances.map(instance => /* @__PURE__ */ jsx(InstanceBand, {
|
|
3890
|
+
instance: instance,
|
|
3891
|
+
...wiring
|
|
3892
|
+
}, instance.instanceId))
|
|
2587
3893
|
});
|
|
2588
3894
|
}
|
|
2589
3895
|
|
|
2590
|
-
function InstanceBand({
|
|
2591
|
-
const {resolvePathFromState: resolvePathFromState} = useRouter();
|
|
3896
|
+
function InstanceBand({bands: bands, instance: instance, onOpenTask: onOpenTask, onOpenWorkflow: onOpenWorkflow, showTerminalActions: showTerminalActions}) {
|
|
3897
|
+
const {open: open, toggle: toggle} = useBandOpen(bands, instance.instanceId), {resolvePathFromState: resolvePathFromState} = useRouter();
|
|
2592
3898
|
/* @__PURE__ */
|
|
2593
3899
|
return jsx(CollapsibleBand, {
|
|
2594
|
-
onToggle:
|
|
2595
|
-
open:
|
|
2596
|
-
title:
|
|
3900
|
+
onToggle: toggle,
|
|
3901
|
+
open: open,
|
|
3902
|
+
title: instance.title,
|
|
2597
3903
|
header: /* @__PURE__ */ jsxs(Fragment, {
|
|
2598
3904
|
children: [
|
|
2599
3905
|
/* @__PURE__ */ jsx(LinkChip, {
|
|
2600
3906
|
hint: "View workflow",
|
|
2601
3907
|
href: resolvePathFromState({
|
|
2602
|
-
instanceId:
|
|
3908
|
+
instanceId: instance.instanceId
|
|
2603
3909
|
}),
|
|
2604
3910
|
onClick: event => {
|
|
2605
|
-
event
|
|
2606
|
-
onOpenWorkflow(band.instanceId));
|
|
3911
|
+
isPlainClick(event) && (event.preventDefault(), onOpenWorkflow(instance.instanceId));
|
|
2607
3912
|
},
|
|
2608
3913
|
children: /* @__PURE__ */ jsxs(Flex, {
|
|
2609
3914
|
align: "center",
|
|
@@ -2619,12 +3924,12 @@ function InstanceBand({band: band, bands: bands, instanceDefaultOpen: instanceDe
|
|
|
2619
3924
|
},
|
|
2620
3925
|
textOverflow: "ellipsis",
|
|
2621
3926
|
weight: "medium",
|
|
2622
|
-
children:
|
|
2623
|
-
}),
|
|
2624
|
-
segments: [
|
|
3927
|
+
children: instance.title
|
|
3928
|
+
}), instance.breadcrumb === void 0 ? null : /* @__PURE__ */ jsx(BreadcrumbTail, {
|
|
3929
|
+
segments: [ instance.breadcrumb ]
|
|
2625
3930
|
}),
|
|
2626
3931
|
/* @__PURE__ */ jsx(StageFace, {
|
|
2627
|
-
title:
|
|
3932
|
+
title: instance.stageTitle
|
|
2628
3933
|
}) ]
|
|
2629
3934
|
})
|
|
2630
3935
|
}),
|
|
@@ -2634,7 +3939,7 @@ function InstanceBand({band: band, bands: bands, instanceDefaultOpen: instanceDe
|
|
|
2634
3939
|
paddingLeft: 5,
|
|
2635
3940
|
children: /* @__PURE__ */ jsx(TaskRows, {
|
|
2636
3941
|
onOpenTask: onOpenTask,
|
|
2637
|
-
rows:
|
|
3942
|
+
rows: instance.rows,
|
|
2638
3943
|
showTerminalActions: showTerminalActions
|
|
2639
3944
|
})
|
|
2640
3945
|
})
|
|
@@ -2668,40 +3973,19 @@ function TaskActivityRow({row: row, onOpen: onOpen, showTerminalActions: showTer
|
|
|
2668
3973
|
dateControl: /* @__PURE__ */ jsx(ActivityDateControl, {
|
|
2669
3974
|
dates: render.dates,
|
|
2670
3975
|
instanceId: row.instanceId,
|
|
2671
|
-
state: render.dateState
|
|
3976
|
+
state: render.dateState,
|
|
3977
|
+
surface: "tool-task-list"
|
|
2672
3978
|
}),
|
|
2673
3979
|
face: render.face,
|
|
2674
3980
|
instanceId: row.instanceId,
|
|
2675
3981
|
onOpen: onOpen,
|
|
3982
|
+
surface: "tool-task-list",
|
|
2676
3983
|
terminalActions: showTerminalActions ? render.terminalActions : []
|
|
2677
3984
|
})
|
|
2678
3985
|
})
|
|
2679
3986
|
});
|
|
2680
3987
|
}
|
|
2681
3988
|
|
|
2682
|
-
function useBandOpenState(args) {
|
|
2683
|
-
const {segment: segment, scope: scope} = args, store = useMemo(() => createBandStateStore({
|
|
2684
|
-
storageKey: bandStateStorageKey(scope)
|
|
2685
|
-
}), [ scope ]), [held, setHeld] = useState(() => ({
|
|
2686
|
-
store: store,
|
|
2687
|
-
toggles: store.read()
|
|
2688
|
-
}));
|
|
2689
|
-
held.store !== store && setHeld({
|
|
2690
|
-
store: store,
|
|
2691
|
-
toggles: store.read()
|
|
2692
|
-
});
|
|
2693
|
-
const qualify = key => `${segment}/${key}`, isOpen = (key, defaultOpen) => held.toggles.get(qualify(key)) ?? defaultOpen;
|
|
2694
|
-
return {
|
|
2695
|
-
isOpen: isOpen,
|
|
2696
|
-
toggle: (key, defaultOpen) => {
|
|
2697
|
-
setHeld({
|
|
2698
|
-
store: store,
|
|
2699
|
-
toggles: store.setOpen(qualify(key), !isOpen(key, defaultOpen))
|
|
2700
|
-
});
|
|
2701
|
-
}
|
|
2702
|
-
};
|
|
2703
|
-
}
|
|
2704
|
-
|
|
2705
3989
|
const NO_MISSING = /* @__PURE__ */ new Set;
|
|
2706
3990
|
|
|
2707
3991
|
function sameIdSet(a, b) {
|
|
@@ -2741,15 +4025,18 @@ function TasksTab({filterSlot: filterSlot, instances: instances, loading: loadin
|
|
|
2741
4025
|
}), [filters, setFilters] = useState({}), groups = useMemo(() => deriveTaskGroups({
|
|
2742
4026
|
instances: instances,
|
|
2743
4027
|
identity: identity
|
|
2744
|
-
}), [ instances, identity ]), orphans = useOrphanedWorkflows(groups), listed = useMemo(() => hideOrphanedGroups(groups, orphans.groupKeys), [ groups, orphans.groupKeys ]), options = useMemo(() => taskFilterOptions(listed), [ listed ]),
|
|
4028
|
+
}), [ instances, identity ]), orphans = useOrphanedWorkflows(groups), listed = useMemo(() => hideOrphanedGroups(groups, orphans.groupKeys), [ groups, orphans.groupKeys ]), options = useMemo(() => taskFilterOptions(listed), [ listed ]), titles = useGroupTitles(listed), revealed = useRevealGate({
|
|
4029
|
+
loading: loading,
|
|
4030
|
+
ready: titles.ready
|
|
4031
|
+
}), visible = useMemo(() => {
|
|
2745
4032
|
const filtered = applyTaskFilters({
|
|
2746
4033
|
groups: listed,
|
|
2747
4034
|
filters: filters,
|
|
2748
4035
|
now: /* @__PURE__ */ new Date
|
|
2749
4036
|
}), cut = mineOnly ? onlyMyTasks(filtered) : filtered;
|
|
2750
|
-
return orderGroupsByPreviewTitle(cut,
|
|
2751
|
-
}, [ listed, filters, mineOnly,
|
|
2752
|
-
if (loading) /* @__PURE__ */
|
|
4037
|
+
return orderGroupsByPreviewTitle(cut, titles.titles);
|
|
4038
|
+
}, [ listed, filters, mineOnly, titles ]);
|
|
4039
|
+
if (loading || !revealed) /* @__PURE__ */
|
|
2753
4040
|
return jsx(TabStatusRow, {
|
|
2754
4041
|
children: /* @__PURE__ */ jsx(LoadingRow, {
|
|
2755
4042
|
label: "Loading tasks…"
|
|
@@ -2757,16 +4044,13 @@ function TasksTab({filterSlot: filterSlot, instances: instances, loading: loadin
|
|
|
2757
4044
|
});
|
|
2758
4045
|
const empty = visible.withDocuments.length === 0 && visible.withoutDocuments.length === 0;
|
|
2759
4046
|
let body;
|
|
2760
|
-
return empty ? mineOnly ? body = /* @__PURE__ */ jsx(ForMeEmptyState, {}) : body = /* @__PURE__ */ jsx(
|
|
2761
|
-
|
|
2762
|
-
|
|
2763
|
-
|
|
2764
|
-
children: "No tasks match — adjust the filters, or start a workflow"
|
|
2765
|
-
})
|
|
4047
|
+
return empty ? mineOnly ? body = /* @__PURE__ */ jsx(ForMeEmptyState, {}) : body = /* @__PURE__ */ jsx(EmptyState, {
|
|
4048
|
+
description: "Adjust the filters, or start a workflow",
|
|
4049
|
+
icon: /* @__PURE__ */ jsx(SearchIcon, {}),
|
|
4050
|
+
title: "No tasks match"
|
|
2766
4051
|
}) : body = /* @__PURE__ */ jsx(TaskGroupList, {
|
|
2767
4052
|
bands: bands,
|
|
2768
4053
|
groups: visible,
|
|
2769
|
-
instanceDefaultOpen: instanceBandDefaultOpen(segment),
|
|
2770
4054
|
onOpenTask: onOpenTask,
|
|
2771
4055
|
onOpenWorkflow: onOpenWorkflow,
|
|
2772
4056
|
showTerminalActions: mineOnly
|
|
@@ -2792,52 +4076,106 @@ function TasksTab({filterSlot: filterSlot, instances: instances, loading: loadin
|
|
|
2792
4076
|
/* @__PURE__ */ jsx(OrphanedWorkflowsNote, {
|
|
2793
4077
|
orphans: orphans
|
|
2794
4078
|
}), body, truncated ? /* @__PURE__ */ jsx(MutedNote, {
|
|
2795
|
-
text: `Tasks from the latest ${INSTANCE_CAP} workflows — older ones aren
|
|
4079
|
+
text: `Tasks from the latest ${INSTANCE_CAP} workflows — older ones aren’t listed.`
|
|
2796
4080
|
}) : null ]
|
|
2797
4081
|
}) ]
|
|
2798
4082
|
});
|
|
2799
4083
|
}
|
|
2800
4084
|
|
|
2801
|
-
const
|
|
2802
|
-
|
|
2803
|
-
|
|
2804
|
-
|
|
2805
|
-
|
|
2806
|
-
|
|
2807
|
-
|
|
2808
|
-
|
|
2809
|
-
|
|
2810
|
-
|
|
4085
|
+
const TOOL_TAB_LABELS = {
|
|
4086
|
+
definitions: "Definitions",
|
|
4087
|
+
documents: "Documents",
|
|
4088
|
+
tasks: "Tasks",
|
|
4089
|
+
"for-me": "For me"
|
|
4090
|
+
}, TOOL_TAB_VALUES = Object.keys(TOOL_TAB_LABELS), TOOL_TABS = TOOL_TAB_VALUES.map(value => ({
|
|
4091
|
+
value: value,
|
|
4092
|
+
label: TOOL_TAB_LABELS[value]
|
|
4093
|
+
})), DEFAULT_TOOL_TAB = "definitions";
|
|
4094
|
+
|
|
4095
|
+
function toolTabState(tab) {
|
|
4096
|
+
return tab === DEFAULT_TOOL_TAB ? {} : {
|
|
4097
|
+
workflowsTab: tab
|
|
4098
|
+
};
|
|
4099
|
+
}
|
|
4100
|
+
|
|
4101
|
+
function boardState(definitionName) {
|
|
4102
|
+
return {
|
|
4103
|
+
boardDefinition: definitionName
|
|
4104
|
+
};
|
|
4105
|
+
}
|
|
4106
|
+
|
|
4107
|
+
function tabSelectionNavigates(route, tab) {
|
|
4108
|
+
return !(route.kind === "home" && tab === route.tab);
|
|
4109
|
+
}
|
|
4110
|
+
|
|
4111
|
+
function backToAllLabel(tab) {
|
|
4112
|
+
return `Back to all ${TOOL_TAB_LABELS[tab].toLowerCase()}`;
|
|
4113
|
+
}
|
|
4114
|
+
|
|
4115
|
+
function toolRoute(state) {
|
|
4116
|
+
const {instanceId: instanceId, definitionName: definitionName, boardDefinition: boardDefinition} = state;
|
|
4117
|
+
if (typeof instanceId == "string") return {
|
|
4118
|
+
kind: "instance",
|
|
4119
|
+
instanceId: instanceId,
|
|
4120
|
+
tab: "tasks"
|
|
4121
|
+
};
|
|
4122
|
+
if (typeof definitionName == "string") return {
|
|
4123
|
+
kind: "definition",
|
|
4124
|
+
definitionName: definitionName,
|
|
4125
|
+
tab: "definitions"
|
|
4126
|
+
};
|
|
4127
|
+
if (typeof boardDefinition == "string") return {
|
|
4128
|
+
kind: "home",
|
|
4129
|
+
tab: "documents",
|
|
4130
|
+
boardDefinition: boardDefinition
|
|
4131
|
+
};
|
|
4132
|
+
const tab = pathSegmentTab({
|
|
4133
|
+
segment: state.workflowsTab,
|
|
4134
|
+
tabs: TOOL_TAB_VALUES,
|
|
4135
|
+
fallback: DEFAULT_TOOL_TAB
|
|
4136
|
+
});
|
|
4137
|
+
return tab === void 0 ? {
|
|
4138
|
+
kind: "not-found",
|
|
4139
|
+
tab: void 0
|
|
4140
|
+
} : {
|
|
4141
|
+
kind: "home",
|
|
4142
|
+
tab: tab,
|
|
4143
|
+
boardDefinition: void 0
|
|
4144
|
+
};
|
|
4145
|
+
}
|
|
2811
4146
|
|
|
2812
4147
|
function InstanceStreamKeepAlive() {
|
|
2813
4148
|
return useToolInstances(), null;
|
|
2814
4149
|
}
|
|
2815
4150
|
|
|
2816
4151
|
function WorkflowsToolRoot() {
|
|
2817
|
-
const router = useRouter(), {seedInstance: seedInstance} = useWorkflowContext(), telemetry = useWorkflowTelemetry(), [filterSlot, setFilterSlot] = useState(null),
|
|
4152
|
+
const router = useRouter(), {seedInstance: seedInstance} = useWorkflowContext(), telemetry = useWorkflowTelemetry(), [filterSlot, setFilterSlot] = useState(null), route = toolRoute(router.state), isHome = route.kind === "home" || route.kind === "not-found", [instanceStreamLatched, setInstanceStreamLatched] = useState(isHome);
|
|
2818
4153
|
useEffect(() => {
|
|
2819
4154
|
isHome && setInstanceStreamLatched(!0);
|
|
2820
4155
|
}, [ isHome ]);
|
|
2821
|
-
|
|
2822
|
-
|
|
2823
|
-
|
|
2824
|
-
|
|
2825
|
-
|
|
2826
|
-
});
|
|
2827
|
-
|
|
2828
|
-
|
|
2829
|
-
|
|
2830
|
-
|
|
2831
|
-
|
|
4156
|
+
const setTab = next => router.navigate(toolTabState(next)), selectBoardWorkflow = useCallback((name, opts) => router.navigate(boardState(name), opts?.replace === !0 ? {
|
|
4157
|
+
replace: !0
|
|
4158
|
+
} : {}), [ router ]), backToList = tab => ({
|
|
4159
|
+
label: backToAllLabel(tab),
|
|
4160
|
+
go: () => setTab(tab)
|
|
4161
|
+
}), badSegment = route.kind === "not-found";
|
|
4162
|
+
useEffect(() => {
|
|
4163
|
+
badSegment && router.navigate({}, {
|
|
4164
|
+
replace: !0
|
|
4165
|
+
});
|
|
4166
|
+
}, [ badSegment, router ]), useLogEventOnMount(WorkflowToolOpened, {
|
|
4167
|
+
tab: route.tab ?? "not-found",
|
|
2832
4168
|
via: "open"
|
|
2833
4169
|
});
|
|
2834
4170
|
let panel;
|
|
2835
|
-
return
|
|
2836
|
-
instanceId: instanceId,
|
|
2837
|
-
|
|
2838
|
-
}, instanceId) :
|
|
2839
|
-
definitionName: definitionName
|
|
2840
|
-
|
|
4171
|
+
return route.kind === "instance" ? panel = /* @__PURE__ */ jsx(WorkflowInstanceDetail, {
|
|
4172
|
+
instanceId: route.instanceId,
|
|
4173
|
+
backToList: backToList(route.tab)
|
|
4174
|
+
}, route.instanceId) : route.kind === "definition" ? panel = /* @__PURE__ */ jsx(DefinitionDetail, {
|
|
4175
|
+
definitionName: route.definitionName,
|
|
4176
|
+
backToList: backToList(route.tab)
|
|
4177
|
+
}, route.definitionName) : route.kind === "not-found" ? panel = null : panel = /* @__PURE__ */ jsx(WorkflowsHome, {
|
|
4178
|
+
boardDefinition: route.boardDefinition,
|
|
2841
4179
|
filterSlot: filterSlot,
|
|
2842
4180
|
onOpenDefinition: name => router.navigate({
|
|
2843
4181
|
definitionName: name
|
|
@@ -2847,7 +4185,8 @@ function WorkflowsToolRoot() {
|
|
|
2847
4185
|
instanceId: typeof instance == "string" ? instance : instance._id
|
|
2848
4186
|
});
|
|
2849
4187
|
},
|
|
2850
|
-
|
|
4188
|
+
onSelectWorkflow: selectBoardWorkflow,
|
|
4189
|
+
tab: route.tab
|
|
2851
4190
|
}),
|
|
2852
4191
|
/* @__PURE__ */ jsxs(Card, {
|
|
2853
4192
|
height: "fill",
|
|
@@ -2882,13 +4221,13 @@ function WorkflowsToolRoot() {
|
|
|
2882
4221
|
ariaControls: "workflows-tool-panel",
|
|
2883
4222
|
idPrefix: "workflows-tool-tab",
|
|
2884
4223
|
onSelect: next => {
|
|
2885
|
-
next !== tab && telemetry.log(WorkflowToolOpened, {
|
|
4224
|
+
tabSelectionNavigates(route, next) && (next !== route.tab && telemetry.log(WorkflowToolOpened, {
|
|
2886
4225
|
tab: next,
|
|
2887
4226
|
via: "tab-switch"
|
|
2888
|
-
}), setTab(next);
|
|
4227
|
+
}), setTab(next));
|
|
2889
4228
|
},
|
|
2890
4229
|
options: TOOL_TABS,
|
|
2891
|
-
selected: tab
|
|
4230
|
+
selected: route.tab
|
|
2892
4231
|
}),
|
|
2893
4232
|
/* @__PURE__ */ jsx("div", {
|
|
2894
4233
|
ref: setFilterSlot
|
|
@@ -2904,17 +4243,20 @@ function WorkflowsToolRoot() {
|
|
|
2904
4243
|
});
|
|
2905
4244
|
}
|
|
2906
4245
|
|
|
2907
|
-
function WorkflowsHome({filterSlot: filterSlot, onOpenDefinition: onOpenDefinition, onOpenInstance: onOpenInstance, tab: tab}) {
|
|
4246
|
+
function WorkflowsHome({boardDefinition: boardDefinition, filterSlot: filterSlot, onOpenDefinition: onOpenDefinition, onOpenInstance: onOpenInstance, onSelectWorkflow: onSelectWorkflow, tab: tab}) {
|
|
2908
4247
|
const instances = useToolInstances(), identity = useAssignmentIdentity(), [openTask, setOpenTask] = useState(null), openInstance = target => {
|
|
2909
4248
|
if (typeof target != "string") return onOpenInstance(target);
|
|
2910
4249
|
const held = [ ...instances.inFlight, ...instances.settled ].find(i => i._id === target);
|
|
2911
4250
|
onOpenInstance(held ?? target);
|
|
2912
4251
|
}, scrollerRef = useRef(null);
|
|
2913
|
-
|
|
4252
|
+
useEffect(() => {
|
|
2914
4253
|
scrollerRef.current?.scrollTo({
|
|
2915
4254
|
top: 0
|
|
2916
4255
|
});
|
|
2917
|
-
}, [ tab ])
|
|
4256
|
+
}, [ tab ]);
|
|
4257
|
+
const bleeds = tab === "documents";
|
|
4258
|
+
/* @__PURE__ */
|
|
4259
|
+
return jsxs(Flex, {
|
|
2918
4260
|
direction: "column",
|
|
2919
4261
|
height: "fill",
|
|
2920
4262
|
overflow: "hidden",
|
|
@@ -2923,9 +4265,9 @@ function WorkflowsHome({filterSlot: filterSlot, onOpenDefinition: onOpenDefiniti
|
|
|
2923
4265
|
ref: scrollerRef,
|
|
2924
4266
|
flex: 1,
|
|
2925
4267
|
overflow: "auto",
|
|
2926
|
-
paddingX:
|
|
4268
|
+
paddingX: bleeds ? 0 : TOOL_PANEL_PADDING,
|
|
2927
4269
|
style: {
|
|
2928
|
-
scrollbarGutter: "stable"
|
|
4270
|
+
scrollbarGutter: bleeds ? "auto" : "stable"
|
|
2929
4271
|
},
|
|
2930
4272
|
children: /* @__PURE__ */ jsx(TabPanel, {
|
|
2931
4273
|
"aria-labelledby": `workflows-tool-tab-${tab}`,
|
|
@@ -2938,18 +4280,19 @@ function WorkflowsHome({filterSlot: filterSlot, onOpenDefinition: onOpenDefiniti
|
|
|
2938
4280
|
children: /* @__PURE__ */ jsx(Flex, {
|
|
2939
4281
|
direction: "column",
|
|
2940
4282
|
flex: 1,
|
|
2941
|
-
|
|
2942
|
-
|
|
2943
|
-
}
|
|
4283
|
+
style: {
|
|
4284
|
+
minHeight: 0
|
|
4285
|
+
},
|
|
4286
|
+
children: /* @__PURE__ */ jsx(HomePanel, {
|
|
4287
|
+
boardDefinition: boardDefinition,
|
|
2944
4288
|
filterSlot: filterSlot,
|
|
2945
4289
|
identity: identity,
|
|
2946
|
-
instances:
|
|
2947
|
-
|
|
4290
|
+
instances: instances,
|
|
4291
|
+
onOpenDefinition: onOpenDefinition,
|
|
2948
4292
|
onOpenTask: setOpenTask,
|
|
2949
4293
|
onOpenWorkflow: openInstance,
|
|
2950
|
-
|
|
2951
|
-
|
|
2952
|
-
unreadable: instances.unreadable
|
|
4294
|
+
onSelectWorkflow: onSelectWorkflow,
|
|
4295
|
+
tab: tab
|
|
2953
4296
|
})
|
|
2954
4297
|
})
|
|
2955
4298
|
})
|
|
@@ -2960,4 +4303,25 @@ function WorkflowsHome({filterSlot: filterSlot, onOpenDefinition: onOpenDefiniti
|
|
|
2960
4303
|
});
|
|
2961
4304
|
}
|
|
2962
4305
|
|
|
4306
|
+
function HomePanel({boardDefinition: boardDefinition, filterSlot: filterSlot, identity: identity, instances: instances, onOpenDefinition: onOpenDefinition, onOpenTask: onOpenTask, onOpenWorkflow: onOpenWorkflow, onSelectWorkflow: onSelectWorkflow, tab: tab}) {
|
|
4307
|
+
return tab === "definitions" ? /* @__PURE__ */ jsx(DefinitionsTab, {
|
|
4308
|
+
onOpenDefinition: onOpenDefinition
|
|
4309
|
+
}) : tab === "documents" ? /* @__PURE__ */ jsx(DocumentsTab, {
|
|
4310
|
+
filterSlot: filterSlot,
|
|
4311
|
+
onOpenDefinition: onOpenDefinition,
|
|
4312
|
+
onSelectWorkflow: onSelectWorkflow,
|
|
4313
|
+
routeDefinition: boardDefinition
|
|
4314
|
+
}) : /* @__PURE__ */ jsx(TasksTab, {
|
|
4315
|
+
filterSlot: filterSlot,
|
|
4316
|
+
identity: identity,
|
|
4317
|
+
instances: [ ...instances.inFlight, ...instances.settled ],
|
|
4318
|
+
loading: instances.loading,
|
|
4319
|
+
onOpenTask: onOpenTask,
|
|
4320
|
+
onOpenWorkflow: onOpenWorkflow,
|
|
4321
|
+
segment: tab,
|
|
4322
|
+
truncated: instances.truncated,
|
|
4323
|
+
unreadable: instances.unreadable
|
|
4324
|
+
});
|
|
4325
|
+
}
|
|
4326
|
+
|
|
2963
4327
|
export { WorkflowsToolRoot as default };
|