@nocobase/plugin-workflow 2.3.0-alpha.1 → 2.3.0-beta.3

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.
Files changed (77) hide show
  1. package/dist/client/438.255c1f798203a3fc.js +10 -0
  2. package/dist/client/509.280de53e5e3e8874.js +10 -0
  3. package/dist/client/{67.56a3d15a55ab7d5c.js → 67.92c849b5dbe07c33.js} +1 -1
  4. package/dist/client/728.e54be200a2eaac45.js +10 -0
  5. package/dist/client/828.eda52a8918f0a56c.js +10 -0
  6. package/dist/client/WorkflowTasks.d.ts +5 -4
  7. package/dist/client/index.d.ts +1 -1
  8. package/dist/client/index.js +1 -1
  9. package/dist/client-v2/32.f7a2f5b51aac18b6.js +10 -0
  10. package/dist/client-v2/438.76337ed02ad35e77.js +10 -0
  11. package/dist/client-v2/513.028d9992cc415e73.js +10 -0
  12. package/dist/client-v2/677.687ffa76229d7e48.js +10 -0
  13. package/dist/client-v2/canvas/WorkflowVariableInput.d.ts +8 -1
  14. package/dist/client-v2/canvas/WorkflowVariableTextArea.d.ts +5 -0
  15. package/dist/client-v2/constants.d.ts +4 -0
  16. package/dist/client-v2/index.js +1 -1
  17. package/dist/client-v2/taskCenter.d.ts +3 -1
  18. package/dist/common/collections/jobs.js +2 -2
  19. package/dist/common/collections/userWorkflowTaskStats.d.ts +54 -0
  20. package/dist/common/collections/userWorkflowTaskStats.js +87 -0
  21. package/dist/externalVersion.js +14 -14
  22. package/dist/locale/de-DE.json +2 -0
  23. package/dist/locale/en-US.json +6 -0
  24. package/dist/locale/es-ES.json +2 -0
  25. package/dist/locale/fr-FR.json +2 -0
  26. package/dist/locale/hu-HU.json +2 -0
  27. package/dist/locale/id-ID.json +2 -0
  28. package/dist/locale/it-IT.json +2 -0
  29. package/dist/locale/ja-JP.json +2 -0
  30. package/dist/locale/ko-KR.json +2 -0
  31. package/dist/locale/nl-NL.json +2 -0
  32. package/dist/locale/pt-BR.json +2 -0
  33. package/dist/locale/ru-RU.json +2 -0
  34. package/dist/locale/tr-TR.json +2 -0
  35. package/dist/locale/uk-UA.json +2 -0
  36. package/dist/locale/vi-VN.json +2 -0
  37. package/dist/locale/zh-CN.json +6 -0
  38. package/dist/locale/zh-TW.json +2 -0
  39. package/dist/node_modules/cron-parser/package.json +1 -1
  40. package/dist/node_modules/joi/package.json +1 -1
  41. package/dist/node_modules/lru-cache/package.json +1 -1
  42. package/dist/node_modules/nodejs-snowflake/package.json +1 -1
  43. package/dist/server/Dispatcher.d.ts +24 -13
  44. package/dist/server/Dispatcher.js +160 -143
  45. package/dist/server/Plugin.d.ts +58 -12
  46. package/dist/server/Plugin.js +356 -16
  47. package/dist/server/Processor.d.ts +2 -7
  48. package/dist/server/Processor.js +37 -18
  49. package/dist/server/RunningExecutionRegistry.d.ts +2 -2
  50. package/dist/server/RunningExecutionRegistry.js +21 -6
  51. package/dist/server/actions/executions.js +3 -6
  52. package/dist/server/actions/index.js +3 -1
  53. package/dist/server/actions/jobs.js +1 -2
  54. package/dist/server/{migrations/20260713000000-remove-workflow-validation.d.ts → actions/userWorkflowTaskStats.d.ts} +2 -5
  55. package/dist/server/actions/userWorkflowTaskStats.js +112 -0
  56. package/dist/server/actions/workflows.js +18 -1
  57. package/dist/server/collections/userWorkflowTaskStats.d.ts +11 -0
  58. package/dist/server/collections/userWorkflowTaskStats.js +43 -0
  59. package/dist/server/index.d.ts +1 -0
  60. package/dist/server/types/Execution.d.ts +2 -0
  61. package/dist/server/types/Job.d.ts +6 -0
  62. package/dist/server/utils.d.ts +1 -0
  63. package/dist/server/utils.js +5 -0
  64. package/dist/shared/WorkflowTaskNavigation.d.ts +56 -0
  65. package/dist/shared/WorkflowTaskNavigation.js +742 -0
  66. package/dist/swagger/index.d.ts +68 -1
  67. package/dist/swagger/index.js +61 -1
  68. package/package.json +2 -2
  69. package/dist/client/438.6c6409d821d8c353.js +0 -10
  70. package/dist/client/509.88792f5bd054b2af.js +0 -10
  71. package/dist/client/728.711fd4f1ed7d4e6a.js +0 -10
  72. package/dist/client/828.6880ab21513b1968.js +0 -10
  73. package/dist/client-v2/438.b7df0416b66f8f64.js +0 -10
  74. package/dist/client-v2/513.617697f74783a611.js +0 -10
  75. package/dist/client-v2/677.7382807126d9621a.js +0 -10
  76. package/dist/client-v2/728.4e8322ff8fce87b9.js +0 -10
  77. package/dist/server/migrations/20260713000000-remove-workflow-validation.js +0 -56
