jettask 0.2.7__py3-none-any.whl → 0.2.8__py3-none-any.whl

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 (66) hide show
  1. jettask/core/cli.py +152 -0
  2. jettask/pg_consumer/sql/add_execution_time_field.sql +29 -0
  3. jettask/pg_consumer/sql/create_new_tables.sql +137 -0
  4. jettask/pg_consumer/sql/create_tables_v3.sql +175 -0
  5. jettask/pg_consumer/sql/migrate_to_new_structure.sql +179 -0
  6. jettask/pg_consumer/sql/modify_time_fields.sql +69 -0
  7. jettask/webui/frontend/package.json +30 -0
  8. jettask/webui/frontend/src/App.css +109 -0
  9. jettask/webui/frontend/src/App.jsx +66 -0
  10. jettask/webui/frontend/src/components/NamespaceSelector.jsx +166 -0
  11. jettask/webui/frontend/src/components/QueueBacklogChart.jsx +298 -0
  12. jettask/webui/frontend/src/components/QueueBacklogTrend.jsx +638 -0
  13. jettask/webui/frontend/src/components/QueueDetailsTable.css +65 -0
  14. jettask/webui/frontend/src/components/QueueDetailsTable.jsx +487 -0
  15. jettask/webui/frontend/src/components/QueueDetailsTableV2.jsx +465 -0
  16. jettask/webui/frontend/src/components/ScheduledTaskFilter.jsx +423 -0
  17. jettask/webui/frontend/src/components/TaskFilter.jsx +425 -0
  18. jettask/webui/frontend/src/components/TimeRangeSelector.css +21 -0
  19. jettask/webui/frontend/src/components/TimeRangeSelector.jsx +160 -0
  20. jettask/webui/frontend/src/components/charts/QueueChart.jsx +111 -0
  21. jettask/webui/frontend/src/components/charts/QueueTrendChart.jsx +115 -0
  22. jettask/webui/frontend/src/components/charts/WorkerChart.jsx +40 -0
  23. jettask/webui/frontend/src/components/common/StatsCard.jsx +18 -0
  24. jettask/webui/frontend/src/components/layout/AppLayout.css +95 -0
  25. jettask/webui/frontend/src/components/layout/AppLayout.jsx +49 -0
  26. jettask/webui/frontend/src/components/layout/Header.css +106 -0
  27. jettask/webui/frontend/src/components/layout/Header.jsx +106 -0
  28. jettask/webui/frontend/src/components/layout/SideMenu.css +137 -0
  29. jettask/webui/frontend/src/components/layout/SideMenu.jsx +209 -0
  30. jettask/webui/frontend/src/components/layout/TabsNav.css +244 -0
  31. jettask/webui/frontend/src/components/layout/TabsNav.jsx +206 -0
  32. jettask/webui/frontend/src/components/layout/UserInfo.css +197 -0
  33. jettask/webui/frontend/src/components/layout/UserInfo.jsx +197 -0
  34. jettask/webui/frontend/src/contexts/LoadingContext.jsx +27 -0
  35. jettask/webui/frontend/src/contexts/NamespaceContext.jsx +72 -0
  36. jettask/webui/frontend/src/contexts/TabsContext.backup.jsx +245 -0
  37. jettask/webui/frontend/src/index.css +114 -0
  38. jettask/webui/frontend/src/main.jsx +20 -0
  39. jettask/webui/frontend/src/pages/Alerts.jsx +684 -0
  40. jettask/webui/frontend/src/pages/Dashboard/index.css +35 -0
  41. jettask/webui/frontend/src/pages/Dashboard/index.jsx +281 -0
  42. jettask/webui/frontend/src/pages/Dashboard.jsx +1330 -0
  43. jettask/webui/frontend/src/pages/QueueDetail.jsx +1117 -0
  44. jettask/webui/frontend/src/pages/QueueMonitor.jsx +527 -0
  45. jettask/webui/frontend/src/pages/Queues.jsx +12 -0
  46. jettask/webui/frontend/src/pages/ScheduledTasks.jsx +809 -0
  47. jettask/webui/frontend/src/pages/Settings.jsx +800 -0
  48. jettask/webui/frontend/src/pages/Workers.jsx +12 -0
  49. jettask/webui/frontend/src/services/api.js +114 -0
  50. jettask/webui/frontend/src/services/queueTrend.js +152 -0
  51. jettask/webui/frontend/src/utils/suppressWarnings.js +22 -0
  52. jettask/webui/frontend/src/utils/userPreferences.js +154 -0
  53. jettask/webui/frontend/vite.config.js +26 -0
  54. {jettask-0.2.7.dist-info → jettask-0.2.8.dist-info}/METADATA +1 -1
  55. {jettask-0.2.7.dist-info → jettask-0.2.8.dist-info}/RECORD +59 -14
  56. jettask/webui/static/dist/assets/index-7129cfe1.css +0 -1
  57. jettask/webui/static/dist/assets/index-8d1935cc.js +0 -774
  58. jettask/webui/static/dist/index.html +0 -15
  59. jettask/webui/static/index.html +0 -1734
  60. jettask/webui/static/queue.html +0 -981
  61. jettask/webui/static/queues.html +0 -549
  62. jettask/webui/static/workers.html +0 -734
  63. {jettask-0.2.7.dist-info → jettask-0.2.8.dist-info}/WHEEL +0 -0
  64. {jettask-0.2.7.dist-info → jettask-0.2.8.dist-info}/entry_points.txt +0 -0
  65. {jettask-0.2.7.dist-info → jettask-0.2.8.dist-info}/licenses/LICENSE +0 -0
  66. {jettask-0.2.7.dist-info → jettask-0.2.8.dist-info}/top_level.txt +0 -0
