plugin-cluster-manager 1.1.10 → 1.1.11

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 (54) hide show
  1. package/client.js +1 -0
  2. package/dist/client/Doctor.d.ts +2 -0
  3. package/dist/client/NginxCacheManager.d.ts +2 -0
  4. package/dist/client/index.js +1 -1
  5. package/dist/client/utils/clientSafeCache.d.ts +3 -0
  6. package/dist/client/utils/requestDedupInterceptor.d.ts +2 -0
  7. package/dist/externalVersion.js +5 -5
  8. package/dist/locale/en-US.json +97 -1
  9. package/dist/locale/vi-VN.json +98 -1
  10. package/dist/locale/zh-CN.json +98 -1
  11. package/dist/server/actions/cache-monitor.d.ts +10 -0
  12. package/dist/server/actions/cache-monitor.js +301 -0
  13. package/dist/server/actions/cluster-nodes.d.ts +15 -0
  14. package/dist/server/actions/cluster-nodes.js +394 -10
  15. package/dist/server/actions/doctor.d.ts +82 -0
  16. package/dist/server/actions/doctor.js +1250 -0
  17. package/dist/server/collections/cluster-manager-doctor-runs.d.ts +3 -0
  18. package/dist/server/collections/cluster-manager-doctor-runs.js +52 -0
  19. package/dist/server/collections/cluster-manager-doctor.d.ts +18 -0
  20. package/dist/server/collections/cluster-manager-doctor.js +44 -0
  21. package/dist/server/hooks/cacheInvalidationHooks.d.ts +1 -0
  22. package/dist/server/hooks/cacheInvalidationHooks.js +81 -0
  23. package/dist/server/middlewares/listMetaCacheMiddleware.d.ts +2 -0
  24. package/dist/server/middlewares/listMetaCacheMiddleware.js +79 -0
  25. package/dist/server/orchestrator/PackageManager.js +20 -16
  26. package/dist/server/plugin.js +61 -8
  27. package/dist/server/utils/versionManager.d.ts +10 -0
  28. package/dist/server/utils/versionManager.js +91 -0
  29. package/package.json +41 -41
  30. package/server.js +1 -0
  31. package/src/client/CacheMonitor.tsx +166 -179
  32. package/src/client/ClusterManagerLayout.tsx +48 -42
  33. package/src/client/ClusterNodes.tsx +691 -418
  34. package/src/client/Doctor.tsx +559 -0
  35. package/src/client/NginxCacheManager.tsx +415 -0
  36. package/src/client/PluginOperations.tsx +234 -234
  37. package/src/client/index.tsx +22 -14
  38. package/src/client/utils/clientSafeCache.ts +41 -0
  39. package/src/client/utils/requestDedupInterceptor.ts +213 -0
  40. package/src/locale/en-US.json +97 -1
  41. package/src/locale/vi-VN.json +98 -1
  42. package/src/locale/zh-CN.json +98 -1
  43. package/src/server/__tests__/doctor.test.ts +53 -0
  44. package/src/server/actions/acl-cache.ts +272 -272
  45. package/src/server/actions/cache-monitor.ts +453 -116
  46. package/src/server/actions/cluster-nodes.ts +882 -378
  47. package/src/server/actions/doctor.ts +1540 -0
  48. package/src/server/collections/cluster-manager-doctor-runs.ts +23 -0
  49. package/src/server/collections/cluster-manager-doctor.ts +19 -0
  50. package/src/server/hooks/cacheInvalidationHooks.ts +58 -0
  51. package/src/server/middlewares/listMetaCacheMiddleware.ts +55 -0
  52. package/src/server/orchestrator/PackageManager.ts +19 -15
  53. package/src/server/plugin.ts +338 -263
  54. package/src/server/utils/versionManager.ts +69 -0
