plugin-cluster-manager 1.1.11 → 1.1.15

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 (116) hide show
  1. package/client-v2.d.ts +2 -0
  2. package/client-v2.js +1 -0
  3. package/dist/client/index.js +1 -1
  4. package/dist/client-v2/914.c0bce51908fd81d7.js +10 -0
  5. package/dist/client-v2/index.js +10 -0
  6. package/dist/externalVersion.js +6 -5
  7. package/dist/locale/en-US.json +138 -124
  8. package/dist/locale/vi-VN.json +139 -125
  9. package/dist/locale/zh-CN.json +140 -125
  10. package/dist/server/actions/cluster-nodes.js +2 -6
  11. package/dist/server/actions/doctor.js +1 -5
  12. package/dist/server/actions/orchestrator.js +37 -0
  13. package/dist/server/actions/queue-mappings.js +107 -0
  14. package/dist/server/collections/worker-queue-mappings.js +106 -0
  15. package/dist/server/orchestrator/PackageManager.js +1 -8
  16. package/dist/server/orchestrator/docker-adapter.js +49 -27
  17. package/dist/server/plugin.js +10 -8
  18. package/dist/server/queue-scanner.js +141 -0
  19. package/dist/server/utils/node.js +30 -2
  20. package/package.json +46 -42
  21. package/src/client/AclCacheManager.tsx +292 -287
  22. package/src/client/CacheMonitor.tsx +2 -2
  23. package/src/client/ClusterManagerLayout.tsx +6 -0
  24. package/src/client/ClusterNodes.tsx +11 -4
  25. package/src/client/ContainerOrchestrator.tsx +186 -104
  26. package/src/client/Doctor.tsx +2 -2
  27. package/src/client/EventQueueMonitor.tsx +2 -2
  28. package/src/client/LockMonitor.tsx +2 -2
  29. package/src/client/NginxCacheManager.tsx +2 -2
  30. package/src/client/PackageInstaller.tsx +2 -2
  31. package/src/client/PluginOperations.tsx +2 -2
  32. package/src/client/QueueAssignment.tsx +355 -0
  33. package/src/client/RedisMonitor.tsx +3 -3
  34. package/src/client/TaskManager.tsx +194 -187
  35. package/src/client/WorkflowExecutions.tsx +243 -238
  36. package/src/client/utils.ts +1 -1
  37. package/src/client-v2/plugin.tsx +24 -0
  38. package/src/locale/en-US.json +138 -124
  39. package/src/locale/vi-VN.json +139 -125
  40. package/src/locale/zh-CN.json +140 -125
  41. package/src/server/actions/cluster-nodes.ts +4 -7
  42. package/src/server/actions/doctor.ts +11 -9
  43. package/src/server/actions/orchestrator.ts +54 -2
  44. package/src/server/actions/queue-mappings.ts +94 -0
  45. package/src/server/adapters/redis-node-registry.ts +126 -131
  46. package/src/server/collections/worker-queue-mappings.ts +85 -0
  47. package/src/server/orchestrator/PackageManager.ts +2 -10
  48. package/src/server/orchestrator/docker-adapter.ts +74 -37
  49. package/src/server/plugin.ts +15 -12
  50. package/src/server/queue-scanner.ts +154 -0
  51. package/src/server/utils/node.ts +48 -0
  52. package/dist/client/AclCacheManager.d.ts +0 -2
  53. package/dist/client/CacheMonitor.d.ts +0 -2
  54. package/dist/client/ClusterManagerLayout.d.ts +0 -2
  55. package/dist/client/ClusterNodes.d.ts +0 -2
  56. package/dist/client/ContainerOrchestrator.d.ts +0 -2
  57. package/dist/client/Doctor.d.ts +0 -2
  58. package/dist/client/EventQueueMonitor.d.ts +0 -2
  59. package/dist/client/LockMonitor.d.ts +0 -2
  60. package/dist/client/NginxCacheManager.d.ts +0 -2
  61. package/dist/client/PackageInstaller.d.ts +0 -2
  62. package/dist/client/PluginOperations.d.ts +0 -2
  63. package/dist/client/RedisMonitor.d.ts +0 -2
  64. package/dist/client/TaskManager.d.ts +0 -2
  65. package/dist/client/WorkflowExecutions.d.ts +0 -2
  66. package/dist/client/index.d.ts +0 -5
  67. package/dist/client/utils/clientSafeCache.d.ts +0 -3
  68. package/dist/client/utils/requestDedupInterceptor.d.ts +0 -2
  69. package/dist/client/utils.d.ts +0 -12
  70. package/dist/index.d.ts +0 -2
  71. package/dist/server/actions/acl-cache.d.ts +0 -53
  72. package/dist/server/actions/cache-monitor.d.ts +0 -33
  73. package/dist/server/actions/cluster-nodes.d.ts +0 -64
  74. package/dist/server/actions/doctor.d.ts +0 -82
  75. package/dist/server/actions/event-queue-monitor.d.ts +0 -13
  76. package/dist/server/actions/lock-monitor.d.ts +0 -19
  77. package/dist/server/actions/orchestrator.d.ts +0 -58
  78. package/dist/server/actions/package-manager.d.ts +0 -6
  79. package/dist/server/actions/plugin-operations.d.ts +0 -6
  80. package/dist/server/actions/redis-monitor.d.ts +0 -12
  81. package/dist/server/actions/tasks.d.ts +0 -7
  82. package/dist/server/actions/workflow-executions.d.ts +0 -7
  83. package/dist/server/adapters/redis-lock-adapter.d.ts +0 -15
  84. package/dist/server/adapters/redis-node-registry.d.ts +0 -12
  85. package/dist/server/adapters/redis-pubsub-adapter.d.ts +0 -16
  86. package/dist/server/collections/app.d.ts +0 -8
  87. package/dist/server/collections/cluster-manager-acl-cache.d.ts +0 -22
  88. package/dist/server/collections/cluster-manager-cache-mgr.d.ts +0 -22
  89. package/dist/server/collections/cluster-manager-cluster.d.ts +0 -22
  90. package/dist/server/collections/cluster-manager-doctor-runs.d.ts +0 -3
  91. package/dist/server/collections/cluster-manager-doctor.d.ts +0 -18
  92. package/dist/server/collections/cluster-manager-lock.d.ts +0 -22
  93. package/dist/server/collections/cluster-manager-plugins.d.ts +0 -18
  94. package/dist/server/collections/cluster-manager-queue.d.ts +0 -22
  95. package/dist/server/collections/cluster-manager-redis.d.ts +0 -22
  96. package/dist/server/collections/cluster-manager-workflow.d.ts +0 -22
  97. package/dist/server/collections/cluster-manager.d.ts +0 -22
  98. package/dist/server/collections/orchestrator-settings.d.ts +0 -59
  99. package/dist/server/collections/orchestrator-stacks.d.ts +0 -102
  100. package/dist/server/collections/worker-orchestrator.d.ts +0 -22
  101. package/dist/server/collections/worker-packages-configs.d.ts +0 -3
  102. package/dist/server/collections/worker-packages.d.ts +0 -22
  103. package/dist/server/hooks/cacheInvalidationHooks.d.ts +0 -1
  104. package/dist/server/middlewares/listMetaCacheMiddleware.d.ts +0 -2
  105. package/dist/server/orchestrator/PackageManager.d.ts +0 -39
  106. package/dist/server/orchestrator/docker-adapter.d.ts +0 -41
  107. package/dist/server/orchestrator/index.d.ts +0 -4
  108. package/dist/server/orchestrator/k8s-adapter.d.ts +0 -50
  109. package/dist/server/orchestrator/leader-election.d.ts +0 -48
  110. package/dist/server/orchestrator/types.d.ts +0 -84
  111. package/dist/server/plugin.d.ts +0 -26
  112. package/dist/server/utils/node.d.ts +0 -6
  113. package/dist/server/utils/redis.d.ts +0 -29
  114. package/dist/server/utils/versionManager.d.ts +0 -10
  115. package/dist/shared/packages.d.ts +0 -23
  116. /package/{dist/server/index.d.ts → src/client-v2/index.tsx} +0 -0
