@sanity/workflow-studio-plugin 0.22.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 +171 -0
- package/README.md +13 -20
- package/dist/_chunks-cjs/index.cjs +3190 -2874
- package/dist/_chunks-cjs/workflows-tool-root.cjs +2776 -668
- package/dist/_chunks-es/index.js +3100 -2844
- package/dist/_chunks-es/workflows-tool-root.js +2803 -681
- package/package.json +12 -12
|
@@ -1,6 +1,247 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
|
|
3
|
-
var jsxRuntime = require("react/jsx-runtime"), ui = require("@sanity/ui"), workflowReact = require("@sanity/workflow-react"), react = require("react"), router = require("sanity/router"), index = require("./index.cjs"),
|
|
3
|
+
var jsxRuntime = require("react/jsx-runtime"), ui = require("@sanity/ui"), workflowReact = require("@sanity/workflow-react"), react = require("react"), router = require("sanity/router"), index = require("./index.cjs"), Search = require("@sanity/icons/Search"), workflowEngine = require("@sanity/workflow-engine"), ChevronDown = require("@sanity/icons/ChevronDown"), Inline = require("@sanity/icons/Inline"), StackCompact = require("@sanity/icons/StackCompact"), reactDom = require("react-dom"), types = require("@sanity/types"), sanity = require("sanity"), workflowStudio = require("@sanity/workflow-studio"), WarningOutline = require("@sanity/icons/WarningOutline"), workflowDiagram = require("@sanity/workflow-diagram"), ArrowLeft = require("@sanity/icons/ArrowLeft"), InfoOutline = require("@sanity/icons/InfoOutline"), Transfer = require("@sanity/icons/Transfer"), pluralize = require("pluralize-esm"), Clock = require("@sanity/icons/Clock"), Cog = require("@sanity/icons/Cog"), EllipsisHorizontal = require("@sanity/icons/EllipsisHorizontal"), Add = require("@sanity/icons/Add"), Checkmark = require("@sanity/icons/Checkmark"), Close = require("@sanity/icons/Close"), Filter = require("@sanity/icons/Filter"), workflowComponents = require("@sanity/workflow-components"), endOfDay = require("date-fns/endOfDay"), Calendar = require("@sanity/icons/Calendar");
|
|
4
|
+
|
|
5
|
+
function _interopDefaultCompat(e) {
|
|
6
|
+
return e && typeof e == "object" && "default" in e ? e : {
|
|
7
|
+
default: e
|
|
8
|
+
};
|
|
9
|
+
}
|
|
10
|
+
|
|
11
|
+
var pluralize__default = /* @__PURE__ */ _interopDefaultCompat(pluralize);
|
|
12
|
+
|
|
13
|
+
function MutedNote({text: text}) {
|
|
14
|
+
/* @__PURE__ */
|
|
15
|
+
return jsxRuntime.jsx(ui.Box, {
|
|
16
|
+
paddingY: 3,
|
|
17
|
+
children: /* @__PURE__ */ jsxRuntime.jsx(ui.Text, {
|
|
18
|
+
muted: !0,
|
|
19
|
+
size: 1,
|
|
20
|
+
children: text
|
|
21
|
+
})
|
|
22
|
+
});
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
function TabStatusRow({children: children}) {
|
|
26
|
+
/* @__PURE__ */
|
|
27
|
+
return jsxRuntime.jsx(ui.Box, {
|
|
28
|
+
paddingLeft: 2,
|
|
29
|
+
paddingY: 3,
|
|
30
|
+
children: children
|
|
31
|
+
});
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
const TOOL_PANEL_PADDING = 3, UNREADABLE = {
|
|
35
|
+
readable: !1,
|
|
36
|
+
raw: void 0
|
|
37
|
+
};
|
|
38
|
+
|
|
39
|
+
function defaultStorage() {
|
|
40
|
+
try {
|
|
41
|
+
return globalThis.localStorage;
|
|
42
|
+
} catch {
|
|
43
|
+
return;
|
|
44
|
+
}
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
function readItem(storage, key) {
|
|
48
|
+
if (!storage) return UNREADABLE;
|
|
49
|
+
try {
|
|
50
|
+
const raw = storage.getItem(key);
|
|
51
|
+
return {
|
|
52
|
+
readable: !0,
|
|
53
|
+
raw: raw === null ? void 0 : raw
|
|
54
|
+
};
|
|
55
|
+
} catch {
|
|
56
|
+
return UNREADABLE;
|
|
57
|
+
}
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
function writeItem(args) {
|
|
61
|
+
if (!args.storage) return !1;
|
|
62
|
+
try {
|
|
63
|
+
return args.storage.setItem(args.key, args.value), !0;
|
|
64
|
+
} catch {
|
|
65
|
+
return !1;
|
|
66
|
+
}
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
const BAND_DEFAULT_OPEN = !0, UNGROUPED_BAND_KEY = "section:no-document", PAYLOAD_VERSION = 2, MAX_ENTRIES = 200;
|
|
70
|
+
|
|
71
|
+
function bandStateStorageKey(scope) {
|
|
72
|
+
return `sanity.workflows.tool.bands:${scope}`;
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
function isRecord(value) {
|
|
76
|
+
return typeof value == "object" && value !== null && !Array.isArray(value);
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
function bandEntryOf(value) {
|
|
80
|
+
if (!isRecord(value)) return;
|
|
81
|
+
const {open: open, touched: touched} = value;
|
|
82
|
+
if (!(typeof open != "boolean" || typeof touched != "number") && Number.isFinite(touched)) return {
|
|
83
|
+
open: open,
|
|
84
|
+
touched: touched
|
|
85
|
+
};
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
function parsePayload(raw) {
|
|
89
|
+
try {
|
|
90
|
+
const parsed = JSON.parse(raw);
|
|
91
|
+
if (!isRecord(parsed) || parsed.version !== PAYLOAD_VERSION || !isRecord(parsed.bands)) return;
|
|
92
|
+
const entries = [];
|
|
93
|
+
for (const [key, value] of Object.entries(parsed.bands)) {
|
|
94
|
+
const entry = bandEntryOf(value);
|
|
95
|
+
if (entry === void 0) return;
|
|
96
|
+
entries.push([ key, entry ]);
|
|
97
|
+
}
|
|
98
|
+
return Object.fromEntries(entries);
|
|
99
|
+
} catch {
|
|
100
|
+
return;
|
|
101
|
+
}
|
|
102
|
+
}
|
|
103
|
+
|
|
104
|
+
function readStored(storage, storageKey) {
|
|
105
|
+
const {readable: readable, raw: raw} = readItem(storage, storageKey);
|
|
106
|
+
if (!readable) return {
|
|
107
|
+
entries: void 0,
|
|
108
|
+
corrupt: !1
|
|
109
|
+
};
|
|
110
|
+
if (raw === void 0) return {
|
|
111
|
+
entries: {},
|
|
112
|
+
corrupt: !1
|
|
113
|
+
};
|
|
114
|
+
const entries = parsePayload(raw);
|
|
115
|
+
return {
|
|
116
|
+
entries: entries,
|
|
117
|
+
corrupt: entries === void 0
|
|
118
|
+
};
|
|
119
|
+
}
|
|
120
|
+
|
|
121
|
+
function writeStored(args) {
|
|
122
|
+
return writeItem({
|
|
123
|
+
storage: args.storage,
|
|
124
|
+
key: args.storageKey,
|
|
125
|
+
value: JSON.stringify({
|
|
126
|
+
version: PAYLOAD_VERSION,
|
|
127
|
+
bands: args.entries
|
|
128
|
+
})
|
|
129
|
+
});
|
|
130
|
+
}
|
|
131
|
+
|
|
132
|
+
function baseEntries(args) {
|
|
133
|
+
return args.stored === void 0 ? args.held : args.unpersisted ? mergeByTouched(args.stored, args.held) : args.stored;
|
|
134
|
+
}
|
|
135
|
+
|
|
136
|
+
function mergeByTouched(stored, held) {
|
|
137
|
+
const merged = {
|
|
138
|
+
...stored
|
|
139
|
+
};
|
|
140
|
+
for (const [key, entry] of Object.entries(held)) {
|
|
141
|
+
const persisted = merged[key];
|
|
142
|
+
(persisted === void 0 || entry.touched >= persisted.touched) && (merged[key] = entry);
|
|
143
|
+
}
|
|
144
|
+
return merged;
|
|
145
|
+
}
|
|
146
|
+
|
|
147
|
+
function prune(entries) {
|
|
148
|
+
const held = Object.entries(entries);
|
|
149
|
+
return held.length <= MAX_ENTRIES ? entries : Object.fromEntries(held.sort(([, a], [, b]) => b.touched - a.touched).slice(0, MAX_ENTRIES));
|
|
150
|
+
}
|
|
151
|
+
|
|
152
|
+
function togglesOf(entries) {
|
|
153
|
+
return new Map(Object.entries(entries).map(([key, entry]) => [ key, entry.open ]));
|
|
154
|
+
}
|
|
155
|
+
|
|
156
|
+
function createBandStateStore(args) {
|
|
157
|
+
const storage = args.storage ?? defaultStorage(), initial = readStored(storage, args.storageKey);
|
|
158
|
+
initial.corrupt && writeStored({
|
|
159
|
+
storage: storage,
|
|
160
|
+
storageKey: args.storageKey,
|
|
161
|
+
entries: {}
|
|
162
|
+
});
|
|
163
|
+
let held = initial.entries ?? {}, toggles = togglesOf(held);
|
|
164
|
+
const subscribers = index.createSubscribers();
|
|
165
|
+
let unpersisted = !1;
|
|
166
|
+
return {
|
|
167
|
+
subscribe: subscribers.subscribe,
|
|
168
|
+
read: () => toggles,
|
|
169
|
+
setOpen(key, open) {
|
|
170
|
+
const stored = readStored(storage, args.storageKey).entries, base = baseEntries({
|
|
171
|
+
stored: stored,
|
|
172
|
+
held: held,
|
|
173
|
+
unpersisted: unpersisted
|
|
174
|
+
});
|
|
175
|
+
held = prune({
|
|
176
|
+
...base,
|
|
177
|
+
[key]: {
|
|
178
|
+
open: open,
|
|
179
|
+
touched: Date.now()
|
|
180
|
+
}
|
|
181
|
+
}), toggles = togglesOf(held), unpersisted = !writeStored({
|
|
182
|
+
storage: storage,
|
|
183
|
+
storageKey: args.storageKey,
|
|
184
|
+
entries: held
|
|
185
|
+
}), subscribers.notify();
|
|
186
|
+
}
|
|
187
|
+
};
|
|
188
|
+
}
|
|
189
|
+
|
|
190
|
+
function useBandOpenState(args) {
|
|
191
|
+
const {segment: segment, scope: scope} = args, store = react.useMemo(() => createBandStateStore({
|
|
192
|
+
storageKey: bandStateStorageKey(scope)
|
|
193
|
+
}), [ scope ]);
|
|
194
|
+
return react.useMemo(() => ({
|
|
195
|
+
segment: segment,
|
|
196
|
+
store: store
|
|
197
|
+
}), [ segment, store ]);
|
|
198
|
+
}
|
|
199
|
+
|
|
200
|
+
function openOf(store, qualified) {
|
|
201
|
+
return store.read().get(qualified) ?? BAND_DEFAULT_OPEN;
|
|
202
|
+
}
|
|
203
|
+
|
|
204
|
+
function useBandOpen(bands, key) {
|
|
205
|
+
const {segment: segment, store: store} = bands, qualified = `${segment}/${key}`;
|
|
206
|
+
return {
|
|
207
|
+
open: react.useSyncExternalStore(store.subscribe, react.useCallback(() => openOf(store, qualified), [ store, qualified ])),
|
|
208
|
+
toggle: () => store.setOpen(qualified, !openOf(store, qualified))
|
|
209
|
+
};
|
|
210
|
+
}
|
|
211
|
+
|
|
212
|
+
const lastRead = /* @__PURE__ */ new WeakMap, issuedReads = /* @__PURE__ */ new WeakMap;
|
|
213
|
+
|
|
214
|
+
function useDeployedDefinitions() {
|
|
215
|
+
const {engine: engine} = index.useWorkflowContext(), [definitions, setDefinitions] = react.useState(() => lastRead.get(engine)?.rows), [error, setError] = react.useState(void 0);
|
|
216
|
+
return react.useEffect(() => {
|
|
217
|
+
let cancelled = !1;
|
|
218
|
+
setDefinitions(lastRead.get(engine)?.rows), setError(void 0);
|
|
219
|
+
const seq = (issuedReads.get(engine) ?? 0) + 1;
|
|
220
|
+
return issuedReads.set(engine, seq), (async () => {
|
|
221
|
+
const rows = await index.readDeployedDefinitions(engine), latest = workflowEngine.latestDeployedDefinitions(rows), held = lastRead.get(engine);
|
|
222
|
+
(held === void 0 || seq > held.seq) && lastRead.set(engine, {
|
|
223
|
+
seq: seq,
|
|
224
|
+
rows: latest
|
|
225
|
+
}), cancelled || (setDefinitions(latest), setError(void 0));
|
|
226
|
+
})().catch(err => {
|
|
227
|
+
cancelled || setError(index.describeError(err));
|
|
228
|
+
}), () => {
|
|
229
|
+
cancelled = !0;
|
|
230
|
+
};
|
|
231
|
+
}, [ engine ]), {
|
|
232
|
+
definitions: definitions,
|
|
233
|
+
error: error
|
|
234
|
+
};
|
|
235
|
+
}
|
|
236
|
+
|
|
237
|
+
const REVEAL_MAX_WAIT_MS = 2e3;
|
|
238
|
+
|
|
239
|
+
function useRevealGate(args) {
|
|
240
|
+
const {loading: loading, ready: ready} = args, settled = !loading && ready, expired = index.useDelayedFlag(!loading && !ready, REVEAL_MAX_WAIT_MS), [revealed, setRevealed] = react.useState(!1);
|
|
241
|
+
return react.useEffect(() => {
|
|
242
|
+
!revealed && (settled || expired) && setRevealed(!0);
|
|
243
|
+
}, [ expired, revealed, settled ]), revealed || settled || expired;
|
|
244
|
+
}
|
|
4
245
|
|
|
5
246
|
function documentRefsOf(instance) {
|
|
6
247
|
const seen = /* @__PURE__ */ new Map;
|
|
@@ -8,24 +249,2093 @@ function documentRefsOf(instance) {
|
|
|
8
249
|
return [ ...seen.values() ];
|
|
9
250
|
}
|
|
10
251
|
|
|
11
|
-
function
|
|
12
|
-
return
|
|
13
|
-
|
|
14
|
-
|
|
252
|
+
function byTitleThenName(a, b) {
|
|
253
|
+
return a.title.localeCompare(b.title) || a.name.localeCompare(b.name);
|
|
254
|
+
}
|
|
255
|
+
|
|
256
|
+
function byResolvedTitle(titleOf, keyOf) {
|
|
257
|
+
return (a, b) => {
|
|
258
|
+
const aTitle = titleOf(a), bTitle = titleOf(b);
|
|
259
|
+
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));
|
|
260
|
+
};
|
|
261
|
+
}
|
|
262
|
+
|
|
263
|
+
const BOARD_EMPTY_STAGE_NOTE = "No items";
|
|
264
|
+
|
|
265
|
+
function faceOf(instance) {
|
|
266
|
+
const document = documentRefsOf(instance)[0];
|
|
267
|
+
return document ? {
|
|
268
|
+
kind: "document",
|
|
269
|
+
document: document
|
|
270
|
+
} : {
|
|
271
|
+
kind: "instance",
|
|
272
|
+
title: index.instanceTitle(instance, index.definitionSnapshotOf(instance))
|
|
273
|
+
};
|
|
274
|
+
}
|
|
275
|
+
|
|
276
|
+
function boardRuns(instances) {
|
|
277
|
+
return instances.filter(instance => workflowEngine.terminalState(instance) !== "aborted");
|
|
278
|
+
}
|
|
279
|
+
|
|
280
|
+
function groupsOf(args) {
|
|
281
|
+
const declared = args.definition.stages.map(stage => stage.name), retired = [ ...args.byStage.keys() ].filter(stage => !declared.includes(stage)).sort();
|
|
282
|
+
return [ ...declared, ...retired ].map(stage => ({
|
|
283
|
+
stage: stage,
|
|
284
|
+
title: index.stageTitle(args.definition, stage),
|
|
285
|
+
cards: args.byStage.get(stage) ?? [],
|
|
286
|
+
retired: !declared.includes(stage)
|
|
287
|
+
}));
|
|
288
|
+
}
|
|
289
|
+
|
|
290
|
+
function deriveBoard(args) {
|
|
291
|
+
const byStage = /* @__PURE__ */ new Map;
|
|
292
|
+
for (const instance of boardRuns(args.instances)) {
|
|
293
|
+
const card = {
|
|
294
|
+
instanceId: instance._id,
|
|
295
|
+
face: faceOf(instance)
|
|
296
|
+
}, held = byStage.get(instance.currentStage);
|
|
297
|
+
held ? held.push(card) : byStage.set(instance.currentStage, [ card ]);
|
|
298
|
+
}
|
|
299
|
+
return {
|
|
300
|
+
groups: groupsOf({
|
|
301
|
+
definition: args.definition,
|
|
302
|
+
byStage: byStage
|
|
303
|
+
})
|
|
304
|
+
};
|
|
305
|
+
}
|
|
306
|
+
|
|
307
|
+
function orderBoardByPreviewTitle(board, titles) {
|
|
308
|
+
const compare = byResolvedTitle(card => card.face.kind === "instance" ? card.face.title : titles.get(card.face.document.id), card => card.instanceId);
|
|
309
|
+
return {
|
|
310
|
+
groups: board.groups.map(group => ({
|
|
311
|
+
...group,
|
|
312
|
+
cards: [ ...group.cards ].sort(compare)
|
|
313
|
+
}))
|
|
314
|
+
};
|
|
315
|
+
}
|
|
316
|
+
|
|
317
|
+
function boardDocuments(board) {
|
|
318
|
+
return board.groups.flatMap(group => group.cards.flatMap(card => card.face.kind === "document" ? [ card.face.document ] : []));
|
|
319
|
+
}
|
|
320
|
+
|
|
321
|
+
function BoardCard({card: card, size: size}) {
|
|
322
|
+
return size === "slim" ? card.face.kind === "instance" ? /* @__PURE__ */ jsxRuntime.jsx(InstanceFace, {
|
|
323
|
+
size: size,
|
|
324
|
+
title: card.face.title
|
|
325
|
+
}) : /* @__PURE__ */ jsxRuntime.jsx(index.DocPreviewLink, {
|
|
326
|
+
gdr: card.face.document,
|
|
327
|
+
layout: "row",
|
|
328
|
+
source: "board-card"
|
|
329
|
+
}) : /* @__PURE__ */ jsxRuntime.jsx(ui.Card, {
|
|
330
|
+
border: !0,
|
|
331
|
+
radius: 3,
|
|
332
|
+
children: card.face.kind === "instance" ? /* @__PURE__ */ jsxRuntime.jsx(InstanceFace, {
|
|
333
|
+
size: size,
|
|
334
|
+
title: card.face.title
|
|
335
|
+
}) : /* @__PURE__ */ jsxRuntime.jsx(index.DocPreviewLink, {
|
|
336
|
+
gdr: card.face.document,
|
|
337
|
+
layout: "bare",
|
|
338
|
+
source: "board-card"
|
|
339
|
+
})
|
|
340
|
+
});
|
|
341
|
+
}
|
|
342
|
+
|
|
343
|
+
function InstanceFace({size: size, title: title}) {
|
|
344
|
+
const fill = size === "slim";
|
|
345
|
+
/* @__PURE__ */
|
|
346
|
+
return jsxRuntime.jsx(ui.Box, {
|
|
347
|
+
padding: fill ? index.chipPadding(!0) : index.NOTICE_PADDING,
|
|
348
|
+
style: fill ? {
|
|
349
|
+
width: "100%"
|
|
350
|
+
} : {},
|
|
351
|
+
children: /* @__PURE__ */ jsxRuntime.jsx(ui.Text, {
|
|
352
|
+
size: 1,
|
|
353
|
+
textOverflow: "ellipsis",
|
|
354
|
+
weight: "medium",
|
|
355
|
+
children: title
|
|
356
|
+
})
|
|
357
|
+
});
|
|
358
|
+
}
|
|
359
|
+
|
|
360
|
+
function StageGroupHeading({group: group}) {
|
|
361
|
+
/* @__PURE__ */
|
|
362
|
+
return jsxRuntime.jsxs(ui.Flex, {
|
|
363
|
+
align: "center",
|
|
364
|
+
gap: 2,
|
|
365
|
+
children: [
|
|
366
|
+
/* @__PURE__ */ jsxRuntime.jsx(index.CountedLabel, {
|
|
367
|
+
count: group.cards.length,
|
|
368
|
+
label: /* @__PURE__ */ jsxRuntime.jsx(ui.Text, {
|
|
369
|
+
size: 1,
|
|
370
|
+
weight: "medium",
|
|
371
|
+
children: group.title
|
|
372
|
+
})
|
|
373
|
+
}), group.retired ?
|
|
374
|
+
/* @__PURE__ */ jsxRuntime.jsx(ui.Text, {
|
|
375
|
+
muted: !0,
|
|
376
|
+
size: 1,
|
|
377
|
+
children: "No longer in this workflow"
|
|
378
|
+
}) : null ]
|
|
379
|
+
});
|
|
380
|
+
}
|
|
381
|
+
|
|
382
|
+
const COLUMN_WIDTH = 320, PANEL_FADE = "linear-gradient(to bottom, rgb(0 0 0) 50%, rgb(0 0 0 / 0) 75%)";
|
|
383
|
+
|
|
384
|
+
function StageColumn({group: group}) {
|
|
385
|
+
/* @__PURE__ */
|
|
386
|
+
return jsxRuntime.jsxs(ui.Box, {
|
|
387
|
+
flex: "none",
|
|
388
|
+
style: {
|
|
389
|
+
display: "flex",
|
|
390
|
+
flexDirection: "column",
|
|
391
|
+
position: "relative",
|
|
392
|
+
width: COLUMN_WIDTH
|
|
393
|
+
},
|
|
394
|
+
children: [
|
|
395
|
+
/* @__PURE__ */ jsxRuntime.jsx(ui.Card, {
|
|
396
|
+
"aria-hidden": !0,
|
|
397
|
+
radius: 3,
|
|
398
|
+
style: {
|
|
399
|
+
inset: 0,
|
|
400
|
+
maskImage: PANEL_FADE,
|
|
401
|
+
position: "absolute",
|
|
402
|
+
WebkitMaskImage: PANEL_FADE
|
|
403
|
+
},
|
|
404
|
+
tone: "transparent"
|
|
405
|
+
}),
|
|
406
|
+
/* @__PURE__ */ jsxRuntime.jsx(ui.Box, {
|
|
407
|
+
flex: "none",
|
|
408
|
+
paddingX: 3,
|
|
409
|
+
paddingY: 4,
|
|
410
|
+
style: {
|
|
411
|
+
position: "relative"
|
|
412
|
+
},
|
|
413
|
+
children: /* @__PURE__ */ jsxRuntime.jsx(StageGroupHeading, {
|
|
414
|
+
group: group
|
|
415
|
+
})
|
|
416
|
+
}), group.cards.length === 0 ?
|
|
417
|
+
/* @__PURE__ */ jsxRuntime.jsx(ui.Flex, {
|
|
418
|
+
align: "center",
|
|
419
|
+
flex: 1,
|
|
420
|
+
justify: "center",
|
|
421
|
+
padding: 2,
|
|
422
|
+
style: {
|
|
423
|
+
position: "relative"
|
|
424
|
+
},
|
|
425
|
+
children: /* @__PURE__ */ jsxRuntime.jsx(ui.Text, {
|
|
426
|
+
muted: !0,
|
|
427
|
+
size: 1,
|
|
428
|
+
children: BOARD_EMPTY_STAGE_NOTE
|
|
429
|
+
})
|
|
430
|
+
}) :
|
|
431
|
+
/* @__PURE__ */ jsxRuntime.jsx(ui.Box, {
|
|
432
|
+
flex: 1,
|
|
433
|
+
overflow: "auto",
|
|
434
|
+
paddingBottom: 2,
|
|
435
|
+
paddingX: 2,
|
|
436
|
+
style: {
|
|
437
|
+
minHeight: 0,
|
|
438
|
+
position: "relative"
|
|
439
|
+
},
|
|
440
|
+
children: /* @__PURE__ */ jsxRuntime.jsx(ui.Stack, {
|
|
441
|
+
gap: 1,
|
|
442
|
+
children: group.cards.map(card => /* @__PURE__ */ jsxRuntime.jsx(BoardCard, {
|
|
443
|
+
card: card,
|
|
444
|
+
size: "block"
|
|
445
|
+
}, card.instanceId))
|
|
446
|
+
})
|
|
447
|
+
}) ]
|
|
448
|
+
});
|
|
449
|
+
}
|
|
450
|
+
|
|
451
|
+
function StageGroups({board: board}) {
|
|
452
|
+
const topGap = index.useSpaceToken(TOOL_PANEL_PADDING);
|
|
453
|
+
/* @__PURE__ */
|
|
454
|
+
return jsxRuntime.jsx(ui.Box, {
|
|
455
|
+
flex: 1,
|
|
456
|
+
style: {
|
|
457
|
+
minHeight: 0,
|
|
458
|
+
position: "relative"
|
|
459
|
+
},
|
|
460
|
+
children: /* @__PURE__ */ jsxRuntime.jsx(ui.Box, {
|
|
461
|
+
style: {
|
|
462
|
+
bottom: 0,
|
|
463
|
+
left: 0,
|
|
464
|
+
overflowX: "auto",
|
|
465
|
+
overflowY: "hidden",
|
|
466
|
+
position: "absolute",
|
|
467
|
+
right: 0,
|
|
468
|
+
top: topGap
|
|
469
|
+
},
|
|
470
|
+
children: /* @__PURE__ */ jsxRuntime.jsx(ui.Flex, {
|
|
471
|
+
align: "stretch",
|
|
472
|
+
gap: 2,
|
|
473
|
+
paddingX: TOOL_PANEL_PADDING,
|
|
474
|
+
style: {
|
|
475
|
+
boxSizing: "border-box",
|
|
476
|
+
height: "100%",
|
|
477
|
+
width: "max-content"
|
|
478
|
+
},
|
|
479
|
+
children: board.groups.map(group => /* @__PURE__ */ jsxRuntime.jsx(StageColumn, {
|
|
480
|
+
group: group
|
|
481
|
+
}, group.stage))
|
|
482
|
+
})
|
|
483
|
+
})
|
|
484
|
+
});
|
|
485
|
+
}
|
|
486
|
+
|
|
487
|
+
function isPlainClick(event) {
|
|
488
|
+
return !event.altKey && !event.ctrlKey && !event.metaKey && !event.shiftKey;
|
|
489
|
+
}
|
|
490
|
+
|
|
491
|
+
const BOARD_LAYOUTS = [ "columns", "stack" ], BOARD_DEFAULT_LAYOUT = "columns";
|
|
492
|
+
|
|
493
|
+
function boardLayoutStorageKey(scope) {
|
|
494
|
+
return `sanity.workflows.tool.board-layout:${scope}`;
|
|
495
|
+
}
|
|
496
|
+
|
|
497
|
+
function layoutOf(raw) {
|
|
498
|
+
return BOARD_LAYOUTS.find(layout => layout === raw) ?? BOARD_DEFAULT_LAYOUT;
|
|
499
|
+
}
|
|
500
|
+
|
|
501
|
+
function createBoardLayoutStore(args) {
|
|
502
|
+
const storage = args.storage ?? defaultStorage();
|
|
503
|
+
return {
|
|
504
|
+
read: () => layoutOf(readItem(storage, args.storageKey).raw),
|
|
505
|
+
set(layout) {
|
|
506
|
+
return writeItem({
|
|
507
|
+
storage: storage,
|
|
508
|
+
key: args.storageKey,
|
|
509
|
+
value: layout
|
|
510
|
+
}), layout;
|
|
511
|
+
}
|
|
512
|
+
};
|
|
513
|
+
}
|
|
514
|
+
|
|
515
|
+
const PICKER_RADIUS = 3;
|
|
516
|
+
|
|
517
|
+
function pickerLabel(face) {
|
|
518
|
+
return face.kind === "named" ? face.title : face.kind === "loading" ? "Loading" : "Select a workflow";
|
|
519
|
+
}
|
|
520
|
+
|
|
521
|
+
function WorkflowPicker({face: face, onSelect: onSelect, options: options}) {
|
|
522
|
+
const empty = options.length === 0, innerRadius = index.useRadiusToken(PICKER_RADIUS) - 1;
|
|
523
|
+
/* @__PURE__ */
|
|
524
|
+
return jsxRuntime.jsx(ui.Card, {
|
|
525
|
+
border: !0,
|
|
526
|
+
radius: PICKER_RADIUS,
|
|
527
|
+
children: /* @__PURE__ */ jsxRuntime.jsxs(ui.Flex, {
|
|
528
|
+
align: "center",
|
|
529
|
+
children: [
|
|
530
|
+
/* @__PURE__ */ jsxRuntime.jsx(ui.Box, {
|
|
531
|
+
paddingLeft: 2,
|
|
532
|
+
paddingRight: 2,
|
|
533
|
+
children: /* @__PURE__ */ jsxRuntime.jsx(ui.Text, {
|
|
534
|
+
muted: !0,
|
|
535
|
+
size: 1,
|
|
536
|
+
children: "Workflow"
|
|
537
|
+
})
|
|
538
|
+
}),
|
|
539
|
+
/* @__PURE__ */ jsxRuntime.jsx(ui.MenuButton, {
|
|
540
|
+
button: /* @__PURE__ */ jsxRuntime.jsx(ui.Button, {
|
|
541
|
+
fontSize: 1,
|
|
542
|
+
gap: 2,
|
|
543
|
+
iconRight: ChevronDown.ChevronDownIcon,
|
|
544
|
+
mode: "bleed",
|
|
545
|
+
disabled: empty,
|
|
546
|
+
padding: 2,
|
|
547
|
+
radius: 0,
|
|
548
|
+
style: {
|
|
549
|
+
borderRadius: `0 ${innerRadius}px ${innerRadius}px 0`
|
|
550
|
+
},
|
|
551
|
+
text: pickerLabel(face)
|
|
552
|
+
}),
|
|
553
|
+
id: "workflows-board-picker",
|
|
554
|
+
menu: /* @__PURE__ */ jsxRuntime.jsx(ui.Menu, {
|
|
555
|
+
children: options.map(option => /* @__PURE__ */ jsxRuntime.jsx(ui.MenuItem, {
|
|
556
|
+
fontSize: 1,
|
|
557
|
+
onClick: () => onSelect(option.name),
|
|
558
|
+
pressed: face.kind === "named" && option.name === face.name,
|
|
559
|
+
text: option.title
|
|
560
|
+
}, option.name))
|
|
561
|
+
}),
|
|
562
|
+
popover: {
|
|
563
|
+
constrainSize: !0,
|
|
564
|
+
fallbackPlacements: [ "top-start" ],
|
|
565
|
+
placement: "bottom-start",
|
|
566
|
+
portal: !0
|
|
567
|
+
}
|
|
568
|
+
}) ]
|
|
569
|
+
})
|
|
570
|
+
});
|
|
571
|
+
}
|
|
572
|
+
|
|
573
|
+
const LAYOUT_LABELS = {
|
|
574
|
+
columns: {
|
|
575
|
+
icon: Inline.InlineIcon,
|
|
576
|
+
label: "Show as boards"
|
|
577
|
+
},
|
|
578
|
+
stack: {
|
|
579
|
+
icon: StackCompact.StackCompactIcon,
|
|
580
|
+
label: "Show as list"
|
|
581
|
+
}
|
|
582
|
+
};
|
|
583
|
+
|
|
584
|
+
function LayoutToggle({layout: layout, onChange: onChange}) {
|
|
585
|
+
/* @__PURE__ */
|
|
586
|
+
return jsxRuntime.jsx(ui.Flex, {
|
|
587
|
+
align: "center",
|
|
588
|
+
gap: 1,
|
|
589
|
+
children: BOARD_LAYOUTS.map(value => {
|
|
590
|
+
const {icon: icon, label: label} = LAYOUT_LABELS[value];
|
|
591
|
+
/* @__PURE__ */
|
|
592
|
+
return jsxRuntime.jsx(index.HoverHint, {
|
|
593
|
+
text: label,
|
|
594
|
+
children: /* @__PURE__ */ jsxRuntime.jsx(ui.Button, {
|
|
595
|
+
"aria-label": label,
|
|
596
|
+
"aria-pressed": value === layout,
|
|
597
|
+
fontSize: 1,
|
|
598
|
+
icon: icon,
|
|
599
|
+
mode: "bleed",
|
|
600
|
+
onClick: () => onChange(value),
|
|
601
|
+
padding: 2,
|
|
602
|
+
selected: value === layout
|
|
603
|
+
})
|
|
604
|
+
}, value);
|
|
605
|
+
})
|
|
606
|
+
});
|
|
607
|
+
}
|
|
608
|
+
|
|
609
|
+
function DefinitionLink({name: name, onOpen: onOpen}) {
|
|
610
|
+
const {resolvePathFromState: resolvePathFromState} = router.useRouter();
|
|
611
|
+
/* @__PURE__ */
|
|
612
|
+
return jsxRuntime.jsx(ui.Button, {
|
|
613
|
+
as: "a",
|
|
614
|
+
fontSize: 1,
|
|
615
|
+
href: resolvePathFromState({
|
|
616
|
+
definitionName: name
|
|
617
|
+
}),
|
|
618
|
+
mode: "bleed",
|
|
619
|
+
onClick: event => {
|
|
620
|
+
isPlainClick(event) && (event.preventDefault(), onOpen(name));
|
|
621
|
+
},
|
|
622
|
+
padding: 2,
|
|
623
|
+
text: "View definition"
|
|
624
|
+
});
|
|
625
|
+
}
|
|
626
|
+
|
|
627
|
+
function BoardControlsPortal({definitionName: definitionName, layout: layout, onChangeLayout: onChangeLayout, face: face, onOpenDefinition: onOpenDefinition, onSelectWorkflow: onSelectWorkflow, options: options, slot: slot}) {
|
|
628
|
+
return slot ? reactDom.createPortal(
|
|
629
|
+
/* @__PURE__ */ jsxRuntime.jsxs(ui.Flex, {
|
|
630
|
+
align: "center",
|
|
631
|
+
gap: 2,
|
|
632
|
+
children: [
|
|
633
|
+
/* @__PURE__ */ jsxRuntime.jsx(WorkflowPicker, {
|
|
634
|
+
face: face,
|
|
635
|
+
onSelect: onSelectWorkflow,
|
|
636
|
+
options: options
|
|
637
|
+
}), definitionName === void 0 ? null : /* @__PURE__ */ jsxRuntime.jsx(DefinitionLink, {
|
|
638
|
+
name: definitionName,
|
|
639
|
+
onOpen: onOpenDefinition
|
|
640
|
+
}),
|
|
641
|
+
/* @__PURE__ */ jsxRuntime.jsx(ui.Box, {
|
|
642
|
+
flex: 1
|
|
643
|
+
}),
|
|
644
|
+
/* @__PURE__ */ jsxRuntime.jsx(LayoutToggle, {
|
|
645
|
+
layout: layout,
|
|
646
|
+
onChange: onChangeLayout
|
|
647
|
+
}) ]
|
|
648
|
+
}), slot) : null;
|
|
649
|
+
}
|
|
650
|
+
|
|
651
|
+
function boardWorkflowOptions(definitions) {
|
|
652
|
+
return definitions.map(definition => ({
|
|
653
|
+
name: definition.name,
|
|
654
|
+
title: definition.title
|
|
655
|
+
})).sort(byTitleThenName);
|
|
656
|
+
}
|
|
657
|
+
|
|
658
|
+
function boardLandingName(selection) {
|
|
659
|
+
if (!(selection.kind !== "resolved" || selection.via !== "default")) return selection.definition.name;
|
|
660
|
+
}
|
|
661
|
+
|
|
662
|
+
function boardPickerFace(args) {
|
|
663
|
+
const {selection: selection, routeName: routeName} = args;
|
|
664
|
+
if (selection.kind === "resolved") {
|
|
665
|
+
const {name: name, title: title} = selection.definition;
|
|
666
|
+
return {
|
|
667
|
+
kind: "named",
|
|
668
|
+
name: name,
|
|
669
|
+
title: title
|
|
670
|
+
};
|
|
671
|
+
}
|
|
672
|
+
return selection.kind === "loading" && routeName !== void 0 ? {
|
|
673
|
+
kind: "loading"
|
|
674
|
+
} : {
|
|
675
|
+
kind: "none"
|
|
676
|
+
};
|
|
677
|
+
}
|
|
678
|
+
|
|
679
|
+
function boardSelectedPayload(selection) {
|
|
680
|
+
if (selection.kind === "resolved") return {
|
|
681
|
+
via: selection.via,
|
|
682
|
+
...index.definitionFingerprint(selection.definition)
|
|
683
|
+
};
|
|
684
|
+
}
|
|
685
|
+
|
|
686
|
+
function resolveBoardSelection(args) {
|
|
687
|
+
const {definitions: definitions, routeName: routeName} = args;
|
|
688
|
+
if (definitions === void 0) return {
|
|
689
|
+
kind: "loading"
|
|
690
|
+
};
|
|
691
|
+
if (routeName !== void 0) {
|
|
692
|
+
const named = definitions.find(definition => definition.name === routeName);
|
|
693
|
+
return named ? {
|
|
694
|
+
kind: "resolved",
|
|
695
|
+
definition: named,
|
|
696
|
+
via: "address"
|
|
697
|
+
} : {
|
|
698
|
+
kind: "unknown",
|
|
699
|
+
name: routeName
|
|
700
|
+
};
|
|
701
|
+
}
|
|
702
|
+
const [landing] = [ ...definitions ].sort(byTitleThenName);
|
|
703
|
+
return landing ? {
|
|
704
|
+
kind: "resolved",
|
|
705
|
+
definition: landing,
|
|
706
|
+
via: "default"
|
|
707
|
+
} : {
|
|
708
|
+
kind: "empty"
|
|
709
|
+
};
|
|
710
|
+
}
|
|
711
|
+
|
|
712
|
+
function StageBand({bands: bands, group: group}) {
|
|
713
|
+
const {open: open, toggle: toggle} = useBandOpen(bands, group.stage);
|
|
714
|
+
/* @__PURE__ */
|
|
715
|
+
return jsxRuntime.jsx(index.CollapsibleBand, {
|
|
716
|
+
background: !0,
|
|
717
|
+
onToggle: toggle,
|
|
718
|
+
open: open,
|
|
719
|
+
sticky: !0,
|
|
720
|
+
title: group.title,
|
|
721
|
+
header: /* @__PURE__ */ jsxRuntime.jsx(StageGroupHeading, {
|
|
722
|
+
group: group
|
|
723
|
+
}),
|
|
724
|
+
children: /* @__PURE__ */ jsxRuntime.jsx(ui.Stack, {
|
|
725
|
+
gap: 1,
|
|
726
|
+
paddingLeft: 5,
|
|
727
|
+
children: group.cards.length === 0 ?
|
|
728
|
+
/* @__PURE__ */ jsxRuntime.jsx(ui.Box, {
|
|
729
|
+
padding: 3,
|
|
730
|
+
children: /* @__PURE__ */ jsxRuntime.jsx(ui.Text, {
|
|
731
|
+
muted: !0,
|
|
732
|
+
size: 1,
|
|
733
|
+
children: BOARD_EMPTY_STAGE_NOTE
|
|
734
|
+
})
|
|
735
|
+
}) : group.cards.map(card => /* @__PURE__ */ jsxRuntime.jsx(BoardCard, {
|
|
736
|
+
card: card,
|
|
737
|
+
size: "slim"
|
|
738
|
+
}, card.instanceId))
|
|
739
|
+
})
|
|
740
|
+
});
|
|
741
|
+
}
|
|
742
|
+
|
|
743
|
+
function BoardStack({bands: bands, board: board}) {
|
|
744
|
+
/* @__PURE__ */
|
|
745
|
+
return jsxRuntime.jsx(ui.Stack, {
|
|
746
|
+
gap: 1,
|
|
747
|
+
paddingBottom: 4,
|
|
748
|
+
paddingTop: 3,
|
|
749
|
+
paddingX: TOOL_PANEL_PADDING,
|
|
750
|
+
children: board.groups.map(group => /* @__PURE__ */ jsxRuntime.jsx(StageBand, {
|
|
751
|
+
bands: bands,
|
|
752
|
+
group: group
|
|
753
|
+
}, group.stage))
|
|
754
|
+
});
|
|
755
|
+
}
|
|
756
|
+
|
|
757
|
+
const ALIAS_PREFIX = "__seed_", MAX_PATH_DEPTH = 3, IDENTIFIER = /^[A-Za-z_][A-Za-z0-9_]*$/;
|
|
758
|
+
|
|
759
|
+
function previewSelectOf(schemaType) {
|
|
760
|
+
const select = schemaType.preview?.select;
|
|
761
|
+
if (!(select === void 0 || Object.keys(select).length === 0)) return select;
|
|
762
|
+
}
|
|
763
|
+
|
|
764
|
+
function fieldTypeOf(parent, name) {
|
|
765
|
+
if (!(!("fields" in parent) || !Array.isArray(parent.fields))) return parent.fields.find(field => field.name === name)?.type;
|
|
766
|
+
}
|
|
767
|
+
|
|
768
|
+
function stepOf(args) {
|
|
769
|
+
const {parent: parent, segment: segment, terminal: terminal} = args, fieldType = fieldTypeOf(parent, segment);
|
|
770
|
+
if (fieldType !== void 0) {
|
|
771
|
+
if (terminal) return {
|
|
772
|
+
part: segment,
|
|
773
|
+
next: fieldType
|
|
774
|
+
};
|
|
775
|
+
if (types.isReferenceSchemaType(fieldType)) {
|
|
776
|
+
const target = fieldType.to.length === 1 ? fieldType.to[0] : void 0;
|
|
777
|
+
return target === void 0 ? void 0 : {
|
|
778
|
+
part: `${segment}->`,
|
|
779
|
+
next: target
|
|
780
|
+
};
|
|
781
|
+
}
|
|
782
|
+
return {
|
|
783
|
+
part: `${segment}.`,
|
|
784
|
+
next: fieldType
|
|
785
|
+
};
|
|
786
|
+
}
|
|
787
|
+
}
|
|
788
|
+
|
|
789
|
+
function compilePath(root, path) {
|
|
790
|
+
const segments = path.split(".");
|
|
791
|
+
if (segments.length > MAX_PATH_DEPTH || segments.some(s => !IDENTIFIER.test(s))) return;
|
|
792
|
+
let parent = root;
|
|
793
|
+
const parts = [];
|
|
794
|
+
for (const [index2, segment] of segments.entries()) {
|
|
795
|
+
const step = stepOf({
|
|
796
|
+
parent: parent,
|
|
797
|
+
segment: segment,
|
|
798
|
+
terminal: index2 === segments.length - 1
|
|
799
|
+
});
|
|
800
|
+
if (step === void 0) return;
|
|
801
|
+
parts.push(step.part), parent = step.next;
|
|
802
|
+
}
|
|
803
|
+
return parts.join("");
|
|
804
|
+
}
|
|
805
|
+
|
|
806
|
+
function selectArmOf(schemaType) {
|
|
807
|
+
const select = previewSelectOf(schemaType);
|
|
808
|
+
if (select === void 0) return;
|
|
809
|
+
const entries = [];
|
|
810
|
+
for (const [key, path] of Object.entries(select)) {
|
|
811
|
+
const compiled = compilePath(schemaType, path);
|
|
812
|
+
if (compiled === void 0) return;
|
|
813
|
+
entries.push(`${JSON.stringify(ALIAS_PREFIX + key)}: ${compiled}`);
|
|
814
|
+
}
|
|
815
|
+
return `_type == ${JSON.stringify(schemaType.name)} => {${entries.join(", ")}}`;
|
|
816
|
+
}
|
|
817
|
+
|
|
818
|
+
function planTitleSeed(types2) {
|
|
819
|
+
const seedable = /* @__PURE__ */ new Map, arms = [];
|
|
820
|
+
for (const type of types2) {
|
|
821
|
+
const arm = selectArmOf(type);
|
|
822
|
+
arm !== void 0 && (seedable.set(type.name, type), arms.push(arm));
|
|
823
|
+
}
|
|
824
|
+
return {
|
|
825
|
+
query: `*[_id in $ids]{_id, _type${arms.length > 0 ? `, ...select(${arms.join(", ")})` : ""}}`,
|
|
826
|
+
seedable: seedable
|
|
827
|
+
};
|
|
828
|
+
}
|
|
829
|
+
|
|
830
|
+
function isSeedRow(value) {
|
|
831
|
+
if (typeof value != "object" || value === null) return !1;
|
|
832
|
+
const row = value;
|
|
833
|
+
return typeof row._id == "string" && typeof row._type == "string";
|
|
834
|
+
}
|
|
835
|
+
|
|
836
|
+
function seededTitleOf(row, schemaType) {
|
|
837
|
+
const select = previewSelectOf(schemaType);
|
|
838
|
+
if (select === void 0) return;
|
|
839
|
+
const selected = {};
|
|
840
|
+
for (const key of Object.keys(select)) selected[key] = row[ALIAS_PREFIX + key];
|
|
841
|
+
const prepare = schemaType.preview?.prepare;
|
|
842
|
+
let title;
|
|
843
|
+
if (prepare === void 0) title = selected.title; else try {
|
|
844
|
+
title = prepare(selected).title;
|
|
845
|
+
} catch (err) {
|
|
846
|
+
console.error(`[workflow-studio-plugin] preview prepare for "${schemaType.name}" failed on seed:`, err);
|
|
847
|
+
return;
|
|
848
|
+
}
|
|
849
|
+
return typeof title == "string" ? title : void 0;
|
|
850
|
+
}
|
|
851
|
+
|
|
852
|
+
function seedFromRows(args) {
|
|
853
|
+
const rows = args.rows.filter(isSeedRow), byBareId = new Map(rows.map(row => [ row._id, row ])), types2 = new Map(rows.map(row => [ row._id, row._type ])), titles = /* @__PURE__ */ new Map, resolved = /* @__PURE__ */ new Set;
|
|
854
|
+
for (const {gdrId: gdrId, bareId: bareId} of args.docs) {
|
|
855
|
+
const row = byBareId.get(bareId);
|
|
856
|
+
if (row === void 0) continue;
|
|
857
|
+
const schemaType = args.seedable.get(row._type);
|
|
858
|
+
if (schemaType === void 0) continue;
|
|
859
|
+
resolved.add(gdrId);
|
|
860
|
+
const title = seededTitleOf(row, schemaType);
|
|
861
|
+
title !== void 0 && titles.set(gdrId, title);
|
|
862
|
+
}
|
|
863
|
+
return {
|
|
864
|
+
types: types2,
|
|
865
|
+
titles: {
|
|
866
|
+
titles: titles,
|
|
867
|
+
resolved: resolved
|
|
868
|
+
}
|
|
869
|
+
};
|
|
870
|
+
}
|
|
871
|
+
|
|
872
|
+
function titleDrift(seed, live) {
|
|
873
|
+
const drifted = [];
|
|
874
|
+
for (const gdrId of seed.resolved) {
|
|
875
|
+
if (!live.resolved.has(gdrId)) continue;
|
|
876
|
+
const seeded = seed.titles.get(gdrId), observed = live.titles.get(gdrId);
|
|
877
|
+
seeded !== observed && drifted.push({
|
|
878
|
+
gdrId: gdrId,
|
|
879
|
+
seeded: seeded,
|
|
880
|
+
observed: observed
|
|
881
|
+
});
|
|
882
|
+
}
|
|
883
|
+
return drifted;
|
|
884
|
+
}
|
|
885
|
+
|
|
886
|
+
function mergeSeededTitles(live, seed) {
|
|
887
|
+
if (seed.resolved.size === 0) return live;
|
|
888
|
+
const titles = new Map(live.titles), resolved = new Set(live.resolved);
|
|
889
|
+
for (const gdrId of seed.resolved) {
|
|
890
|
+
if (live.resolved.has(gdrId)) continue;
|
|
891
|
+
resolved.add(gdrId);
|
|
892
|
+
const title = seed.titles.get(gdrId);
|
|
893
|
+
title !== void 0 && titles.set(gdrId, title);
|
|
894
|
+
}
|
|
895
|
+
return {
|
|
896
|
+
titles: titles,
|
|
897
|
+
resolved: resolved
|
|
898
|
+
};
|
|
899
|
+
}
|
|
900
|
+
|
|
901
|
+
const NO_TITLES = {
|
|
902
|
+
titles: /* @__PURE__ */ new Map,
|
|
903
|
+
resolved: /* @__PURE__ */ new Set
|
|
904
|
+
};
|
|
905
|
+
|
|
906
|
+
function useDocPreviewTitles(documents) {
|
|
907
|
+
const previewStore = sanity.useDocumentPreviewStore(), schema = sanity.useSchema(), {perspectiveStack: perspectiveStack} = sanity.usePerspective(), {actualTypes: actualTypes, binding: binding} = index.useWorkflowContext(), [state, setState] = react.useState(NO_TITLES), key = documents.map(doc => doc.id).join("|");
|
|
908
|
+
return react.useEffect(() => {
|
|
909
|
+
const titles = /* @__PURE__ */ new Map, resolved = /* @__PURE__ */ new Set, previews = /* @__PURE__ */ new Map, publish = () => setState({
|
|
910
|
+
titles: new Map(titles),
|
|
911
|
+
resolved: new Set(resolved)
|
|
912
|
+
}), localDocs = documents.flatMap(doc => {
|
|
913
|
+
const {parsed: parsed, local: local} = index.gdrLocality(doc.id, binding.contentResource);
|
|
914
|
+
return !parsed || !local ? (resolved.add(doc.id), []) : [ {
|
|
915
|
+
doc: doc,
|
|
916
|
+
bareId: parsed.documentId
|
|
917
|
+
} ];
|
|
918
|
+
}), untracks = localDocs.map(({bareId: bareId}) => actualTypes.track(bareId)), dropPreview = docId => {
|
|
919
|
+
previews.get(docId)?.unsubscribe(), previews.delete(docId), titles.delete(docId);
|
|
920
|
+
}, observe = ({docId: docId, bareId: bareId, typeName: typeName}) => {
|
|
921
|
+
const schemaType = index.openableSchemaType(schema, typeName);
|
|
922
|
+
if (!schemaType) return !1;
|
|
923
|
+
if (previews.get(docId)?.typeName === typeName) return !0;
|
|
924
|
+
dropPreview(docId), resolved.delete(docId);
|
|
925
|
+
const subscription = previewStore.observeForPreview({
|
|
926
|
+
_id: bareId,
|
|
927
|
+
_type: schemaType.name
|
|
928
|
+
}, schemaType, {
|
|
929
|
+
perspective: perspectiveStack
|
|
930
|
+
}).subscribe({
|
|
931
|
+
next: event => {
|
|
932
|
+
resolved.add(docId);
|
|
933
|
+
const title = event.snapshot?.title;
|
|
934
|
+
typeof title == "string" ? titles.set(docId, title) : titles.delete(docId), publish();
|
|
935
|
+
},
|
|
936
|
+
error: err => {
|
|
937
|
+
console.error(`[workflow-studio-plugin] preview for "${docId}" failed:`, err), resolved.add(docId),
|
|
938
|
+
publish();
|
|
939
|
+
}
|
|
940
|
+
});
|
|
941
|
+
return previews.set(docId, {
|
|
942
|
+
typeName: typeName,
|
|
943
|
+
unsubscribe: () => subscription.unsubscribe()
|
|
944
|
+
}), !0;
|
|
945
|
+
}, evaluate = () => {
|
|
946
|
+
for (const {doc: doc, bareId: bareId} of localDocs) {
|
|
947
|
+
const probe = actualTypes.read(bareId);
|
|
948
|
+
if (probe === null) {
|
|
949
|
+
dropPreview(doc.id), resolved.add(doc.id);
|
|
950
|
+
continue;
|
|
951
|
+
}
|
|
952
|
+
!observe({
|
|
953
|
+
docId: doc.id,
|
|
954
|
+
bareId: bareId,
|
|
955
|
+
typeName: probe ?? doc.type
|
|
956
|
+
}) && typeof probe == "string" && (dropPreview(doc.id), resolved.add(doc.id));
|
|
957
|
+
}
|
|
958
|
+
publish();
|
|
959
|
+
}, unsubscribeProbes = actualTypes.subscribe(evaluate);
|
|
960
|
+
return evaluate(), () => {
|
|
961
|
+
unsubscribeProbes(), untracks.forEach(untrack => untrack()), previews.forEach(preview => preview.unsubscribe());
|
|
962
|
+
};
|
|
963
|
+
}, [ key, previewStore, schema, actualTypes, binding.contentResource.id, perspectiveStack.join("|") ]),
|
|
964
|
+
state;
|
|
965
|
+
}
|
|
966
|
+
|
|
967
|
+
function usePreviewSeed(documents) {
|
|
968
|
+
const client = sanity.useClient({
|
|
969
|
+
apiVersion: index.WORKFLOW_API_VERSION
|
|
970
|
+
}), schema = sanity.useSchema(), {perspectiveStack: perspectiveStack} = sanity.usePerspective(), {actualTypes: actualTypes, binding: binding} = index.useWorkflowContext(), [seed, setSeed] = react.useState(NO_TITLES), docs = react.useMemo(() => documents.flatMap(doc => {
|
|
971
|
+
const {parsed: parsed, local: local} = index.gdrLocality(doc.id, binding.contentResource);
|
|
972
|
+
return parsed === void 0 || !local ? [] : [ {
|
|
973
|
+
gdrId: doc.id,
|
|
974
|
+
bareId: parsed.documentId
|
|
975
|
+
} ];
|
|
976
|
+
}), [ documents, binding.contentResource ]), key = docs.map(doc => doc.gdrId).join("|");
|
|
977
|
+
return react.useEffect(() => {
|
|
978
|
+
if (setSeed(NO_TITLES), key === "") return;
|
|
979
|
+
const plan = planTitleSeed(schema.getTypeNames().flatMap(name => index.openableSchemaType(schema, name) ?? []));
|
|
980
|
+
let cancelled = !1;
|
|
981
|
+
return client.fetch(plan.query, {
|
|
982
|
+
ids: docs.map(doc => doc.bareId)
|
|
983
|
+
}, {
|
|
984
|
+
tag: "workflows.preview-seed",
|
|
985
|
+
...perspectiveStack.length > 0 ? {
|
|
986
|
+
perspective: [ ...perspectiveStack ]
|
|
987
|
+
} : {}
|
|
988
|
+
}).then(rows => {
|
|
989
|
+
if (cancelled) return;
|
|
990
|
+
const result = seedFromRows({
|
|
991
|
+
rows: rows,
|
|
992
|
+
docs: docs,
|
|
993
|
+
seedable: plan.seedable
|
|
994
|
+
});
|
|
995
|
+
actualTypes.seed(result.types), setSeed(result.titles);
|
|
996
|
+
}).catch(err => {
|
|
997
|
+
cancelled || console.error("[workflow-studio-plugin] preview seed failed:", err);
|
|
998
|
+
}), () => {
|
|
999
|
+
cancelled = !0;
|
|
1000
|
+
};
|
|
1001
|
+
}, [ key, client, schema, actualTypes, binding.contentResource.id, perspectiveStack.join("|") ]),
|
|
1002
|
+
seed;
|
|
1003
|
+
}
|
|
1004
|
+
|
|
1005
|
+
function useSeededTitles(args) {
|
|
1006
|
+
const {ordering: ordering, warm: warm} = args, seed = usePreviewSeed(warm), live = useDocPreviewTitles(ordering), telemetry = workflowReact.useWorkflowTelemetry(), warned = react.useRef(/* @__PURE__ */ new Set);
|
|
1007
|
+
return react.useEffect(() => {
|
|
1008
|
+
const fresh = titleDrift(seed, live).filter(drift => !warned.current.has(drift.gdrId));
|
|
1009
|
+
if (fresh.length !== 0) {
|
|
1010
|
+
warned.current.size === 0 && telemetry.log(index.WorkflowTitleSeedDrifted, {
|
|
1011
|
+
driftCount: fresh.length
|
|
1012
|
+
});
|
|
1013
|
+
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`);
|
|
1014
|
+
}
|
|
1015
|
+
}, [ seed, live, telemetry ]), react.useMemo(() => {
|
|
1016
|
+
const merged = mergeSeededTitles(live, seed);
|
|
1017
|
+
return {
|
|
1018
|
+
...merged,
|
|
1019
|
+
ready: ordering.every(doc => merged.resolved.has(doc.id))
|
|
1020
|
+
};
|
|
1021
|
+
}, [ ordering, live, seed ]);
|
|
1022
|
+
}
|
|
1023
|
+
|
|
1024
|
+
function useGroupTitles(groups) {
|
|
1025
|
+
const ordering = react.useMemo(() => groups.withDocuments.map(group => group.document), [ groups ]), warm = react.useMemo(() => groups.withDocuments.flatMap(group => group.documents), [ groups ]);
|
|
1026
|
+
return useSeededTitles({
|
|
1027
|
+
ordering: ordering,
|
|
1028
|
+
warm: warm
|
|
1029
|
+
});
|
|
1030
|
+
}
|
|
1031
|
+
|
|
1032
|
+
const NO_DOCUMENTS = [];
|
|
1033
|
+
|
|
1034
|
+
function useBoard(args) {
|
|
1035
|
+
const {definition: definition, instances: instances} = args, derived = react.useMemo(() => definition ? deriveBoard({
|
|
1036
|
+
instances: instances,
|
|
1037
|
+
definition: definition
|
|
1038
|
+
}) : void 0, [ definition, instances ]), documents = react.useMemo(() => derived ? boardDocuments(derived) : NO_DOCUMENTS, [ derived ]), {titles: titles, ready: ready} = useSeededTitles({
|
|
1039
|
+
ordering: documents,
|
|
1040
|
+
warm: documents
|
|
1041
|
+
}), board = react.useMemo(() => derived ? orderBoardByPreviewTitle(derived, titles) : void 0, [ derived, titles ]);
|
|
1042
|
+
return react.useMemo(() => ({
|
|
1043
|
+
board: board,
|
|
1044
|
+
ready: ready
|
|
1045
|
+
}), [ board, ready ]);
|
|
1046
|
+
}
|
|
1047
|
+
|
|
1048
|
+
const INSTANCE_CAP = 200;
|
|
1049
|
+
|
|
1050
|
+
function useCappedInstances(filter) {
|
|
1051
|
+
const {engine: engine} = index.useWorkflowContext(), capped = react.useMemo(() => ({
|
|
1052
|
+
...filter,
|
|
1053
|
+
limit: INSTANCE_CAP
|
|
1054
|
+
}), [ filter ]), {instances: instances, loading: loading, unreadable: unreadable} = workflowStudio.useWorkflowInstances({
|
|
1055
|
+
engine: engine,
|
|
1056
|
+
filter: capped
|
|
1057
|
+
});
|
|
1058
|
+
return react.useMemo(() => {
|
|
1059
|
+
const rows = instances ?? [];
|
|
1060
|
+
return {
|
|
1061
|
+
rows: rows,
|
|
1062
|
+
truncated: rows.length + unreadable.length === INSTANCE_CAP,
|
|
1063
|
+
loading: loading,
|
|
1064
|
+
unreadable: unreadable
|
|
1065
|
+
};
|
|
1066
|
+
}, [ instances, loading, unreadable ]);
|
|
1067
|
+
}
|
|
1068
|
+
|
|
1069
|
+
const BOARD_CAP_NOTE = `Showing the latest ${INSTANCE_CAP} workflows — older ones aren’t on the board.`, NOTHING = {
|
|
1070
|
+
ids: []
|
|
1071
|
+
};
|
|
1072
|
+
|
|
1073
|
+
function useBoardInstances(definitionName) {
|
|
1074
|
+
const filter = react.useMemo(() => definitionName === void 0 ? NOTHING : {
|
|
1075
|
+
definition: definitionName,
|
|
1076
|
+
includeCompleted: !0
|
|
1077
|
+
}, [ definitionName ]);
|
|
1078
|
+
return useCappedInstances(filter);
|
|
1079
|
+
}
|
|
1080
|
+
|
|
1081
|
+
function useBoardLayout(scope) {
|
|
1082
|
+
const store = react.useMemo(() => createBoardLayoutStore({
|
|
1083
|
+
storageKey: boardLayoutStorageKey(scope)
|
|
1084
|
+
}), [ scope ]), [held, setHeld] = react.useState(() => ({
|
|
1085
|
+
store: store,
|
|
1086
|
+
layout: store.read()
|
|
1087
|
+
}));
|
|
1088
|
+
return held.store !== store && setHeld({
|
|
1089
|
+
store: store,
|
|
1090
|
+
layout: store.read()
|
|
1091
|
+
}), {
|
|
1092
|
+
layout: held.layout,
|
|
1093
|
+
setLayout: layout => setHeld({
|
|
1094
|
+
store: store,
|
|
1095
|
+
layout: store.set(layout)
|
|
1096
|
+
})
|
|
1097
|
+
};
|
|
1098
|
+
}
|
|
1099
|
+
|
|
1100
|
+
function DocumentsTab({filterSlot: filterSlot, onOpenDefinition: onOpenDefinition, onSelectWorkflow: onSelectWorkflow, routeDefinition: routeDefinition}) {
|
|
1101
|
+
const {binding: binding} = index.useWorkflowContext(), telemetry = workflowReact.useWorkflowTelemetry(), {definitions: definitions, error: error} = useDeployedDefinitions(), {layout: layout, setLayout: setLayout} = useBoardLayout(binding.engineResource.id), bands = useBandOpenState({
|
|
1102
|
+
segment: "documents",
|
|
1103
|
+
scope: binding.engineResource.id
|
|
1104
|
+
}), selection = resolveBoardSelection({
|
|
1105
|
+
definitions: definitions,
|
|
1106
|
+
routeName: routeDefinition
|
|
1107
|
+
}), selected = selection.kind === "resolved" ? selection.definition : void 0, instances = useBoardInstances(selected?.name), {board: board, ready: ready} = useBoard({
|
|
1108
|
+
definition: selected,
|
|
1109
|
+
instances: instances.rows
|
|
1110
|
+
}), revealed = useRevealGate({
|
|
1111
|
+
loading: instances.loading,
|
|
1112
|
+
ready: ready
|
|
1113
|
+
}), landing = boardLandingName(selection);
|
|
1114
|
+
react.useEffect(() => {
|
|
1115
|
+
landing !== void 0 && onSelectWorkflow(landing, {
|
|
1116
|
+
replace: !0
|
|
1117
|
+
});
|
|
1118
|
+
}, [ landing, onSelectWorkflow ]);
|
|
1119
|
+
const selectedPayload = boardSelectedPayload(selection);
|
|
1120
|
+
/* @__PURE__ */
|
|
1121
|
+
return jsxRuntime.jsxs(ui.Flex, {
|
|
1122
|
+
direction: "column",
|
|
1123
|
+
flex: 1,
|
|
1124
|
+
style: {
|
|
1125
|
+
minHeight: 0
|
|
1126
|
+
},
|
|
1127
|
+
children: [
|
|
1128
|
+
/* @__PURE__ */ jsxRuntime.jsx(BoardControlsPortal, {
|
|
1129
|
+
definitionName: selected?.name,
|
|
1130
|
+
layout: layout,
|
|
1131
|
+
onOpenDefinition: onOpenDefinition,
|
|
1132
|
+
onChangeLayout: next => {
|
|
1133
|
+
next !== layout && (telemetry.log(index.WorkflowBoardLayoutChanged, {
|
|
1134
|
+
layout: next
|
|
1135
|
+
}), setLayout(next));
|
|
1136
|
+
},
|
|
1137
|
+
onSelectWorkflow: onSelectWorkflow,
|
|
1138
|
+
options: boardWorkflowOptions(definitions ?? []),
|
|
1139
|
+
face: boardPickerFace({
|
|
1140
|
+
selection: selection,
|
|
1141
|
+
routeName: routeDefinition
|
|
1142
|
+
}),
|
|
1143
|
+
slot: filterSlot
|
|
1144
|
+
}),
|
|
1145
|
+
/* @__PURE__ */ jsxRuntime.jsxs(ui.Flex, {
|
|
1146
|
+
direction: "column",
|
|
1147
|
+
flex: 1,
|
|
1148
|
+
gap: 2,
|
|
1149
|
+
style: {
|
|
1150
|
+
minHeight: 0
|
|
1151
|
+
},
|
|
1152
|
+
children: [ instances.unreadable.length === 0 ? null : /* @__PURE__ */ jsxRuntime.jsx(ui.Box, {
|
|
1153
|
+
paddingX: TOOL_PANEL_PADDING,
|
|
1154
|
+
children: /* @__PURE__ */ jsxRuntime.jsx(index.UnreadableDocsNote, {
|
|
1155
|
+
unreadable: instances.unreadable
|
|
1156
|
+
})
|
|
1157
|
+
}),
|
|
1158
|
+
/* @__PURE__ */ jsxRuntime.jsx(BoardBody, {
|
|
1159
|
+
bands: bands,
|
|
1160
|
+
board: board,
|
|
1161
|
+
error: error,
|
|
1162
|
+
layout: layout,
|
|
1163
|
+
loading: !revealed,
|
|
1164
|
+
selection: selection
|
|
1165
|
+
}), instances.truncated ? /* @__PURE__ */ jsxRuntime.jsx(ui.Box, {
|
|
1166
|
+
paddingX: TOOL_PANEL_PADDING,
|
|
1167
|
+
children: /* @__PURE__ */ jsxRuntime.jsx(MutedNote, {
|
|
1168
|
+
text: BOARD_CAP_NOTE
|
|
1169
|
+
})
|
|
1170
|
+
}) : null ]
|
|
1171
|
+
}), selectedPayload === void 0 ? null :
|
|
1172
|
+
/* @__PURE__ */ jsxRuntime.jsx(index.LogEventOnMount, {
|
|
1173
|
+
data: selectedPayload,
|
|
1174
|
+
event: index.WorkflowBoardWorkflowSelected
|
|
1175
|
+
}, selected?.name) ]
|
|
1176
|
+
});
|
|
1177
|
+
}
|
|
1178
|
+
|
|
1179
|
+
function BoardBody({bands: bands, board: board, error: error, layout: layout, loading: loading, selection: selection}) {
|
|
1180
|
+
return error !== void 0 ? /* @__PURE__ */ jsxRuntime.jsx(StatusBox, {
|
|
1181
|
+
children: /* @__PURE__ */ jsxRuntime.jsx(MutedNote, {
|
|
1182
|
+
text: `Could not load the deployed workflows: ${error}`
|
|
1183
|
+
})
|
|
1184
|
+
}) : selection.kind === "loading" ? /* @__PURE__ */ jsxRuntime.jsx(StatusBox, {
|
|
1185
|
+
children: /* @__PURE__ */ jsxRuntime.jsx(TabStatusRow, {
|
|
1186
|
+
children: /* @__PURE__ */ jsxRuntime.jsx(index.LoadingRow, {
|
|
1187
|
+
label: "Loading workflows…"
|
|
1188
|
+
})
|
|
1189
|
+
})
|
|
1190
|
+
}) : selection.kind === "empty" ? /* @__PURE__ */ jsxRuntime.jsx(StatusBox, {
|
|
1191
|
+
children: /* @__PURE__ */ jsxRuntime.jsx(index.EmptyState, {
|
|
1192
|
+
description: "Deploy a workflow to see its documents here",
|
|
1193
|
+
icon: /* @__PURE__ */ jsxRuntime.jsx(Search.SearchIcon, {}),
|
|
1194
|
+
title: "No workflows deployed"
|
|
1195
|
+
})
|
|
1196
|
+
}) : selection.kind === "unknown" ? /* @__PURE__ */ jsxRuntime.jsx(StatusBox, {
|
|
1197
|
+
children: /* @__PURE__ */ jsxRuntime.jsx(index.EmptyState, {
|
|
1198
|
+
description: `No deployed workflow is named “${selection.name}” — pick one above`,
|
|
1199
|
+
icon: /* @__PURE__ */ jsxRuntime.jsx(Search.SearchIcon, {}),
|
|
1200
|
+
title: "Workflow not found"
|
|
1201
|
+
})
|
|
1202
|
+
}) : loading || board === void 0 ? /* @__PURE__ */ jsxRuntime.jsx(StatusBox, {
|
|
1203
|
+
children: /* @__PURE__ */ jsxRuntime.jsx(TabStatusRow, {
|
|
1204
|
+
children: /* @__PURE__ */ jsxRuntime.jsx(index.LoadingRow, {
|
|
1205
|
+
label: "Loading documents…"
|
|
1206
|
+
})
|
|
1207
|
+
})
|
|
1208
|
+
}) : layout === "stack" ? /* @__PURE__ */ jsxRuntime.jsx(BoardStack, {
|
|
1209
|
+
bands: bands,
|
|
1210
|
+
board: board
|
|
1211
|
+
}) : /* @__PURE__ */ jsxRuntime.jsx(StageGroups, {
|
|
1212
|
+
board: board
|
|
1213
|
+
});
|
|
1214
|
+
}
|
|
1215
|
+
|
|
1216
|
+
function StatusBox({children: children}) {
|
|
1217
|
+
/* @__PURE__ */
|
|
1218
|
+
return jsxRuntime.jsx(ui.Flex, {
|
|
1219
|
+
direction: "column",
|
|
1220
|
+
flex: 1,
|
|
1221
|
+
paddingX: TOOL_PANEL_PADDING,
|
|
1222
|
+
children: children
|
|
1223
|
+
});
|
|
1224
|
+
}
|
|
1225
|
+
|
|
1226
|
+
function definitionCatalog(args) {
|
|
1227
|
+
const rejected = [ ...args.issues.values() ];
|
|
1228
|
+
return args.definitions.map(definition => ({
|
|
1229
|
+
name: definition.name,
|
|
1230
|
+
title: definition.title ?? definition.name,
|
|
1231
|
+
description: definition.description,
|
|
1232
|
+
activeCount: args.inFlight.filter(instance => instance.definition === definition.name).length,
|
|
1233
|
+
docTypes: [ ...new Set(args.mappings.filter(mapping => mapping.definition === definition.name).map(mapping => mapping.docType)) ],
|
|
1234
|
+
brokenBindings: rejected.filter(issue => issue.definition === definition.name && issue.version === definition.version).map(issue => ({
|
|
1235
|
+
docType: issue.docType,
|
|
1236
|
+
detail: index.mappingIssueDetail(issue)
|
|
1237
|
+
})).sort((a, b) => a.docType.localeCompare(b.docType))
|
|
1238
|
+
})).sort(byTitleThenName);
|
|
1239
|
+
}
|
|
1240
|
+
|
|
1241
|
+
function undeployedWorkflowNotices(args) {
|
|
1242
|
+
return [ ...args.issues.values() ].filter(index.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`);
|
|
1243
|
+
}
|
|
1244
|
+
|
|
1245
|
+
function docTypeLabels(docTypes, titleOf) {
|
|
1246
|
+
return docTypes.map(name => ({
|
|
1247
|
+
name: name,
|
|
1248
|
+
title: titleOf(name) ?? name
|
|
1249
|
+
})).sort(byTitleThenName);
|
|
1250
|
+
}
|
|
1251
|
+
|
|
1252
|
+
function startPhrase(definition) {
|
|
1253
|
+
if (definition.lifecycle === "child") return "Started by a parent workflow";
|
|
1254
|
+
if (workflowEngine.startKindOf(definition) === "autonomous") return "Starts automatically";
|
|
1255
|
+
const subject = (definition.fields ?? []).find(workflowEngine.isSubjectEntry);
|
|
1256
|
+
return subject !== void 0 && workflowEngine.isInputSourced(subject) ? "Started manually, from a document" : "Started manually";
|
|
1257
|
+
}
|
|
1258
|
+
|
|
1259
|
+
function deployedAtOf(definition) {
|
|
1260
|
+
return typeof definition._updatedAt == "string" ? definition._updatedAt : void 0;
|
|
1261
|
+
}
|
|
1262
|
+
|
|
1263
|
+
function deployedPhrase(definition) {
|
|
1264
|
+
const deployedAt = deployedAtOf(definition);
|
|
1265
|
+
if (deployedAt === void 0) return `v${definition.version}`;
|
|
1266
|
+
const ago = index.formatTimeAgo(deployedAt);
|
|
1267
|
+
return ago === "" ? index.formatShortDateTime(deployedAt) : `${index.formatShortDateTime(deployedAt)} (${ago})`;
|
|
1268
|
+
}
|
|
1269
|
+
|
|
1270
|
+
function DetailNotFound({back: back, message: message}) {
|
|
1271
|
+
/* @__PURE__ */
|
|
1272
|
+
return jsxRuntime.jsxs(ui.Stack, {
|
|
1273
|
+
gap: 4,
|
|
1274
|
+
children: [
|
|
1275
|
+
/* @__PURE__ */ jsxRuntime.jsx(ui.Text, {
|
|
1276
|
+
muted: !0,
|
|
1277
|
+
size: 1,
|
|
1278
|
+
children: message
|
|
1279
|
+
}),
|
|
1280
|
+
/* @__PURE__ */ jsxRuntime.jsx(ui.Flex, {
|
|
1281
|
+
children: /* @__PURE__ */ jsxRuntime.jsx(ui.Button, {
|
|
1282
|
+
fontSize: 1,
|
|
1283
|
+
gap: 2,
|
|
1284
|
+
icon: ArrowLeft.ArrowLeftIcon,
|
|
1285
|
+
mode: "ghost",
|
|
1286
|
+
onClick: back.go,
|
|
1287
|
+
padding: 2,
|
|
1288
|
+
text: back.label
|
|
1289
|
+
})
|
|
1290
|
+
}) ]
|
|
1291
|
+
});
|
|
1292
|
+
}
|
|
1293
|
+
|
|
1294
|
+
function DetailTitle({busy: busy = !1, documentGdr: documentGdr, title: title}) {
|
|
1295
|
+
const chipPullback = -index.useSpaceToken(1);
|
|
1296
|
+
/* @__PURE__ */
|
|
1297
|
+
return jsxRuntime.jsxs(ui.Flex, {
|
|
1298
|
+
align: "center",
|
|
1299
|
+
gap: 2,
|
|
1300
|
+
paddingLeft: 2,
|
|
1301
|
+
children: [
|
|
1302
|
+
/* @__PURE__ */ jsxRuntime.jsx(ui.Box, {
|
|
1303
|
+
style: {
|
|
1304
|
+
minWidth: 0
|
|
1305
|
+
},
|
|
1306
|
+
children: /* @__PURE__ */ jsxRuntime.jsx(ui.Text, {
|
|
1307
|
+
size: 1,
|
|
1308
|
+
textOverflow: "ellipsis",
|
|
1309
|
+
weight: "semibold",
|
|
1310
|
+
children: title
|
|
1311
|
+
})
|
|
1312
|
+
}), documentGdr === void 0 ? null : /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, {
|
|
1313
|
+
children: [
|
|
1314
|
+
/* @__PURE__ */ jsxRuntime.jsx(ui.Text, {
|
|
1315
|
+
muted: !0,
|
|
1316
|
+
size: 1,
|
|
1317
|
+
children: "in"
|
|
1318
|
+
}),
|
|
1319
|
+
/* @__PURE__ */ jsxRuntime.jsx(ui.Flex, {
|
|
1320
|
+
align: "center",
|
|
1321
|
+
flex: "none",
|
|
1322
|
+
style: {
|
|
1323
|
+
height: 0,
|
|
1324
|
+
marginLeft: chipPullback
|
|
1325
|
+
},
|
|
1326
|
+
children: /* @__PURE__ */ jsxRuntime.jsx(index.DocPreviewLink, {
|
|
1327
|
+
gdr: documentGdr,
|
|
1328
|
+
layout: "inline",
|
|
1329
|
+
source: "detail-title"
|
|
1330
|
+
})
|
|
1331
|
+
}) ]
|
|
1332
|
+
}),
|
|
1333
|
+
/* @__PURE__ */ jsxRuntime.jsx(index.SpinnerSlot, {
|
|
1334
|
+
busy: busy
|
|
1335
|
+
}) ]
|
|
1336
|
+
});
|
|
1337
|
+
}
|
|
1338
|
+
|
|
1339
|
+
const INSTANCE_CAP_COUNT_NOTE = `Counts from the latest ${INSTANCE_CAP} workflows — older ones aren’t counted.`, NEWEST_INSTANCES = {
|
|
1340
|
+
includeCompleted: !0
|
|
1341
|
+
};
|
|
1342
|
+
|
|
1343
|
+
function useToolInstances() {
|
|
1344
|
+
const {rows: rows, truncated: truncated, loading: loading, unreadable: unreadable} = useCappedInstances(NEWEST_INSTANCES);
|
|
1345
|
+
return react.useMemo(() => ({
|
|
1346
|
+
inFlight: rows.filter(instance => workflowEngine.terminalState(instance) === "in-flight"),
|
|
1347
|
+
settled: rows.filter(instance => workflowEngine.terminalState(instance) !== "in-flight"),
|
|
1348
|
+
truncated: truncated,
|
|
1349
|
+
loading: loading,
|
|
1350
|
+
unreadable: unreadable
|
|
1351
|
+
}), [ rows, truncated, loading, unreadable ]);
|
|
1352
|
+
}
|
|
1353
|
+
|
|
1354
|
+
function DefinitionDetail({definitionName: definitionName, backToList: backToList}) {
|
|
1355
|
+
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__ */ jsxRuntime.jsx(index.LogEventOnMount, {
|
|
1356
|
+
data: {
|
|
1357
|
+
found: definition !== void 0,
|
|
1358
|
+
...index.definitionFingerprint(definition)
|
|
1359
|
+
},
|
|
1360
|
+
event: index.WorkflowDefinitionDetailViewed
|
|
1361
|
+
});
|
|
1362
|
+
return !loading && error === void 0 && definition === void 0 ? /* @__PURE__ */ jsxRuntime.jsxs(ui.Box, {
|
|
1363
|
+
paddingX: 3,
|
|
1364
|
+
children: [ viewed,
|
|
1365
|
+
/* @__PURE__ */ jsxRuntime.jsx(TabStatusRow, {
|
|
1366
|
+
children: /* @__PURE__ */ jsxRuntime.jsx(DetailNotFound, {
|
|
1367
|
+
back: backToList,
|
|
1368
|
+
message: /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, {
|
|
1369
|
+
children: [ "Unable to find a definition with name “",
|
|
1370
|
+
/* @__PURE__ */ jsxRuntime.jsx("strong", {
|
|
1371
|
+
children: definitionName
|
|
1372
|
+
}), "”." ]
|
|
1373
|
+
})
|
|
1374
|
+
})
|
|
1375
|
+
}) ]
|
|
1376
|
+
}) : /* @__PURE__ */ jsxRuntime.jsxs(ui.Flex, {
|
|
1377
|
+
direction: "column",
|
|
1378
|
+
height: "fill",
|
|
1379
|
+
overflow: "hidden",
|
|
1380
|
+
children: [ viewed,
|
|
1381
|
+
/* @__PURE__ */ jsxRuntime.jsx(ui.Box, {
|
|
1382
|
+
flex: "none",
|
|
1383
|
+
paddingBottom: 2,
|
|
1384
|
+
paddingTop: 3,
|
|
1385
|
+
paddingX: 3,
|
|
1386
|
+
children: loading ? /* @__PURE__ */ jsxRuntime.jsx(ui.Box, {
|
|
1387
|
+
paddingLeft: 2,
|
|
1388
|
+
children: /* @__PURE__ */ jsxRuntime.jsx(index.LoadingRow, {
|
|
1389
|
+
label: "Loading definition…"
|
|
1390
|
+
})
|
|
1391
|
+
}) : /* @__PURE__ */ jsxRuntime.jsx(DetailTitle, {
|
|
1392
|
+
title: definition?.title ?? definitionName
|
|
1393
|
+
})
|
|
1394
|
+
}),
|
|
1395
|
+
/* @__PURE__ */ jsxRuntime.jsx(ui.Box, {
|
|
1396
|
+
flex: 1,
|
|
1397
|
+
overflow: "auto",
|
|
1398
|
+
paddingX: 3,
|
|
1399
|
+
children: /* @__PURE__ */ jsxRuntime.jsx(ui.Flex, {
|
|
1400
|
+
direction: "column",
|
|
1401
|
+
paddingBottom: 5,
|
|
1402
|
+
paddingLeft: 2,
|
|
1403
|
+
paddingTop: 4,
|
|
1404
|
+
style: {
|
|
1405
|
+
boxSizing: "border-box",
|
|
1406
|
+
minHeight: "100%"
|
|
1407
|
+
},
|
|
1408
|
+
children: /* @__PURE__ */ jsxRuntime.jsx(DefinitionBody, {
|
|
1409
|
+
definition: definition,
|
|
1410
|
+
error: error
|
|
1411
|
+
})
|
|
1412
|
+
})
|
|
1413
|
+
}) ]
|
|
1414
|
+
});
|
|
1415
|
+
}
|
|
1416
|
+
|
|
1417
|
+
function DefinitionBody({definition: definition, error: error}) {
|
|
1418
|
+
return error !== void 0 ? /* @__PURE__ */ jsxRuntime.jsx(MutedNote, {
|
|
1419
|
+
text: `Could not load the deployed workflows: ${error}`
|
|
1420
|
+
}) : definition === void 0 ? null : /* @__PURE__ */ jsxRuntime.jsx(DefinitionFacts, {
|
|
1421
|
+
definition: definition
|
|
1422
|
+
});
|
|
1423
|
+
}
|
|
1424
|
+
|
|
1425
|
+
function SetupIssues({bindings: bindings}) {
|
|
1426
|
+
const schema = sanity.useSchema();
|
|
1427
|
+
return bindings.length === 0 ? null : /* @__PURE__ */ jsxRuntime.jsx(ui.Card, {
|
|
1428
|
+
padding: 3,
|
|
1429
|
+
radius: 3,
|
|
1430
|
+
tone: "caution",
|
|
1431
|
+
children: /* @__PURE__ */ jsxRuntime.jsxs(ui.Flex, {
|
|
1432
|
+
align: "flex-start",
|
|
1433
|
+
gap: 3,
|
|
1434
|
+
children: [
|
|
1435
|
+
/* @__PURE__ */ jsxRuntime.jsx(ui.Text, {
|
|
1436
|
+
size: 1,
|
|
1437
|
+
children: /* @__PURE__ */ jsxRuntime.jsx(WarningOutline.WarningOutlineIcon, {})
|
|
1438
|
+
}),
|
|
1439
|
+
/* @__PURE__ */ jsxRuntime.jsxs(ui.Stack, {
|
|
1440
|
+
flex: 1,
|
|
1441
|
+
gap: 3,
|
|
1442
|
+
children: [
|
|
1443
|
+
/* @__PURE__ */ jsxRuntime.jsx(ui.Text, {
|
|
1444
|
+
size: 1,
|
|
1445
|
+
weight: "semibold",
|
|
1446
|
+
children: "Setup issue"
|
|
1447
|
+
}), bindings.map(binding => /* @__PURE__ */ jsxRuntime.jsx(ui.Text, {
|
|
1448
|
+
size: 1,
|
|
1449
|
+
children: `${schema.get(binding.docType)?.title ?? binding.docType}: ${binding.detail}.`
|
|
1450
|
+
}, binding.docType)),
|
|
1451
|
+
/* @__PURE__ */ jsxRuntime.jsx(ui.Text, {
|
|
1452
|
+
muted: !0,
|
|
1453
|
+
size: 1,
|
|
1454
|
+
children: "Editors see this workflow disabled on these document types until a developer fixes it."
|
|
1455
|
+
}) ]
|
|
1456
|
+
}) ]
|
|
1457
|
+
})
|
|
1458
|
+
});
|
|
1459
|
+
}
|
|
1460
|
+
|
|
1461
|
+
function DefinitionFacts({definition: definition}) {
|
|
1462
|
+
const {mappingIssues: mappingIssues, mappings: mappings} = index.useWorkflowContext(), schema = sanity.useSchema(), instances = useToolInstances(), snapshotWidth = index.useContainerToken(2), [row] = definitionCatalog({
|
|
1463
|
+
definitions: [ definition ],
|
|
1464
|
+
mappings: mappings,
|
|
1465
|
+
inFlight: instances.inFlight,
|
|
1466
|
+
issues: mappingIssues
|
|
1467
|
+
}), runsOn = docTypeLabels(row?.docTypes ?? [], name => schema.get(name)?.title).map(docType => docType.title);
|
|
1468
|
+
/* @__PURE__ */
|
|
1469
|
+
return jsxRuntime.jsxs(ui.Flex, {
|
|
1470
|
+
direction: "column",
|
|
1471
|
+
flex: 1,
|
|
1472
|
+
gap: 4,
|
|
1473
|
+
children: [ row === void 0 || row.brokenBindings.length === 0 ? null : /* @__PURE__ */ jsxRuntime.jsx(ui.Box, {
|
|
1474
|
+
flex: "none",
|
|
1475
|
+
children: /* @__PURE__ */ jsxRuntime.jsx(SetupIssues, {
|
|
1476
|
+
bindings: row.brokenBindings
|
|
1477
|
+
})
|
|
1478
|
+
}),
|
|
1479
|
+
/* @__PURE__ */ jsxRuntime.jsx(ui.Box, {
|
|
1480
|
+
flex: "none",
|
|
1481
|
+
style: {
|
|
1482
|
+
maxWidth: snapshotWidth
|
|
1483
|
+
},
|
|
1484
|
+
children: /* @__PURE__ */ jsxRuntime.jsxs(ui.Stack, {
|
|
1485
|
+
gap: 4,
|
|
1486
|
+
children: [
|
|
1487
|
+
/* @__PURE__ */ jsxRuntime.jsx(index.MetaRow, {
|
|
1488
|
+
label: "Deployed",
|
|
1489
|
+
children: /* @__PURE__ */ jsxRuntime.jsx(ui.Text, {
|
|
1490
|
+
size: 1,
|
|
1491
|
+
children: deployedPhrase(definition)
|
|
1492
|
+
})
|
|
1493
|
+
}),
|
|
1494
|
+
/* @__PURE__ */ jsxRuntime.jsx(index.MetaRow, {
|
|
1495
|
+
label: "Active instances",
|
|
1496
|
+
children: instances.loading ? /* @__PURE__ */ jsxRuntime.jsx(ui.Text, {
|
|
1497
|
+
muted: !0,
|
|
1498
|
+
size: 1,
|
|
1499
|
+
children: "—"
|
|
1500
|
+
}) : /* @__PURE__ */ jsxRuntime.jsxs(ui.Stack, {
|
|
1501
|
+
gap: 2,
|
|
1502
|
+
children: [
|
|
1503
|
+
/* @__PURE__ */ jsxRuntime.jsx(ui.Text, {
|
|
1504
|
+
size: 1,
|
|
1505
|
+
children: row?.activeCount ?? 0
|
|
1506
|
+
}), instances.truncated ? /* @__PURE__ */ jsxRuntime.jsx(ui.Text, {
|
|
1507
|
+
muted: !0,
|
|
1508
|
+
size: 1,
|
|
1509
|
+
children: INSTANCE_CAP_COUNT_NOTE
|
|
1510
|
+
}) : null ]
|
|
1511
|
+
})
|
|
1512
|
+
}),
|
|
1513
|
+
/* @__PURE__ */ jsxRuntime.jsx(index.MetaRow, {
|
|
1514
|
+
label: "Trigger",
|
|
1515
|
+
children: /* @__PURE__ */ jsxRuntime.jsx(ui.Text, {
|
|
1516
|
+
size: 1,
|
|
1517
|
+
children: startPhrase(definition)
|
|
1518
|
+
})
|
|
1519
|
+
}),
|
|
1520
|
+
/* @__PURE__ */ jsxRuntime.jsx(index.MetaRow, {
|
|
1521
|
+
label: "Document types",
|
|
1522
|
+
children: runsOn.length === 0 ? /* @__PURE__ */ jsxRuntime.jsx(ui.Text, {
|
|
1523
|
+
muted: !0,
|
|
1524
|
+
size: 1,
|
|
1525
|
+
children: "No document types in this Studio"
|
|
1526
|
+
}) : /* @__PURE__ */ jsxRuntime.jsx(ui.Text, {
|
|
1527
|
+
size: 1,
|
|
1528
|
+
children: runsOn.join(", ")
|
|
1529
|
+
})
|
|
1530
|
+
}),
|
|
1531
|
+
/* @__PURE__ */ jsxRuntime.jsx(index.MetaRow, {
|
|
1532
|
+
label: "Description",
|
|
1533
|
+
children: definition.description === void 0 ? /* @__PURE__ */ jsxRuntime.jsx(ui.Text, {
|
|
1534
|
+
muted: !0,
|
|
1535
|
+
size: 1,
|
|
1536
|
+
children: /* @__PURE__ */ jsxRuntime.jsx("em", {
|
|
1537
|
+
children: "No description"
|
|
1538
|
+
})
|
|
1539
|
+
}) : /* @__PURE__ */ jsxRuntime.jsx(ui.Text, {
|
|
1540
|
+
size: 1,
|
|
1541
|
+
style: {
|
|
1542
|
+
whiteSpace: "pre-wrap"
|
|
1543
|
+
},
|
|
1544
|
+
children: definition.description
|
|
1545
|
+
})
|
|
1546
|
+
}) ]
|
|
1547
|
+
})
|
|
1548
|
+
}),
|
|
1549
|
+
/* @__PURE__ */ jsxRuntime.jsx(ui.Flex, {
|
|
1550
|
+
direction: "column",
|
|
1551
|
+
flex: 1,
|
|
1552
|
+
style: {
|
|
1553
|
+
minHeight: 340
|
|
1554
|
+
},
|
|
1555
|
+
children: /* @__PURE__ */ jsxRuntime.jsx(index.MetaRow, {
|
|
1556
|
+
fillHeight: !0,
|
|
1557
|
+
label: "Stages",
|
|
1558
|
+
children: /* @__PURE__ */ jsxRuntime.jsx(workflowDiagram.WorkflowDiagram, {
|
|
1559
|
+
definition: definition,
|
|
1560
|
+
explain: !0,
|
|
1561
|
+
fill: !0,
|
|
1562
|
+
height: "100%"
|
|
1563
|
+
})
|
|
1564
|
+
})
|
|
1565
|
+
}) ]
|
|
1566
|
+
});
|
|
1567
|
+
}
|
|
1568
|
+
|
|
1569
|
+
const MAX_VISIBLE_DOC_TYPES = 4, COLUMNS = {
|
|
1570
|
+
definition: 6,
|
|
1571
|
+
instances: 2,
|
|
1572
|
+
docTypes: 2
|
|
1573
|
+
};
|
|
1574
|
+
|
|
1575
|
+
function Col({flex: flex, children: children}) {
|
|
1576
|
+
/* @__PURE__ */
|
|
1577
|
+
return jsxRuntime.jsx(ui.Box, {
|
|
1578
|
+
flex: flex,
|
|
1579
|
+
paddingRight: 3,
|
|
1580
|
+
children: children
|
|
1581
|
+
});
|
|
1582
|
+
}
|
|
1583
|
+
|
|
1584
|
+
function DefinitionsTab({onOpenDefinition: onOpenDefinition}) {
|
|
1585
|
+
const {definitions: definitions, error: error} = useDeployedDefinitions(), {mappingIssues: mappingIssues, mappings: mappings} = index.useWorkflowContext(), schema = sanity.useSchema(), instances = useToolInstances(), undeployed = /* @__PURE__ */ jsxRuntime.jsx(UndeployedWorkflows, {
|
|
1586
|
+
notices: undeployedWorkflowNotices({
|
|
1587
|
+
issues: mappingIssues,
|
|
1588
|
+
titleOf: name => schema.get(name)?.title
|
|
1589
|
+
})
|
|
1590
|
+
});
|
|
1591
|
+
if (error !== void 0) /* @__PURE__ */
|
|
1592
|
+
return jsxRuntime.jsx(TabStatusRow, {
|
|
1593
|
+
children: /* @__PURE__ */ jsxRuntime.jsx(ui.Text, {
|
|
1594
|
+
muted: !0,
|
|
1595
|
+
size: 1,
|
|
1596
|
+
children: `Could not load the deployed workflows: ${error}`
|
|
1597
|
+
})
|
|
1598
|
+
});
|
|
1599
|
+
if (definitions === void 0) /* @__PURE__ */
|
|
1600
|
+
return jsxRuntime.jsx(TabStatusRow, {
|
|
1601
|
+
children: /* @__PURE__ */ jsxRuntime.jsx(index.LoadingRow, {
|
|
1602
|
+
label: "Loading definitions…"
|
|
1603
|
+
})
|
|
1604
|
+
});
|
|
1605
|
+
if (definitions.length === 0) /* @__PURE__ */
|
|
1606
|
+
return jsxRuntime.jsxs(ui.Flex, {
|
|
1607
|
+
direction: "column",
|
|
1608
|
+
flex: 1,
|
|
1609
|
+
gap: 3,
|
|
1610
|
+
paddingBottom: 4,
|
|
1611
|
+
paddingTop: 3,
|
|
1612
|
+
children: [ undeployed,
|
|
1613
|
+
/* @__PURE__ */ jsxRuntime.jsx(index.EmptyState, {
|
|
1614
|
+
description: "Workflow definitions deployed to this project will appear here",
|
|
1615
|
+
icon: /* @__PURE__ */ jsxRuntime.jsx(Transfer.TransferIcon, {}),
|
|
1616
|
+
title: "No definitions deployed"
|
|
1617
|
+
}) ]
|
|
1618
|
+
});
|
|
1619
|
+
const rows = definitionCatalog({
|
|
1620
|
+
definitions: definitions,
|
|
1621
|
+
mappings: mappings,
|
|
1622
|
+
inFlight: instances.inFlight,
|
|
1623
|
+
issues: mappingIssues
|
|
1624
|
+
}), active = rows.reduce((sum, row) => sum + row.activeCount, 0);
|
|
1625
|
+
/* @__PURE__ */
|
|
1626
|
+
return jsxRuntime.jsxs(ui.Stack, {
|
|
1627
|
+
gap: 3,
|
|
1628
|
+
paddingBottom: 4,
|
|
1629
|
+
paddingTop: 3,
|
|
1630
|
+
children: [ undeployed,
|
|
1631
|
+
/* @__PURE__ */ jsxRuntime.jsx(ui.Box, {
|
|
1632
|
+
paddingX: 2,
|
|
1633
|
+
children: /* @__PURE__ */ jsxRuntime.jsxs(ui.Flex, {
|
|
1634
|
+
align: "center",
|
|
1635
|
+
gap: 2,
|
|
1636
|
+
children: [
|
|
1637
|
+
/* @__PURE__ */ jsxRuntime.jsx(ui.Text, {
|
|
1638
|
+
size: 1,
|
|
1639
|
+
weight: "semibold",
|
|
1640
|
+
children: pluralize__default.default("definition", rows.length, !0)
|
|
1641
|
+
}),
|
|
1642
|
+
/* @__PURE__ */ jsxRuntime.jsx(ui.Text, {
|
|
1643
|
+
muted: !0,
|
|
1644
|
+
size: 1,
|
|
1645
|
+
children: instances.loading ? "counting active instances…" : activeSummary(active)
|
|
1646
|
+
}) ]
|
|
1647
|
+
})
|
|
1648
|
+
}),
|
|
1649
|
+
/* @__PURE__ */ jsxRuntime.jsxs(ui.Stack, {
|
|
1650
|
+
gap: 2,
|
|
1651
|
+
children: [
|
|
1652
|
+
/* @__PURE__ */ jsxRuntime.jsx(ui.Card, {
|
|
1653
|
+
paddingX: 2,
|
|
1654
|
+
paddingY: 2,
|
|
1655
|
+
style: {
|
|
1656
|
+
position: "sticky",
|
|
1657
|
+
top: 0,
|
|
1658
|
+
zIndex: 1
|
|
1659
|
+
},
|
|
1660
|
+
children: /* @__PURE__ */ jsxRuntime.jsxs(ui.Flex, {
|
|
1661
|
+
align: "center",
|
|
1662
|
+
gap: 4,
|
|
1663
|
+
children: [
|
|
1664
|
+
/* @__PURE__ */ jsxRuntime.jsx(Col, {
|
|
1665
|
+
flex: COLUMNS.definition,
|
|
1666
|
+
children: /* @__PURE__ */ jsxRuntime.jsx(ui.Text, {
|
|
1667
|
+
muted: !0,
|
|
1668
|
+
size: 1,
|
|
1669
|
+
weight: "medium",
|
|
1670
|
+
children: "Definition"
|
|
1671
|
+
})
|
|
1672
|
+
}),
|
|
1673
|
+
/* @__PURE__ */ jsxRuntime.jsx(Col, {
|
|
1674
|
+
flex: COLUMNS.instances,
|
|
1675
|
+
children: /* @__PURE__ */ jsxRuntime.jsxs(ui.Flex, {
|
|
1676
|
+
align: "center",
|
|
1677
|
+
gap: 2,
|
|
1678
|
+
children: [
|
|
1679
|
+
/* @__PURE__ */ jsxRuntime.jsx(ui.Text, {
|
|
1680
|
+
muted: !0,
|
|
1681
|
+
size: 1,
|
|
1682
|
+
weight: "medium",
|
|
1683
|
+
children: "Active instances"
|
|
1684
|
+
}),
|
|
1685
|
+
/* @__PURE__ */ jsxRuntime.jsx(index.HoverHint, {
|
|
1686
|
+
text: "Counts only active instances — completed and aborted workflows are not included",
|
|
1687
|
+
children: /* @__PURE__ */ jsxRuntime.jsx(ui.Text, {
|
|
1688
|
+
muted: !0,
|
|
1689
|
+
size: 1,
|
|
1690
|
+
style: {
|
|
1691
|
+
opacity: .7
|
|
1692
|
+
},
|
|
1693
|
+
children: /* @__PURE__ */ jsxRuntime.jsx(InfoOutline.InfoOutlineIcon, {})
|
|
1694
|
+
})
|
|
1695
|
+
}) ]
|
|
1696
|
+
})
|
|
1697
|
+
}),
|
|
1698
|
+
/* @__PURE__ */ jsxRuntime.jsx(Col, {
|
|
1699
|
+
flex: COLUMNS.docTypes,
|
|
1700
|
+
children: /* @__PURE__ */ jsxRuntime.jsx(ui.Text, {
|
|
1701
|
+
muted: !0,
|
|
1702
|
+
size: 1,
|
|
1703
|
+
weight: "medium",
|
|
1704
|
+
children: "Document types"
|
|
1705
|
+
})
|
|
1706
|
+
}) ]
|
|
1707
|
+
})
|
|
1708
|
+
}),
|
|
1709
|
+
/* @__PURE__ */ jsxRuntime.jsx(ui.Stack, {
|
|
1710
|
+
gap: 1,
|
|
1711
|
+
children: rows.map(row => /* @__PURE__ */ jsxRuntime.jsx(DefinitionRow, {
|
|
1712
|
+
countPending: instances.loading,
|
|
1713
|
+
onOpen: () => onOpenDefinition(row.name),
|
|
1714
|
+
row: row
|
|
1715
|
+
}, row.name))
|
|
1716
|
+
}) ]
|
|
1717
|
+
}), instances.truncated ? /* @__PURE__ */ jsxRuntime.jsx(MutedNote, {
|
|
1718
|
+
text: INSTANCE_CAP_COUNT_NOTE
|
|
1719
|
+
}) : null ]
|
|
1720
|
+
});
|
|
1721
|
+
}
|
|
1722
|
+
|
|
1723
|
+
function activeSummary(active) {
|
|
1724
|
+
return `${pluralize__default.default("active instance", active, !0)}`;
|
|
1725
|
+
}
|
|
1726
|
+
|
|
1727
|
+
const ROW_ISSUES_HINT = "This definition has issues";
|
|
1728
|
+
|
|
1729
|
+
function UndeployedWorkflows({notices: notices}) {
|
|
1730
|
+
return notices.length === 0 ? null :
|
|
1731
|
+
/* @__PURE__ */ jsxRuntime.jsx(ui.Stack, {
|
|
1732
|
+
gap: 2,
|
|
1733
|
+
paddingBottom: 1,
|
|
1734
|
+
children: notices.map(notice => /* @__PURE__ */ jsxRuntime.jsx(index.CautionNote, {
|
|
1735
|
+
label: notice
|
|
1736
|
+
}, notice))
|
|
1737
|
+
});
|
|
1738
|
+
}
|
|
1739
|
+
|
|
1740
|
+
function DefinitionRow({countPending: countPending, onOpen: onOpen, row: row}) {
|
|
1741
|
+
const flagged = row.brokenBindings.length > 0, card = /* @__PURE__ */ jsxRuntime.jsx(ui.Card, {
|
|
1742
|
+
as: "button",
|
|
1743
|
+
onClick: onOpen,
|
|
1744
|
+
paddingX: 2,
|
|
1745
|
+
paddingY: 3,
|
|
1746
|
+
radius: 2,
|
|
1747
|
+
style: {
|
|
1748
|
+
textAlign: "left",
|
|
1749
|
+
width: "100%"
|
|
1750
|
+
},
|
|
1751
|
+
...flagged ? {
|
|
1752
|
+
tone: "caution"
|
|
1753
|
+
} : {},
|
|
1754
|
+
children: /* @__PURE__ */ jsxRuntime.jsxs(ui.Flex, {
|
|
1755
|
+
align: "flex-start",
|
|
1756
|
+
gap: 4,
|
|
1757
|
+
children: [
|
|
1758
|
+
/* @__PURE__ */ jsxRuntime.jsx(Col, {
|
|
1759
|
+
flex: COLUMNS.definition,
|
|
1760
|
+
children: /* @__PURE__ */ jsxRuntime.jsxs(ui.Flex, {
|
|
1761
|
+
align: "flex-start",
|
|
1762
|
+
gap: 3,
|
|
1763
|
+
paddingLeft: flagged ? 1 : 0,
|
|
1764
|
+
children: [ flagged ? /* @__PURE__ */ jsxRuntime.jsx(ui.Text, {
|
|
1765
|
+
size: 1,
|
|
1766
|
+
children: /* @__PURE__ */ jsxRuntime.jsx(WarningOutline.WarningOutlineIcon, {})
|
|
1767
|
+
}) : null,
|
|
1768
|
+
/* @__PURE__ */ jsxRuntime.jsxs(ui.Stack, {
|
|
1769
|
+
flex: 1,
|
|
1770
|
+
gap: 3,
|
|
1771
|
+
style: {
|
|
1772
|
+
minWidth: 0
|
|
1773
|
+
},
|
|
1774
|
+
children: [
|
|
1775
|
+
/* @__PURE__ */ jsxRuntime.jsx(ui.Text, {
|
|
1776
|
+
size: 1,
|
|
1777
|
+
weight: "semibold",
|
|
1778
|
+
children: row.title
|
|
1779
|
+
}), row.description === void 0 ? /* @__PURE__ */ jsxRuntime.jsx(ui.Text, {
|
|
1780
|
+
muted: !0,
|
|
1781
|
+
size: 1,
|
|
1782
|
+
children: /* @__PURE__ */ jsxRuntime.jsx("em", {
|
|
1783
|
+
children: "No description"
|
|
1784
|
+
})
|
|
1785
|
+
}) : /* @__PURE__ */ jsxRuntime.jsx(ui.Text, {
|
|
1786
|
+
muted: !0,
|
|
1787
|
+
size: 1,
|
|
1788
|
+
children: row.description
|
|
1789
|
+
}) ]
|
|
1790
|
+
}) ]
|
|
1791
|
+
})
|
|
1792
|
+
}),
|
|
1793
|
+
/* @__PURE__ */ jsxRuntime.jsx(Col, {
|
|
1794
|
+
flex: COLUMNS.instances,
|
|
1795
|
+
children: /* @__PURE__ */ jsxRuntime.jsx(ui.Text, {
|
|
1796
|
+
muted: !0,
|
|
1797
|
+
size: 1,
|
|
1798
|
+
children: countPending ? "—" : `${row.activeCount} active`
|
|
1799
|
+
})
|
|
1800
|
+
}),
|
|
1801
|
+
/* @__PURE__ */ jsxRuntime.jsx(Col, {
|
|
1802
|
+
flex: COLUMNS.docTypes,
|
|
1803
|
+
children: /* @__PURE__ */ jsxRuntime.jsx(DocTypeChips, {
|
|
1804
|
+
docTypes: row.docTypes
|
|
1805
|
+
})
|
|
1806
|
+
}) ]
|
|
1807
|
+
})
|
|
1808
|
+
});
|
|
1809
|
+
return flagged ? /* @__PURE__ */ jsxRuntime.jsx(index.HoverHint, {
|
|
1810
|
+
fill: !0,
|
|
1811
|
+
text: ROW_ISSUES_HINT,
|
|
1812
|
+
children: card
|
|
1813
|
+
}) : card;
|
|
1814
|
+
}
|
|
1815
|
+
|
|
1816
|
+
function DocTypeChips({docTypes: docTypes}) {
|
|
1817
|
+
const schema = sanity.useSchema(), badgeTrim = index.useBadgeCapTrim();
|
|
1818
|
+
if (docTypes.length === 0) /* @__PURE__ */
|
|
1819
|
+
return jsxRuntime.jsx(ui.Text, {
|
|
1820
|
+
muted: !0,
|
|
1821
|
+
size: 1,
|
|
1822
|
+
children: "—"
|
|
1823
|
+
});
|
|
1824
|
+
const labels = docTypeLabels(docTypes, name => schema.get(name)?.title), shown = labels.slice(0, MAX_VISIBLE_DOC_TYPES), overflow = labels.length - shown.length;
|
|
1825
|
+
/* @__PURE__ */
|
|
1826
|
+
return jsxRuntime.jsxs(ui.Flex, {
|
|
1827
|
+
align: "center",
|
|
1828
|
+
gap: 2,
|
|
1829
|
+
style: badgeTrim,
|
|
1830
|
+
wrap: "wrap",
|
|
1831
|
+
children: [ shown.map(docType =>
|
|
1832
|
+
/* @__PURE__ */ jsxRuntime.jsx(ui.Badge, {
|
|
1833
|
+
fontSize: 1,
|
|
1834
|
+
style: {
|
|
1835
|
+
minWidth: 0
|
|
1836
|
+
},
|
|
1837
|
+
children: /* @__PURE__ */ jsxRuntime.jsx("span", {
|
|
1838
|
+
style: {
|
|
1839
|
+
display: "block",
|
|
1840
|
+
overflow: "hidden",
|
|
1841
|
+
textOverflow: "ellipsis",
|
|
1842
|
+
whiteSpace: "nowrap"
|
|
1843
|
+
},
|
|
1844
|
+
children: docType.title
|
|
1845
|
+
})
|
|
1846
|
+
}, docType.name)), overflow > 0 ? /* @__PURE__ */ jsxRuntime.jsxs(ui.Text, {
|
|
1847
|
+
muted: !0,
|
|
1848
|
+
size: 1,
|
|
1849
|
+
children: [ "+", overflow, " more" ]
|
|
1850
|
+
}) : null ]
|
|
1851
|
+
});
|
|
1852
|
+
}
|
|
1853
|
+
|
|
1854
|
+
function normalizeAbortReason(raw) {
|
|
1855
|
+
const trimmed = raw.trim();
|
|
1856
|
+
return trimmed === "" ? void 0 : trimmed;
|
|
1857
|
+
}
|
|
1858
|
+
|
|
1859
|
+
function abortedToast(title) {
|
|
1860
|
+
return {
|
|
1861
|
+
id: index.TOAST_ID.abort,
|
|
1862
|
+
status: "info",
|
|
1863
|
+
title: `Aborted “${title}”`
|
|
1864
|
+
};
|
|
1865
|
+
}
|
|
1866
|
+
|
|
1867
|
+
function abortAlreadySettledToast(title) {
|
|
1868
|
+
return {
|
|
1869
|
+
id: index.TOAST_ID.abort,
|
|
1870
|
+
status: "info",
|
|
1871
|
+
title: `“${title}” had already finished`,
|
|
1872
|
+
description: "Nothing was aborted — the workflow reached a terminal state first."
|
|
1873
|
+
};
|
|
1874
|
+
}
|
|
1875
|
+
|
|
1876
|
+
function abortUnconfirmedToast(args) {
|
|
1877
|
+
return {
|
|
1878
|
+
id: index.TOAST_ID.abort,
|
|
1879
|
+
status: "warning",
|
|
1880
|
+
title: `Couldn’t confirm “${args.title}” was aborted`,
|
|
1881
|
+
description: `${index.describeError(args.err)} — the abort may still have committed, so check the workflow’s state before trying again.`
|
|
1882
|
+
};
|
|
1883
|
+
}
|
|
1884
|
+
|
|
1885
|
+
function AbortWorkflowDialog({entry: entry, onClose: onClose}) {
|
|
1886
|
+
const {engine: engine} = index.useWorkflowContext(), definition = index.useDefinition(entry), toast = index.useWorkflowToast(), [typedReason, setTypedReason] = react.useState(""), [pending, setPending] = react.useState(!1), {instance: instance} = entry, title = index.instanceTitle(instance, definition), reason = normalizeAbortReason(typedReason), reasonInputId = `abort-workflow-reason-${instance._id}`, confirm = async () => {
|
|
1887
|
+
if (reason !== void 0) {
|
|
1888
|
+
setPending(!0);
|
|
1889
|
+
try {
|
|
1890
|
+
const {changed: changed} = await engine.abortInstance({
|
|
1891
|
+
instanceId: instance._id,
|
|
1892
|
+
reason: reason
|
|
1893
|
+
});
|
|
1894
|
+
toast.push(changed ? abortedToast(title) : abortAlreadySettledToast(title)), onClose();
|
|
1895
|
+
} catch (err) {
|
|
1896
|
+
toast.push(abortUnconfirmedToast({
|
|
1897
|
+
title: title,
|
|
1898
|
+
err: err
|
|
1899
|
+
})), setPending(!1);
|
|
1900
|
+
}
|
|
1901
|
+
}
|
|
1902
|
+
};
|
|
1903
|
+
/* @__PURE__ */
|
|
1904
|
+
return jsxRuntime.jsx(ui.Dialog, {
|
|
1905
|
+
footer: /* @__PURE__ */ jsxRuntime.jsx(ui.Box, {
|
|
1906
|
+
padding: 3,
|
|
1907
|
+
children: /* @__PURE__ */ jsxRuntime.jsxs(ui.Flex, {
|
|
1908
|
+
gap: 2,
|
|
1909
|
+
justify: "flex-end",
|
|
1910
|
+
children: [
|
|
1911
|
+
/* @__PURE__ */ jsxRuntime.jsx(ui.Button, {
|
|
1912
|
+
disabled: pending,
|
|
1913
|
+
fontSize: 1,
|
|
1914
|
+
mode: "bleed",
|
|
1915
|
+
onClick: onClose,
|
|
1916
|
+
padding: 2,
|
|
1917
|
+
text: "Cancel"
|
|
1918
|
+
}),
|
|
1919
|
+
/* @__PURE__ */ jsxRuntime.jsx(ui.Button, {
|
|
1920
|
+
disabled: reason === void 0,
|
|
1921
|
+
fontSize: 1,
|
|
1922
|
+
loading: pending,
|
|
1923
|
+
onClick: () => {
|
|
1924
|
+
confirm();
|
|
1925
|
+
},
|
|
1926
|
+
padding: 2,
|
|
1927
|
+
text: "Abort workflow",
|
|
1928
|
+
tone: "critical"
|
|
1929
|
+
}) ]
|
|
1930
|
+
})
|
|
1931
|
+
}),
|
|
1932
|
+
header: "Abort workflow",
|
|
1933
|
+
id: `abort-workflow-${instance._id}`,
|
|
1934
|
+
onClose: () => {
|
|
1935
|
+
pending || onClose();
|
|
1936
|
+
},
|
|
1937
|
+
width: 0,
|
|
1938
|
+
children: /* @__PURE__ */ jsxRuntime.jsx(ui.Box, {
|
|
1939
|
+
padding: 4,
|
|
1940
|
+
children: /* @__PURE__ */ jsxRuntime.jsxs(ui.Stack, {
|
|
1941
|
+
gap: 5,
|
|
1942
|
+
children: [
|
|
1943
|
+
/* @__PURE__ */ jsxRuntime.jsxs(ui.Text, {
|
|
1944
|
+
size: 1,
|
|
1945
|
+
children: [ "Abort the ",
|
|
1946
|
+
/* @__PURE__ */ jsxRuntime.jsx("strong", {
|
|
1947
|
+
children: title
|
|
1948
|
+
}), " workflow? This cannot be undone." ]
|
|
1949
|
+
}),
|
|
1950
|
+
/* @__PURE__ */ jsxRuntime.jsxs(ui.Stack, {
|
|
1951
|
+
gap: 3,
|
|
1952
|
+
children: [
|
|
1953
|
+
/* @__PURE__ */ jsxRuntime.jsx(ui.Text, {
|
|
1954
|
+
as: "label",
|
|
1955
|
+
htmlFor: reasonInputId,
|
|
1956
|
+
size: 1,
|
|
1957
|
+
weight: "medium",
|
|
1958
|
+
children: "Reason"
|
|
1959
|
+
}),
|
|
1960
|
+
/* @__PURE__ */ jsxRuntime.jsx(ui.TextInput, {
|
|
1961
|
+
autoFocus: !0,
|
|
1962
|
+
fontSize: 1,
|
|
1963
|
+
id: reasonInputId,
|
|
1964
|
+
onChange: event => setTypedReason(event.currentTarget.value),
|
|
1965
|
+
placeholder: "Why is this workflow being stopped?",
|
|
1966
|
+
value: typedReason
|
|
1967
|
+
}) ]
|
|
1968
|
+
}) ]
|
|
1969
|
+
})
|
|
1970
|
+
})
|
|
1971
|
+
});
|
|
1972
|
+
}
|
|
1973
|
+
|
|
1974
|
+
function AbortWorkflowSection({entry: entry}) {
|
|
1975
|
+
const [aborting, setAborting] = react.useState(!1);
|
|
1976
|
+
return index.isLiveEntry(entry) ? /* @__PURE__ */ jsxRuntime.jsxs(ui.Stack, {
|
|
1977
|
+
gap: 4,
|
|
1978
|
+
children: [
|
|
1979
|
+
/* @__PURE__ */ jsxRuntime.jsx(ui.Text, {
|
|
1980
|
+
size: 1,
|
|
1981
|
+
weight: "semibold",
|
|
1982
|
+
children: "Manage workflow"
|
|
1983
|
+
}),
|
|
1984
|
+
/* @__PURE__ */ jsxRuntime.jsx(ui.Flex, {
|
|
1985
|
+
children: /* @__PURE__ */ jsxRuntime.jsx(ui.Button, {
|
|
1986
|
+
fontSize: 1,
|
|
1987
|
+
mode: "ghost",
|
|
1988
|
+
onClick: () => setAborting(!0),
|
|
1989
|
+
padding: 2,
|
|
1990
|
+
text: "Abort workflow…",
|
|
1991
|
+
tone: "critical"
|
|
1992
|
+
})
|
|
1993
|
+
}), aborting ? /* @__PURE__ */ jsxRuntime.jsx(AbortWorkflowDialog, {
|
|
1994
|
+
entry: entry,
|
|
1995
|
+
onClose: () => setAborting(!1)
|
|
1996
|
+
}) : null ]
|
|
1997
|
+
}) : null;
|
|
1998
|
+
}
|
|
1999
|
+
|
|
2000
|
+
function makeTitleResolver(definition) {
|
|
2001
|
+
const activities = (definition?.stages ?? []).flatMap(s => s.activities ?? []);
|
|
2002
|
+
return {
|
|
2003
|
+
action: (activityName, actionName) => activities.find(t => t.name === activityName)?.actions?.find(a => a.name === actionName)?.title ?? actionName,
|
|
2004
|
+
activity: name => activities.find(t => t.name === name)?.title ?? name,
|
|
2005
|
+
stage: name => index.stageTitle(definition, name)
|
|
2006
|
+
};
|
|
2007
|
+
}
|
|
2008
|
+
|
|
2009
|
+
function attributed(actor, ...parts) {
|
|
2010
|
+
if (actor) return {
|
|
2011
|
+
actorId: actor.id,
|
|
2012
|
+
parts: parts
|
|
2013
|
+
};
|
|
2014
|
+
const [first, ...rest] = parts;
|
|
2015
|
+
return typeof first != "string" ? {
|
|
2016
|
+
actorId: void 0,
|
|
2017
|
+
parts: parts
|
|
2018
|
+
} : {
|
|
2019
|
+
actorId: void 0,
|
|
2020
|
+
parts: [ first.charAt(0).toUpperCase() + first.slice(1), ...rest ]
|
|
2021
|
+
};
|
|
2022
|
+
}
|
|
2023
|
+
|
|
2024
|
+
function standalone(...parts) {
|
|
2025
|
+
return {
|
|
2026
|
+
actorId: void 0,
|
|
2027
|
+
parts: parts
|
|
2028
|
+
};
|
|
2029
|
+
}
|
|
2030
|
+
|
|
2031
|
+
const historyLiner = {
|
|
2032
|
+
stageEntered: (h, titles) => attributed(h.actor, `entered ${titles.stage(h.stage)}${h.fromStage ? ` from ${titles.stage(h.fromStage)}` : ""}`),
|
|
2033
|
+
stageExited: (h, titles) => attributed(h.actor, `left ${titles.stage(h.stage)} for ${titles.stage(h.toStage)}`),
|
|
2034
|
+
activityStatusChanged: (h, titles) => attributed(h.actor, `changed ${titles.activity(h.activity)}: ${h.from} → ${h.to}`),
|
|
2035
|
+
actionFired: (h, titles) => {
|
|
2036
|
+
const phrase = `fired ${titles.action(h.activity, h.action)} on ${titles.activity(h.activity)}`;
|
|
2037
|
+
return h.triggered ? standalone(`The workflow ${phrase}`) : attributed(h.actor, phrase);
|
|
2038
|
+
},
|
|
2039
|
+
transitionFired: (h, titles) => attributed(h.actor, `moved ${titles.stage(h.fromStage)} → ${titles.stage(h.toStage)}`),
|
|
2040
|
+
effectQueued: h => standalone("Effect ", {
|
|
2041
|
+
code: h.effect
|
|
2042
|
+
}, " queued"),
|
|
2043
|
+
effectCompleted: h => {
|
|
2044
|
+
const detail = h.detail ? ` — ${h.detail}` : "";
|
|
2045
|
+
return h.actor ? attributed(h.actor, "resolved effect ", {
|
|
2046
|
+
code: h.effect
|
|
2047
|
+
}, ` — ${h.status}${detail}`) : standalone("Effect ", {
|
|
2048
|
+
code: h.effect
|
|
2049
|
+
}, ` ${h.status}${detail}`);
|
|
2050
|
+
},
|
|
2051
|
+
effectClaimReleased: h => attributed(h.actor, "released a stale claim on effect ", {
|
|
2052
|
+
code: h.effect
|
|
2053
|
+
}, ` ${h.via === "sweep" ? "via the sweeper" : "via a drain takeover"}`),
|
|
2054
|
+
spawned: (h, titles) => attributed(h.actor, `spawned a child workflow from ${titles.activity(h.activity)}`),
|
|
2055
|
+
subworkflowAdopted: (h, titles) => standalone(`Re-adopted child workflow into ${titles.activity(h.activity)} on re-entering ${titles.stage(h.stage)}`),
|
|
2056
|
+
subworkflowResolved: (h, titles) => standalone(`Child workflow of ${titles.activity(h.activity)} ${h.status === "done" ? "completed" : "was aborted"}`),
|
|
2057
|
+
subworkflowOrphaned: h => standalone(`Orphaned child workflow reached terminal — ${h.detail}`),
|
|
2058
|
+
aborted: (h, titles) => attributed(h.actor, `aborted the workflow at ${titles.stage(h.stage)}${h.reason ? ` — ${h.reason}` : ""}`),
|
|
2059
|
+
opApplied: (h, titles) => h.action ? attributed(h.actor, `changed state via action ${titles.action(h.activity ?? "", h.action)}`) : h.activity ? attributed(h.actor, `changed state via activity ${titles.activity(h.activity)}`) : attributed(h.actor, "changed state via ", {
|
|
2060
|
+
code: h.opType
|
|
2061
|
+
}),
|
|
2062
|
+
fieldQueryDiscarded: h => standalone({
|
|
2063
|
+
code: JSON.stringify(h)
|
|
2064
|
+
})
|
|
2065
|
+
};
|
|
2066
|
+
|
|
2067
|
+
function historyLine(h, titles) {
|
|
2068
|
+
return historyLiner[h._type](h, titles);
|
|
2069
|
+
}
|
|
2070
|
+
|
|
2071
|
+
function PendingEffectRows({instance: instance, now: now}) {
|
|
2072
|
+
const {drainEffectsFor: drainEffectsFor, completeEffectFor: completeEffectFor, effectHandlers: effectHandlers} = index.useWorkflowContext(), toast = index.useWorkflowToast(), [busy, setBusy] = react.useState(!1), pending = instance.pendingEffects ?? [];
|
|
2073
|
+
if (pending.length === 0) return null;
|
|
2074
|
+
const runRegistered = async () => {
|
|
2075
|
+
setBusy(!0);
|
|
2076
|
+
try {
|
|
2077
|
+
await drainEffectsFor(instance._id), toast.push({
|
|
2078
|
+
id: index.TOAST_ID.effectsDrain,
|
|
2079
|
+
status: "info",
|
|
2080
|
+
title: "Ran the registered handlers"
|
|
2081
|
+
});
|
|
2082
|
+
} catch (err) {
|
|
2083
|
+
toast.push({
|
|
2084
|
+
id: index.TOAST_ID.effectsDrain,
|
|
2085
|
+
status: "error",
|
|
2086
|
+
title: "Failed to run pending effects",
|
|
2087
|
+
description: index.describeError(err)
|
|
2088
|
+
});
|
|
2089
|
+
} finally {
|
|
2090
|
+
setBusy(!1);
|
|
2091
|
+
}
|
|
2092
|
+
}, resolve = async (effectKey, status) => {
|
|
2093
|
+
setBusy(!0);
|
|
2094
|
+
try {
|
|
2095
|
+
await completeEffectFor(instance._id, {
|
|
2096
|
+
effectKey: effectKey,
|
|
2097
|
+
status: status,
|
|
2098
|
+
detail: "Resolved in Studio"
|
|
2099
|
+
}), toast.push({
|
|
2100
|
+
id: index.TOAST_ID.effectResolve,
|
|
2101
|
+
status: "info",
|
|
2102
|
+
title: `Effect marked as ${status}`
|
|
2103
|
+
});
|
|
2104
|
+
} catch (err) {
|
|
2105
|
+
toast.push({
|
|
2106
|
+
id: index.TOAST_ID.effectResolve,
|
|
2107
|
+
status: "error",
|
|
2108
|
+
title: "Failed to resolve the effect",
|
|
2109
|
+
description: index.describeError(err)
|
|
2110
|
+
});
|
|
2111
|
+
} finally {
|
|
2112
|
+
setBusy(!1);
|
|
2113
|
+
}
|
|
2114
|
+
};
|
|
2115
|
+
/* @__PURE__ */
|
|
2116
|
+
return jsxRuntime.jsx(jsxRuntime.Fragment, {
|
|
2117
|
+
children: pending.map(fx => /* @__PURE__ */ jsxRuntime.jsx(PendingEffectRow, {
|
|
2118
|
+
busy: busy,
|
|
2119
|
+
effect: fx,
|
|
2120
|
+
instanceId: instance._id,
|
|
2121
|
+
now: now,
|
|
2122
|
+
onResolve: status => resolve(fx._key, status),
|
|
2123
|
+
onRunHandlers: runRegistered,
|
|
2124
|
+
registered: fx.name in effectHandlers
|
|
2125
|
+
}, fx._key))
|
|
2126
|
+
});
|
|
2127
|
+
}
|
|
2128
|
+
|
|
2129
|
+
function PendingEffectRow({busy: busy, effect: effect, instanceId: instanceId, now: now, onResolve: onResolve, onRunHandlers: onRunHandlers, registered: registered}) {
|
|
2130
|
+
const label = effect.title ?? effect.name, avatarSize = index.useAvatarSize();
|
|
2131
|
+
/* @__PURE__ */
|
|
2132
|
+
return jsxRuntime.jsxs(ui.Flex, {
|
|
2133
|
+
align: "center",
|
|
2134
|
+
gap: 2,
|
|
2135
|
+
children: [
|
|
2136
|
+
/* @__PURE__ */ jsxRuntime.jsx(FeedGlyph, {
|
|
2137
|
+
hint: "Waiting to run",
|
|
2138
|
+
icon: /* @__PURE__ */ jsxRuntime.jsx(Clock.ClockIcon, {})
|
|
2139
|
+
}),
|
|
2140
|
+
/* @__PURE__ */ jsxRuntime.jsxs(ui.Flex, {
|
|
2141
|
+
align: "center",
|
|
2142
|
+
flex: 1,
|
|
2143
|
+
gap: 1,
|
|
2144
|
+
style: {
|
|
2145
|
+
minWidth: 0
|
|
2146
|
+
},
|
|
2147
|
+
children: [
|
|
2148
|
+
/* @__PURE__ */ jsxRuntime.jsx(ui.Box, {
|
|
2149
|
+
style: {
|
|
2150
|
+
minWidth: 0
|
|
2151
|
+
},
|
|
2152
|
+
children: /* @__PURE__ */ jsxRuntime.jsxs(ui.Text, {
|
|
2153
|
+
size: 1,
|
|
2154
|
+
textOverflow: "ellipsis",
|
|
2155
|
+
children: [ effect.title ?? /* @__PURE__ */ jsxRuntime.jsx(CodeChip, {
|
|
2156
|
+
value: effect.name
|
|
2157
|
+
}), registered ? " — ready to run in Studio" : " — waiting for the runtime" ]
|
|
2158
|
+
})
|
|
2159
|
+
}),
|
|
2160
|
+
/* @__PURE__ */ jsxRuntime.jsx(ui.Text, {
|
|
2161
|
+
muted: !0,
|
|
2162
|
+
size: 1,
|
|
2163
|
+
children: "·"
|
|
2164
|
+
}),
|
|
2165
|
+
/* @__PURE__ */ jsxRuntime.jsx(index.HoverHint, {
|
|
2166
|
+
text: index.formatDateTime(effect.queuedAt),
|
|
2167
|
+
children: /* @__PURE__ */ jsxRuntime.jsx(ui.Text, {
|
|
2168
|
+
muted: !0,
|
|
2169
|
+
size: 1,
|
|
2170
|
+
style: {
|
|
2171
|
+
whiteSpace: "nowrap"
|
|
2172
|
+
},
|
|
2173
|
+
children: index.formatShortAgo(effect.queuedAt, now)
|
|
2174
|
+
})
|
|
2175
|
+
}) ]
|
|
2176
|
+
}),
|
|
2177
|
+
/* @__PURE__ */ jsxRuntime.jsx(ui.Flex, {
|
|
2178
|
+
align: "center",
|
|
2179
|
+
flex: "none",
|
|
2180
|
+
style: {
|
|
2181
|
+
height: avatarSize
|
|
2182
|
+
},
|
|
2183
|
+
children: /* @__PURE__ */ jsxRuntime.jsx(index.HintedMenuButton, {
|
|
2184
|
+
button: /* @__PURE__ */ jsxRuntime.jsx(ui.Button, {
|
|
2185
|
+
"aria-label": `Resolve ${label}`,
|
|
2186
|
+
disabled: busy,
|
|
2187
|
+
fontSize: 1,
|
|
2188
|
+
icon: EllipsisHorizontal.EllipsisHorizontalIcon,
|
|
2189
|
+
mode: "bleed",
|
|
2190
|
+
padding: 2
|
|
2191
|
+
}),
|
|
2192
|
+
hint: "Resolve",
|
|
2193
|
+
id: `pending-effect-menu-${instanceId}-${effect._key}`,
|
|
2194
|
+
menu: /* @__PURE__ */ jsxRuntime.jsxs(ui.Menu, {
|
|
2195
|
+
children: [ registered ? /* @__PURE__ */ jsxRuntime.jsx(ui.MenuItem, {
|
|
2196
|
+
onClick: onRunHandlers,
|
|
2197
|
+
text: "Run registered handlers"
|
|
2198
|
+
}) : null,
|
|
2199
|
+
/* @__PURE__ */ jsxRuntime.jsx(ui.MenuItem, {
|
|
2200
|
+
onClick: () => onResolve("done"),
|
|
2201
|
+
text: "Mark done"
|
|
2202
|
+
}),
|
|
2203
|
+
/* @__PURE__ */ jsxRuntime.jsx(ui.MenuItem, {
|
|
2204
|
+
onClick: () => onResolve("failed"),
|
|
2205
|
+
text: "Mark failed",
|
|
2206
|
+
tone: "critical"
|
|
2207
|
+
}) ]
|
|
2208
|
+
}),
|
|
2209
|
+
popover: {
|
|
2210
|
+
placement: "bottom-end",
|
|
2211
|
+
portal: !0
|
|
2212
|
+
}
|
|
2213
|
+
})
|
|
2214
|
+
}) ]
|
|
2215
|
+
});
|
|
2216
|
+
}
|
|
2217
|
+
|
|
2218
|
+
function ActivityLog({instance: instance, definition: definition}) {
|
|
2219
|
+
const titles = react.useMemo(() => makeTitleResolver(definition), [ definition ]), entries = react.useMemo(() => instance.history.toReversed(), [ instance.history ]), [now, setNow] = react.useState(() => /* @__PURE__ */ new Date);
|
|
2220
|
+
return react.useEffect(() => {
|
|
2221
|
+
const timer = setInterval(() => setNow(/* @__PURE__ */ new Date), 6e4);
|
|
2222
|
+
return () => clearInterval(timer);
|
|
2223
|
+
}, []), entries.length === 0 && (instance.pendingEffects ?? []).length === 0 ? /* @__PURE__ */ jsxRuntime.jsx(ui.Text, {
|
|
2224
|
+
muted: !0,
|
|
2225
|
+
size: 1,
|
|
2226
|
+
children: "No activity yet"
|
|
2227
|
+
}) : /* @__PURE__ */ jsxRuntime.jsxs(ui.Stack, {
|
|
2228
|
+
gap: 3,
|
|
2229
|
+
children: [
|
|
2230
|
+
/* @__PURE__ */ jsxRuntime.jsx(PendingEffectRows, {
|
|
2231
|
+
instance: instance,
|
|
2232
|
+
now: now
|
|
2233
|
+
}), entries.map(h => /* @__PURE__ */ jsxRuntime.jsx(HistoryRow, {
|
|
2234
|
+
entry: h,
|
|
2235
|
+
now: now,
|
|
2236
|
+
titles: titles
|
|
2237
|
+
}, h._key)) ]
|
|
2238
|
+
});
|
|
2239
|
+
}
|
|
2240
|
+
|
|
2241
|
+
function HistoryRow({entry: entry, now: now, titles: titles}) {
|
|
2242
|
+
const line = historyLine(entry, titles);
|
|
2243
|
+
/* @__PURE__ */
|
|
2244
|
+
return jsxRuntime.jsxs(ui.Flex, {
|
|
2245
|
+
align: "center",
|
|
2246
|
+
gap: 2,
|
|
2247
|
+
children: [ line.actorId === void 0 ? /* @__PURE__ */ jsxRuntime.jsx(FeedGlyph, {
|
|
2248
|
+
hint: "The workflow",
|
|
2249
|
+
icon: /* @__PURE__ */ jsxRuntime.jsx(Cog.CogIcon, {})
|
|
2250
|
+
}) : /* @__PURE__ */ jsxRuntime.jsx(index.UserAvatar, {
|
|
2251
|
+
id: line.actorId
|
|
2252
|
+
}),
|
|
2253
|
+
/* @__PURE__ */ jsxRuntime.jsxs(ui.Flex, {
|
|
2254
|
+
align: "center",
|
|
2255
|
+
flex: 1,
|
|
2256
|
+
gap: 1,
|
|
2257
|
+
style: {
|
|
2258
|
+
minWidth: 0
|
|
2259
|
+
},
|
|
15
2260
|
children: [
|
|
16
|
-
/* @__PURE__ */ jsxRuntime.jsx(
|
|
17
|
-
|
|
18
|
-
|
|
2261
|
+
/* @__PURE__ */ jsxRuntime.jsx(ui.Box, {
|
|
2262
|
+
style: {
|
|
2263
|
+
minWidth: 0
|
|
2264
|
+
},
|
|
2265
|
+
children: /* @__PURE__ */ jsxRuntime.jsxs(ui.Text, {
|
|
2266
|
+
size: 1,
|
|
2267
|
+
textOverflow: "ellipsis",
|
|
2268
|
+
children: [ line.actorId === void 0 ? null : /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, {
|
|
2269
|
+
children: [
|
|
2270
|
+
/* @__PURE__ */ jsxRuntime.jsx(ActorNameSpan, {
|
|
2271
|
+
id: line.actorId
|
|
2272
|
+
}), " " ]
|
|
2273
|
+
}), line.parts.map((part, index2) => typeof part == "string" ? part : /* @__PURE__ */ jsxRuntime.jsx(CodeChip, {
|
|
2274
|
+
value: part.code
|
|
2275
|
+
}, index2)) ]
|
|
2276
|
+
})
|
|
2277
|
+
}),
|
|
2278
|
+
/* @__PURE__ */ jsxRuntime.jsx(ui.Text, {
|
|
2279
|
+
muted: !0,
|
|
2280
|
+
size: 1,
|
|
2281
|
+
children: "·"
|
|
19
2282
|
}),
|
|
20
|
-
/* @__PURE__ */ jsxRuntime.jsx(index.
|
|
21
|
-
|
|
22
|
-
|
|
2283
|
+
/* @__PURE__ */ jsxRuntime.jsx(index.HoverHint, {
|
|
2284
|
+
text: index.formatDateTime(entry.at),
|
|
2285
|
+
children: /* @__PURE__ */ jsxRuntime.jsx(ui.Text, {
|
|
2286
|
+
muted: !0,
|
|
2287
|
+
size: 1,
|
|
2288
|
+
style: {
|
|
2289
|
+
whiteSpace: "nowrap"
|
|
2290
|
+
},
|
|
2291
|
+
children: index.formatShortAgo(entry.at, now)
|
|
2292
|
+
})
|
|
23
2293
|
}) ]
|
|
2294
|
+
}) ]
|
|
2295
|
+
});
|
|
2296
|
+
}
|
|
2297
|
+
|
|
2298
|
+
function ActorNameSpan({id: id}) {
|
|
2299
|
+
const {name: name} = index.useUserDisplay(id), {font: font} = ui.useTheme_v2();
|
|
2300
|
+
/* @__PURE__ */
|
|
2301
|
+
return jsxRuntime.jsx("span", {
|
|
2302
|
+
style: {
|
|
2303
|
+
fontWeight: font.text.weights.medium
|
|
2304
|
+
},
|
|
2305
|
+
children: name
|
|
2306
|
+
});
|
|
2307
|
+
}
|
|
2308
|
+
|
|
2309
|
+
function CodeChip({value: value}) {
|
|
2310
|
+
/* @__PURE__ */
|
|
2311
|
+
return jsxRuntime.jsx("code", {
|
|
2312
|
+
children: value
|
|
2313
|
+
});
|
|
2314
|
+
}
|
|
2315
|
+
|
|
2316
|
+
function FeedGlyph({hint: hint, icon: icon}) {
|
|
2317
|
+
const size = index.useAvatarSize();
|
|
2318
|
+
/* @__PURE__ */
|
|
2319
|
+
return jsxRuntime.jsx(index.HoverHint, {
|
|
2320
|
+
text: hint,
|
|
2321
|
+
children: /* @__PURE__ */ jsxRuntime.jsx(ui.Flex, {
|
|
2322
|
+
align: "center",
|
|
2323
|
+
flex: "none",
|
|
2324
|
+
justify: "center",
|
|
2325
|
+
style: {
|
|
2326
|
+
height: size,
|
|
2327
|
+
width: size
|
|
2328
|
+
},
|
|
2329
|
+
children: /* @__PURE__ */ jsxRuntime.jsx(ui.Text, {
|
|
2330
|
+
muted: !0,
|
|
2331
|
+
size: 1,
|
|
2332
|
+
children: icon
|
|
2333
|
+
})
|
|
24
2334
|
})
|
|
25
2335
|
});
|
|
26
2336
|
}
|
|
27
2337
|
|
|
28
|
-
function WorkflowInstanceDetail({instanceId: instanceId,
|
|
2338
|
+
function WorkflowInstanceDetail({instanceId: instanceId, backToList: backToList}) {
|
|
29
2339
|
const entry = index.useWorkflowInstanceEntry(instanceId);
|
|
30
2340
|
index.useLogEventOnMount(index.WorkflowInstanceDetailViewed, {
|
|
31
2341
|
instanceId: instanceId
|
|
@@ -35,49 +2345,32 @@ function WorkflowInstanceDetail({instanceId: instanceId, onBack: onBack}) {
|
|
|
35
2345
|
const timer = setTimeout(() => setGraceOver(!0), 2500);
|
|
36
2346
|
return () => clearTimeout(timer);
|
|
37
2347
|
}, [ instanceId ]), entry?.invalid ? /* @__PURE__ */ jsxRuntime.jsx(ui.Box, {
|
|
38
|
-
padding: 4,
|
|
39
|
-
children: /* @__PURE__ */ jsxRuntime.jsx(index.InvalidDocNotice, {
|
|
40
|
-
invalid: entry.invalid
|
|
41
|
-
})
|
|
42
|
-
}) : entry ? /* @__PURE__ */ jsxRuntime.jsx(InstanceDetailPanel, {
|
|
43
|
-
entry: entry
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
}
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
/* @__PURE__ */
|
|
58
|
-
return jsxRuntime.jsxs(ui.Stack, {
|
|
59
|
-
gap: 4,
|
|
60
|
-
children: [
|
|
61
|
-
/* @__PURE__ */ jsxRuntime.jsxs(ui.Text, {
|
|
62
|
-
muted: !0,
|
|
63
|
-
size: 1,
|
|
64
|
-
children: [ "No workflow with id “", id, "” — it may have been deleted." ]
|
|
65
|
-
}),
|
|
66
|
-
/* @__PURE__ */ jsxRuntime.jsx(ui.Flex, {
|
|
67
|
-
children: /* @__PURE__ */ jsxRuntime.jsx(ui.Button, {
|
|
68
|
-
fontSize: 1,
|
|
69
|
-
icon: ArrowLeft.ArrowLeftIcon,
|
|
70
|
-
mode: "ghost",
|
|
71
|
-
onClick: onBack,
|
|
72
|
-
padding: 2,
|
|
73
|
-
text: "Back to workflows"
|
|
2348
|
+
padding: 4,
|
|
2349
|
+
children: /* @__PURE__ */ jsxRuntime.jsx(index.InvalidDocNotice, {
|
|
2350
|
+
invalid: entry.invalid
|
|
2351
|
+
})
|
|
2352
|
+
}) : entry ? /* @__PURE__ */ jsxRuntime.jsx(InstanceDetailPanel, {
|
|
2353
|
+
entry: entry
|
|
2354
|
+
}) : /* @__PURE__ */ jsxRuntime.jsx(ui.Box, {
|
|
2355
|
+
paddingX: 3,
|
|
2356
|
+
children: /* @__PURE__ */ jsxRuntime.jsx(TabStatusRow, {
|
|
2357
|
+
children: graceOver ? /* @__PURE__ */ jsxRuntime.jsx(DetailNotFound, {
|
|
2358
|
+
back: backToList,
|
|
2359
|
+
message: /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, {
|
|
2360
|
+
children: [ "Unable to find workflow with id “",
|
|
2361
|
+
/* @__PURE__ */ jsxRuntime.jsx("strong", {
|
|
2362
|
+
children: instanceId
|
|
2363
|
+
}), "”." ]
|
|
2364
|
+
})
|
|
2365
|
+
}) : /* @__PURE__ */ jsxRuntime.jsx(index.LoadingRow, {
|
|
2366
|
+
label: "Loading workflow…"
|
|
74
2367
|
})
|
|
75
|
-
})
|
|
2368
|
+
})
|
|
76
2369
|
});
|
|
77
2370
|
}
|
|
78
2371
|
|
|
79
|
-
function InstanceDetailPanel({entry: entry
|
|
80
|
-
const definition = index.useDefinition(entry), [openActivity, setOpenActivity] = react.useState(null), {instance: instance} = entry;
|
|
2372
|
+
function InstanceDetailPanel({entry: entry}) {
|
|
2373
|
+
const definition = index.useDefinition(entry), snapshotWidth = index.useContainerToken(2), [openActivity, setOpenActivity] = react.useState(null), {instance: instance, ready: ready} = entry;
|
|
81
2374
|
return react.useEffect(() => {
|
|
82
2375
|
openActivity && index.openActivityGone({
|
|
83
2376
|
entry: entry,
|
|
@@ -88,36 +2381,56 @@ function InstanceDetailPanel({entry: entry, onBack: onBack}) {
|
|
|
88
2381
|
height: "fill",
|
|
89
2382
|
overflow: "hidden",
|
|
90
2383
|
children: [
|
|
91
|
-
/* @__PURE__ */ jsxRuntime.jsx(
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
2384
|
+
/* @__PURE__ */ jsxRuntime.jsx(ui.Box, {
|
|
2385
|
+
flex: "none",
|
|
2386
|
+
paddingBottom: 2,
|
|
2387
|
+
paddingTop: 3,
|
|
2388
|
+
paddingX: 3,
|
|
2389
|
+
children: /* @__PURE__ */ jsxRuntime.jsx(DetailTitle, {
|
|
2390
|
+
busy: !ready || index.isEvaluationStale(entry),
|
|
2391
|
+
documentGdr: documentRefsOf(instance)[0],
|
|
2392
|
+
title: index.instanceTitle(instance, definition)
|
|
2393
|
+
})
|
|
95
2394
|
}),
|
|
96
2395
|
/* @__PURE__ */ jsxRuntime.jsx(ui.Box, {
|
|
97
2396
|
flex: 1,
|
|
98
2397
|
overflow: "auto",
|
|
99
|
-
paddingX:
|
|
100
|
-
children: /* @__PURE__ */ jsxRuntime.
|
|
101
|
-
gap: 4,
|
|
2398
|
+
paddingX: 3,
|
|
2399
|
+
children: /* @__PURE__ */ jsxRuntime.jsx(ui.Box, {
|
|
102
2400
|
paddingBottom: 5,
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
2401
|
+
paddingLeft: 2,
|
|
2402
|
+
paddingTop: 2,
|
|
2403
|
+
style: {
|
|
2404
|
+
maxWidth: snapshotWidth
|
|
2405
|
+
},
|
|
2406
|
+
children: /* @__PURE__ */ jsxRuntime.jsxs(ui.Stack, {
|
|
2407
|
+
gap: 6,
|
|
2408
|
+
children: [
|
|
2409
|
+
/* @__PURE__ */ jsxRuntime.jsx(index.InstanceSnapshotBody, {
|
|
2410
|
+
entry: entry,
|
|
2411
|
+
onOpenActivity: name => setOpenActivity({
|
|
2412
|
+
stage: instance.currentStage,
|
|
2413
|
+
activityName: name
|
|
2414
|
+
}),
|
|
2415
|
+
surface: "tool-instance-detail"
|
|
2416
|
+
}),
|
|
2417
|
+
/* @__PURE__ */ jsxRuntime.jsx(AbortWorkflowSection, {
|
|
2418
|
+
entry: entry
|
|
2419
|
+
}),
|
|
2420
|
+
/* @__PURE__ */ jsxRuntime.jsxs(ui.Stack, {
|
|
2421
|
+
gap: 4,
|
|
2422
|
+
children: [
|
|
2423
|
+
/* @__PURE__ */ jsxRuntime.jsx(ui.Text, {
|
|
2424
|
+
size: 1,
|
|
2425
|
+
weight: "semibold",
|
|
2426
|
+
children: "History"
|
|
2427
|
+
}),
|
|
2428
|
+
/* @__PURE__ */ jsxRuntime.jsx(ActivityLog, {
|
|
2429
|
+
definition: definition,
|
|
2430
|
+
instance: instance
|
|
2431
|
+
}) ]
|
|
2432
|
+
}) ]
|
|
2433
|
+
})
|
|
121
2434
|
})
|
|
122
2435
|
}), openActivity ? /* @__PURE__ */ jsxRuntime.jsx(index.ActivityDetailDialog, {
|
|
123
2436
|
activityName: openActivity.activityName,
|
|
@@ -130,130 +2443,14 @@ function InstanceDetailPanel({entry: entry, onBack: onBack}) {
|
|
|
130
2443
|
});
|
|
131
2444
|
}
|
|
132
2445
|
|
|
133
|
-
function DetailHeader({entry: entry, definition: definition, onBack: onBack}) {
|
|
134
|
-
const {instance: instance, ready: ready} = entry;
|
|
135
|
-
/* @__PURE__ */
|
|
136
|
-
return jsxRuntime.jsx(ui.Card, {
|
|
137
|
-
flex: "none",
|
|
138
|
-
paddingX: 4,
|
|
139
|
-
paddingY: 3,
|
|
140
|
-
children: /* @__PURE__ */ jsxRuntime.jsxs(ui.Flex, {
|
|
141
|
-
align: "center",
|
|
142
|
-
gap: 3,
|
|
143
|
-
wrap: "wrap",
|
|
144
|
-
children: [
|
|
145
|
-
/* @__PURE__ */ jsxRuntime.jsx(index.HoverHint, {
|
|
146
|
-
text: "Back to workflows",
|
|
147
|
-
children: /* @__PURE__ */ jsxRuntime.jsx(ui.Button, {
|
|
148
|
-
"aria-label": "Back to workflows",
|
|
149
|
-
fontSize: 1,
|
|
150
|
-
icon: ArrowLeft.ArrowLeftIcon,
|
|
151
|
-
mode: "bleed",
|
|
152
|
-
onClick: onBack,
|
|
153
|
-
padding: 2
|
|
154
|
-
})
|
|
155
|
-
}),
|
|
156
|
-
/* @__PURE__ */ jsxRuntime.jsxs(ui.Stack, {
|
|
157
|
-
gap: 2,
|
|
158
|
-
children: [
|
|
159
|
-
/* @__PURE__ */ jsxRuntime.jsx(ui.Text, {
|
|
160
|
-
size: 1,
|
|
161
|
-
weight: "semibold",
|
|
162
|
-
children: index.instanceTitle(instance, definition)
|
|
163
|
-
}),
|
|
164
|
-
/* @__PURE__ */ jsxRuntime.jsxs(ui.Text, {
|
|
165
|
-
muted: !0,
|
|
166
|
-
size: 1,
|
|
167
|
-
children: [ "Started ", index.formatDate(instance.startedAt) ]
|
|
168
|
-
}) ]
|
|
169
|
-
}), workflowEngine.terminalState(instance) === "in-flight" ? /* @__PURE__ */ jsxRuntime.jsx(index.StageChip, {
|
|
170
|
-
title: index.stageTitle(definition, instance.currentStage)
|
|
171
|
-
}) : /* @__PURE__ */ jsxRuntime.jsx(index.AbortedBadge, {
|
|
172
|
-
instance: instance
|
|
173
|
-
}),
|
|
174
|
-
/* @__PURE__ */ jsxRuntime.jsx(index.SpinnerSlot, {
|
|
175
|
-
busy: !ready || index.isEvaluationStale(entry)
|
|
176
|
-
}) ]
|
|
177
|
-
})
|
|
178
|
-
});
|
|
179
|
-
}
|
|
180
|
-
|
|
181
|
-
function StudioDocumentsSection({instance: instance}) {
|
|
182
|
-
const refs = documentRefsOf(instance);
|
|
183
|
-
return refs.length === 0 ? null : /* @__PURE__ */ jsxRuntime.jsxs(ui.Stack, {
|
|
184
|
-
gap: 3,
|
|
185
|
-
marginTop: 3,
|
|
186
|
-
children: [
|
|
187
|
-
/* @__PURE__ */ jsxRuntime.jsx(ui.Text, {
|
|
188
|
-
muted: !0,
|
|
189
|
-
size: 1,
|
|
190
|
-
weight: "medium",
|
|
191
|
-
children: refs.length === 1 ? "Studio document" : "Studio documents"
|
|
192
|
-
}),
|
|
193
|
-
/* @__PURE__ */ jsxRuntime.jsx(ui.Stack, {
|
|
194
|
-
gap: 2,
|
|
195
|
-
children: refs.map(ref => /* @__PURE__ */ jsxRuntime.jsx(index.DocPreviewLink, {
|
|
196
|
-
gdr: ref
|
|
197
|
-
}, ref.id))
|
|
198
|
-
}) ]
|
|
199
|
-
});
|
|
200
|
-
}
|
|
201
|
-
|
|
202
|
-
function StageDiagramSection({entry: entry, definition: definition}) {
|
|
203
|
-
const {instance: instance} = entry;
|
|
204
|
-
return definition ?
|
|
205
|
-
/* @__PURE__ */ jsxRuntime.jsx(workflowDiagram.WorkflowDiagram, {
|
|
206
|
-
currentStage: workflowEngine.terminalState(instance) === "in-flight" ? instance.currentStage : void 0,
|
|
207
|
-
definition: definition,
|
|
208
|
-
evaluation: entry.evaluation,
|
|
209
|
-
explain: !0,
|
|
210
|
-
guardCount: entry.guards?.length,
|
|
211
|
-
height: 340,
|
|
212
|
-
history: instance.history
|
|
213
|
-
}, instance._id) : /* @__PURE__ */ jsxRuntime.jsx(ui.Card, {
|
|
214
|
-
border: !0,
|
|
215
|
-
marginTop: 3,
|
|
216
|
-
padding: 3,
|
|
217
|
-
radius: 2,
|
|
218
|
-
tone: "caution",
|
|
219
|
-
children: /* @__PURE__ */ jsxRuntime.jsx(ui.Text, {
|
|
220
|
-
muted: !0,
|
|
221
|
-
size: 1,
|
|
222
|
-
children: "Couldn’t load this workflow’s full details — the stage diagram is unavailable, and technical names show instead of titles."
|
|
223
|
-
})
|
|
224
|
-
});
|
|
225
|
-
}
|
|
226
|
-
|
|
227
|
-
function MutedNote({text: text}) {
|
|
228
|
-
/* @__PURE__ */
|
|
229
|
-
return jsxRuntime.jsx(ui.Box, {
|
|
230
|
-
paddingY: 3,
|
|
231
|
-
children: /* @__PURE__ */ jsxRuntime.jsx(ui.Text, {
|
|
232
|
-
muted: !0,
|
|
233
|
-
size: 1,
|
|
234
|
-
children: text
|
|
235
|
-
})
|
|
236
|
-
});
|
|
237
|
-
}
|
|
238
|
-
|
|
239
2446
|
function useStartableDefinitions() {
|
|
240
|
-
const {
|
|
241
|
-
return
|
|
242
|
-
|
|
243
|
-
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
|
|
247
|
-
description: row.description
|
|
248
|
-
}));
|
|
249
|
-
cancelled || (setDefinitions(startable), setError(void 0));
|
|
250
|
-
})().catch(err => {
|
|
251
|
-
cancelled || setError(index.describeError(err));
|
|
252
|
-
}), () => {
|
|
253
|
-
cancelled = !0;
|
|
254
|
-
};
|
|
255
|
-
}, [ engine ]), {
|
|
256
|
-
definitions: definitions,
|
|
2447
|
+
const {definitions: definitions, error: error} = useDeployedDefinitions();
|
|
2448
|
+
return {
|
|
2449
|
+
definitions: react.useMemo(() => definitions?.filter(row => workflowEngine.isStartableDefinition(row)).map(row => ({
|
|
2450
|
+
name: row.name,
|
|
2451
|
+
title: row.title ?? row.name,
|
|
2452
|
+
description: row.description
|
|
2453
|
+
})), [ definitions ]),
|
|
257
2454
|
error: error
|
|
258
2455
|
};
|
|
259
2456
|
}
|
|
@@ -343,196 +2540,55 @@ function DefinitionPickerPanel({onPick: onPick}) {
|
|
|
343
2540
|
textOverflow: "ellipsis",
|
|
344
2541
|
children: definition.description
|
|
345
2542
|
}) : null ]
|
|
346
|
-
})
|
|
347
|
-
}, definition.name))
|
|
348
|
-
}) ]
|
|
349
|
-
})
|
|
350
|
-
});
|
|
351
|
-
}
|
|
352
|
-
|
|
353
|
-
function ToolActivityDialog({target: target, onClose: onClose}) {
|
|
354
|
-
const entry = index.useWorkflowInstanceEntry(target.instanceId), definition = index.useDefinition(entry), resolvedOnce = react.useRef(!1);
|
|
355
|
-
return entry && (resolvedOnce.current = !0), react.useEffect(() => {
|
|
356
|
-
resolvedOnce.current && index.openActivityGone({
|
|
357
|
-
entry: entry,
|
|
358
|
-
target: target
|
|
359
|
-
}) && onClose();
|
|
360
|
-
}, [ entry, target, onClose ]), entry?.invalid ? /* @__PURE__ */ jsxRuntime.jsx(ui.Dialog, {
|
|
361
|
-
header: "Workflow unavailable",
|
|
362
|
-
id: "workflow-activity-detail",
|
|
363
|
-
onClose: onClose,
|
|
364
|
-
width: 1,
|
|
365
|
-
children: /* @__PURE__ */ jsxRuntime.jsx(ui.Box, {
|
|
366
|
-
padding: 4,
|
|
367
|
-
children: /* @__PURE__ */ jsxRuntime.jsx(index.InvalidDocNotice, {
|
|
368
|
-
invalid: entry.invalid
|
|
369
|
-
})
|
|
370
|
-
})
|
|
371
|
-
}) : entry?.evaluation ? /* @__PURE__ */ jsxRuntime.jsx(index.ActivityDetailDialog, {
|
|
372
|
-
activityName: target.activityName,
|
|
373
|
-
breadcrumb: index.instanceBreadcrumb(entry.instance, definition),
|
|
374
|
-
definition: definition,
|
|
375
|
-
document: documentRefsOf(entry.instance)[0],
|
|
376
|
-
entry: entry,
|
|
377
|
-
onClose: onClose,
|
|
378
|
-
source: "tool-task-list"
|
|
379
|
-
}) : /* @__PURE__ */ jsxRuntime.jsx(ui.Dialog, {
|
|
380
|
-
header: "Loading activity…",
|
|
381
|
-
id: "workflow-activity-detail",
|
|
382
|
-
onClose: onClose,
|
|
383
|
-
width: 1,
|
|
384
|
-
children: /* @__PURE__ */ jsxRuntime.jsx(ui.Box, {
|
|
385
|
-
padding: 4,
|
|
386
|
-
children: /* @__PURE__ */ jsxRuntime.jsx(index.LoadingRow, {
|
|
387
|
-
label: "Fetching the live workflow state…"
|
|
388
|
-
})
|
|
389
|
-
})
|
|
390
|
-
});
|
|
391
|
-
}
|
|
392
|
-
|
|
393
|
-
const GROUP_DEFAULT_OPEN = !0;
|
|
394
|
-
|
|
395
|
-
function instanceBandDefaultOpen(segment) {
|
|
396
|
-
return segment === "for-me";
|
|
397
|
-
}
|
|
398
|
-
|
|
399
|
-
const UNGROUPED_BAND_KEY = "section:no-document", PAYLOAD_VERSION = 1, MAX_ENTRIES = 200;
|
|
400
|
-
|
|
401
|
-
function bandStateStorageKey(scope) {
|
|
402
|
-
return `sanity.workflows.tool.bands:${scope}`;
|
|
403
|
-
}
|
|
404
|
-
|
|
405
|
-
function isRecord(value) {
|
|
406
|
-
return typeof value == "object" && value !== null && !Array.isArray(value);
|
|
407
|
-
}
|
|
408
|
-
|
|
409
|
-
function bandEntryOf(value) {
|
|
410
|
-
if (!isRecord(value)) return;
|
|
411
|
-
const {open: open, touched: touched} = value;
|
|
412
|
-
if (!(typeof open != "boolean" || typeof touched != "number") && Number.isFinite(touched)) return {
|
|
413
|
-
open: open,
|
|
414
|
-
touched: touched
|
|
415
|
-
};
|
|
416
|
-
}
|
|
417
|
-
|
|
418
|
-
function parsePayload(raw) {
|
|
419
|
-
try {
|
|
420
|
-
const parsed = JSON.parse(raw);
|
|
421
|
-
if (!isRecord(parsed) || parsed.version !== PAYLOAD_VERSION || !isRecord(parsed.bands)) return;
|
|
422
|
-
const entries = [];
|
|
423
|
-
for (const [key, value] of Object.entries(parsed.bands)) {
|
|
424
|
-
const entry = bandEntryOf(value);
|
|
425
|
-
if (entry === void 0) return;
|
|
426
|
-
entries.push([ key, entry ]);
|
|
427
|
-
}
|
|
428
|
-
return Object.fromEntries(entries);
|
|
429
|
-
} catch {
|
|
430
|
-
return;
|
|
431
|
-
}
|
|
432
|
-
}
|
|
433
|
-
|
|
434
|
-
function readStored(storage, storageKey) {
|
|
435
|
-
if (!storage) return {
|
|
436
|
-
entries: void 0,
|
|
437
|
-
corrupt: !1
|
|
438
|
-
};
|
|
439
|
-
let raw;
|
|
440
|
-
try {
|
|
441
|
-
raw = storage.getItem(storageKey);
|
|
442
|
-
} catch {
|
|
443
|
-
return {
|
|
444
|
-
entries: void 0,
|
|
445
|
-
corrupt: !1
|
|
446
|
-
};
|
|
447
|
-
}
|
|
448
|
-
if (raw === null) return {
|
|
449
|
-
entries: {},
|
|
450
|
-
corrupt: !1
|
|
451
|
-
};
|
|
452
|
-
const entries = parsePayload(raw);
|
|
453
|
-
return {
|
|
454
|
-
entries: entries,
|
|
455
|
-
corrupt: entries === void 0
|
|
456
|
-
};
|
|
457
|
-
}
|
|
458
|
-
|
|
459
|
-
function writeStored(args) {
|
|
460
|
-
if (!args.storage) return !1;
|
|
461
|
-
try {
|
|
462
|
-
return args.storage.setItem(args.storageKey, JSON.stringify({
|
|
463
|
-
version: PAYLOAD_VERSION,
|
|
464
|
-
bands: args.entries
|
|
465
|
-
})), !0;
|
|
466
|
-
} catch {
|
|
467
|
-
return !1;
|
|
468
|
-
}
|
|
469
|
-
}
|
|
470
|
-
|
|
471
|
-
function baseEntries(args) {
|
|
472
|
-
return args.stored === void 0 ? args.held : args.unpersisted ? mergeByTouched(args.stored, args.held) : args.stored;
|
|
473
|
-
}
|
|
474
|
-
|
|
475
|
-
function mergeByTouched(stored, held) {
|
|
476
|
-
const merged = {
|
|
477
|
-
...stored
|
|
478
|
-
};
|
|
479
|
-
for (const [key, entry] of Object.entries(held)) {
|
|
480
|
-
const persisted = merged[key];
|
|
481
|
-
(persisted === void 0 || entry.touched >= persisted.touched) && (merged[key] = entry);
|
|
482
|
-
}
|
|
483
|
-
return merged;
|
|
484
|
-
}
|
|
485
|
-
|
|
486
|
-
function prune(entries) {
|
|
487
|
-
const held = Object.entries(entries);
|
|
488
|
-
return held.length <= MAX_ENTRIES ? entries : Object.fromEntries(held.sort(([, a], [, b]) => b.touched - a.touched).slice(0, MAX_ENTRIES));
|
|
489
|
-
}
|
|
490
|
-
|
|
491
|
-
function togglesOf(entries) {
|
|
492
|
-
return new Map(Object.entries(entries).map(([key, entry]) => [ key, entry.open ]));
|
|
493
|
-
}
|
|
494
|
-
|
|
495
|
-
function defaultStorage() {
|
|
496
|
-
try {
|
|
497
|
-
return globalThis.localStorage;
|
|
498
|
-
} catch {
|
|
499
|
-
return;
|
|
500
|
-
}
|
|
2543
|
+
})
|
|
2544
|
+
}, definition.name))
|
|
2545
|
+
}) ]
|
|
2546
|
+
})
|
|
2547
|
+
});
|
|
501
2548
|
}
|
|
502
2549
|
|
|
503
|
-
function
|
|
504
|
-
const
|
|
505
|
-
|
|
506
|
-
|
|
507
|
-
|
|
508
|
-
|
|
2550
|
+
function ToolActivityDialog({target: target, onClose: onClose}) {
|
|
2551
|
+
const entry = index.useWorkflowInstanceEntry(target.instanceId), definition = index.useDefinition(entry), resolvedOnce = react.useRef(!1);
|
|
2552
|
+
return entry && (resolvedOnce.current = !0), react.useEffect(() => {
|
|
2553
|
+
resolvedOnce.current && index.openActivityGone({
|
|
2554
|
+
entry: entry,
|
|
2555
|
+
target: target
|
|
2556
|
+
}) && onClose();
|
|
2557
|
+
}, [ entry, target, onClose ]), entry?.invalid ? /* @__PURE__ */ jsxRuntime.jsx(ui.Dialog, {
|
|
2558
|
+
header: "Workflow unavailable",
|
|
2559
|
+
id: "workflow-activity-detail",
|
|
2560
|
+
onClose: onClose,
|
|
2561
|
+
width: 1,
|
|
2562
|
+
children: /* @__PURE__ */ jsxRuntime.jsx(ui.Box, {
|
|
2563
|
+
padding: 4,
|
|
2564
|
+
children: /* @__PURE__ */ jsxRuntime.jsx(index.InvalidDocNotice, {
|
|
2565
|
+
invalid: entry.invalid
|
|
2566
|
+
})
|
|
2567
|
+
})
|
|
2568
|
+
}) : entry?.evaluation ? /* @__PURE__ */ jsxRuntime.jsx(index.ActivityDetailDialog, {
|
|
2569
|
+
activityName: target.activityName,
|
|
2570
|
+
breadcrumb: index.instanceBreadcrumb(entry.instance, definition),
|
|
2571
|
+
definition: definition,
|
|
2572
|
+
document: documentRefsOf(entry.instance)[0],
|
|
2573
|
+
entry: entry,
|
|
2574
|
+
onClose: onClose,
|
|
2575
|
+
source: "tool-task-list"
|
|
2576
|
+
}) : /* @__PURE__ */ jsxRuntime.jsx(ui.Dialog, {
|
|
2577
|
+
header: "Loading activity…",
|
|
2578
|
+
id: "workflow-activity-detail",
|
|
2579
|
+
onClose: onClose,
|
|
2580
|
+
width: 1,
|
|
2581
|
+
children: /* @__PURE__ */ jsxRuntime.jsx(ui.Box, {
|
|
2582
|
+
padding: 4,
|
|
2583
|
+
children: /* @__PURE__ */ jsxRuntime.jsx(index.LoadingRow, {
|
|
2584
|
+
label: "Fetching the live workflow state…"
|
|
2585
|
+
})
|
|
2586
|
+
})
|
|
509
2587
|
});
|
|
510
|
-
let held = initial.entries ?? {}, unpersisted = !1;
|
|
511
|
-
return {
|
|
512
|
-
read: () => togglesOf(held),
|
|
513
|
-
setOpen(key, open) {
|
|
514
|
-
const stored = readStored(storage, args.storageKey).entries, base = baseEntries({
|
|
515
|
-
stored: stored,
|
|
516
|
-
held: held,
|
|
517
|
-
unpersisted: unpersisted
|
|
518
|
-
});
|
|
519
|
-
return held = prune({
|
|
520
|
-
...base,
|
|
521
|
-
[key]: {
|
|
522
|
-
open: open,
|
|
523
|
-
touched: Date.now()
|
|
524
|
-
}
|
|
525
|
-
}), unpersisted = !writeStored({
|
|
526
|
-
storage: storage,
|
|
527
|
-
storageKey: args.storageKey,
|
|
528
|
-
entries: held
|
|
529
|
-
}), togglesOf(held);
|
|
530
|
-
}
|
|
531
|
-
};
|
|
532
2588
|
}
|
|
533
2589
|
|
|
534
2590
|
function datesOf(state) {
|
|
535
|
-
return state.filter(entry =>
|
|
2591
|
+
return state.filter(entry => index.isDateFieldKind(entry._type)).map(entry => entry.value).filter(value => typeof value == "string" && value !== "");
|
|
536
2592
|
}
|
|
537
2593
|
|
|
538
2594
|
function spawnOrigins(instances) {
|
|
@@ -632,6 +2688,14 @@ function deriveTaskGroups(args) {
|
|
|
632
2688
|
};
|
|
633
2689
|
}
|
|
634
2690
|
|
|
2691
|
+
function orderGroupsByPreviewTitle(groups, titles) {
|
|
2692
|
+
const withDocuments = [ ...groups.withDocuments ].sort(byResolvedTitle(group => titles.get(group.document.id), group => group.key));
|
|
2693
|
+
return {
|
|
2694
|
+
...groups,
|
|
2695
|
+
withDocuments: withDocuments
|
|
2696
|
+
};
|
|
2697
|
+
}
|
|
2698
|
+
|
|
635
2699
|
function cutTaskGroups(groups, cut) {
|
|
636
2700
|
const cutBands = bands => bands.filter(band => cut.keepBand?.(band) ?? !0).map(band => ({
|
|
637
2701
|
...band,
|
|
@@ -777,11 +2841,13 @@ function workflowTally(workflows) {
|
|
|
777
2841
|
function settleToast(outcome) {
|
|
778
2842
|
const total = outcome.settled + outcome.skipped.length + outcome.failures.length;
|
|
779
2843
|
if (outcome.skipped.length === 0 && outcome.failures.length === 0) return {
|
|
780
|
-
|
|
2844
|
+
id: index.TOAST_ID.orphanSettle,
|
|
2845
|
+
status: "info",
|
|
781
2846
|
title: outcome.settled === 1 ? "Cleaned up 1 workflow" : `Cleaned up ${outcome.settled} workflows`
|
|
782
2847
|
};
|
|
783
2848
|
const lines = [ ...outcome.skipped.map(workflow => `${workflow.title}: its document exists again — left running`), ...outcome.failures.map(failure => `${failure.workflow.title}: ${failure.message}`) ];
|
|
784
2849
|
return {
|
|
2850
|
+
id: index.TOAST_ID.orphanSettle,
|
|
785
2851
|
status: "warning",
|
|
786
2852
|
title: `Cleaned up ${outcome.settled} of ${total} workflows`,
|
|
787
2853
|
description: lines.join(`\n`)
|
|
@@ -790,9 +2856,10 @@ function settleToast(outcome) {
|
|
|
790
2856
|
|
|
791
2857
|
function recheckFailedToast(err) {
|
|
792
2858
|
return {
|
|
2859
|
+
id: index.TOAST_ID.orphanSettle,
|
|
793
2860
|
status: "error",
|
|
794
|
-
title: "Nothing was cleaned up
|
|
795
|
-
description: index.describeError(err)
|
|
2861
|
+
title: "Nothing was cleaned up",
|
|
2862
|
+
description: `The documents could not be re-checked: ${index.describeError(err)}`
|
|
796
2863
|
};
|
|
797
2864
|
}
|
|
798
2865
|
|
|
@@ -822,7 +2889,7 @@ function OrphanedWorkflowsNote({orphans: orphans}) {
|
|
|
822
2889
|
function SettleOrphansDialog({workflows: workflows, onClose: onClose}) {
|
|
823
2890
|
const {engine: engine} = index.useWorkflowContext(), client = sanity.useClient({
|
|
824
2891
|
apiVersion: index.WORKFLOW_API_VERSION
|
|
825
|
-
}), toast = index.
|
|
2892
|
+
}), toast = index.useWorkflowToast(), [pending, setPending] = react.useState(!1), confirm = async () => {
|
|
826
2893
|
setPending(!0);
|
|
827
2894
|
try {
|
|
828
2895
|
const outcome = await settleOrphans({
|
|
@@ -1067,38 +3134,6 @@ function applyTaskFilters(args) {
|
|
|
1067
3134
|
});
|
|
1068
3135
|
}
|
|
1069
3136
|
|
|
1070
|
-
const NOTHING = {
|
|
1071
|
-
titles: /* @__PURE__ */ new Map,
|
|
1072
|
-
resolved: /* @__PURE__ */ new Set
|
|
1073
|
-
};
|
|
1074
|
-
|
|
1075
|
-
function useDocPreviewTitles(documents) {
|
|
1076
|
-
const previewStore = sanity.useDocumentPreviewStore(), schema = sanity.useSchema(), {binding: binding} = index.useWorkflowContext(), [state, setState] = react.useState(NOTHING), key = documents.map(doc => doc.id).join("|");
|
|
1077
|
-
return react.useEffect(() => {
|
|
1078
|
-
const titles = /* @__PURE__ */ new Map, resolved = /* @__PURE__ */ new Set, publish = () => setState({
|
|
1079
|
-
titles: new Map(titles),
|
|
1080
|
-
resolved: new Set(resolved)
|
|
1081
|
-
}), subscriptions = documents.flatMap(doc => {
|
|
1082
|
-
const {parsed: parsedRef, local: local} = index.gdrLocality(doc.id, binding.contentResource), schemaType = schema.get(doc.type);
|
|
1083
|
-
return !parsedRef || !local || !schemaType ? (resolved.add(doc.id), []) : [ previewStore.observeForPreview({
|
|
1084
|
-
_type: "reference",
|
|
1085
|
-
_ref: parsedRef.documentId
|
|
1086
|
-
}, schemaType).subscribe({
|
|
1087
|
-
next: event => {
|
|
1088
|
-
resolved.add(doc.id);
|
|
1089
|
-
const title = event.snapshot?.title;
|
|
1090
|
-
typeof title == "string" && titles.set(doc.id, title), publish();
|
|
1091
|
-
},
|
|
1092
|
-
error: err => {
|
|
1093
|
-
console.error(`[workflow-studio-plugin] preview for "${doc.id}" failed:`, err),
|
|
1094
|
-
resolved.add(doc.id), publish();
|
|
1095
|
-
}
|
|
1096
|
-
}) ];
|
|
1097
|
-
});
|
|
1098
|
-
return publish(), () => subscriptions.forEach(sub => sub.unsubscribe());
|
|
1099
|
-
}, [ key, previewStore, schema, binding.contentResource.id ]), state;
|
|
1100
|
-
}
|
|
1101
|
-
|
|
1102
3137
|
const HITS_CAP = 6;
|
|
1103
3138
|
|
|
1104
3139
|
function TaskFilterMenu({filters: filters, options: options, onChange: onChange}) {
|
|
@@ -1597,8 +3632,10 @@ function FilterRowPortal({filters: filters, onChange: onChange, options: options
|
|
|
1597
3632
|
}), slot) : null;
|
|
1598
3633
|
}
|
|
1599
3634
|
|
|
1600
|
-
function ActivityDateControl({instanceId: instanceId, state: state, dates: dates}) {
|
|
1601
|
-
const
|
|
3635
|
+
function ActivityDateControl({instanceId: instanceId, state: state, surface: surface, dates: dates}) {
|
|
3636
|
+
const editField = index.useEditField(surface), {save: save} = index.useSaveField({
|
|
3637
|
+
instanceId: instanceId
|
|
3638
|
+
}), [open, setOpen] = react.useState(!1), raw = index.dateControlValue({
|
|
1602
3639
|
state: state,
|
|
1603
3640
|
dates: dates
|
|
1604
3641
|
}), display = raw === void 0 ? null : /* @__PURE__ */ jsxRuntime.jsx(ui.Text, {
|
|
@@ -1621,15 +3658,16 @@ function ActivityDateControl({instanceId: instanceId, state: state, dates: dates
|
|
|
1621
3658
|
})
|
|
1622
3659
|
});
|
|
1623
3660
|
const kind = index.dateControlKind(state), commit = (mode, value) => {
|
|
1624
|
-
state.kind === "editable" && save(() =>
|
|
1625
|
-
|
|
3661
|
+
state.kind === "editable" && save(() => editField({
|
|
3662
|
+
instanceId: instanceId,
|
|
3663
|
+
field: state.field,
|
|
1626
3664
|
...mode === "set" ? {
|
|
1627
3665
|
mode: mode,
|
|
1628
3666
|
value: value
|
|
1629
3667
|
} : {
|
|
1630
3668
|
mode: mode
|
|
1631
3669
|
}
|
|
1632
|
-
})
|
|
3670
|
+
}));
|
|
1633
3671
|
}, handleClick = e => {
|
|
1634
3672
|
e.stopPropagation(), setOpen(v => !v);
|
|
1635
3673
|
};
|
|
@@ -1646,9 +3684,9 @@ function ActivityDateControl({instanceId: instanceId, state: state, dates: dates
|
|
|
1646
3684
|
setOpen(!1), commit("unset");
|
|
1647
3685
|
},
|
|
1648
3686
|
onPick: next => {
|
|
1649
|
-
kind
|
|
3687
|
+
index.hasTimeOfDay(kind) || setOpen(!1), commit("set", index.serializeDateFieldValue(next, kind));
|
|
1650
3688
|
},
|
|
1651
|
-
selectTime: kind
|
|
3689
|
+
selectTime: index.hasTimeOfDay(kind),
|
|
1652
3690
|
value: index.parseDateFieldValue(state.field.value, kind)
|
|
1653
3691
|
})
|
|
1654
3692
|
}),
|
|
@@ -1712,7 +3750,8 @@ function RefChips({refs: refs, max: max = 2}) {
|
|
|
1712
3750
|
wrap: "wrap",
|
|
1713
3751
|
children: [ shown.map(ref => /* @__PURE__ */ jsxRuntime.jsx(index.DocPreviewLink, {
|
|
1714
3752
|
gdr: ref,
|
|
1715
|
-
layout: "inline"
|
|
3753
|
+
layout: "inline",
|
|
3754
|
+
source: "doc-ref-chip"
|
|
1716
3755
|
}, ref.id)), overflow > 0 ? /* @__PURE__ */ jsxRuntime.jsxs(ui.Text, {
|
|
1717
3756
|
muted: !0,
|
|
1718
3757
|
size: 1,
|
|
@@ -1721,57 +3760,18 @@ function RefChips({refs: refs, max: max = 2}) {
|
|
|
1721
3760
|
});
|
|
1722
3761
|
}
|
|
1723
3762
|
|
|
1724
|
-
const
|
|
3763
|
+
const UNGROUPED_TITLE = "Workflows without Studio documents";
|
|
1725
3764
|
|
|
1726
|
-
function TaskGroupList({
|
|
1727
|
-
|
|
1728
|
-
|
|
1729
|
-
|
|
1730
|
-
|
|
1731
|
-
|
|
1732
|
-
|
|
1733
|
-
|
|
1734
|
-
|
|
1735
|
-
|
|
1736
|
-
title: workflowEngine.toBareId(group.document.id),
|
|
1737
|
-
header: /* @__PURE__ */ jsxRuntime.jsx(ui.Flex, {
|
|
1738
|
-
align: "center",
|
|
1739
|
-
flex: "none",
|
|
1740
|
-
style: {
|
|
1741
|
-
maxWidth: "60%"
|
|
1742
|
-
},
|
|
1743
|
-
children: /* @__PURE__ */ jsxRuntime.jsx(RefChips, {
|
|
1744
|
-
max: 2,
|
|
1745
|
-
refs: group.documents
|
|
1746
|
-
})
|
|
1747
|
-
}),
|
|
1748
|
-
children: /* @__PURE__ */ jsxRuntime.jsx(InstanceBands, {
|
|
1749
|
-
bands: bands,
|
|
1750
|
-
instanceDefaultOpen: instanceDefaultOpen,
|
|
1751
|
-
instances: group.instances,
|
|
1752
|
-
onOpenTask: onOpenTask,
|
|
1753
|
-
onOpenWorkflow: onOpenWorkflow,
|
|
1754
|
-
showTerminalActions: showTerminalActions
|
|
1755
|
-
})
|
|
1756
|
-
}, group.key)), groups.withoutDocuments.length > 0 ? /* @__PURE__ */ jsxRuntime.jsx(index.CollapsibleBand, {
|
|
1757
|
-
background: !0,
|
|
1758
|
-
onToggle: () => bands.toggle(UNGROUPED_BAND_KEY, GROUP_DEFAULT_OPEN),
|
|
1759
|
-
open: bands.isOpen(UNGROUPED_BAND_KEY, GROUP_DEFAULT_OPEN),
|
|
1760
|
-
sticky: !0,
|
|
1761
|
-
title: UNGROUPED_TITLE,
|
|
1762
|
-
header: /* @__PURE__ */ jsxRuntime.jsx(ui.Text, {
|
|
1763
|
-
size: 1,
|
|
1764
|
-
weight: "semibold",
|
|
1765
|
-
children: UNGROUPED_TITLE
|
|
1766
|
-
}),
|
|
1767
|
-
children: /* @__PURE__ */ jsxRuntime.jsx(InstanceBands, {
|
|
1768
|
-
bands: bands,
|
|
1769
|
-
instanceDefaultOpen: instanceDefaultOpen,
|
|
1770
|
-
instances: groups.withoutDocuments,
|
|
1771
|
-
onOpenTask: onOpenTask,
|
|
1772
|
-
onOpenWorkflow: onOpenWorkflow,
|
|
1773
|
-
showTerminalActions: showTerminalActions
|
|
1774
|
-
})
|
|
3765
|
+
function TaskGroupList({groups: groups, ...wiring}) {
|
|
3766
|
+
/* @__PURE__ */
|
|
3767
|
+
return jsxRuntime.jsxs(ui.Stack, {
|
|
3768
|
+
gap: 1,
|
|
3769
|
+
children: [ groups.withDocuments.map(group => /* @__PURE__ */ jsxRuntime.jsx(DocumentBand, {
|
|
3770
|
+
group: group,
|
|
3771
|
+
...wiring
|
|
3772
|
+
}, group.key)), groups.withoutDocuments.length > 0 ? /* @__PURE__ */ jsxRuntime.jsx(UngroupedBand, {
|
|
3773
|
+
instances: groups.withoutDocuments,
|
|
3774
|
+
...wiring
|
|
1775
3775
|
}) : null ]
|
|
1776
3776
|
});
|
|
1777
3777
|
}
|
|
@@ -1784,38 +3784,81 @@ function targetOf(row) {
|
|
|
1784
3784
|
};
|
|
1785
3785
|
}
|
|
1786
3786
|
|
|
1787
|
-
function
|
|
3787
|
+
function DocumentBand({group: group, ...wiring}) {
|
|
3788
|
+
const {open: open, toggle: toggle} = useBandOpen(wiring.bands, group.key);
|
|
3789
|
+
/* @__PURE__ */
|
|
3790
|
+
return jsxRuntime.jsx(index.CollapsibleBand, {
|
|
3791
|
+
background: !0,
|
|
3792
|
+
onToggle: toggle,
|
|
3793
|
+
open: open,
|
|
3794
|
+
sticky: !0,
|
|
3795
|
+
title: workflowEngine.toBareId(group.document.id),
|
|
3796
|
+
header: /* @__PURE__ */ jsxRuntime.jsx(ui.Flex, {
|
|
3797
|
+
align: "center",
|
|
3798
|
+
flex: "none",
|
|
3799
|
+
style: {
|
|
3800
|
+
maxWidth: "60%"
|
|
3801
|
+
},
|
|
3802
|
+
children: /* @__PURE__ */ jsxRuntime.jsx(RefChips, {
|
|
3803
|
+
max: 2,
|
|
3804
|
+
refs: group.documents
|
|
3805
|
+
})
|
|
3806
|
+
}),
|
|
3807
|
+
children: /* @__PURE__ */ jsxRuntime.jsx(InstanceBands, {
|
|
3808
|
+
instances: group.instances,
|
|
3809
|
+
...wiring
|
|
3810
|
+
})
|
|
3811
|
+
});
|
|
3812
|
+
}
|
|
3813
|
+
|
|
3814
|
+
function UngroupedBand({instances: instances, ...wiring}) {
|
|
3815
|
+
const {open: open, toggle: toggle} = useBandOpen(wiring.bands, UNGROUPED_BAND_KEY);
|
|
3816
|
+
/* @__PURE__ */
|
|
3817
|
+
return jsxRuntime.jsx(index.CollapsibleBand, {
|
|
3818
|
+
background: !0,
|
|
3819
|
+
onToggle: toggle,
|
|
3820
|
+
open: open,
|
|
3821
|
+
sticky: !0,
|
|
3822
|
+
title: UNGROUPED_TITLE,
|
|
3823
|
+
header: /* @__PURE__ */ jsxRuntime.jsx(ui.Text, {
|
|
3824
|
+
size: 1,
|
|
3825
|
+
weight: "semibold",
|
|
3826
|
+
children: UNGROUPED_TITLE
|
|
3827
|
+
}),
|
|
3828
|
+
children: /* @__PURE__ */ jsxRuntime.jsx(InstanceBands, {
|
|
3829
|
+
instances: instances,
|
|
3830
|
+
...wiring
|
|
3831
|
+
})
|
|
3832
|
+
});
|
|
3833
|
+
}
|
|
3834
|
+
|
|
3835
|
+
function InstanceBands({instances: instances, ...wiring}) {
|
|
1788
3836
|
/* @__PURE__ */
|
|
1789
3837
|
return jsxRuntime.jsx(ui.Stack, {
|
|
1790
3838
|
gap: 1,
|
|
1791
|
-
children: instances.map(
|
|
1792
|
-
|
|
1793
|
-
|
|
1794
|
-
|
|
1795
|
-
onOpenTask: onOpenTask,
|
|
1796
|
-
onOpenWorkflow: onOpenWorkflow,
|
|
1797
|
-
showTerminalActions: showTerminalActions
|
|
1798
|
-
}, band.instanceId))
|
|
3839
|
+
children: instances.map(instance => /* @__PURE__ */ jsxRuntime.jsx(InstanceBand, {
|
|
3840
|
+
instance: instance,
|
|
3841
|
+
...wiring
|
|
3842
|
+
}, instance.instanceId))
|
|
1799
3843
|
});
|
|
1800
3844
|
}
|
|
1801
3845
|
|
|
1802
|
-
function InstanceBand({
|
|
1803
|
-
const {resolvePathFromState: resolvePathFromState} = router.useRouter();
|
|
3846
|
+
function InstanceBand({bands: bands, instance: instance, onOpenTask: onOpenTask, onOpenWorkflow: onOpenWorkflow, showTerminalActions: showTerminalActions}) {
|
|
3847
|
+
const {open: open, toggle: toggle} = useBandOpen(bands, instance.instanceId), {resolvePathFromState: resolvePathFromState} = router.useRouter();
|
|
1804
3848
|
/* @__PURE__ */
|
|
1805
3849
|
return jsxRuntime.jsx(index.CollapsibleBand, {
|
|
1806
|
-
onToggle:
|
|
1807
|
-
open:
|
|
1808
|
-
title:
|
|
3850
|
+
onToggle: toggle,
|
|
3851
|
+
open: open,
|
|
3852
|
+
title: instance.title,
|
|
1809
3853
|
header: /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, {
|
|
1810
3854
|
children: [
|
|
1811
3855
|
/* @__PURE__ */ jsxRuntime.jsx(index.LinkChip, {
|
|
1812
3856
|
hint: "View workflow",
|
|
1813
3857
|
href: resolvePathFromState({
|
|
1814
|
-
instanceId:
|
|
3858
|
+
instanceId: instance.instanceId
|
|
1815
3859
|
}),
|
|
1816
3860
|
onClick: event => {
|
|
1817
|
-
event
|
|
1818
|
-
onOpenWorkflow(band.instanceId));
|
|
3861
|
+
isPlainClick(event) && (event.preventDefault(), onOpenWorkflow(instance.instanceId));
|
|
1819
3862
|
},
|
|
1820
3863
|
children: /* @__PURE__ */ jsxRuntime.jsxs(ui.Flex, {
|
|
1821
3864
|
align: "center",
|
|
@@ -1831,12 +3874,12 @@ function InstanceBand({band: band, bands: bands, instanceDefaultOpen: instanceDe
|
|
|
1831
3874
|
},
|
|
1832
3875
|
textOverflow: "ellipsis",
|
|
1833
3876
|
weight: "medium",
|
|
1834
|
-
children:
|
|
1835
|
-
}),
|
|
1836
|
-
segments: [
|
|
3877
|
+
children: instance.title
|
|
3878
|
+
}), instance.breadcrumb === void 0 ? null : /* @__PURE__ */ jsxRuntime.jsx(index.BreadcrumbTail, {
|
|
3879
|
+
segments: [ instance.breadcrumb ]
|
|
1837
3880
|
}),
|
|
1838
3881
|
/* @__PURE__ */ jsxRuntime.jsx(index.StageFace, {
|
|
1839
|
-
title:
|
|
3882
|
+
title: instance.stageTitle
|
|
1840
3883
|
}) ]
|
|
1841
3884
|
})
|
|
1842
3885
|
}),
|
|
@@ -1846,7 +3889,7 @@ function InstanceBand({band: band, bands: bands, instanceDefaultOpen: instanceDe
|
|
|
1846
3889
|
paddingLeft: 5,
|
|
1847
3890
|
children: /* @__PURE__ */ jsxRuntime.jsx(TaskRows, {
|
|
1848
3891
|
onOpenTask: onOpenTask,
|
|
1849
|
-
rows:
|
|
3892
|
+
rows: instance.rows,
|
|
1850
3893
|
showTerminalActions: showTerminalActions
|
|
1851
3894
|
})
|
|
1852
3895
|
})
|
|
@@ -1880,40 +3923,19 @@ function TaskActivityRow({row: row, onOpen: onOpen, showTerminalActions: showTer
|
|
|
1880
3923
|
dateControl: /* @__PURE__ */ jsxRuntime.jsx(ActivityDateControl, {
|
|
1881
3924
|
dates: render.dates,
|
|
1882
3925
|
instanceId: row.instanceId,
|
|
1883
|
-
state: render.dateState
|
|
3926
|
+
state: render.dateState,
|
|
3927
|
+
surface: "tool-task-list"
|
|
1884
3928
|
}),
|
|
1885
3929
|
face: render.face,
|
|
1886
3930
|
instanceId: row.instanceId,
|
|
1887
3931
|
onOpen: onOpen,
|
|
3932
|
+
surface: "tool-task-list",
|
|
1888
3933
|
terminalActions: showTerminalActions ? render.terminalActions : []
|
|
1889
3934
|
})
|
|
1890
3935
|
})
|
|
1891
3936
|
});
|
|
1892
3937
|
}
|
|
1893
3938
|
|
|
1894
|
-
function useBandOpenState(args) {
|
|
1895
|
-
const {segment: segment, scope: scope} = args, store = react.useMemo(() => createBandStateStore({
|
|
1896
|
-
storageKey: bandStateStorageKey(scope)
|
|
1897
|
-
}), [ scope ]), [held, setHeld] = react.useState(() => ({
|
|
1898
|
-
store: store,
|
|
1899
|
-
toggles: store.read()
|
|
1900
|
-
}));
|
|
1901
|
-
held.store !== store && setHeld({
|
|
1902
|
-
store: store,
|
|
1903
|
-
toggles: store.read()
|
|
1904
|
-
});
|
|
1905
|
-
const qualify = key => `${segment}/${key}`, isOpen = (key, defaultOpen) => held.toggles.get(qualify(key)) ?? defaultOpen;
|
|
1906
|
-
return {
|
|
1907
|
-
isOpen: isOpen,
|
|
1908
|
-
toggle: (key, defaultOpen) => {
|
|
1909
|
-
setHeld({
|
|
1910
|
-
store: store,
|
|
1911
|
-
toggles: store.setOpen(qualify(key), !isOpen(key, defaultOpen))
|
|
1912
|
-
});
|
|
1913
|
-
}
|
|
1914
|
-
};
|
|
1915
|
-
}
|
|
1916
|
-
|
|
1917
3939
|
const NO_MISSING = /* @__PURE__ */ new Set;
|
|
1918
3940
|
|
|
1919
3941
|
function sameIdSet(a, b) {
|
|
@@ -1946,28 +3968,6 @@ function useOrphanedWorkflows(groups) {
|
|
|
1946
3968
|
}), [ groups, contentResource, missing ]);
|
|
1947
3969
|
}
|
|
1948
3970
|
|
|
1949
|
-
const INSTANCE_CAP = 200, NEWEST_INSTANCES = {
|
|
1950
|
-
includeCompleted: !0,
|
|
1951
|
-
limit: INSTANCE_CAP
|
|
1952
|
-
};
|
|
1953
|
-
|
|
1954
|
-
function useToolInstances() {
|
|
1955
|
-
const {engine: engine} = index.useWorkflowContext(), {instances: instances, loading: loading, unreadable: unreadable} = workflowStudio.useWorkflowInstances({
|
|
1956
|
-
engine: engine,
|
|
1957
|
-
filter: NEWEST_INSTANCES
|
|
1958
|
-
});
|
|
1959
|
-
return react.useMemo(() => {
|
|
1960
|
-
const rows = instances ?? [];
|
|
1961
|
-
return {
|
|
1962
|
-
inFlight: rows.filter(instance => workflowEngine.terminalState(instance) === "in-flight"),
|
|
1963
|
-
settled: rows.filter(instance => workflowEngine.terminalState(instance) !== "in-flight"),
|
|
1964
|
-
truncated: rows.length + unreadable.length === INSTANCE_CAP,
|
|
1965
|
-
loading: loading,
|
|
1966
|
-
unreadable: unreadable
|
|
1967
|
-
};
|
|
1968
|
-
}, [ instances, loading, unreadable ]);
|
|
1969
|
-
}
|
|
1970
|
-
|
|
1971
3971
|
function TasksTab({filterSlot: filterSlot, instances: instances, loading: loading, identity: identity, onOpenTask: onOpenTask, onOpenWorkflow: onOpenWorkflow, segment: segment, truncated: truncated, unreadable: unreadable}) {
|
|
1972
3972
|
const mineOnly = segment === "for-me", {binding: binding} = index.useWorkflowContext(), bands = useBandOpenState({
|
|
1973
3973
|
segment: segment,
|
|
@@ -1975,21 +3975,38 @@ function TasksTab({filterSlot: filterSlot, instances: instances, loading: loadin
|
|
|
1975
3975
|
}), [filters, setFilters] = react.useState({}), groups = react.useMemo(() => deriveTaskGroups({
|
|
1976
3976
|
instances: instances,
|
|
1977
3977
|
identity: identity
|
|
1978
|
-
}), [ instances, identity ]), orphans = useOrphanedWorkflows(groups), listed = react.useMemo(() => hideOrphanedGroups(groups, orphans.groupKeys), [ groups, orphans.groupKeys ]), options = react.useMemo(() => taskFilterOptions(listed), [ listed ]),
|
|
3978
|
+
}), [ instances, identity ]), orphans = useOrphanedWorkflows(groups), listed = react.useMemo(() => hideOrphanedGroups(groups, orphans.groupKeys), [ groups, orphans.groupKeys ]), options = react.useMemo(() => taskFilterOptions(listed), [ listed ]), titles = useGroupTitles(listed), revealed = useRevealGate({
|
|
3979
|
+
loading: loading,
|
|
3980
|
+
ready: titles.ready
|
|
3981
|
+
}), visible = react.useMemo(() => {
|
|
1979
3982
|
const filtered = applyTaskFilters({
|
|
1980
3983
|
groups: listed,
|
|
1981
3984
|
filters: filters,
|
|
1982
3985
|
now: /* @__PURE__ */ new Date
|
|
1983
|
-
});
|
|
1984
|
-
return
|
|
1985
|
-
}, [ listed, filters, mineOnly ]);
|
|
1986
|
-
|
|
1987
|
-
|
|
1988
|
-
paddingLeft: 2,
|
|
3986
|
+
}), cut = mineOnly ? onlyMyTasks(filtered) : filtered;
|
|
3987
|
+
return orderGroupsByPreviewTitle(cut, titles.titles);
|
|
3988
|
+
}, [ listed, filters, mineOnly, titles ]);
|
|
3989
|
+
if (loading || !revealed) /* @__PURE__ */
|
|
3990
|
+
return jsxRuntime.jsx(TabStatusRow, {
|
|
1989
3991
|
children: /* @__PURE__ */ jsxRuntime.jsx(index.LoadingRow, {
|
|
1990
3992
|
label: "Loading tasks…"
|
|
1991
3993
|
})
|
|
1992
|
-
})
|
|
3994
|
+
});
|
|
3995
|
+
const empty = visible.withDocuments.length === 0 && visible.withoutDocuments.length === 0;
|
|
3996
|
+
let body;
|
|
3997
|
+
return empty ? mineOnly ? body = /* @__PURE__ */ jsxRuntime.jsx(index.ForMeEmptyState, {}) : body = /* @__PURE__ */ jsxRuntime.jsx(index.EmptyState, {
|
|
3998
|
+
description: "Adjust the filters, or start a workflow",
|
|
3999
|
+
icon: /* @__PURE__ */ jsxRuntime.jsx(Search.SearchIcon, {}),
|
|
4000
|
+
title: "No tasks match"
|
|
4001
|
+
}) : body = /* @__PURE__ */ jsxRuntime.jsx(TaskGroupList, {
|
|
4002
|
+
bands: bands,
|
|
4003
|
+
groups: visible,
|
|
4004
|
+
onOpenTask: onOpenTask,
|
|
4005
|
+
onOpenWorkflow: onOpenWorkflow,
|
|
4006
|
+
showTerminalActions: mineOnly
|
|
4007
|
+
}), /* @__PURE__ */ jsxRuntime.jsxs(ui.Flex, {
|
|
4008
|
+
direction: "column",
|
|
4009
|
+
flex: 1,
|
|
1993
4010
|
children: [
|
|
1994
4011
|
/* @__PURE__ */ jsxRuntime.jsx(FilterRowPortal, {
|
|
1995
4012
|
filters: filters,
|
|
@@ -1997,91 +4014,133 @@ function TasksTab({filterSlot: filterSlot, instances: instances, loading: loadin
|
|
|
1997
4014
|
options: options,
|
|
1998
4015
|
slot: filterSlot
|
|
1999
4016
|
}),
|
|
2000
|
-
/* @__PURE__ */ jsxRuntime.jsxs(ui.
|
|
4017
|
+
/* @__PURE__ */ jsxRuntime.jsxs(ui.Flex, {
|
|
4018
|
+
direction: "column",
|
|
4019
|
+
flex: 1,
|
|
2001
4020
|
gap: 2,
|
|
4021
|
+
paddingBottom: 4,
|
|
2002
4022
|
children: [
|
|
2003
4023
|
/* @__PURE__ */ jsxRuntime.jsx(index.UnreadableDocsNote, {
|
|
2004
4024
|
unreadable: unreadable
|
|
2005
4025
|
}),
|
|
2006
4026
|
/* @__PURE__ */ jsxRuntime.jsx(OrphanedWorkflowsNote, {
|
|
2007
4027
|
orphans: orphans
|
|
2008
|
-
}),
|
|
2009
|
-
|
|
2010
|
-
|
|
2011
|
-
|
|
2012
|
-
instanceDefaultOpen: instanceBandDefaultOpen(segment),
|
|
2013
|
-
onOpenTask: onOpenTask,
|
|
2014
|
-
onOpenWorkflow: onOpenWorkflow,
|
|
2015
|
-
showTerminalActions: mineOnly
|
|
2016
|
-
}) ]
|
|
2017
|
-
}), truncated ? /* @__PURE__ */ jsxRuntime.jsx(MutedNote, {
|
|
2018
|
-
text: `Tasks from the latest ${INSTANCE_CAP} workflows — older ones aren't listed.`
|
|
2019
|
-
}) : null ]
|
|
4028
|
+
}), body, truncated ? /* @__PURE__ */ jsxRuntime.jsx(MutedNote, {
|
|
4029
|
+
text: `Tasks from the latest ${INSTANCE_CAP} workflows — older ones aren’t listed.`
|
|
4030
|
+
}) : null ]
|
|
4031
|
+
}) ]
|
|
2020
4032
|
});
|
|
2021
4033
|
}
|
|
2022
4034
|
|
|
2023
|
-
const
|
|
2024
|
-
|
|
2025
|
-
|
|
2026
|
-
|
|
2027
|
-
|
|
2028
|
-
|
|
2029
|
-
|
|
4035
|
+
const TOOL_TAB_LABELS = {
|
|
4036
|
+
definitions: "Definitions",
|
|
4037
|
+
documents: "Documents",
|
|
4038
|
+
tasks: "Tasks",
|
|
4039
|
+
"for-me": "For me"
|
|
4040
|
+
}, TOOL_TAB_VALUES = Object.keys(TOOL_TAB_LABELS), TOOL_TABS = TOOL_TAB_VALUES.map(value => ({
|
|
4041
|
+
value: value,
|
|
4042
|
+
label: TOOL_TAB_LABELS[value]
|
|
4043
|
+
})), DEFAULT_TOOL_TAB = "definitions";
|
|
4044
|
+
|
|
4045
|
+
function toolTabState(tab) {
|
|
4046
|
+
return tab === DEFAULT_TOOL_TAB ? {} : {
|
|
4047
|
+
workflowsTab: tab
|
|
4048
|
+
};
|
|
4049
|
+
}
|
|
2030
4050
|
|
|
2031
|
-
function
|
|
2032
|
-
const router$1 = router.useRouter(), params = Object.fromEntries(router$1.state._searchParams ?? []);
|
|
4051
|
+
function boardState(definitionName) {
|
|
2033
4052
|
return {
|
|
2034
|
-
|
|
2035
|
-
setTab: next => router$1.navigate({
|
|
2036
|
-
_searchParams: definedEntries(TOOL_TAB_CODEC.write(params, next))
|
|
2037
|
-
})
|
|
4053
|
+
boardDefinition: definitionName
|
|
2038
4054
|
};
|
|
2039
4055
|
}
|
|
2040
4056
|
|
|
2041
|
-
function
|
|
2042
|
-
return
|
|
4057
|
+
function tabSelectionNavigates(route, tab) {
|
|
4058
|
+
return !(route.kind === "home" && tab === route.tab);
|
|
4059
|
+
}
|
|
4060
|
+
|
|
4061
|
+
function backToAllLabel(tab) {
|
|
4062
|
+
return `Back to all ${TOOL_TAB_LABELS[tab].toLowerCase()}`;
|
|
2043
4063
|
}
|
|
2044
4064
|
|
|
2045
|
-
function
|
|
2046
|
-
|
|
2047
|
-
|
|
2048
|
-
|
|
4065
|
+
function toolRoute(state) {
|
|
4066
|
+
const {instanceId: instanceId, definitionName: definitionName, boardDefinition: boardDefinition} = state;
|
|
4067
|
+
if (typeof instanceId == "string") return {
|
|
4068
|
+
kind: "instance",
|
|
4069
|
+
instanceId: instanceId,
|
|
4070
|
+
tab: "tasks"
|
|
4071
|
+
};
|
|
4072
|
+
if (typeof definitionName == "string") return {
|
|
4073
|
+
kind: "definition",
|
|
4074
|
+
definitionName: definitionName,
|
|
4075
|
+
tab: "definitions"
|
|
4076
|
+
};
|
|
4077
|
+
if (typeof boardDefinition == "string") return {
|
|
4078
|
+
kind: "home",
|
|
4079
|
+
tab: "documents",
|
|
4080
|
+
boardDefinition: boardDefinition
|
|
4081
|
+
};
|
|
4082
|
+
const tab = index.pathSegmentTab({
|
|
4083
|
+
segment: state.workflowsTab,
|
|
4084
|
+
tabs: TOOL_TAB_VALUES,
|
|
4085
|
+
fallback: DEFAULT_TOOL_TAB
|
|
4086
|
+
});
|
|
4087
|
+
return tab === void 0 ? {
|
|
4088
|
+
kind: "not-found",
|
|
4089
|
+
tab: void 0
|
|
4090
|
+
} : {
|
|
4091
|
+
kind: "home",
|
|
4092
|
+
tab: tab,
|
|
4093
|
+
boardDefinition: void 0
|
|
2049
4094
|
};
|
|
2050
4095
|
}
|
|
2051
4096
|
|
|
4097
|
+
function InstanceStreamKeepAlive() {
|
|
4098
|
+
return useToolInstances(), null;
|
|
4099
|
+
}
|
|
4100
|
+
|
|
2052
4101
|
function WorkflowsToolRoot() {
|
|
2053
|
-
const router$1 = router.useRouter(), {seedInstance: seedInstance} = index.useWorkflowContext(),
|
|
2054
|
-
|
|
2055
|
-
|
|
4102
|
+
const router$1 = router.useRouter(), {seedInstance: seedInstance} = index.useWorkflowContext(), telemetry = workflowReact.useWorkflowTelemetry(), [filterSlot, setFilterSlot] = react.useState(null), route = toolRoute(router$1.state), isHome = route.kind === "home" || route.kind === "not-found", [instanceStreamLatched, setInstanceStreamLatched] = react.useState(isHome);
|
|
4103
|
+
react.useEffect(() => {
|
|
4104
|
+
isHome && setInstanceStreamLatched(!0);
|
|
4105
|
+
}, [ isHome ]);
|
|
4106
|
+
const setTab = next => router$1.navigate(toolTabState(next)), selectBoardWorkflow = react.useCallback((name, opts) => router$1.navigate(boardState(name), opts?.replace === !0 ? {
|
|
4107
|
+
replace: !0
|
|
4108
|
+
} : {}), [ router$1 ]), backToList = tab => ({
|
|
4109
|
+
label: backToAllLabel(tab),
|
|
4110
|
+
go: () => setTab(tab)
|
|
4111
|
+
}), badSegment = route.kind === "not-found";
|
|
4112
|
+
react.useEffect(() => {
|
|
4113
|
+
badSegment && router$1.navigate({}, {
|
|
4114
|
+
replace: !0
|
|
4115
|
+
});
|
|
4116
|
+
}, [ badSegment, router$1 ]), index.useLogEventOnMount(index.WorkflowToolOpened, {
|
|
4117
|
+
tab: route.tab ?? "not-found",
|
|
2056
4118
|
via: "open"
|
|
2057
4119
|
});
|
|
2058
|
-
|
|
2059
|
-
return
|
|
2060
|
-
instanceId: instanceId,
|
|
2061
|
-
|
|
2062
|
-
}, instanceId) : /* @__PURE__ */ jsxRuntime.jsx(
|
|
4120
|
+
let panel;
|
|
4121
|
+
return route.kind === "instance" ? panel = /* @__PURE__ */ jsxRuntime.jsx(WorkflowInstanceDetail, {
|
|
4122
|
+
instanceId: route.instanceId,
|
|
4123
|
+
backToList: backToList(route.tab)
|
|
4124
|
+
}, route.instanceId) : route.kind === "definition" ? panel = /* @__PURE__ */ jsxRuntime.jsx(DefinitionDetail, {
|
|
4125
|
+
definitionName: route.definitionName,
|
|
4126
|
+
backToList: backToList(route.tab)
|
|
4127
|
+
}, route.definitionName) : route.kind === "not-found" ? panel = null : panel = /* @__PURE__ */ jsxRuntime.jsx(WorkflowsHome, {
|
|
4128
|
+
boardDefinition: route.boardDefinition,
|
|
4129
|
+
filterSlot: filterSlot,
|
|
4130
|
+
onOpenDefinition: name => router$1.navigate({
|
|
4131
|
+
definitionName: name
|
|
4132
|
+
}),
|
|
2063
4133
|
onOpenInstance: instance => {
|
|
2064
|
-
typeof instance != "string" && seedInstance(instance), router$1.navigate(
|
|
4134
|
+
typeof instance != "string" && seedInstance(instance), router$1.navigate({
|
|
2065
4135
|
instanceId: typeof instance == "string" ? instance : instance._id
|
|
2066
|
-
}
|
|
2067
|
-
}
|
|
2068
|
-
|
|
2069
|
-
|
|
2070
|
-
|
|
2071
|
-
function WorkflowsHome({onOpenInstance: onOpenInstance}) {
|
|
2072
|
-
const {tab: tab, setTab: setTab} = useToolTab(), telemetry = workflowReact.useWorkflowTelemetry(), instances = useToolInstances(), identity = index.useAssignmentIdentity(), [openTask, setOpenTask] = react.useState(null), openInstance = target => {
|
|
2073
|
-
if (typeof target != "string") return onOpenInstance(target);
|
|
2074
|
-
const held = [ ...instances.inFlight, ...instances.settled ].find(i => i._id === target);
|
|
2075
|
-
onOpenInstance(held ?? target);
|
|
2076
|
-
}, [filterSlot, setFilterSlot] = react.useState(null), scrollerRef = react.useRef(null);
|
|
2077
|
-
return react.useEffect(() => {
|
|
2078
|
-
scrollerRef.current?.scrollTo({
|
|
2079
|
-
top: 0
|
|
2080
|
-
});
|
|
2081
|
-
}, [ tab ]),
|
|
4136
|
+
});
|
|
4137
|
+
},
|
|
4138
|
+
onSelectWorkflow: selectBoardWorkflow,
|
|
4139
|
+
tab: route.tab
|
|
4140
|
+
}),
|
|
2082
4141
|
/* @__PURE__ */ jsxRuntime.jsxs(ui.Card, {
|
|
2083
4142
|
height: "fill",
|
|
2084
|
-
children: [
|
|
4143
|
+
children: [ instanceStreamLatched ? /* @__PURE__ */ jsxRuntime.jsx(InstanceStreamKeepAlive, {}) : null,
|
|
2085
4144
|
/* @__PURE__ */ jsxRuntime.jsxs(ui.Flex, {
|
|
2086
4145
|
direction: "column",
|
|
2087
4146
|
height: "fill",
|
|
@@ -2090,75 +4149,103 @@ function WorkflowsHome({onOpenInstance: onOpenInstance}) {
|
|
|
2090
4149
|
/* @__PURE__ */ jsxRuntime.jsx(ui.Box, {
|
|
2091
4150
|
flex: "none",
|
|
2092
4151
|
padding: 3,
|
|
2093
|
-
children: /* @__PURE__ */ jsxRuntime.
|
|
2094
|
-
|
|
2095
|
-
children:
|
|
4152
|
+
children: /* @__PURE__ */ jsxRuntime.jsxs(ui.Stack, {
|
|
4153
|
+
gap: 3,
|
|
4154
|
+
children: [
|
|
4155
|
+
/* @__PURE__ */ jsxRuntime.jsxs(ui.Flex, {
|
|
4156
|
+
align: "center",
|
|
2096
4157
|
gap: 3,
|
|
4158
|
+
paddingLeft: 2,
|
|
2097
4159
|
children: [
|
|
2098
|
-
/* @__PURE__ */ jsxRuntime.
|
|
2099
|
-
|
|
2100
|
-
|
|
2101
|
-
|
|
2102
|
-
children: [
|
|
2103
|
-
/* @__PURE__ */ jsxRuntime.jsx(ui.Text, {
|
|
2104
|
-
size: 2,
|
|
2105
|
-
weight: "semibold",
|
|
2106
|
-
children: "Workflows"
|
|
2107
|
-
}),
|
|
2108
|
-
/* @__PURE__ */ jsxRuntime.jsx(ui.Box, {
|
|
2109
|
-
flex: 1
|
|
2110
|
-
}),
|
|
2111
|
-
/* @__PURE__ */ jsxRuntime.jsx(NewWorkflowButton, {}) ]
|
|
4160
|
+
/* @__PURE__ */ jsxRuntime.jsx(ui.Text, {
|
|
4161
|
+
size: 1,
|
|
4162
|
+
weight: "semibold",
|
|
4163
|
+
children: "Workflows"
|
|
2112
4164
|
}),
|
|
2113
|
-
/* @__PURE__ */ jsxRuntime.jsx(
|
|
2114
|
-
|
|
2115
|
-
idPrefix: "workflows-tool-tab",
|
|
2116
|
-
onSelect: next => {
|
|
2117
|
-
next !== tab && telemetry.log(index.WorkflowToolOpened, {
|
|
2118
|
-
tab: next,
|
|
2119
|
-
via: "tab-switch"
|
|
2120
|
-
}), setTab(next);
|
|
2121
|
-
},
|
|
2122
|
-
options: TOOL_TABS,
|
|
2123
|
-
selected: tab
|
|
4165
|
+
/* @__PURE__ */ jsxRuntime.jsx(ui.Box, {
|
|
4166
|
+
flex: 1
|
|
2124
4167
|
}),
|
|
2125
|
-
/* @__PURE__ */ jsxRuntime.jsx(
|
|
2126
|
-
|
|
2127
|
-
|
|
2128
|
-
|
|
4168
|
+
/* @__PURE__ */ jsxRuntime.jsx(NewWorkflowButton, {}) ]
|
|
4169
|
+
}),
|
|
4170
|
+
/* @__PURE__ */ jsxRuntime.jsx(index.TabSwitch, {
|
|
4171
|
+
ariaControls: "workflows-tool-panel",
|
|
4172
|
+
idPrefix: "workflows-tool-tab",
|
|
4173
|
+
onSelect: next => {
|
|
4174
|
+
tabSelectionNavigates(route, next) && (next !== route.tab && telemetry.log(index.WorkflowToolOpened, {
|
|
4175
|
+
tab: next,
|
|
4176
|
+
via: "tab-switch"
|
|
4177
|
+
}), setTab(next));
|
|
4178
|
+
},
|
|
4179
|
+
options: TOOL_TABS,
|
|
4180
|
+
selected: route.tab
|
|
4181
|
+
}),
|
|
4182
|
+
/* @__PURE__ */ jsxRuntime.jsx("div", {
|
|
4183
|
+
ref: setFilterSlot
|
|
4184
|
+
}) ]
|
|
2129
4185
|
})
|
|
2130
4186
|
}),
|
|
2131
4187
|
/* @__PURE__ */ jsxRuntime.jsx(ui.Box, {
|
|
2132
|
-
ref: scrollerRef,
|
|
2133
4188
|
flex: 1,
|
|
2134
|
-
overflow: "
|
|
2135
|
-
|
|
4189
|
+
overflow: "hidden",
|
|
4190
|
+
children: panel
|
|
4191
|
+
}) ]
|
|
4192
|
+
}) ]
|
|
4193
|
+
});
|
|
4194
|
+
}
|
|
4195
|
+
|
|
4196
|
+
function WorkflowsHome({boardDefinition: boardDefinition, filterSlot: filterSlot, onOpenDefinition: onOpenDefinition, onOpenInstance: onOpenInstance, onSelectWorkflow: onSelectWorkflow, tab: tab}) {
|
|
4197
|
+
const instances = useToolInstances(), identity = index.useAssignmentIdentity(), [openTask, setOpenTask] = react.useState(null), openInstance = target => {
|
|
4198
|
+
if (typeof target != "string") return onOpenInstance(target);
|
|
4199
|
+
const held = [ ...instances.inFlight, ...instances.settled ].find(i => i._id === target);
|
|
4200
|
+
onOpenInstance(held ?? target);
|
|
4201
|
+
}, scrollerRef = react.useRef(null);
|
|
4202
|
+
react.useEffect(() => {
|
|
4203
|
+
scrollerRef.current?.scrollTo({
|
|
4204
|
+
top: 0
|
|
4205
|
+
});
|
|
4206
|
+
}, [ tab ]);
|
|
4207
|
+
const bleeds = tab === "documents";
|
|
4208
|
+
/* @__PURE__ */
|
|
4209
|
+
return jsxRuntime.jsxs(ui.Flex, {
|
|
4210
|
+
direction: "column",
|
|
4211
|
+
height: "fill",
|
|
4212
|
+
overflow: "hidden",
|
|
4213
|
+
children: [
|
|
4214
|
+
/* @__PURE__ */ jsxRuntime.jsx(ui.Box, {
|
|
4215
|
+
ref: scrollerRef,
|
|
4216
|
+
flex: 1,
|
|
4217
|
+
overflow: "auto",
|
|
4218
|
+
paddingX: bleeds ? 0 : TOOL_PANEL_PADDING,
|
|
4219
|
+
style: {
|
|
4220
|
+
scrollbarGutter: bleeds ? "auto" : "stable"
|
|
4221
|
+
},
|
|
4222
|
+
children: /* @__PURE__ */ jsxRuntime.jsx(ui.TabPanel, {
|
|
4223
|
+
"aria-labelledby": `workflows-tool-tab-${tab}`,
|
|
4224
|
+
id: "workflows-tool-panel",
|
|
2136
4225
|
style: {
|
|
2137
|
-
|
|
4226
|
+
display: "flex",
|
|
4227
|
+
flexDirection: "column",
|
|
4228
|
+
minHeight: "100%"
|
|
2138
4229
|
},
|
|
2139
|
-
children: /* @__PURE__ */ jsxRuntime.jsx(ui.
|
|
2140
|
-
|
|
2141
|
-
|
|
2142
|
-
|
|
2143
|
-
|
|
2144
|
-
|
|
2145
|
-
|
|
2146
|
-
|
|
2147
|
-
|
|
2148
|
-
|
|
2149
|
-
|
|
2150
|
-
|
|
2151
|
-
|
|
2152
|
-
|
|
2153
|
-
|
|
2154
|
-
|
|
2155
|
-
truncated: instances.truncated,
|
|
2156
|
-
unreadable: instances.unreadable
|
|
2157
|
-
})
|
|
2158
|
-
})
|
|
4230
|
+
children: /* @__PURE__ */ jsxRuntime.jsx(ui.Flex, {
|
|
4231
|
+
direction: "column",
|
|
4232
|
+
flex: 1,
|
|
4233
|
+
style: {
|
|
4234
|
+
minHeight: 0
|
|
4235
|
+
},
|
|
4236
|
+
children: /* @__PURE__ */ jsxRuntime.jsx(HomePanel, {
|
|
4237
|
+
boardDefinition: boardDefinition,
|
|
4238
|
+
filterSlot: filterSlot,
|
|
4239
|
+
identity: identity,
|
|
4240
|
+
instances: instances,
|
|
4241
|
+
onOpenDefinition: onOpenDefinition,
|
|
4242
|
+
onOpenTask: setOpenTask,
|
|
4243
|
+
onOpenWorkflow: openInstance,
|
|
4244
|
+
onSelectWorkflow: onSelectWorkflow,
|
|
4245
|
+
tab: tab
|
|
2159
4246
|
})
|
|
2160
4247
|
})
|
|
2161
|
-
})
|
|
4248
|
+
})
|
|
2162
4249
|
}), openTask ? /* @__PURE__ */ jsxRuntime.jsx(ToolActivityDialog, {
|
|
2163
4250
|
onClose: () => setOpenTask(null),
|
|
2164
4251
|
target: openTask
|
|
@@ -2166,4 +4253,25 @@ function WorkflowsHome({onOpenInstance: onOpenInstance}) {
|
|
|
2166
4253
|
});
|
|
2167
4254
|
}
|
|
2168
4255
|
|
|
4256
|
+
function HomePanel({boardDefinition: boardDefinition, filterSlot: filterSlot, identity: identity, instances: instances, onOpenDefinition: onOpenDefinition, onOpenTask: onOpenTask, onOpenWorkflow: onOpenWorkflow, onSelectWorkflow: onSelectWorkflow, tab: tab}) {
|
|
4257
|
+
return tab === "definitions" ? /* @__PURE__ */ jsxRuntime.jsx(DefinitionsTab, {
|
|
4258
|
+
onOpenDefinition: onOpenDefinition
|
|
4259
|
+
}) : tab === "documents" ? /* @__PURE__ */ jsxRuntime.jsx(DocumentsTab, {
|
|
4260
|
+
filterSlot: filterSlot,
|
|
4261
|
+
onOpenDefinition: onOpenDefinition,
|
|
4262
|
+
onSelectWorkflow: onSelectWorkflow,
|
|
4263
|
+
routeDefinition: boardDefinition
|
|
4264
|
+
}) : /* @__PURE__ */ jsxRuntime.jsx(TasksTab, {
|
|
4265
|
+
filterSlot: filterSlot,
|
|
4266
|
+
identity: identity,
|
|
4267
|
+
instances: [ ...instances.inFlight, ...instances.settled ],
|
|
4268
|
+
loading: instances.loading,
|
|
4269
|
+
onOpenTask: onOpenTask,
|
|
4270
|
+
onOpenWorkflow: onOpenWorkflow,
|
|
4271
|
+
segment: tab,
|
|
4272
|
+
truncated: instances.truncated,
|
|
4273
|
+
unreadable: instances.unreadable
|
|
4274
|
+
});
|
|
4275
|
+
}
|
|
4276
|
+
|
|
2169
4277
|
exports.default = WorkflowsToolRoot;
|