@@ -1,179 +1,166 @@
1
- import React, { useState, useEffect, useCallback } from 'react';
2
- import { Card, Table, Tag, Button, Space, Row, Col, Statistic, Tabs, Spin, Popconfirm, message } from 'antd';
3
- import {
4
- ReloadOutlined,
5
- DatabaseOutlined,
6
- DeleteOutlined,
7
- } from '@ant-design/icons';
8
- import { useAPIClient } from '@nocobase/client';
9
- import { AclCacheManager } from './AclCacheManager';
10
- import { RedisMonitor } from './RedisMonitor';
11
- import { LockMonitor } from './LockMonitor';
12
- import { EventQueueMonitor } from './EventQueueMonitor';
13
- import { useT } from './utils';
14
-
15
- export function CacheMonitor() {
16
- const t = useT();
17
- const api = useAPIClient();
18
- const [loading, setLoading] = useState(false);
19
- const [stores, setStores] = useState<any[]>([]);
20
- const [caches, setCaches] = useState<any[]>([]);
21
- const [redisMemory, setRedisMemory] = useState<any>(null);
22
-
23
- const fetchData = useCallback(async () => {
24
- setLoading(true);
25
- try {
26
- const [storesRes, cachesRes, memRes] = await Promise.all([
27
- api.request({ url: 'clusterManagerCacheMgr:stores' }),
28
- api.request({ url: 'clusterManagerCacheMgr:caches' }),
29
- api.request({ url: 'clusterManagerCacheMgr:redisMemory' }),
30
- ]);
31
- setStores(storesRes?.data?.data?.data || []);
32
- setCaches(cachesRes?.data?.data?.data || []);
33
- setRedisMemory(memRes?.data?.data);
34
- } catch {
35
- // Ignore
36
- } finally {
37
- setLoading(false);
38
- }
39
- }, [api]);
40
-
41
- useEffect(() => {
42
- fetchData();
43
- }, [fetchData]);
44
-
45
- const handleFlushAll = async () => {
46
- try {
47
- await api.request({ url: 'clusterManagerCacheMgr:flushAll', method: 'post' });
48
- message.success(t('All caches flushed'));
49
- fetchData();
50
- } catch {
51
- message.error(t('Failed to flush caches'));
52
- }
53
- };
54
-
55
- const storeColumns = [
56
- { title: t('Store Name'), dataIndex: 'name', key: 'name' },
57
- {
58
- title: t('Type'),
59
- dataIndex: 'type',
60
- key: 'type',
61
- width: 120,
62
- render: (v: string) => <Tag color={v === 'redis' ? 'blue' : 'default'}>{v}</Tag>,
63
- },
64
- {
65
- title: t('Default'),
66
- dataIndex: 'isDefault',
67
- key: 'isDefault',
68
- width: 100,
69
- render: (v: boolean) => (v ? <Tag color="green">Yes</Tag> : '-'),
70
- },
71
- ];
72
-
73
- const cacheColumns = [
74
- { title: t('Cache Name'), dataIndex: 'name', key: 'name' },
75
- {
76
- title: t('Prefix'),
77
- dataIndex: 'prefix',
78
- key: 'prefix',
79
- render: (v: string | null) => (v ? <code style={{ fontSize: 11 }}>{v}</code> : '-'),
80
- },
81
- ];
82
-
83
- return (
84
- <Tabs
85
- defaultActiveKey="overview"
86
- items={[
87
- {
88
- key: 'overview',
89
- label: t('Cache Stores'),
90
- children: (
91
- <Spin spinning={loading}>
92
- <Space direction="vertical" style={{ width: '100%' }} size="middle">
93
- <Space>
94
- <Button icon={<ReloadOutlined />} onClick={fetchData}>{t('Refresh')}</Button>
95
- <Popconfirm
96
- title={t('Flush all caches?')}
97
- description={t('This will clear all cached data across all stores.')}
98
- onConfirm={handleFlushAll}
99
- >
100
- <Button danger icon={<DeleteOutlined />}>{t('Flush All')}</Button>
101
- </Popconfirm>
102
- </Space>
103
-
104
- <Row gutter={16}>
105
- <Col span={8}>
106
- <Card size="small">
107
- <Statistic
108
- title={t('Cache Stores')}
109
- value={stores.length}
110
- prefix={<DatabaseOutlined />}
111
- />
112
- </Card>
113
- </Col>
114
- <Col span={8}>
115
- <Card size="small">
116
- <Statistic
117
- title={t('Named Caches')}
118
- value={caches.length}
119
- />
120
- </Card>
121
- </Col>
122
- <Col span={8}>
123
- <Card size="small">
124
- <Statistic
125
- title={t('Redis Keys')}
126
- value={redisMemory?.available ? redisMemory.totalKeys : '-'}
127
- suffix={redisMemory?.available ? `(${redisMemory.usedMemory})` : ''}
128
- />
129
- </Card>
130
- </Col>
131
- </Row>
132
-
133
- <Card title={t('Registered Stores')} size="small">
134
- <Table
135
- dataSource={stores}
136
- columns={storeColumns}
137
- rowKey="name"
138
- size="small"
139
- pagination={false}
140
- />
141
- </Card>
142
-
143
- <Card title={t('Named Caches')} size="small">
144
- <Table
145
- dataSource={caches}
146
- columns={cacheColumns}
147
- rowKey="name"
148
- size="small"
149
- pagination={false}
150
- />
151
- </Card>
152
- </Space>
153
- </Spin>
154
- ),
155
- },
156
- {
157
- key: 'acl',
158
- label: t('ACL Cache'),
159
- children: <AclCacheManager />,
160
- },
161
- {
162
- key: 'redis',
163
- label: t('Redis Monitor'),
164
- children: <RedisMonitor />,
165
- },
166
- {
167
- key: 'locks',
168
- label: t('Locks'),
169
- children: <LockMonitor />,
170
- },
171
- {
172
- key: 'queue',
173
- label: t('Event Queue'),
174
- children: <EventQueueMonitor />,
175
- },
176
- ]}
177
- />
178
- );
179
- }
1
+ import React, { useState, useEffect, useCallback } from 'react';
2
+ import { Card, Table, Tag, Button, Space, Row, Col, Statistic, Tabs, Spin, Popconfirm, message } from 'antd';
3
+ import { ReloadOutlined, DatabaseOutlined, DeleteOutlined } from '@ant-design/icons';
4
+ import { useAPIClient } from '@nocobase/client';
5
+ import { AclCacheManager } from './AclCacheManager';
6
+ import { RedisMonitor } from './RedisMonitor';
7
+ import { LockMonitor } from './LockMonitor';
8
+ import { EventQueueMonitor } from './EventQueueMonitor';
9
+ import { NginxCacheManager } from './NginxCacheManager';
10
+ import { useT } from './utils';
11
+
12
+ export function CacheMonitor() {
13
+ const t = useT();
14
+ const api = useAPIClient();
15
+ const [loading, setLoading] = useState(false);
16
+ const [stores, setStores] = useState<any[]>([]);
17
+ const [caches, setCaches] = useState<any[]>([]);
18
+ const [redisMemory, setRedisMemory] = useState<any>(null);
19
+
20
+ const fetchData = useCallback(async () => {
21
+ setLoading(true);
22
+ try {
23
+ const [storesRes, cachesRes, memRes] = await Promise.all([
24
+ api.request({ url: 'clusterManagerCacheMgr:stores' }),
25
+ api.request({ url: 'clusterManagerCacheMgr:caches' }),
26
+ api.request({ url: 'clusterManagerCacheMgr:redisMemory' }),
27
+ ]);
28
+ setStores(storesRes?.data?.data?.data || []);
29
+ setCaches(cachesRes?.data?.data?.data || []);
30
+ setRedisMemory(memRes?.data?.data);
31
+ } catch {
32
+ // Ignore
33
+ } finally {
34
+ setLoading(false);
35
+ }
36
+ }, [api]);
37
+
38
+ useEffect(() => {
39
+ fetchData();
40
+ }, [fetchData]);
41
+
42
+ const handleFlushAll = async () => {
43
+ try {
44
+ await api.request({ url: 'clusterManagerCacheMgr:flushAll', method: 'post' });
45
+ message.success(t('All caches flushed'));
46
+ fetchData();
47
+ } catch {
48
+ message.error(t('Failed to flush caches'));
49
+ }
50
+ };
51
+
52
+ const storeColumns = [
53
+ { title: t('Store Name'), dataIndex: 'name', key: 'name' },
54
+ {
55
+ title: t('Type'),
56
+ dataIndex: 'type',
57
+ key: 'type',
58
+ width: 120,
59
+ render: (v: string) => <Tag color={v === 'redis' ? 'blue' : 'default'}>{v}</Tag>,
60
+ },
61
+ {
62
+ title: t('Default'),
63
+ dataIndex: 'isDefault',
64
+ key: 'isDefault',
65
+ width: 100,
66
+ render: (v: boolean) => (v ? <Tag color="green">Yes</Tag> : '-'),
67
+ },
68
+ ];
69
+
70
+ const cacheColumns = [
71
+ { title: t('Cache Name'), dataIndex: 'name', key: 'name' },
72
+ {
73
+ title: t('Prefix'),
74
+ dataIndex: 'prefix',
75
+ key: 'prefix',
76
+ render: (v: string | null) => (v ? <code style={{ fontSize: 11 }}>{v}</code> : '-'),
77
+ },
78
+ ];
79
+
80
+ return (
81
+ <Tabs
82
+ defaultActiveKey="overview"
83
+ items={[
84
+ {
85
+ key: 'overview',
86
+ label: t('Cache Stores'),
87
+ children: (
88
+ <Spin spinning={loading}>
89
+ <Space direction="vertical" style={{ width: '100%' }} size="middle">
90
+ <Space>
91
+ <Button icon={<ReloadOutlined />} onClick={fetchData}>
92
+ {t('Refresh')}
93
+ </Button>
94
+ <Popconfirm
95
+ title={t('Flush all caches?')}
96
+ description={t('This will clear all cached data across all stores.')}
97
+ onConfirm={handleFlushAll}
98
+ >
99
+ <Button danger icon={<DeleteOutlined />}>
100
+ {t('Flush All')}
101
+ </Button>
102
+ </Popconfirm>
103
+ </Space>
104
+
105
+ <Row gutter={16}>
106
+ <Col span={8}>
107
+ <Card size="small">
108
+ <Statistic title={t('Cache Stores')} value={stores.length} prefix={<DatabaseOutlined />} />
109
+ </Card>
110
+ </Col>
111
+ <Col span={8}>
112
+ <Card size="small">
113
+ <Statistic title={t('Named Caches')} value={caches.length} />
114
+ </Card>
115
+ </Col>
116
+ <Col span={8}>
117
+ <Card size="small">
118
+ <Statistic
119
+ title={t('Redis Keys')}
120
+ value={redisMemory?.available ? redisMemory.totalKeys : '-'}
121
+ suffix={redisMemory?.available ? `(${redisMemory.usedMemory})` : ''}
122
+ />
123
+ </Card>
124
+ </Col>
125
+ </Row>
126
+
127
+ <Card title={t('Registered Stores')} size="small">
128
+ <Table dataSource={stores} columns={storeColumns} rowKey="name" size="small" pagination={false} />
129
+ </Card>
130
+
131
+ <Card title={t('Named Caches')} size="small">
132
+ <Table dataSource={caches} columns={cacheColumns} rowKey="name" size="small" pagination={false} />
133
+ </Card>
134
+ </Space>
135
+ </Spin>
136
+ ),
137
+ },
138
+ {
139
+ key: 'acl',
140
+ label: t('ACL Cache'),
141
+ children: <AclCacheManager />,
142
+ },
143
+ {
144
+ key: 'redis',
145
+ label: t('Redis Monitor'),
146
+ children: <RedisMonitor />,
147
+ },
148
+ {
149
+ key: 'locks',
150
+ label: t('Locks'),
151
+ children: <LockMonitor />,
152
+ },
153
+ {
154
+ key: 'queue',
155
+ label: t('Event Queue'),
156
+ children: <EventQueueMonitor />,
157
+ },
158
+ {
159
+ key: 'nginx',
160
+ label: t('Nginx Cache'),
161
+ children: <NginxCacheManager />,
162
+ },
163
+ ]}
164
+ />
165
+ );
166
+ }
@@ -1,46 +1,47 @@
1
- import React from 'react';
2
- import { Tabs } from 'antd';
3
- import { TaskManager } from './TaskManager';
4
- import { WorkflowExecutions } from './WorkflowExecutions';
5
- import { ClusterNodes } from './ClusterNodes';
6
- import { CacheMonitor } from './CacheMonitor';
1
+ import React from 'react';
2
+ import { Tabs } from 'antd';
3
+ import { TaskManager } from './TaskManager';
4
+ import { WorkflowExecutions } from './WorkflowExecutions';
5
+ import { ClusterNodes } from './ClusterNodes';
6
+ import { CacheMonitor } from './CacheMonitor';
7
7
  import { ContainerOrchestrator } from './ContainerOrchestrator';