@@ -0,0 +1,742 @@
1
+ /**
2
+ * This file is part of the NocoBase (R) project.
3
+ * Copyright (c) 2020-2024 NocoBase Co., Ltd.
4
+ * Authors: NocoBase Team.
5
+ *
6
+ * This project is dual-licensed under AGPL-3.0 and NocoBase Commercial License.
7
+ * For more information, please refer to: https://www.nocobase.com/agreement.
8
+ */
9
+
10
+ var __create = Object.create;
11
+ var __defProp = Object.defineProperty;
12
+ var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
13
+ var __getOwnPropNames = Object.getOwnPropertyNames;
14
+ var __getProtoOf = Object.getPrototypeOf;
15
+ var __hasOwnProp = Object.prototype.hasOwnProperty;
16
+ var __export = (target, all) => {
17
+ for (var name in all)
18
+ __defProp(target, name, { get: all[name], enumerable: true });
19
+ };
20
+ var __copyProps = (to, from, except, desc) => {
21
+ if (from && typeof from === "object" || typeof from === "function") {
22
+ for (let key of __getOwnPropNames(from))
23
+ if (!__hasOwnProp.call(to, key) && key !== except)
24
+ __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
25
+ }
26
+ return to;
27
+ };
28
+ var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps(
29
+ // If the importer is in node compatibility mode or this is not an ESM
30
+ // file that has been converted to a CommonJS file using a Babel-
31
+ // compatible transform (i.e. "__esModule" has not been set), then set
32
+ // "default" to the CommonJS "module.exports" for node compatibility.
33
+ isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", { value: mod, enumerable: true }) : target,
34
+ mod
35
+ ));
36
+ var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
37
+ var WorkflowTaskNavigation_exports = {};
38
+ __export(WorkflowTaskNavigation_exports, {
39
+ WorkflowTaskFilterProvider: () => WorkflowTaskFilterProvider,
40
+ WorkflowTaskNavigation: () => WorkflowTaskNavigation,
41
+ useWorkflowTaskFilterContext: () => useWorkflowTaskFilterContext
42
+ });
43
+ module.exports = __toCommonJS(WorkflowTaskNavigation_exports);
44
+ var import_icons = require("@ant-design/icons");
45
+ var import_css = require("@emotion/css");
46
+ var import_antd = require("antd");
47
+ var import_react = __toESM(require("react"));
48
+ const WorkflowTaskFilterContext = (0, import_react.createContext)({
49
+ selectedWorkflow: null,
50
+ selectWorkflow() {
51
+ },
52
+ workflows: [],
53
+ loading: false,
54
+ loadingMore: false,
55
+ hasNext: false,
56
+ error: false,
57
+ search: "",
58
+ setSearch() {
59
+ },
60
+ loadMore() {
61
+ },
62
+ reload() {
63
+ }
64
+ });
65
+ function useWorkflowTaskFilterContext() {
66
+ return (0, import_react.useContext)(WorkflowTaskFilterContext);
67
+ }
68
+ const WORKFLOW_TASK_STATS_PAGE_SIZE = 200;
69
+ function isRecord(value) {
70
+ return Boolean(value) && typeof value === "object" && !Array.isArray(value);
71
+ }
72
+ function normalizeWorkflowTaskStatsResponse(response) {
73
+ const responseData = isRecord(response) ? response.data : void 0;
74
+ const payload = isRecord(responseData) ? responseData : void 0;
75
+ const rows = Array.isArray(responseData) ? responseData : payload == null ? void 0 : payload.data;
76
+ const meta = isRecord(payload == null ? void 0 : payload.meta) ? payload.meta : void 0;
77
+ return {
78
+ rows: Array.isArray(rows) ? rows.filter(
79
+ (item) => isRecord(item) && typeof item.workflowKey === "string" && typeof item.title === "string" && isRecord(item.stats)
80
+ ) : [],
81
+ hasNext: (meta == null ? void 0 : meta.hasNext) === true
82
+ };
83
+ }
84
+ function WorkflowTaskFilterProvider(props) {
85
+ const { children, eventBus, loadWorkflowTaskStats, typeKey } = props;
86
+ const [workflowSelection, setWorkflowSelection] = (0, import_react.useState)(null);
87
+ const [workflows, setWorkflows] = (0, import_react.useState)([]);
88
+ const [page, setPage] = (0, import_react.useState)(1);
89
+ const [hasNext, setHasNext] = (0, import_react.useState)(false);
90
+ const [loading, setLoading] = (0, import_react.useState)(false);
91
+ const [loadingMore, setLoadingMore] = (0, import_react.useState)(false);
92
+ const [error, setError] = (0, import_react.useState)(false);
93
+ const [search, setSearch] = (0, import_react.useState)("");
94
+ const requestIdRef = (0, import_react.useRef)(0);
95
+ const previousTypeKeyRef = (0, import_react.useRef)(typeKey);
96
+ const selectedWorkflow = (workflowSelection == null ? void 0 : workflowSelection.typeKey) === typeKey ? workflowSelection.workflow : null;
97
+ const selectWorkflow = (0, import_react.useCallback)(
98
+ (workflow) => {
99
+ setWorkflowSelection(workflow && typeKey ? { typeKey, workflow } : null);
100
+ },
101
+ [typeKey]
102
+ );
103
+ const loadPage = (0, import_react.useCallback)(
104
+ async (nextPage, append) => {
105
+ if (!typeKey) {
106
+ setWorkflows([]);
107
+ setHasNext(false);
108
+ return;
109
+ }
110
+ const requestId = ++requestIdRef.current;
111
+ if (append) {
112
+ setLoadingMore(true);
113
+ } else {
114
+ setLoading(true);
115
+ setHasNext(false);
116
+ }
117
+ setError(false);
118
+ try {
119
+ const response = await loadWorkflowTaskStats({
120
+ type: typeKey,
121
+ page: nextPage,
122
+ pageSize: WORKFLOW_TASK_STATS_PAGE_SIZE,
123
+ ...search ? { search } : {}
124
+ });
125
+ if (requestId !== requestIdRef.current) {
126
+ return;
127
+ }
128
+ const result = normalizeWorkflowTaskStatsResponse(response);
129
+ setWorkflowSelection((selection) => {
130
+ if (!selection || selection.typeKey !== typeKey) {
131
+ return selection;
132
+ }
133
+ const workflow = result.rows.find((item) => item.workflowKey === selection.workflow.workflowKey);
134
+ return workflow ? { ...selection, workflow } : selection;
135
+ });
136
+ setWorkflows((previous) => {
137
+ if (!append) {
138
+ return result.rows;
139
+ }
140
+ const merged = new Map(previous.map((item) => [item.workflowKey, item]));
141
+ result.rows.forEach((item) => merged.set(item.workflowKey, item));
142
+ return Array.from(merged.values());
143
+ });
144
+ setPage(nextPage);
145
+ setHasNext(result.hasNext);
146
+ } catch (loadError) {
147
+ if (requestId === requestIdRef.current) {
148
+ setError(true);
149
+ console.error("Failed to load workflow task stats", loadError);
150
+ }
151
+ } finally {
152
+ if (requestId === requestIdRef.current) {
153
+ setLoading(false);
154
+ setLoadingMore(false);
155
+ }
156
+ }
157
+ },
158
+ [loadWorkflowTaskStats, search, typeKey]
159
+ );
160
+ const reload = (0, import_react.useCallback)(() => {
161
+ loadPage(1, false);
162
+ }, [loadPage]);
163
+ const loadMore = (0, import_react.useCallback)(() => {
164
+ if (!hasNext || loading || loadingMore) {
165
+ return;
166
+ }
167
+ loadPage(page + 1, true);
168
+ }, [hasNext, loadPage, loading, loadingMore, page]);
169
+ (0, import_react.useEffect)(() => {
170
+ if (previousTypeKeyRef.current === typeKey) {
171
+ return;
172
+ }
173
+ previousTypeKeyRef.current = typeKey;
174
+ requestIdRef.current += 1;
175
+ setWorkflowSelection(null);
176
+ setWorkflows([]);
177
+ setPage(1);
178
+ setHasNext(false);
179
+ setSearch("");
180
+ }, [typeKey]);
181
+ (0, import_react.useEffect)(() => {
182
+ reload();
183
+ }, [reload]);
184
+ (0, import_react.useEffect)(() => {
185
+ if (!eventBus) {
186
+ return;
187
+ }
188
+ let timer;
189
+ const onTaskUpdate = (event) => {
190
+ if (!("detail" in event) || !isRecord(event.detail)) {
191
+ return;
192
+ }
193
+ const detail = event.detail;
194
+ if (detail.type !== typeKey) {
195
+ return;
196
+ }
197
+ if (timer) {
198
+ clearTimeout(timer);
199
+ }
200
+ timer = setTimeout(reload, 300);
201
+ };
202
+ eventBus.addEventListener("ws:message:workflow:tasks:updated", onTaskUpdate);
203
+ return () => {
204
+ if (timer) {
205
+ clearTimeout(timer);
206
+ }
207
+ eventBus.removeEventListener("ws:message:workflow:tasks:updated", onTaskUpdate);
208
+ };
209
+ }, [eventBus, reload, typeKey]);
210
+ const value = (0, import_react.useMemo)(
211
+ () => ({
212
+ selectedWorkflow,
213
+ selectWorkflow,
214
+ workflows,
215
+ loading,
216
+ loadingMore,
217
+ hasNext,
218
+ error,
219
+ search,
220
+ setSearch,
221
+ loadMore,
222
+ reload
223
+ }),
224
+ [error, hasNext, loadMore, loading, loadingMore, reload, search, selectWorkflow, selectedWorkflow, workflows]
225
+ );
226
+ return /* @__PURE__ */ import_react.default.createElement(WorkflowTaskFilterContext.Provider, { value }, children);
227
+ }
228
+ function NavigationItemLabel({ count, title }) {
229
+ const { token } = import_antd.theme.useToken();
230
+ return /* @__PURE__ */ import_react.default.createElement(
231
+ "span",
232
+ {
233
+ className: import_css.css`
234
+ display: flex;
235
+ gap: ${token.marginXS}px;
236
+ align-items: center;
237
+ justify-content: space-between;
238
+ width: 100%;
239
+ min-width: 0;
240
+
241
+ > span:first-child {
242
+ flex: 1;
243
+ min-width: 0;
244
+ overflow: hidden;
245
+ text-overflow: ellipsis;
246
+ white-space: nowrap;
247
+ }
248
+
249
+ > .ant-badge {
250
+ flex: none;
251
+ }
252
+ `
253
+ },
254
+ /* @__PURE__ */ import_react.default.createElement("span", null, title),
255
+ /* @__PURE__ */ import_react.default.createElement(import_antd.Badge, { count, size: "small" })
256
+ );
257
+ }
258
+ function WorkflowItemLabel({ title, count }) {
259
+ const { token } = import_antd.theme.useToken();
260
+ return /* @__PURE__ */ import_react.default.createElement(
261
+ "span",
262
+ {
263
+ className: import_css.css`
264
+ display: flex;
265
+ gap: ${token.marginXS}px;
266
+ align-items: center;
267
+ justify-content: space-between;
268
+ width: 100%;
269
+ min-width: 0;
270
+
271
+ > span:first-child {
272
+ flex: 1;
273
+ min-width: 0;
274
+ overflow: hidden;
275
+ text-overflow: ellipsis;
276
+ white-space: nowrap;
277
+ }
278
+ `
279
+ },
280
+ /* @__PURE__ */ import_react.default.createElement("span", null, title),
281
+ /* @__PURE__ */ import_react.default.createElement(
282
+ "span",
283
+ {
284
+ className: import_css.css`
285
+ flex: none;
286
+ color: ${token.colorTextTertiary};
287
+ font-size: ${token.fontSizeSM}px;
288
+ font-variant-numeric: tabular-nums;
289
+ `
290
+ },
291
+ count
292
+ )
293
+ );
294
+ }
295
+ function AllWorkflowsLabel(props) {
296
+ const { search, searchValue, setSearchValue, setSearch, t } = props;
297
+ const { token } = import_antd.theme.useToken();
298
+ const [searchExpanded, setSearchExpanded] = (0, import_react.useState)(Boolean(search));
299
+ const [searchFocused, setSearchFocused] = (0, import_react.useState)(false);
300
+ const searchInputRef = (0, import_react.useRef)(null);
301
+ const focusAfterExpandRef = (0, import_react.useRef)(false);
302
+ const isComposingRef = (0, import_react.useRef)(false);
303
+ const suppressSubmitRef = (0, import_react.useRef)(false);
304
+ (0, import_react.useEffect)(() => {
305
+ if (search) {
306
+ setSearchExpanded(true);
307
+ }
308
+ }, [search]);
309
+ (0, import_react.useEffect)(() => {
310
+ var _a;
311
+ if (searchExpanded && focusAfterExpandRef.current) {
312
+ focusAfterExpandRef.current = false;
313
+ (_a = searchInputRef.current) == null ? void 0 : _a.focus();
314
+ }
315
+ }, [searchExpanded]);
316
+ const expandSearchWithFocus = (0, import_react.useCallback)(() => {
317
+ focusAfterExpandRef.current = true;
318
+ setSearchExpanded(true);
319
+ }, []);
320
+ const collapseSearch = (0, import_react.useCallback)(() => {
321
+ if (!searchFocused && !searchValue) {
322
+ setSearchExpanded(false);
323
+ }
324
+ }, [searchFocused, searchValue]);
325
+ return /* @__PURE__ */ import_react.default.createElement(
326
+ "div",
327
+ {
328
+ onMouseLeave: collapseSearch,
329
+ className: import_css.css`
330
+ display: flex;
331
+ align-items: center;
332
+ width: 100%;
333
+ height: ${token.controlHeight}px;
334
+ `
335
+ },
336
+ searchExpanded ? /* @__PURE__ */ import_react.default.createElement(
337
+ "form",
338
+ {
339
+ onMouseDown: (event) => event.stopPropagation(),
340
+ onClick: (event) => event.stopPropagation(),
341
+ onSubmit: (event) => {
342
+ event.preventDefault();
343
+ event.stopPropagation();
344
+ if (isComposingRef.current || suppressSubmitRef.current) {
345
+ suppressSubmitRef.current = false;
346
+ return;
347
+ }
348
+ setSearch(searchValue.trim());
349
+ },
350
+ className: import_css.css`
351
+ width: 100%;
352
+ `
353
+ },
354
+ /* @__PURE__ */ import_react.default.createElement(
355
+ import_antd.Input,
356
+ {
357
+ ref: searchInputRef,
358
+ allowClear: true,
359
+ size: "small",
360
+ value: searchValue,
361
+ placeholder: t("Search workflows"),
362
+ "aria-label": t("Search workflows"),
363
+ onCompositionStart: () => {
364
+ isComposingRef.current = true;
365
+ },
366
+ onCompositionEnd: () => {
367
+ isComposingRef.current = false;
368
+ },
369
+ onFocus: () => setSearchFocused(true),
370
+ onBlur: () => {
371
+ setSearchFocused(false);
372
+ if (!searchValue) {
373
+ setSearchExpanded(false);
374
+ }
375
+ },
376
+ onChange: (event) => {
377
+ const value = event.target.value;
378
+ setSearchValue(value);
379
+ if (!value && search) {
380
+ setSearch("");
381
+ }
382
+ },
383
+ onKeyDown: (event) => {
384
+ event.stopPropagation();
385
+ if (event.key === "Enter") {
386
+ suppressSubmitRef.current = event.nativeEvent.isComposing || isComposingRef.current;
387
+ }
388
+ if (event.key === "Escape") {
389
+ setSearchValue("");
390
+ setSearch("");
391
+ setSearchExpanded(false);
392
+ }
393
+ }
394
+ }
395
+ )
396
+ ) : /* @__PURE__ */ import_react.default.createElement(import_react.default.Fragment, null, /* @__PURE__ */ import_react.default.createElement(
397
+ "span",
398
+ {
399
+ className: import_css.css`
400
+ flex: 1;
401
+ min-width: 0;
402
+ overflow: hidden;
403
+ text-overflow: ellipsis;
404
+ white-space: nowrap;
405
+ `
406
+ },
407
+ t("All workflows")
408
+ ), /* @__PURE__ */ import_react.default.createElement(
409
+ "button",
410
+ {
411
+ type: "button",
412
+ "aria-label": t("Search workflows"),
413
+ onMouseDown: (event) => event.stopPropagation(),
414
+ onClick: (event) => {
415
+ event.stopPropagation();
416
+ expandSearchWithFocus();
417
+ },
418
+ onMouseEnter: () => setSearchExpanded(true),
419
+ onFocus: expandSearchWithFocus,
420
+ className: import_css.css`
421
+ display: inline-flex;
422
+ flex: none;
423
+ align-items: center;
424
+ justify-content: flex-end;
425
+ width: ${token.controlHeightSM}px;
426
+ height: ${token.controlHeightSM}px;
427
+ padding: 0;
428
+ color: ${token.colorTextSecondary};
429
+ cursor: pointer;
430
+ background: transparent;
431
+ border: 0;
432
+ border-radius: ${token.borderRadiusSM}px;
433
+
434
+ &:hover,
435
+ &:focus-visible {
436
+ color: ${token.colorPrimary};
437
+ }
438
+
439
+ &:focus-visible {
440
+ outline: ${token.lineWidthFocus}px solid ${token.colorPrimaryBorder};
441
+ outline-offset: -${token.lineWidthFocus}px;
442
+ }
443
+ `
444
+ },
445
+ /* @__PURE__ */ import_react.default.createElement(import_icons.SearchOutlined, null)
446
+ ))
447
+ );
448
+ }
449
+ function WorkflowTaskNavigationMenu(props) {
450
+ const { currentTypeKey, onTaskTypeSelect, onWorkflowSelect, taskTypes, t } = props;
451
+ const { token } = import_antd.theme.useToken();
452
+ const {
453
+ selectedWorkflow,
454
+ selectWorkflow,
455
+ workflows,
456
+ loading,
457
+ loadingMore,
458
+ hasNext,
459
+ error,
460
+ search,
461
+ setSearch,
462
+ loadMore,
463
+ reload
464
+ } = useWorkflowTaskFilterContext();
465
+ const [searchValue, setSearchValue] = (0, import_react.useState)(search);
466
+ const typeMenuKey = currentTypeKey ? `type:${currentTypeKey}` : void 0;
467
+ (0, import_react.useEffect)(() => {
468
+ setSearchValue(search);
469
+ }, [search]);
470
+ const handleWorkflowSelect = (0, import_react.useCallback)(
471
+ (workflow) => {
472
+ selectWorkflow(workflow);
473
+ onWorkflowSelect == null ? void 0 : onWorkflowSelect();
474
+ },
475
+ [onWorkflowSelect, selectWorkflow]
476
+ );
477
+ const handleMenuClick = (0, import_react.useCallback)(
478
+ ({ key }) => {
479
+ if (key === "workflow:all") {
480
+ handleWorkflowSelect(null);
481
+ return;
482
+ }
483
+ if (key === "action:retry") {
484
+ reload();
485
+ return;
486
+ }
487
+ if (key === "action:loadMore") {
488
+ loadMore();
489
+ return;
490
+ }
491
+ if (!key.startsWith("workflow:")) {
492
+ return;
493
+ }
494
+ const workflowKey = key.slice("workflow:".length);
495
+ const workflow = workflows.find((item) => item.workflowKey === workflowKey);
496
+ if (workflow) {
497
+ handleWorkflowSelect(workflow);
498
+ }
499
+ },
500
+ [handleWorkflowSelect, loadMore, reload, workflows]
501
+ );
502
+ const handleOpenChange = (0, import_react.useCallback)(
503
+ (openKeys) => {
504
+ const nextTypeMenuKey = [...openKeys].reverse().find((key) => key.startsWith("type:") && key !== typeMenuKey);
505
+ if (!nextTypeMenuKey) {
506
+ selectWorkflow(null);
507
+ return;
508
+ }
509
+ const nextType = nextTypeMenuKey.slice("type:".length);
510
+ if (nextType !== currentTypeKey) {
511
+ onTaskTypeSelect(nextType);
512
+ }
513
+ },
514
+ [currentTypeKey, onTaskTypeSelect, selectWorkflow, typeMenuKey]
515
+ );
516
+ const workflowMenuItems = [
517
+ {
518
+ key: "workflow:all",
519
+ label: /* @__PURE__ */ import_react.default.createElement(
520
+ AllWorkflowsLabel,
521
+ {
522
+ search,
523
+ searchValue,
524
+ setSearchValue,
525
+ setSearch,
526
+ t
527
+ }
528
+ )
529
+ },
530
+ ...workflows.map((workflow) => ({
531
+ key: `workflow:${workflow.workflowKey}`,
532
+ label: /* @__PURE__ */ import_react.default.createElement(WorkflowItemLabel, { title: workflow.title, count: workflow.stats.pending })
533
+ }))
534
+ ];
535
+ if (loading) {
536
+ workflowMenuItems.push({
537
+ key: "status:loading",
538
+ disabled: true,
539
+ label: /* @__PURE__ */ import_react.default.createElement(import_antd.Flex, { justify: "center" }, /* @__PURE__ */ import_react.default.createElement(import_antd.Spin, { size: "small" }))
540
+ });
541
+ }
542
+ if (error) {
543
+ workflowMenuItems.push({ key: "action:retry", label: /* @__PURE__ */ import_react.default.createElement(import_antd.Flex, { justify: "center" }, t("Retry")) });
544
+ }
545
+ if (hasNext && !error) {
546
+ workflowMenuItems.push({
547
+ key: "action:loadMore",
548
+ disabled: loadingMore,
549
+ label: /* @__PURE__ */ import_react.default.createElement(import_antd.Flex, { justify: "center" }, loadingMore ? /* @__PURE__ */ import_react.default.createElement(import_antd.Spin, { size: "small" }) : t("Load more"))
550
+ });
551
+ }
552
+ return /* @__PURE__ */ import_react.default.createElement(
553
+ import_antd.Menu,
554
+ {
555
+ "data-testid": "workflow-task-navigation-menu",
556
+ mode: "inline",
557
+ inlineIndent: token.padding,
558
+ expandIcon: null,
559
+ openKeys: typeMenuKey ? [typeMenuKey] : [],
560
+ selectedKeys: [selectedWorkflow ? `workflow:${selectedWorkflow.workflowKey}` : "workflow:all"],
561
+ onClick: handleMenuClick,
562
+ onOpenChange: handleOpenChange,
563
+ items: taskTypes.map((type) => ({
564
+ key: `type:${type.key}`,
565
+ label: /* @__PURE__ */ import_react.default.createElement(NavigationItemLabel, { title: type.title, count: type.count }),
566
+ children: type.key === currentTypeKey ? workflowMenuItems : [
567
+ {
568
+ key: `placeholder:${type.key}`,
569
+ disabled: true,
570
+ className: "workflow-task-menu-placeholder",
571
+ label: null
572
+ }
573
+ ]
574
+ })),
575
+ className: import_css.css`
576
+ display: flex;
577
+ flex-direction: column;
578
+ height: 100%;
579
+ min-height: 0;
580
+ overflow: hidden;
581
+ background: ${token.colorBgContainer};
582
+ border-inline-end: 0 !important;
583
+
584
+ > .ant-menu-submenu {
585
+ flex: none;
586
+ min-height: 0;
587
+ }
588
+
589
+ > .ant-menu-submenu-open {
590
+ display: flex;
591
+ flex: 0 1 auto;
592
+ flex-direction: column;
593
+ min-height: ${token.controlHeightLG + token.marginXXS * 2}px;
594
+ overflow: hidden;
595
+ }
596
+
597
+ > .ant-menu-submenu-open > .ant-menu-submenu-title {
598
+ flex: none;
599
+ }
600
+
601
+ > .ant-menu-submenu-open > .ant-menu-sub.ant-menu-inline {
602
+ flex: 1;
603
+ min-height: 0;
604
+ overflow-x: hidden;
605
+ overflow-y: auto;
606
+ overscroll-behavior: contain;
607
+ }
608
+
609
+ .ant-menu-sub.ant-menu-inline {
610
+ width: calc(100% - ${token.marginXXS * 2}px);
611
+ margin-inline: ${token.marginXXS}px;
612
+ padding-block: ${token.paddingXXS}px;
613
+ background: ${token.colorFillTertiary} !important;
614
+ border-radius: ${token.borderRadius}px;
615
+ }
616
+
617
+ .ant-menu-submenu-title {
618
+ padding-inline-end: ${token.padding}px;
619
+ }
620
+
621
+ .ant-menu-sub.ant-menu-inline > .ant-menu-item {
622
+ height: ${token.controlHeight}px;
623
+ margin-block: 0;
624
+ line-height: ${token.controlHeight}px;
625
+ }
626
+
627
+ .ant-menu-title-content {
628
+ min-width: 0;
629
+ }
630
+
631
+ .workflow-task-menu-placeholder {
632
+ display: none !important;
633
+ }
634
+ `
635
+ }
636
+ );
637
+ }
638
+ function WorkflowTaskNavigation(props) {
639
+ const { currentTypeKey, mobile, onTaskTypeSelect, taskTypes, t } = props;
640
+ const { selectedWorkflow } = useWorkflowTaskFilterContext();
641
+ const { token } = import_antd.theme.useToken();
642
+ const [open, setOpen] = (0, import_react.useState)(false);
643
+ const currentType = taskTypes.find((type) => type.key === currentTypeKey);
644
+ if (mobile) {
645
+ return /* @__PURE__ */ import_react.default.createElement(
646
+ import_antd.Layout.Header,
647
+ {
648
+ style: {
649
+ background: token.colorBgContainer,
650
+ height: "auto",
651
+ lineHeight: "normal",
652
+ padding: `${token.paddingXXS}px ${token.padding}px`
653
+ }
654
+ },
655
+ /* @__PURE__ */ import_react.default.createElement(
656
+ import_antd.Button,
657
+ {
658
+ block: true,
659
+ type: "text",
660
+ "aria-expanded": open,
661
+ "aria-label": t("Select workflow"),
662
+ onClick: () => setOpen(true),
663
+ className: import_css.css`
664
+ height: ${token.controlHeight}px;
665
+ padding-inline: ${token.paddingSM}px;
666
+ background: ${token.colorFillAlter};
667
+ border: 0;
668
+
669
+ &:hover,
670
+ &:focus-visible {
671
+ background: ${token.colorFillSecondary} !important;
672
+ }
673
+ `
674
+ },
675
+ /* @__PURE__ */ import_react.default.createElement(import_antd.Flex, { align: "center", justify: "space-between", gap: token.marginXS, style: { minWidth: 0, width: "100%" } }, /* @__PURE__ */ import_react.default.createElement(import_antd.Flex, { align: "center", gap: token.marginXXS, style: { minWidth: 0 } }, /* @__PURE__ */ import_react.default.createElement("span", null, currentType == null ? void 0 : currentType.title), selectedWorkflow ? /* @__PURE__ */ import_react.default.createElement(import_react.default.Fragment, null, /* @__PURE__ */ import_react.default.createElement(import_icons.RightOutlined, { "aria-hidden": true, style: { color: token.colorTextTertiary, flex: "none" } }), /* @__PURE__ */ import_react.default.createElement(
676
+ "span",
677
+ {
678
+ style: {
679
+ overflow: "hidden",
680
+ textOverflow: "ellipsis",
681
+ whiteSpace: "nowrap"
682
+ }
683
+ },
684
+ selectedWorkflow.title
685
+ )) : null), /* @__PURE__ */ import_react.default.createElement(
686
+ import_icons.DownOutlined,
687
+ {
688
+ "aria-hidden": true,
689
+ style: { color: token.colorTextSecondary, flex: "none", marginInlineStart: "auto" }
690
+ }
691
+ ))
692
+ ),
693
+ /* @__PURE__ */ import_react.default.createElement(
694
+ import_antd.Drawer,
695
+ {
696
+ title: t("Workflow tasks"),
697
+ placement: "left",
698
+ open,
699
+ onClose: () => setOpen(false),
700
+ styles: { body: { padding: 0 } }
701
+ },
702
+ /* @__PURE__ */ import_react.default.createElement(
703
+ WorkflowTaskNavigationMenu,
704
+ {
705
+ currentTypeKey,
706
+ onTaskTypeSelect,
707
+ onWorkflowSelect: () => setOpen(false),
708
+ taskTypes,
709
+ t
710
+ }
711
+ )
712
+ )
713
+ );
714
+ }
715
+ return /* @__PURE__ */ import_react.default.createElement(
716
+ import_antd.Layout.Sider,
717
+ {
718
+ theme: "light",
719
+ breakpoint: "md",
720
+ collapsedWidth: 0,
721
+ style: {
722
+ background: token.colorBgContainer,
723
+ borderInlineEnd: `${token.lineWidth}px ${token.lineType} ${token.colorBorderSecondary}`
724
+ }
725
+ },
726
+ /* @__PURE__ */ import_react.default.createElement(
727
+ WorkflowTaskNavigationMenu,
728
+ {
729
+ currentTypeKey,
730
+ onTaskTypeSelect,
731
+ taskTypes,
732
+ t
733
+ }
734
+ )
735
+ );
736
+ }
737
+ // Annotate the CommonJS export names for ESM import in node:
738
+ 0 && (module.exports = {
739
+ WorkflowTaskFilterProvider,
740
+ WorkflowTaskNavigation,
741
+ useWorkflowTaskFilterContext
742
+ });