@@ -0,0 +1,298 @@
1
+ import { useState, useEffect, useCallback } from 'react';
2
+ import { Card, Select, Spin, Empty, Space, Button, message } from 'antd';
3
+ import { Line } from '@ant-design/plots';
4
+ import { ReloadOutlined, ExpandOutlined } from '@ant-design/icons';
5
+ import { useNamespace } from '../contexts/NamespaceContext';
6
+ import dayjs from 'dayjs';
7
+ import axios from 'axios';
8
+
9
+ const { Option } = Select;
10
+
11
+ // 时间范围选项
12
+ const TIME_RANGES = {
13
+ '15m': { label: '15分钟', minutes: 15 },
14
+ '30m': { label: '30分钟', minutes: 30 },
15
+ '1h': { label: '1小时', minutes: 60 },
16
+ '3h': { label: '3小时', minutes: 180 },
17
+ '6h': { label: '6小时', minutes: 360 },
18
+ '12h': { label: '12小时', minutes: 720 },
19
+ '24h': { label: '24小时', minutes: 1440 },
20
+ };
21
+
22
+ function QueueBacklogChart({
23
+ height = 300,
24
+ showTitle = true,
25
+ defaultTimeRange = '1h',
26
+ autoRefresh = true,
27
+ refreshInterval = 60000, // 默认60秒刷新一次
28
+ onExpand = null
29
+ }) {
30
+ const { currentNamespace } = useNamespace();
31
+ const [loading, setLoading] = useState(false);
32
+ const [timeRange, setTimeRange] = useState(defaultTimeRange);
33
+ const [selectedQueues, setSelectedQueues] = useState([]);
34
+ const [availableQueues, setAvailableQueues] = useState([]);
35
+ const [chartData, setChartData] = useState([]);
36
+ const [lastUpdateTime, setLastUpdateTime] = useState(null);
37
+
38
+ // 获取可用队列列表
39
+ const fetchAvailableQueues = useCallback(async () => {
40
+ try {
41
+ const namespace = currentNamespace || 'default';
42
+ const response = await axios.get(`/api/queues/${namespace}`);
43
+ if (response.data.success) {
44
+ const queues = response.data.data.map(q => q.name);
45
+ setAvailableQueues(queues);
46
+
47
+ // 默认选择前5个队列
48
+ if (selectedQueues.length === 0 && queues.length > 0) {
49
+ setSelectedQueues(queues.slice(0, 5));
50
+ }
51
+ }
52
+ } catch (error) {
53
+ console.error('Failed to fetch queues:', error);
54
+ }
55
+ }, [currentNamespace, selectedQueues.length]);
56
+
57
+ // 获取队列积压数据
58
+ const fetchBacklogData = useCallback(async () => {
59
+ if (selectedQueues.length === 0) return;
60
+
61
+ setLoading(true);
62
+ try {
63
+ const namespace = currentNamespace || 'default';
64
+ const endTime = dayjs();
65
+ const startTime = endTime.subtract(TIME_RANGES[timeRange].minutes, 'minute');
66
+
67
+ const params = {
68
+ namespace,
69
+ queues: selectedQueues,
70
+ time_range: timeRange,
71
+ start_time: startTime.toISOString(),
72
+ end_time: endTime.toISOString(),
73
+ filters: [] // 不需要额外筛选
74
+ };
75
+
76
+ // 使用队列流量接口获取积压数据
77
+ const response = await axios.post(`/api/data/queue-flow-rates/${namespace}`, params);
78
+
79
+ if (response.data.success) {
80
+ const { data } = response.data;
81
+
82
+ // 转换数据格式,只保留pending数据作为积压量
83
+ const backlogData = data
84
+ .filter(item => item.metric === 'pending')
85
+ .map(item => ({
86
+ time: dayjs(item.time).format('HH:mm'),
87
+ timestamp: item.time,
88
+ queue: item.queue,
89
+ value: item.value || 0,
90
+ type: '积压量'
91
+ }));
92
+
93
+ setChartData(backlogData);
94
+ setLastUpdateTime(dayjs());
95
+ }
96
+ } catch (error) {
97
+ message.error('获取队列积压数据失败');
98
+ console.error('Failed to fetch backlog data:', error);
99
+ } finally {
100
+ setLoading(false);
101
+ }
102
+ }, [currentNamespace, selectedQueues, timeRange]);
103
+
104
+ // 初始化
105
+ useEffect(() => {
106
+ fetchAvailableQueues();
107
+ }, [fetchAvailableQueues]);
108
+
109
+ // 当选中队列变化时,获取数据
110
+ useEffect(() => {
111
+ if (selectedQueues.length > 0) {
112
+ fetchBacklogData();
113
+ }
114
+ }, [selectedQueues, fetchBacklogData]);
115
+
116
+ // 自动刷新
117
+ useEffect(() => {
118
+ if (!autoRefresh || selectedQueues.length === 0) return;
119
+
120
+ const timer = setInterval(() => {
121
+ fetchBacklogData();
122
+ }, refreshInterval);
123
+
124
+ return () => clearInterval(timer);
125
+ }, [autoRefresh, refreshInterval, fetchBacklogData, selectedQueues.length]);
126
+
127
+ // 图表配置
128
+ const config = {
129
+ data: chartData,
130
+ xField: 'time',
131
+ yField: 'value',
132
+ seriesField: 'queue',
133
+ height: height,
134
+ smooth: true,
135
+ animation: {
136
+ appear: {
137
+ animation: 'wave-in',
138
+ duration: 1000,
139
+ },
140
+ },
141
+ xAxis: {
142
+ title: {
143
+ text: '时间',
144
+ style: { fontSize: 12 },
145
+ },
146
+ label: {
147
+ autoRotate: true,
148
+ autoHide: true,
149
+ },
150
+ },
151
+ yAxis: {
152
+ title: {
153
+ text: '积压任务数',
154
+ style: { fontSize: 12 },
155
+ },
156
+ min: 0,
157
+ nice: true,
158
+ },
159
+ legend: {
160
+ position: 'top-right',
161
+ itemSpacing: 10,
162
+ },
163
+ tooltip: {
164
+ shared: true,
165
+ showCrosshairs: true,
166
+ formatter: (datum) => {
167
+ return {
168
+ name: datum.queue,
169
+ value: `${datum.value.toLocaleString()} 个任务`,
170
+ };
171
+ },
172
+ },
173
+ theme: {
174
+ colors10: [
175
+ '#5B8FF9',
176
+ '#5AD8A6',
177
+ '#5D7092',
178
+ '#F6BD16',
179
+ '#E8684A',
180
+ '#6DC8EC',
181
+ '#9270CA',
182
+ '#FF9D4D',
183
+ '#269A99',
184
+ '#FF99C3',
185
+ ],
186
+ },
187
+ // 添加告警线(可选)
188
+ annotations: [
189
+ {
190
+ type: 'line',
191
+ start: ['min', 1000],
192
+ end: ['max', 1000],
193
+ style: {
194
+ stroke: '#ff9800',
195
+ lineDash: [4, 4],
196
+ lineWidth: 1,
197
+ },
198
+ text: {
199
+ content: '警告线 (1000)',
200
+ position: 'end',
201
+ style: {
202
+ textAlign: 'end',
203
+ fontSize: 10,
204
+ fill: '#ff9800',
205
+ },
206
+ offsetY: -5,
207
+ },
208
+ },
209
+ {
210
+ type: 'line',
211
+ start: ['min', 5000],
212
+ end: ['max', 5000],
213
+ style: {
214
+ stroke: '#f44336',
215
+ lineDash: [4, 4],
216
+ lineWidth: 1,
217
+ },
218
+ text: {
219
+ content: '危险线 (5000)',
220
+ position: 'end',
221
+ style: {
222
+ textAlign: 'end',
223
+ fontSize: 10,
224
+ fill: '#f44336',
225
+ },
226
+ offsetY: -5,
227
+ },
228
+ },
229
+ ],
230
+ };
231
+
232
+ return (
233
+ <Card
234
+ title={showTitle ? "队列积压趋势" : null}
235
+ size="small"
236
+ extra={
237
+ <Space>
238
+ {lastUpdateTime && (
239
+ <span style={{ fontSize: 12, color: '#999' }}>
240
+ 更新于 {lastUpdateTime.format('HH:mm:ss')}
241
+ </span>
242
+ )}
243
+ <Select
244
+ value={timeRange}
245
+ onChange={setTimeRange}
246
+ style={{ width: 100 }}
247
+ size="small"
248
+ >
249
+ {Object.entries(TIME_RANGES).map(([key, { label }]) => (
250
+ <Option key={key} value={key}>{label}</Option>
251
+ ))}
252
+ </Select>
253
+ <Select
254
+ mode="multiple"
255
+ placeholder="选择队列"
256
+ value={selectedQueues}
257
+ onChange={setSelectedQueues}
258
+ style={{ minWidth: 200, maxWidth: 400 }}
259
+ size="small"
260
+ maxTagCount={2}
261
+ maxTagTextLength={10}
262
+ >
263
+ {availableQueues.map(queue => (
264
+ <Option key={queue} value={queue}>{queue}</Option>
265
+ ))}
266
+ </Select>
267
+ <Button
268
+ icon={<ReloadOutlined />}
269
+ size="small"
270
+ onClick={fetchBacklogData}
271
+ loading={loading}
272
+ />
273
+ {onExpand && (
274
+ <Button
275
+ icon={<ExpandOutlined />}
276
+ size="small"
277
+ onClick={onExpand}
278
+ title="展开详情"
279
+ />
280
+ )}
281
+ </Space>
282
+ }
283
+ >
284
+ <Spin spinning={loading}>
285
+ {chartData.length > 0 ? (
286
+ <Line {...config} />
287
+ ) : (
288
+ <Empty
289
+ description={selectedQueues.length === 0 ? "请选择要监控的队列" : "暂无数据"}
290
+ style={{ height: height, display: 'flex', alignItems: 'center', justifyContent: 'center', flexDirection: 'column' }}
291
+ />
292
+ )}
293
+ </Spin>
294
+ </Card>
295
+ );
296
+ }
297
+
298
+ export default QueueBacklogChart;