8
8
  import { PackageInstaller } from './PackageInstaller';
9
9
  import { PluginOperations } from './PluginOperations';
10
+ import { Doctor } from './Doctor';
10
11
  import { useT } from './utils';
11
-
12
- export function ClusterManagerLayout() {
13
- const t = useT();
14
- return (
15
- <div style={{ padding: 24 }}>
16
- <Tabs
17
- defaultActiveKey="cluster"
18
- items={[
19
- {
20
- key: 'cluster',
21
- label: t('Cluster Nodes'),
22
- children: <ClusterNodes />,
23
- },
24
- {
25
- key: 'tasks',
26
- label: t('Async Tasks'),
27
- children: <TaskManager />,
28
- },
29
- {
30
- key: 'executions',
31
- label: t('Workflow Executions'),
32
- children: <WorkflowExecutions />,
33
- },
34
- {
35
- key: 'cache',
36
- label: t('Cache Monitor'),
37
- children: <CacheMonitor />,
38
- },
39
- {
40
- key: 'orchestrator',
41
- label: t('Container Orchestrator'),
42
- children: <ContainerOrchestrator />,
43
- },
12
+
13
+ export function ClusterManagerLayout() {
14
+ const t = useT();
15
+ return (
16
+ <div style={{ padding: 24 }}>
17
+ <Tabs
18
+ defaultActiveKey="cluster"
19
+ items={[
20
+ {
21
+ key: 'cluster',
22
+ label: t('Cluster Nodes'),
23
+ children: <ClusterNodes />,
24
+ },
25
+ {
26
+ key: 'tasks',
27
+ label: t('Async Tasks'),
28
+ children: <TaskManager />,
29
+ },
30
+ {
31
+ key: 'executions',
32
+ label: t('Workflow Executions'),
33
+ children: <WorkflowExecutions />,
34
+ },
35
+ {
36
+ key: 'cache',
37
+ label: t('Cache Monitor'),
38
+ children: <CacheMonitor />,
39
+ },
40
+ {
41
+ key: 'orchestrator',
42
+ label: t('Container Orchestrator'),
43
+ children: <ContainerOrchestrator />,
44
+ },
44
45
  {
45
46
  key: 'packages',
46
47
  label: t('Packages'),
@@ -51,8 +52,13 @@ export function ClusterManagerLayout() {
51
52
  label: t('Plugins'),
52
53
  children: <PluginOperations />,
53
54
  },
55
+ {
56
+ key: 'doctor',
57
+ label: t('Doctor'),
58
+ children: <Doctor />,
59
+ },
54
60
  ]}
55
61
  />
56
- </div>
57
- );
58
- }
62
+ </div>
63
+ );
64
+ }