@lokvis/ui-react 0.2.1 → 0.4.1
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/dist/components/AssetPanel.d.ts.map +1 -1
- package/dist/components/AssetPanel.js +18 -62
- package/dist/components/AssetPanel.js.map +1 -1
- package/dist/components/Canvas.d.ts +4 -4
- package/dist/components/Canvas.d.ts.map +1 -1
- package/dist/components/Canvas.js +9 -9
- package/dist/components/Canvas.js.map +1 -1
- package/dist/components/CommandPalette.d.ts +7 -7
- package/dist/components/CommandPalette.d.ts.map +1 -1
- package/dist/components/CommandPalette.js +10 -10
- package/dist/components/CommandPalette.js.map +1 -1
- package/dist/components/CompareSlider.d.ts +9 -8
- package/dist/components/CompareSlider.d.ts.map +1 -1
- package/dist/components/CompareSlider.js +10 -9
- package/dist/components/CompareSlider.js.map +1 -1
- package/dist/components/DownloadPanel.d.ts +3 -3
- package/dist/components/DownloadPanel.d.ts.map +1 -1
- package/dist/components/DownloadPanel.js +10 -17
- package/dist/components/DownloadPanel.js.map +1 -1
- package/dist/components/ErrorBanner.d.ts +2 -2
- package/dist/components/ErrorBanner.d.ts.map +1 -1
- package/dist/components/ErrorBanner.js +3 -3
- package/dist/components/ErrorBanner.js.map +1 -1
- package/dist/components/ErrorBoundary.d.ts +40 -0
- package/dist/components/ErrorBoundary.d.ts.map +1 -0
- package/dist/components/ErrorBoundary.js +52 -0
- package/dist/components/ErrorBoundary.js.map +1 -0
- package/dist/components/ExifPanel.d.ts +1 -1
- package/dist/components/ExifPanel.d.ts.map +1 -1
- package/dist/components/ExifPanel.js +2 -2
- package/dist/components/ExifPanel.js.map +1 -1
- package/dist/components/GlobalDropzone.d.ts +5 -5
- package/dist/components/GlobalDropzone.d.ts.map +1 -1
- package/dist/components/GlobalDropzone.js +15 -8
- package/dist/components/GlobalDropzone.js.map +1 -1
- package/dist/components/HistoryPanel.d.ts +2 -2
- package/dist/components/HistoryPanel.d.ts.map +1 -1
- package/dist/components/HistoryPanel.js +23 -23
- package/dist/components/HistoryPanel.js.map +1 -1
- package/dist/components/Inspector.d.ts.map +1 -1
- package/dist/components/Inspector.js +13 -10
- package/dist/components/Inspector.js.map +1 -1
- package/dist/components/ParamForm.d.ts.map +1 -1
- package/dist/components/ParamForm.js +10 -7
- package/dist/components/ParamForm.js.map +1 -1
- package/dist/components/PipelineBar.d.ts.map +1 -1
- package/dist/components/PipelineBar.js +19 -28
- package/dist/components/PipelineBar.js.map +1 -1
- package/dist/components/ProgressBar.d.ts +4 -4
- package/dist/components/ProgressBar.d.ts.map +1 -1
- package/dist/components/ProgressBar.js +8 -8
- package/dist/components/ProgressBar.js.map +1 -1
- package/dist/components/StatusBar.d.ts +3 -3
- package/dist/components/StatusBar.d.ts.map +1 -1
- package/dist/components/StatusBar.js +12 -21
- package/dist/components/StatusBar.js.map +1 -1
- package/dist/components/StatusDot.d.ts +12 -0
- package/dist/components/StatusDot.d.ts.map +1 -0
- package/dist/components/StatusDot.js +15 -0
- package/dist/components/StatusDot.js.map +1 -0
- package/dist/components/ThemeToggle.d.ts +4 -4
- package/dist/components/ThemeToggle.d.ts.map +1 -1
- package/dist/components/ThemeToggle.js +7 -7
- package/dist/components/ThemeToggle.js.map +1 -1
- package/dist/components/ToolRunner.d.ts +53 -0
- package/dist/components/ToolRunner.d.ts.map +1 -0
- package/dist/components/ToolRunner.js +142 -0
- package/dist/components/ToolRunner.js.map +1 -0
- package/dist/components/Toolbar.d.ts.map +1 -1
- package/dist/components/Toolbar.js +3 -3
- package/dist/components/Toolbar.js.map +1 -1
- package/dist/components/WorkflowEditor.d.ts +6 -6
- package/dist/components/WorkflowEditor.d.ts.map +1 -1
- package/dist/components/WorkflowEditor.js +40 -49
- package/dist/components/WorkflowEditor.js.map +1 -1
- package/dist/components/WorkflowTemplates.d.ts +2 -2
- package/dist/components/WorkflowTemplates.d.ts.map +1 -1
- package/dist/components/WorkflowTemplates.js +17 -7
- package/dist/components/WorkflowTemplates.js.map +1 -1
- package/dist/components/Workspace.d.ts +45 -23
- package/dist/components/Workspace.d.ts.map +1 -1
- package/dist/components/Workspace.js +87 -40
- package/dist/components/Workspace.js.map +1 -1
- package/dist/hooks/useCustomPresets.d.ts +98 -0
- package/dist/hooks/useCustomPresets.d.ts.map +1 -0
- package/dist/hooks/useCustomPresets.js +210 -0
- package/dist/hooks/useCustomPresets.js.map +1 -0
- package/dist/hooks/useLokvis.d.ts +19 -1
- package/dist/hooks/useLokvis.d.ts.map +1 -1
- package/dist/hooks/useLokvis.js +30 -9
- package/dist/hooks/useLokvis.js.map +1 -1
- package/dist/index.d.ts +4 -0
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +6 -0
- package/dist/index.js.map +1 -1
- package/dist/store/assets-slice.d.ts +8 -1
- package/dist/store/assets-slice.d.ts.map +1 -1
- package/dist/store/assets-slice.js +101 -54
- package/dist/store/assets-slice.js.map +1 -1
- package/dist/store/capabilities-slice.d.ts +1 -1
- package/dist/store/capabilities-slice.d.ts.map +1 -1
- package/dist/store/capabilities-slice.js +8 -1
- package/dist/store/capabilities-slice.js.map +1 -1
- package/dist/store/index.d.ts +1 -1
- package/dist/store/index.d.ts.map +1 -1
- package/dist/store/index.js +1 -1
- package/dist/store/index.js.map +1 -1
- package/dist/store/runtime-slice.d.ts.map +1 -1
- package/dist/store/runtime-slice.js +22 -16
- package/dist/store/runtime-slice.js.map +1 -1
- package/dist/store/subscribe-utils.d.ts +45 -0
- package/dist/store/subscribe-utils.d.ts.map +1 -0
- package/dist/store/subscribe-utils.js +69 -0
- package/dist/store/subscribe-utils.js.map +1 -0
- package/dist/store/types.d.ts +19 -11
- package/dist/store/types.d.ts.map +1 -1
- package/dist/store/types.js +0 -10
- package/dist/store/types.js.map +1 -1
- package/dist/store/workflow-slice.d.ts +1 -1
- package/dist/store/workflow-slice.d.ts.map +1 -1
- package/dist/store/workflow-slice.js +19 -51
- package/dist/store/workflow-slice.js.map +1 -1
- package/dist/utils.d.ts +24 -0
- package/dist/utils.d.ts.map +1 -0
- package/dist/utils.js +31 -0
- package/dist/utils.js.map +1 -0
- package/package.json +7 -6
- package/src/components/AssetPanel.tsx +224 -264
- package/src/components/Canvas.tsx +178 -174
- package/src/components/CommandPalette.tsx +242 -242
- package/src/components/CompareSlider.tsx +168 -165
- package/src/components/DownloadPanel.tsx +201 -207
- package/src/components/ErrorBanner.tsx +64 -64
- package/src/components/ErrorBoundary.tsx +101 -0
- package/src/components/ExifPanel.tsx +154 -154
- package/src/components/GlobalDropzone.tsx +175 -170
- package/src/components/HistoryPanel.tsx +219 -219
- package/src/components/Inspector.tsx +145 -137
- package/src/components/ParamForm.tsx +140 -137
- package/src/components/PipelineBar.tsx +97 -104
- package/src/components/ProgressBar.tsx +78 -78
- package/src/components/StatusBar.tsx +145 -152
- package/src/components/StatusDot.tsx +27 -0
- package/src/components/ThemeToggle.tsx +98 -98
- package/src/components/ToolRunner.tsx +352 -0
- package/src/components/Toolbar.tsx +65 -65
- package/src/components/WorkflowEditor.tsx +333 -326
- package/src/components/WorkflowTemplates.tsx +101 -78
- package/src/components/Workspace.tsx +310 -223
- package/src/css-modules.d.ts +3 -0
- package/src/hooks/useCustomPresets.ts +284 -0
- package/src/hooks/useLokvis.ts +43 -10
- package/src/index.ts +7 -0
- package/src/store/assets-slice.ts +106 -52
- package/src/store/capabilities-slice.ts +10 -2
- package/src/store/index.ts +1 -1
- package/src/store/runtime-slice.ts +20 -15
- package/src/store/subscribe-utils.ts +82 -0
- package/src/store/types.ts +19 -12
- package/src/store/workflow-slice.ts +19 -53
- package/src/utils.ts +41 -0
- package/dist/store.d.ts +0 -76
- package/dist/store.d.ts.map +0 -1
- package/dist/store.js +0 -217
- package/dist/store.js.map +0 -1
|
@@ -6,121 +6,114 @@
|
|
|
6
6
|
*/
|
|
7
7
|
|
|
8
8
|
import * as React from 'react';
|
|
9
|
-
import { Icon } from '@lokvis/ui-core';
|
|
9
|
+
import { FOCUS_RING, Icon } from '@lokvis/ui-core';
|
|
10
10
|
import { useWorkspaceStore } from '../store/index.js';
|
|
11
|
+
import { StatusDot } from './StatusDot.js';
|
|
11
12
|
|
|
12
13
|
export interface PipelineBarProps {
|
|
13
|
-
|
|
14
|
+
className?: string;
|
|
14
15
|
}
|
|
15
16
|
|
|
16
17
|
export function PipelineBar({ className = '' }: PipelineBarProps) {
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
18
|
+
const nodes = useWorkspaceStore((s) => s.nodes);
|
|
19
|
+
const selectedNodeId = useWorkspaceStore((s) => s.selectedNodeId);
|
|
20
|
+
const selectNode = useWorkspaceStore((s) => s.selectNode);
|
|
21
|
+
const removeNode = useWorkspaceStore((s) => s.removeNode);
|
|
21
22
|
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
23
|
+
return (
|
|
24
|
+
<div className={`flex h-10 shrink-0 items-center gap-2 border-t border-[var(--lokvis-border)] bg-[var(--lokvis-surface)] px-3 ${className}`}>
|
|
25
|
+
<span className="text-[10px] font-semibold uppercase tracking-wider text-[var(--lokvis-fg-subtle)] shrink-0">
|
|
26
|
+
Pipeline
|
|
27
|
+
</span>
|
|
27
28
|
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
29
|
+
{nodes.length === 0 ? (
|
|
30
|
+
<span className="text-[11px] text-[var(--lokvis-fg-subtle)]">
|
|
31
|
+
Empty — add capabilities from the right panel
|
|
32
|
+
</span>
|
|
33
|
+
) : (
|
|
34
|
+
<div className="flex flex-1 items-center gap-1 overflow-x-auto min-w-0">
|
|
35
|
+
{/* Source indicator */}
|
|
36
|
+
<div className="flex items-center gap-1 rounded-md bg-[var(--lokvis-surface-muted)] px-2 py-1 text-[10px] font-medium text-[var(--lokvis-fg-muted)] shrink-0">
|
|
37
|
+
<Icon size={12}><path d="M12 4.5v15m7.5-7.5h-15" /></Icon>
|
|
38
|
+
Source
|
|
39
|
+
</div>
|
|
39
40
|
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
41
|
+
{/* Arrow */}
|
|
42
|
+
<Icon size={12} className="shrink-0 text-[var(--lokvis-fg-subtle)]">
|
|
43
|
+
<path d="m9 5 7 7-7 7" />
|
|
44
|
+
</Icon>
|
|
44
45
|
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
46
|
+
{/* Nodes */}
|
|
47
|
+
{nodes.map((node, i) => {
|
|
48
|
+
const selected = node.id === selectedNodeId;
|
|
49
|
+
return (
|
|
50
|
+
<React.Fragment key={node.id}>
|
|
51
|
+
{/* D7: remove button 作为 node button 的兄弟而非子元素(HTML 规范禁止 button 嵌套) */}
|
|
52
|
+
<div className="group flex shrink-0 items-center gap-0.5">
|
|
53
|
+
<button
|
|
54
|
+
type="button"
|
|
55
|
+
onClick={() => selectNode(node.id)}
|
|
56
|
+
onKeyDown={(e) => {
|
|
57
|
+
// 键盘可达:Delete/Backspace 删除节点(与 WorkflowEditor 一致)
|
|
58
|
+
if (e.key === 'Delete' || e.key === 'Backspace') {
|
|
59
|
+
e.preventDefault();
|
|
60
|
+
removeNode(node.id);
|
|
61
|
+
}
|
|
62
|
+
}}
|
|
63
|
+
aria-label={`节点 ${node.capability},位置 ${i + 1},Delete 删除`}
|
|
64
|
+
aria-pressed={selected}
|
|
65
|
+
className={`flex shrink-0 items-center gap-1.5 rounded-md px-2.5 py-1 text-[11px] font-medium transition-all ${FOCUS_RING} ${
|
|
66
|
+
selected
|
|
67
|
+
? 'bg-[var(--lokvis-primary)]/15 text-[var(--lokvis-primary)] ring-1 ring-[var(--lokvis-primary)]/50'
|
|
68
|
+
: node.status === 'running'
|
|
69
|
+
? 'bg-[var(--lokvis-warning)]/15 text-[var(--lokvis-warning)]'
|
|
70
|
+
: node.status === 'success'
|
|
71
|
+
? 'bg-[var(--lokvis-success)]/15 text-[var(--lokvis-success)]'
|
|
72
|
+
: node.status === 'failed'
|
|
73
|
+
? 'bg-[var(--lokvis-danger)]/15 text-[var(--lokvis-danger)]'
|
|
74
|
+
: 'bg-[var(--lokvis-surface-muted)] text-[var(--lokvis-fg-muted)] hover:bg-[var(--lokvis-border)]'
|
|
75
|
+
}`}
|
|
76
|
+
>
|
|
77
|
+
<span className="font-mono">{node.capability}</span>
|
|
78
|
+
<StatusDot status={node.status} />
|
|
79
|
+
</button>
|
|
80
|
+
<button
|
|
81
|
+
type="button"
|
|
82
|
+
onClick={() => removeNode(node.id)}
|
|
83
|
+
className="rounded p-0.5 opacity-0 transition-opacity group-hover:opacity-100 focus-visible:opacity-100 focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-[var(--lokvis-danger)] hover:bg-[var(--lokvis-danger)]/15 hover:text-[var(--lokvis-danger)]"
|
|
84
|
+
aria-label="Remove step"
|
|
85
|
+
>
|
|
86
|
+
<Icon size={10} strokeWidth={3}><path d="M6 18L18 6M6 6l12 12" /></Icon>
|
|
87
|
+
</button>
|
|
88
|
+
</div>
|
|
79
89
|
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
90
|
+
{/* Arrow between nodes */}
|
|
91
|
+
{i < nodes.length - 1 && (
|
|
92
|
+
<Icon size={12} className="shrink-0 text-[var(--lokvis-fg-subtle)]">
|
|
93
|
+
<path d="m9 5 7 7-7 7" />
|
|
94
|
+
</Icon>
|
|
95
|
+
)}
|
|
96
|
+
</React.Fragment>
|
|
97
|
+
);
|
|
98
|
+
})}
|
|
89
99
|
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
+
{/* Output indicator */}
|
|
101
|
+
<Icon size={12} className="shrink-0 text-[var(--lokvis-fg-subtle)]">
|
|
102
|
+
<path d="m9 5 7 7-7 7" />
|
|
103
|
+
</Icon>
|
|
104
|
+
<div className="flex items-center gap-1 rounded-md bg-[var(--lokvis-surface-muted)] px-2 py-1 text-[10px] font-medium text-[var(--lokvis-fg-muted)] shrink-0">
|
|
105
|
+
<Icon size={12}><path d="M3 16.5v2.25A2.25 2.25 0 0 0 5.25 21h13.5A2.25 2.25 0 0 0 21 18.75V16.5M16.5 12 12 16.5m0 0L7.5 12m4.5 4.5V3" /></Icon>
|
|
106
|
+
Output
|
|
107
|
+
</div>
|
|
108
|
+
</div>
|
|
109
|
+
)}
|
|
100
110
|
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
}
|
|
110
|
-
|
|
111
|
-
function StatusDot({ status }: { status: string }) {
|
|
112
|
-
const color =
|
|
113
|
-
status === 'running'
|
|
114
|
-
? 'bg-amber-500'
|
|
115
|
-
: status === 'success'
|
|
116
|
-
? 'bg-emerald-500'
|
|
117
|
-
: status === 'failed'
|
|
118
|
-
? 'bg-red-500'
|
|
119
|
-
: status === 'pending'
|
|
120
|
-
? 'bg-zinc-400 dark:bg-zinc-500'
|
|
121
|
-
: 'bg-zinc-300 dark:bg-zinc-600';
|
|
122
|
-
|
|
123
|
-
const animate = status === 'running' ? 'animate-pulse' : '';
|
|
124
|
-
|
|
125
|
-
return <span className={`h-1.5 w-1.5 rounded-full shrink-0 ${color} ${animate}`} />;
|
|
111
|
+
{/* Step count */}
|
|
112
|
+
{nodes.length > 0 && (
|
|
113
|
+
<span className="shrink-0 text-[10px] tabular-nums text-[var(--lokvis-fg-subtle)]">
|
|
114
|
+
{nodes.length} step{nodes.length !== 1 ? 's' : ''}
|
|
115
|
+
</span>
|
|
116
|
+
)}
|
|
117
|
+
</div>
|
|
118
|
+
);
|
|
126
119
|
}
|
|
@@ -2,10 +2,10 @@
|
|
|
2
2
|
* ProgressBar - 工作流执行进度条 + 取消按钮(W11.6)
|
|
3
3
|
*
|
|
4
4
|
* 展示:
|
|
5
|
-
*
|
|
6
|
-
*
|
|
7
|
-
*
|
|
8
|
-
*
|
|
5
|
+
* - 节点完成进度(成功数 / 总数)
|
|
6
|
+
* - 横向进度条(running 时动画)
|
|
7
|
+
* - Cancel 按钮(调用 cancelRun)
|
|
8
|
+
* - 状态消息(statusMessage)
|
|
9
9
|
*
|
|
10
10
|
* 仅在 running 或最近一次执行有结果时显示。
|
|
11
11
|
*
|
|
@@ -17,88 +17,88 @@ import { useWorkspaceStore } from '../store/index.js';
|
|
|
17
17
|
import { useWorkflowProgress } from '../hooks/useWorkflowProgress.js';
|
|
18
18
|
|
|
19
19
|
export interface ProgressBarProps {
|
|
20
|
-
|
|
20
|
+
className?: string;
|
|
21
21
|
}
|
|
22
22
|
|
|
23
23
|
export function ProgressBar({ className = '' }: ProgressBarProps) {
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
24
|
+
const running = useWorkspaceStore((s) => s.running);
|
|
25
|
+
const statusMessage = useWorkspaceStore((s) => s.statusMessage);
|
|
26
|
+
const cancelRun = useWorkspaceStore((s) => s.cancelRun);
|
|
27
27
|
|
|
28
|
-
|
|
29
|
-
|
|
28
|
+
// 进度计算抽取到共享 hook(与 StatusBar 共用,避免重复逻辑)
|
|
29
|
+
const { total, done, failedCount, pct, hasFailure } = useWorkflowProgress();
|
|
30
30
|
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
31
|
+
// 没有节点或未运行且无最近结果时不渲染
|
|
32
|
+
if (total === 0) return null;
|
|
33
|
+
if (!running && done === 0) return null;
|
|
34
34
|
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
35
|
+
return (
|
|
36
|
+
<div
|
|
37
|
+
className={`flex items-center gap-2 border-b border-[var(--lokvis-border)] bg-[var(--lokvis-surface)] px-3 py-1.5 ${className}`}
|
|
38
|
+
role="status"
|
|
39
|
+
aria-live="polite"
|
|
40
|
+
aria-label={`工作流进度:${done} / ${total}`}
|
|
41
|
+
>
|
|
42
|
+
{/* 进度条 */}
|
|
43
|
+
<div className="relative h-1.5 flex-1 overflow-hidden rounded-full bg-[var(--lokvis-border)]">
|
|
44
|
+
<div
|
|
45
|
+
className={`absolute inset-y-0 left-0 transition-all duration-300 ${
|
|
46
|
+
hasFailure
|
|
47
|
+
? 'bg-[var(--lokvis-danger)]'
|
|
48
|
+
: running
|
|
49
|
+
? 'bg-[var(--lokvis-primary)]'
|
|
50
|
+
: 'bg-[var(--lokvis-success)]'
|
|
51
|
+
} ${running ? 'animate-pulse' : ''}`}
|
|
52
|
+
style={{ width: `${pct}%` }}
|
|
53
|
+
/>
|
|
54
|
+
</div>
|
|
55
55
|
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
56
|
+
{/* 计数 */}
|
|
57
|
+
<span className="shrink-0 text-[10px] font-medium tabular-nums text-[var(--lokvis-fg-muted)]">
|
|
58
|
+
{done}/{total}
|
|
59
|
+
{failedCount > 0 && (
|
|
60
|
+
<span className="ml-1 text-[var(--lokvis-danger)]">({failedCount} failed)</span>
|
|
61
|
+
)}
|
|
62
|
+
</span>
|
|
63
63
|
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
64
|
+
{/* 状态消息(running 时显示) */}
|
|
65
|
+
{running && statusMessage && (
|
|
66
|
+
<span className="hidden shrink-0 truncate text-[10px] text-[var(--lokvis-fg-subtle)] sm:inline">
|
|
67
|
+
{statusMessage}
|
|
68
|
+
</span>
|
|
69
|
+
)}
|
|
70
70
|
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
71
|
+
{/* Cancel 按钮(仅 running 时) */}
|
|
72
|
+
{running && (
|
|
73
|
+
<button
|
|
74
|
+
type="button"
|
|
75
|
+
onClick={() => void cancelRun()}
|
|
76
|
+
aria-label="取消运行"
|
|
77
|
+
title="取消运行"
|
|
78
|
+
className="flex shrink-0 items-center gap-1 rounded-md bg-[var(--lokvis-danger)]/10 px-2 py-0.5 text-[10px] font-medium text-[var(--lokvis-danger)] transition-colors hover:bg-[var(--lokvis-danger)]/15"
|
|
79
|
+
>
|
|
80
|
+
<Icon size={10} strokeWidth={3}><path d="M6 6l12 12M6 18L18 6" /></Icon>
|
|
81
|
+
Cancel
|
|
82
|
+
</button>
|
|
83
|
+
)}
|
|
84
84
|
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
85
|
+
{/* 完成图标(非 running 且有结果) */}
|
|
86
|
+
{!running && done === total && (
|
|
87
|
+
<span
|
|
88
|
+
className={`flex shrink-0 items-center gap-1 text-[10px] font-medium ${
|
|
89
|
+
hasFailure ? 'text-[var(--lokvis-danger)]' : 'text-[var(--lokvis-success)]'
|
|
90
|
+
}`}
|
|
91
|
+
>
|
|
92
|
+
<Icon size={10} strokeWidth={3}>
|
|
93
|
+
{hasFailure ? (
|
|
94
|
+
<path d="M12 2L2 22h20L12 2zM12 9v5M12 17v.01" />
|
|
95
|
+
) : (
|
|
96
|
+
<path d="M20 6L9 17l-5-5" />
|
|
97
|
+
)}
|
|
98
|
+
</Icon>
|
|
99
|
+
{hasFailure ? 'Failed' : 'Done'}
|
|
100
|
+
</span>
|
|
101
|
+
)}
|
|
102
|
+
</div>
|
|
103
|
+
);
|
|
104
104
|
}
|