@@ -0,0 +1,355 @@
1
+ import React, { useState, useEffect, useCallback } from 'react';
2
+ import {
3
+ Card,
4
+ Table,
5
+ Tag,
6
+ Button,
7
+ Space,
8
+ Select,
9
+ message,
10
+ Modal,
11
+ Typography,
12
+ Alert,
13
+ Switch,
14
+ Popconfirm,
15
+ Row,
16
+ Col,
17
+ Tooltip,
18
+ } from 'antd';
19
+ import {
20
+ ReloadOutlined,
21
+ ScanOutlined,
22
+ BranchesOutlined,
23
+ CheckCircleOutlined,
24
+ CloseCircleOutlined,
25
+ MinusCircleOutlined,
26
+ } from '@ant-design/icons';
27
+ import { useApp } from '@nocobase/client-v2';
28
+ import { useT } from './utils';
29
+
30
+ const { Text } = Typography;
31
+
32
+ interface DiscoveredQueue {
33
+ name: string;
34
+ label: string;
35
+ description: string;
36
+ type: 'event-queue' | 'redis-list';
37
+ pending: number | null;
38
+ }
39
+
40
+ interface RegisteredMapping {
41
+ id: number;
42
+ queueName: string;
43
+ label: string;
44
+ stackId: number | null;
45
+ enabled: boolean;
46
+ type: string;
47
+ }
48
+
49
+ interface StackInfo {
50
+ id: number;
51
+ name: string;
52
+ adapter: string;
53
+ }
54
+
55
+ export function QueueAssignment() {
56
+ const t = useT();
57
+ const api = useApp().apiClient;
58
+ const [loading, setLoading] = useState(false);
59
+ const [scanning, setScanning] = useState(false);
60
+ const [discovered, setDiscovered] = useState<DiscoveredQueue[]>([]);
61
+ const [mappings, setMappings] = useState<RegisteredMapping[]>([]);
62
+ const [unmapped, setUnmapped] = useState<DiscoveredQueue[]>([]);
63
+ const [stacks, setStacks] = useState<StackInfo[]>([]);
64
+
65
+ const fetchStacks = useCallback(async () => {
66
+ try {
67
+ const res = await api.request({ url: '/orchestratorStacks:list', params: { pageSize: 50 } });
68
+ const data = res.data?.data || [];
69
+ setStacks(data);
70
+ } catch {
71
+ // Collection not available
72
+ }
73
+ }, [api]);
74
+
75
+ const fetchMappings = useCallback(async () => {
76
+ try {
77
+ const res = await api.request({ url: '/workerQueueMappings:list', params: { pageSize: 200 } });
78
+ const data = res.data?.data || [];
79
+ setMappings(data);
80
+ } catch {
81
+ // Collection may not exist yet
82
+ }
83
+ }, [api]);
84
+
85
+ const scanQueues = useCallback(async () => {
86
+ setScanning(true);
87
+ try {
88
+ const res = await api.request({ url: '/workerQueueMappings:scanQueues' });
89
+ const data = res.data?.data || res.data;
90
+ setDiscovered(data.discovered || []);
91
+ setMappings(data.registered || []);
92
+ setUnmapped(data.unmapped || []);
93
+ } catch (err: any) {
94
+ message.error(`Scan failed: ${err.message}`);
95
+ } finally {
96
+ setScanning(false);
97
+ }
98
+ }, [api]);
99
+
100
+ const handleAutoMap = async () => {
101
+ setLoading(true);
102
+ try {
103
+ const res = await api.request({
104
+ url: '/workerQueueMappings:autoMap',
105
+ method: 'POST',
106
+ data: {},
107
+ });
108
+ const { created } = res.data?.data || res.data;
109
+ message.success(`Auto-mapped ${created.length} queue(s)`);
110
+ await scanQueues();
111
+ } catch (err: any) {
112
+ message.error(`Auto-map failed: ${err.message}`);
113
+ } finally {
114
+ setLoading(false);
115
+ }
116
+ };
117
+
118
+ const handleUpdateMapping = async (id: number, values: Partial<RegisteredMapping>) => {
119
+ setLoading(true);
120
+ try {
121
+ await api.request({
122
+ url: '/workerQueueMappings:update',
123
+ method: 'PUT',
124
+ params: { filterByTk: id },
125
+ data: values,
126
+ });
127
+ await fetchMappings();
128
+ } catch (err: any) {
129
+ message.error(`Update failed: ${err.message}`);
130
+ } finally {
131
+ setLoading(false);
132
+ }
133
+ };
134
+
135
+ const handleCreateMapping = async (queue: DiscoveredQueue) => {
136
+ setLoading(true);
137
+ try {
138
+ await api.request({
139
+ url: '/workerQueueMappings:create',
140
+ method: 'POST',
141
+ data: {
142
+ queueName: queue.name,
143
+ label: queue.label,
144
+ description: queue.description,
145
+ type: queue.type,
146
+ stackId: null,
147
+ enabled: true,
148
+ },
149
+ });
150
+ message.success(`Mapping created for "${queue.name}"`);
151
+ await scanQueues();
152
+ } catch (err: any) {
153
+ message.error(`Create failed: ${err.message}`);
154
+ } finally {
155
+ setLoading(false);
156
+ }
157
+ };
158
+
159
+ const handleDeleteMapping = async (id: number) => {
160
+ setLoading(true);
161
+ try {
162
+ await api.request({
163
+ url: '/workerQueueMappings:destroy',
164
+ method: 'POST',
165
+ params: { filterByTk: id },
166
+ });
167
+ message.success('Mapping deleted');
168
+ await scanQueues();
169
+ } catch (err: any) {
170
+ message.error(`Delete failed: ${err.message}`);
171
+ } finally {
172
+ setLoading(false);
173
+ }
174
+ };
175
+
176
+ useEffect(() => {
177
+ scanQueues();
178
+ fetchStacks();
179
+ }, [scanQueues, fetchStacks]);
180
+
181
+ const stackOptions = stacks.map((s) => ({
182
+ value: s.id,
183
+ label: s.name,
184
+ }));
185
+
186
+ const mappingMap = new Map(mappings.map((m) => [m.queueName, m]));
187
+
188
+ const allRows = discovered.map((q) => {
189
+ const mapping = mappingMap.get(q.name);
190
+ return {
191
+ key: q.name,
192
+ ...q,
193
+ mappingId: mapping?.id ?? null,
194
+ registered: Boolean(mapping),
195
+ stackId: mapping?.stackId ?? null,
196
+ enabled: mapping?.enabled ?? true,
197
+ };
198
+ });
199
+
200
+ const columns = [
201
+ {
202
+ title: t('Queue Name'),
203
+ dataIndex: 'name',
204
+ render: (name: string, record: any) => (
205
+ <Space>
206
+ {record.type === 'event-queue' ? (
207
+ <BranchesOutlined style={{ color: '#1890ff' }} />
208
+ ) : (
209
+ <MinusCircleOutlined style={{ color: '#52c41a' }} />
210
+ )}
211
+ <Text code>{name}</Text>
212
+ </Space>
213
+ ),
214
+ },
215
+ {
216
+ title: t('Label'),
217
+ dataIndex: 'label',
218
+ render: (label: string) => <Text>{label}</Text>,
219
+ },
220
+ {
221
+ title: t('Type'),
222
+ dataIndex: 'type',
223
+ width: 110,
224
+ render: (type: string) => (
225
+ <Tag color={type === 'event-queue' ? 'blue' : 'green'}>
226
+ {type === 'event-queue' ? 'EventQueue' : 'Redis List'}
227
+ </Tag>
228
+ ),
229
+ },
230
+ {
231
+ title: t('Pending'),
232
+ dataIndex: 'pending',
233
+ width: 80,
234
+ render: (val: number | null) => (val !== null ? <Text>{val}</Text> : <Text type="secondary">-</Text>),
235
+ },
236
+ {
237
+ title: t('Assigned Stack'),
238
+ dataIndex: 'stackId',
239
+ width: 160,
240
+ render: (stackId: number | null, record: any) => {
241
+ if (!record.registered) {
242
+ return <Text type="secondary">—</Text>;
243
+ }
244
+ return (
245
+ <Select
246
+ style={{ width: 150 }}
247
+ size="small"
248
+ allowClear
249
+ placeholder={t('All (default)')}
250
+ value={stackId}
251
+ options={stackOptions}
252
+ onChange={(value) => handleUpdateMapping(record.mappingId, { stackId: value ?? null })}
253
+ />
254
+ );
255
+ },
256
+ },
257
+ {
258
+ title: t('Enabled'),
259
+ dataIndex: 'enabled',
260
+ width: 80,
261
+ render: (enabled: boolean, record: any) => {
262
+ if (!record.registered) {
263
+ return <Text type="secondary">—</Text>;
264
+ }
265
+ return (
266
+ <Switch
267
+ size="small"
268
+ checked={enabled}
269
+ onChange={(checked) => handleUpdateMapping(record.mappingId, { enabled: checked })}
270
+ />
271
+ );
272
+ },
273
+ },
274
+ {
275
+ title: t('Actions'),
276
+ key: 'actions',
277
+ width: 200,
278
+ render: (_: any, record: any) => {
279
+ if (!record.registered) {
280
+ return (
281
+ <Button
282
+ size="small"
283
+ type="link"
284
+ icon={<CheckCircleOutlined style={{ color: '#52c41a' }} />}
285
+ onClick={() => handleCreateMapping(record)}
286
+ >
287
+ {t('Register')}
288
+ </Button>
289
+ );
290
+ }
291
+ return (
292
+ <Popconfirm title={t('Delete this mapping?')} onConfirm={() => handleDeleteMapping(record.mappingId)}>
293
+ <Button size="small" type="link" danger>
294
+ {t('Unregister')}
295
+ </Button>
296
+ </Popconfirm>
297
+ );
298
+ },
299
+ },
300
+ ];
301
+
302
+ return (
303
+ <div>
304
+ <Card size="small" style={{ marginBottom: 16 }}>
305
+ <Row justify="space-between" align="middle">
306
+ <Col>
307
+ <Space>
308
+ <Text strong>{t('Queue Assignment')}</Text>
309
+ <Text type="secondary">{t('Map queues to worker stacks. Unassigned queues run on all workers.')}</Text>
310
+ </Space>
311
+ </Col>
312
+ <Col>
313
+ <Space>
314
+ <Button icon={<ScanOutlined />} onClick={scanQueues} loading={scanning}>
315
+ {t('Scan Queues')}
316
+ </Button>
317
+ {unmapped.length > 0 && (
318
+ <Button onClick={handleAutoMap} loading={loading}>
319
+ {t('Auto-map ({count})', { count: unmapped.length })}
320
+ </Button>
321
+ )}
322
+ <Button
323
+ icon={<ReloadOutlined />}
324
+ onClick={() => {
325
+ scanQueues();
326
+ fetchStacks();
327
+ }}
328
+ >
329
+ {t('Refresh')}
330
+ </Button>
331
+ </Space>
332
+ </Col>
333
+ </Row>
334
+ </Card>
335
+
336
+ {unmapped.length > 0 && (
337
+ <Alert
338
+ type="info"
339
+ showIcon
340
+ style={{ marginBottom: 16 }}
341
+ message={`${unmapped.length} queue(s) discovered but not yet registered. Click "Register" on each row or use "Auto-map" to create mappings.`}
342
+ />
343
+ )}
344
+
345
+ <Table
346
+ dataSource={allRows}
347
+ columns={columns}
348
+ rowKey="key"
349
+ size="small"
350
+ pagination={false}
351
+ locale={{ emptyText: t('No queues discovered. Click "Scan Queues" to detect registered queues.') }}
352
+ />
353
+ </div>
354
+ );
355
+ }
@@ -7,7 +7,7 @@ import {
7
7
  ThunderboltOutlined,
8
8
  FieldTimeOutlined,
9
9
  } from '@ant-design/icons';
10
- import { useAPIClient } from '@nocobase/client';
10
+ import { useApp } from '@nocobase/client-v2';
11
11
  import { formatBytes, formatUptime } from './utils';
12
12
 
13
13
  const { Text } = Typography;
@@ -40,7 +40,7 @@ interface RedisInfo {
40
40
 
41
41
 
42
42
  export function RedisMonitor() {
43
- const api = useAPIClient();
43
+ const api = useApp().apiClient;
44
44
  const [info, setInfo] = useState<RedisInfo | null>(null);
45
45
  const [channels, setChannels] = useState<Record<string, number>>({});
46
46
  const [totalChannels, setTotalChannels] = useState(0);
@@ -306,7 +306,7 @@ export function RedisMonitor() {
306
306
  }
307
307
 
308
308
  function SyncMessagesSection() {
309
- const api = useAPIClient();
309
+ const api = useApp().apiClient;
310
310
  const [data, setData] = useState<any>(null);
311
311
 
312
312
  useEffect(() => {