@v587d/capital-generation 2.13.1 → 2.13.2
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/CHANGELOG.md +18 -0
- package/README.md +25 -26
- package/automation/client.js +28 -18
- package/automation/client.src.cjs +260 -136
- package/automation/package.json +1 -1
- package/chart-ui/package.json +1 -1
- package/config/package.json +1 -1
- package/lib/web-retriever/local-fetch.d.ts +1 -1
- package/lib/web-retriever/local-fetch.js +1 -1
- package/lib/web-retriever/wind-client.d.ts +1 -1
- package/lib/web-retriever/wind-client.js +1 -1
- package/package.json +1 -1
- package/watchlist/package.json +1 -1
|
@@ -7,6 +7,7 @@ const { createElement: h, useEffect, useRef, useState } = require('react')
|
|
|
7
7
|
const {
|
|
8
8
|
IconAlarmClockOutlineRegular,
|
|
9
9
|
IconChecklistOutlineRegular,
|
|
10
|
+
IconChevronDownOutlineRegular,
|
|
10
11
|
IconChevronLeftOutlineRegular,
|
|
11
12
|
IconChevronRightOutlineRegular,
|
|
12
13
|
IconClockOutlineRegular,
|
|
@@ -23,6 +24,7 @@ const {
|
|
|
23
24
|
IconPlayOutlineRegular,
|
|
24
25
|
IconPlusOutlineRegular,
|
|
25
26
|
IconRefreshOutlineRegular,
|
|
27
|
+
IconRightUpOutlineRegular,
|
|
26
28
|
IconSearchOutlineRegular,
|
|
27
29
|
IconSparkleRegular,
|
|
28
30
|
IconTrashOutlineRegular,
|
|
@@ -39,6 +41,7 @@ const PANEL_ID = 'capital-automation'
|
|
|
39
41
|
const STYLE_TAG = 'capital-automation-css'
|
|
40
42
|
const ACTIVE_RUN_STATUSES = ['queued', 'starting', 'running']
|
|
41
43
|
const FAILURE_RUN_STATUSES = ['failed', 'timed_out', 'blocked_requires_user', 'unknown_after_restart']
|
|
44
|
+
const SKIPPED_RUN_STATUSES = ['skipped_overlap', 'skipped_calendar_unavailable', 'missed']
|
|
42
45
|
const DEFAULT_LIMITS = { runTimeoutMinutes: 30, idleTimeoutMinutes: 5, maxSteps: 300, maxToolCalls: 1200 }
|
|
43
46
|
const WEEKDAYS = [
|
|
44
47
|
{ value: 1, label: '一' },
|
|
@@ -51,6 +54,7 @@ const WEEKDAYS = [
|
|
|
51
54
|
]
|
|
52
55
|
const TIMEZONES = ['Asia/Shanghai', 'Asia/Hong_Kong', 'Asia/Singapore', 'Asia/Tokyo', 'UTC', 'Europe/London', 'America/New_York', 'America/Los_Angeles']
|
|
53
56
|
const HISTORY_DAYS = 30
|
|
57
|
+
const DETAIL_RECENT_RUN_LIMIT = 3
|
|
54
58
|
|
|
55
59
|
const zh = {
|
|
56
60
|
panel: 'CapGen 投研自动化',
|
|
@@ -104,7 +108,7 @@ const zh = {
|
|
|
104
108
|
categoryField: '任务分类',
|
|
105
109
|
categoryFixed: '内置模板的分类固定;复制为我的任务后可以调整。',
|
|
106
110
|
modeField: '输出侧重',
|
|
107
|
-
modeHint: '
|
|
111
|
+
modeHint: '只影响输出结构;所有运行固定使用自动模式。',
|
|
108
112
|
mode: { news: '资讯', market: '行情', review: '复盘', research: '研究' },
|
|
109
113
|
cadence: { daily: '每天', weekly: '每周', monthly: '每月' },
|
|
110
114
|
stateLabel: '状态',
|
|
@@ -137,7 +141,11 @@ const zh = {
|
|
|
137
141
|
dirty: '有未保存的修改',
|
|
138
142
|
noDirty: '配置已同步',
|
|
139
143
|
nextRun: '下次运行',
|
|
144
|
+
nextRunDormant: '添加后开始调度',
|
|
145
|
+
nextRunPaused: '启用后恢复调度',
|
|
146
|
+
notScheduled: '当前不会自动运行',
|
|
140
147
|
lastResult: '上次结果',
|
|
148
|
+
lastRunEmpty: '运行后可在这里查看结果',
|
|
141
149
|
never: '暂无',
|
|
142
150
|
calendarUnavailable: '日历不可用',
|
|
143
151
|
unread: '未读',
|
|
@@ -182,16 +190,13 @@ const zh = {
|
|
|
182
190
|
notifyFailure: '失败时通知',
|
|
183
191
|
notifySuccess: '成功时通知',
|
|
184
192
|
notifyHint: '通知只记录在当前 profile;不会发送邮件或外部消息。',
|
|
185
|
-
presetLabel: '
|
|
186
|
-
presetValue: '
|
|
187
|
-
policy: '执行策略',
|
|
188
|
-
policyText: '固定 preset:capital-generation(Capital 自动模式)。工作区来自已注册列表;未选择时使用专属自动化工作区。无人值守运行禁止提问、写文件与 shell 提权。',
|
|
193
|
+
presetLabel: '运行模式',
|
|
194
|
+
presetValue: '自动模式',
|
|
189
195
|
budgetHint: '工具调用与步骤预算覆盖整棵运行子树:子 Agent 与 PTC 派发都计入。',
|
|
190
196
|
environment: '执行环境',
|
|
191
197
|
policyField: '无人值守策略',
|
|
192
198
|
cwdKind: '工作区来源',
|
|
193
199
|
techInfo: '技术信息',
|
|
194
|
-
version: '版本',
|
|
195
200
|
profileKey: 'profileKey',
|
|
196
201
|
runHistory: '运行历史',
|
|
197
202
|
last30Days: '最近 30 天',
|
|
@@ -258,9 +263,9 @@ const zh = {
|
|
|
258
263
|
runBlocked: '任务正在运行,结束或取消后才能再次运行。',
|
|
259
264
|
configWhileRunning: '任务正在运行;修改会在下一次运行时生效。',
|
|
260
265
|
configBuiltinHint: '这是内置模板;修改只覆盖当前 profile,休眠后会恢复默认。',
|
|
261
|
-
detailRecentRuns: '
|
|
266
|
+
detailRecentRuns: '最近 {n} 次运行',
|
|
262
267
|
detailNoRuns: '还没有运行记录。',
|
|
263
|
-
detailAllRuns: '
|
|
268
|
+
detailAllRuns: '完整记录',
|
|
264
269
|
detailTaskNotifications: '任务通知',
|
|
265
270
|
taskRunsLimit: '这里显示当前任务最近 20 次运行;全部运行见「运行」页。',
|
|
266
271
|
runErrors: '{n} 条错误',
|
|
@@ -467,8 +472,6 @@ function installStyles() {
|
|
|
467
472
|
.capital-automation-herotitle { display: flex; flex-wrap: wrap; align-items: center; gap: 8px; }
|
|
468
473
|
.capital-automation-herotitle h2 { margin: 0; font-size: 22px; line-height: 30px; font-weight: 600; letter-spacing: .1px; overflow-wrap: anywhere; }
|
|
469
474
|
.capital-automation-herodesc { max-width: 760px; margin: 5px 0 0; color: var(--ca-muted); font-size: 12.5px; line-height: 19px; }
|
|
470
|
-
.capital-automation-herometa { display: flex; flex-wrap: wrap; align-items: center; gap: 5px 14px; margin-top: 10px; color: var(--ca-muted); font-size: 11.5px; line-height: 18px; }
|
|
471
|
-
.capital-automation-herometa > span { display: inline-flex; align-items: center; gap: 5px; }
|
|
472
475
|
.capital-automation-heroactions { display: flex; flex-wrap: wrap; align-items: center; gap: 7px; flex: none; padding-top: 2px; }
|
|
473
476
|
.capital-automation-detailtabs { display: flex; align-items: center; gap: 26px; overflow-x: auto; overflow-y: hidden; border-bottom: .5px solid var(--ca-line); }
|
|
474
477
|
.capital-automation-detailtab { position: relative; flex: none; height: 42px; padding: 0 1px; border: 0; background: transparent; color: var(--ca-muted); font: inherit; font-size: 12.5px; font-weight: 500; cursor: pointer; }
|
|
@@ -487,11 +490,13 @@ function installStyles() {
|
|
|
487
490
|
.capital-automation-statvalue[data-tone="ok"] { color: var(--ca-success-text); }
|
|
488
491
|
.capital-automation-statvalue[data-tone="error"] { color: var(--ca-error-text); }
|
|
489
492
|
.capital-automation-statvalue[data-tone="running"] { color: var(--ca-business-text); }
|
|
493
|
+
.capital-automation-statvalue[data-tone="warn"] { color: var(--ca-warn-text); }
|
|
490
494
|
.capital-automation-statsub { color: var(--ca-caption); font-size: 11px; line-height: 16px; }
|
|
491
495
|
.capital-automation-panel { padding: 16px 18px; }
|
|
492
496
|
.capital-automation-panelhead { display: flex; flex-wrap: wrap; align-items: center; justify-content: space-between; gap: 8px 12px; margin-bottom: 12px; }
|
|
493
497
|
.capital-automation-panelhead h3 { margin: 0; font-size: 13.5px; line-height: 20px; font-weight: 600; }
|
|
494
498
|
.capital-automation-panelhead .capital-automation-btn { margin-left: auto; }
|
|
499
|
+
.capital-automation-panelhead .capital-automation-btn[data-variant="ghost"] { padding-right: 0; }
|
|
495
500
|
.capital-automation-kv { display: grid; grid-template-columns: repeat(auto-fit, minmax(150px, 1fr)); gap: 12px 18px; }
|
|
496
501
|
.capital-automation-kvitem { min-width: 0; }
|
|
497
502
|
.capital-automation-kvlabel { display: block; color: var(--ca-caption); font-size: 11px; line-height: 16px; }
|
|
@@ -505,25 +510,35 @@ function installStyles() {
|
|
|
505
510
|
.capital-automation-error { margin: 0; color: var(--ca-error-text); font-size: 12px; line-height: 18px; }
|
|
506
511
|
.capital-automation-toast { position: fixed; bottom: 26px; left: 50%; z-index: 1300; max-width: min(520px, calc(100vw - 40px)); transform: translateX(-50%); padding: 8px 15px; border: .5px solid var(--ca-line-soft); border-radius: 999px; background: var(--dsw-alias-label-primary); color: var(--dsw-alias-bg-base); box-shadow: 0 8px 26px rgba(0,0,0,.22); font-size: 12px; line-height: 18px; }
|
|
507
512
|
.capital-automation-form { display: flex; flex-direction: column; gap: 16px; }
|
|
513
|
+
.capital-automation-formnote { display: flex; align-items: flex-start; gap: 7px; padding: 9px 11px; border: .5px solid var(--ca-line); border-radius: 10px; background: var(--ca-field); color: var(--ca-muted); font-size: 11.5px; line-height: 18px; }
|
|
514
|
+
.capital-automation-formnote svg { flex: none; margin-top: 2px; }
|
|
508
515
|
.capital-automation-formgrid { display: grid; grid-template-columns: repeat(auto-fit, minmax(170px, 1fr)); gap: 12px; }
|
|
509
516
|
.capital-automation-field { display: flex; flex-direction: column; gap: 5px; min-width: 0; }
|
|
510
517
|
.capital-automation-field > span { color: var(--ca-muted); font-size: 11.5px; line-height: 17px; }
|
|
511
|
-
.capital-automation-field input, .capital-automation-field
|
|
512
|
-
.capital-automation-field input
|
|
518
|
+
.capital-automation-field input, .capital-automation-field textarea { box-sizing: border-box; width: 100%; padding: 0 10px; border: .5px solid var(--ca-line-soft); border-radius: 10px; background: var(--ca-field); color: var(--dsw-alias-label-primary); font: inherit; font-size: 12.5px; line-height: 32px; }
|
|
519
|
+
.capital-automation-field input { height: 34px; }
|
|
513
520
|
.capital-automation-field textarea { min-height: 110px; padding: 9px 10px; line-height: 19px; resize: vertical; }
|
|
514
|
-
.capital-automation-field input:hover, .capital-automation-field
|
|
515
|
-
.capital-automation-field input:focus-visible, .capital-automation-field
|
|
516
|
-
.capital-automation-field input:disabled, .capital-automation-field
|
|
521
|
+
.capital-automation-field input:hover, .capital-automation-field textarea:hover { border-color: var(--ca-line); }
|
|
522
|
+
.capital-automation-field input:focus-visible, .capital-automation-field textarea:focus-visible { border-color: var(--ca-business); outline: 2px solid color-mix(in srgb, var(--ca-business) 22%, transparent); outline-offset: 0; }
|
|
523
|
+
.capital-automation-field input:disabled, .capital-automation-field textarea:disabled { color: var(--ca-muted); opacity: .8; }
|
|
524
|
+
.capital-automation-select { box-sizing: border-box; display: inline-flex; align-items: center; justify-content: space-between; gap: 10px; min-width: 0; height: 34px; padding: 0 10px 0 12px; border: 0; border-radius: 10px; background: var(--ca-field); color: var(--dsw-alias-label-primary); font: inherit; font-size: 12.5px; line-height: 20px; text-align: left; cursor: pointer; transition: background .15s, opacity .15s; }
|
|
525
|
+
.capital-automation-select:hover:not(:disabled) { background: var(--ca-hover); }
|
|
526
|
+
.capital-automation-select[data-block="true"] { width: 100%; }
|
|
527
|
+
.capital-automation-select[data-size="sm"] { height: 28px; padding: 0 8px 0 9px; border-radius: 8px; font-size: 11.5px; }
|
|
528
|
+
.capital-automation-select:focus-visible { outline: 2px solid var(--dsw-focus-ring-color, var(--ca-business)); outline-offset: 0; }
|
|
529
|
+
.capital-automation-select:disabled { opacity: .5; cursor: not-allowed; }
|
|
530
|
+
.capital-automation-selectvalue { min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
|
|
531
|
+
.capital-automation-select > svg { flex: none; color: var(--ca-muted); }
|
|
517
532
|
.capital-automation-formactions { display: flex; flex-wrap: wrap; align-items: center; justify-content: flex-end; gap: 8px; padding-top: 14px; border-top: .5px solid var(--ca-line); }
|
|
518
533
|
.capital-automation-formactions[data-sticky="true"] { position: sticky; bottom: -1px; z-index: 2; margin-top: 2px; padding: 12px 0 4px; background: var(--dsw-alias-bg-base); }
|
|
519
534
|
.capital-automation-formstatus { margin-right: auto; color: var(--ca-caption); font-size: 11.5px; line-height: 18px; }
|
|
520
535
|
.capital-automation-triggerbox { display: flex; flex-direction: column; gap: 12px; padding: 13px 14px; border: .5px solid var(--ca-line); border-radius: 14px; background: var(--ca-field); }
|
|
521
536
|
.capital-automation-triggerrow { display: flex; flex-wrap: wrap; align-items: center; gap: 8px; }
|
|
522
537
|
.capital-automation-triggerclock { display: inline-grid; place-items: center; width: 32px; height: 32px; border-radius: 10px; background: linear-gradient(135deg, #5b9dff, #2563eb); color: #fff; flex: none; }
|
|
523
|
-
.capital-automation-triggerrow label { display: inline-flex; align-items: center; gap: 6px; color: var(--ca-muted); font-size: 12px; }
|
|
524
|
-
.capital-automation-triggerrow input
|
|
538
|
+
.capital-automation-triggerrow label, .capital-automation-triggerfield { display: inline-flex; align-items: center; gap: 6px; color: var(--ca-muted); font-size: 12px; }
|
|
539
|
+
.capital-automation-triggerrow input { box-sizing: border-box; height: 32px; padding: 0 9px; border: .5px solid var(--ca-line-soft); border-radius: 9px; background: var(--ca-card); color: var(--dsw-alias-label-primary); font: inherit; font-size: 12px; }
|
|
525
540
|
.capital-automation-triggerrow input[type="time"] { width: 112px; }
|
|
526
|
-
.capital-automation-triggerrow select { max-width: 190px; }
|
|
541
|
+
.capital-automation-triggerrow .capital-automation-select { max-width: 190px; height: 32px; background: var(--ca-card); }
|
|
527
542
|
.capital-automation-weekdays { display: flex; flex-wrap: wrap; gap: 4px; }
|
|
528
543
|
.capital-automation-weekday { width: 30px; height: 30px; padding: 0; border: .5px solid var(--ca-line-soft); border-radius: 999px; background: transparent; color: var(--ca-muted); font: inherit; font-size: 11.5px; cursor: pointer; }
|
|
529
544
|
.capital-automation-weekday:hover:not(:disabled) { border-color: var(--ca-line); color: var(--dsw-alias-label-primary); }
|
|
@@ -594,14 +609,14 @@ function installStyles() {
|
|
|
594
609
|
.capital-automation-promptbox textarea { box-sizing: border-box; width: 100%; min-height: 120px; max-height: 320px; padding: 13px 14px; border: 0; outline: 0; background: transparent; color: var(--dsw-alias-label-primary); font: inherit; font-size: 13px; line-height: 21px; resize: vertical; }
|
|
595
610
|
.capital-automation-promptbox textarea::placeholder { color: var(--ca-caption); }
|
|
596
611
|
.capital-automation-prompttoolbar { display: flex; flex-wrap: wrap; align-items: center; gap: 8px; padding: 8px 10px; border-top: .5px solid var(--ca-line); }
|
|
597
|
-
.capital-automation-prompttoolbar label { display: inline-flex; align-items: center; gap: 5px; color: var(--ca-muted); font-size: 11.5px; }
|
|
598
|
-
.capital-automation-prompttoolbar select { max-width: 168px;
|
|
612
|
+
.capital-automation-prompttoolbar label, .capital-automation-toolbarfield { display: inline-flex; align-items: center; gap: 5px; color: var(--ca-muted); font-size: 11.5px; }
|
|
613
|
+
.capital-automation-prompttoolbar .capital-automation-select { max-width: 168px; background: var(--ca-card); }
|
|
599
614
|
.capital-automation-prompttoolbar .capital-automation-presetchip { margin-left: auto; }
|
|
600
615
|
.capital-automation-presetchip { display: inline-flex; align-items: center; gap: 5px; height: 26px; padding: 0 9px; border-radius: 999px; background: color-mix(in srgb, var(--ca-business) 12%, var(--ca-card)); color: var(--ca-business-text); font-size: 11px; font-weight: 500; white-space: nowrap; }
|
|
601
616
|
.capital-automation-checklist { display: flex; flex-direction: column; gap: 2px; }
|
|
602
|
-
.capital-automation-technical { margin-top:
|
|
603
|
-
.capital-automation-
|
|
604
|
-
.capital-automation-technical dl { display: grid; grid-template-columns: auto 1fr; gap: 3px 10px; margin:
|
|
617
|
+
.capital-automation-technical { margin-top: 14px; padding-top: 12px; border-top: .5px solid var(--ca-line); color: var(--ca-caption); font-size: 11px; line-height: 17px; }
|
|
618
|
+
.capital-automation-technicaltitle { margin: 0 0 7px; color: var(--ca-muted); font-size: 11.5px; line-height: 17px; font-weight: 500; }
|
|
619
|
+
.capital-automation-technical dl { display: grid; grid-template-columns: auto 1fr; gap: 3px 10px; margin: 0; }
|
|
605
620
|
.capital-automation-technical dt { color: var(--ca-caption); }
|
|
606
621
|
.capital-automation-technical dd { min-width: 0; margin: 0; overflow-wrap: anywhere; color: var(--ca-muted); }
|
|
607
622
|
.capital-automation-page :focus-visible { outline: 2px solid var(--dsw-focus-ring-color, var(--ca-business)); outline-offset: 2px; }
|
|
@@ -846,6 +861,31 @@ function scheduleRangeSummary(trigger) {
|
|
|
846
861
|
return '每天'
|
|
847
862
|
}
|
|
848
863
|
|
|
864
|
+
// Dormant/paused tasks still carry a computed nextRunLocal, but that instant will not fire until
|
|
865
|
+
// the task is activated; don't present it as a pending schedule.
|
|
866
|
+
function nextRunView(task) {
|
|
867
|
+
if (task?.state === 'dormant') return { value: zh.nextRunDormant, sub: zh.notScheduled }
|
|
868
|
+
if (task?.state === 'paused') return { value: zh.nextRunPaused, sub: zh.notScheduled }
|
|
869
|
+
const value = task?.nextRunLocal ?? (task?.nextRunUnavailable ? zh.calendarUnavailable : zh.never)
|
|
870
|
+
const sub = task?.nextRunAt ? formatRelative(task.nextRunAt) : (task?.nextRunUnavailable ? zh.nextRunUnavailable : zh.never)
|
|
871
|
+
return { value, sub }
|
|
872
|
+
}
|
|
873
|
+
|
|
874
|
+
function lastRunView(run, timeZone) {
|
|
875
|
+
if (run === null || run === undefined) return { value: zh.neverRun, sub: zh.lastRunEmpty }
|
|
876
|
+
const active = isActiveRun(run)
|
|
877
|
+
const parts = [formatShortTime(run.queuedAt, timeZone)]
|
|
878
|
+
if (!active && typeof run.durationMs === 'number') parts.push(formatDuration(run.durationMs))
|
|
879
|
+
const errors = Array.isArray(run.errors) ? run.errors.length : 0
|
|
880
|
+
if (errors > 0) parts.push(zh.runErrors.replace('{n}', String(errors)))
|
|
881
|
+
let tone
|
|
882
|
+
if (run.status === 'succeeded') tone = 'ok'
|
|
883
|
+
else if (isFailureStatus(run.status)) tone = 'error'
|
|
884
|
+
else if (active) tone = 'running'
|
|
885
|
+
else if (SKIPPED_RUN_STATUSES.includes(run.status)) tone = 'warn'
|
|
886
|
+
return { value: statusLabel(run.status), sub: parts.filter(Boolean).join(' · '), tone }
|
|
887
|
+
}
|
|
888
|
+
|
|
849
889
|
function workspaceOptions(meta, current) {
|
|
850
890
|
const options = [{ id: '', title: zh.workspaceDefault }]
|
|
851
891
|
const list = Array.isArray(meta?.workspaces) ? meta.workspaces : []
|
|
@@ -1039,6 +1079,21 @@ function RunRow(props) {
|
|
|
1039
1079
|
const errorCount = Array.isArray(run.errors) ? run.errors.length : 0
|
|
1040
1080
|
const [errorsOpen, setErrorsOpen] = useState(false)
|
|
1041
1081
|
const errorPanelId = `capital-automation-run-errors-${run.id}`
|
|
1082
|
+
const errorBadge = errorCount > 0
|
|
1083
|
+
? h('button', {
|
|
1084
|
+
type: 'button',
|
|
1085
|
+
className: 'capital-automation-runerrorbadge',
|
|
1086
|
+
'data-tone': isFailureStatus(run.status) ? 'error' : 'warn',
|
|
1087
|
+
'aria-expanded': errorsOpen ? 'true' : 'false',
|
|
1088
|
+
'aria-controls': errorPanelId,
|
|
1089
|
+
'aria-label': `${zh.runErrors.replace('{n}', String(errorCount))},${errorsOpen ? zh.hideErrorDetails : zh.showErrorDetails}`,
|
|
1090
|
+
title: errorsOpen ? zh.hideErrorDetails : zh.showErrorDetails,
|
|
1091
|
+
onClick: () => setErrorsOpen((current) => !current),
|
|
1092
|
+
},
|
|
1093
|
+
h(IconWarningOutlineRegular, { size: 12 }),
|
|
1094
|
+
zh.runErrors.replace('{n}', String(errorCount)),
|
|
1095
|
+
h(IconChevronRightOutlineRegular, { size: 12 }))
|
|
1096
|
+
: null
|
|
1042
1097
|
return h('div', { className: 'capital-automation-run' },
|
|
1043
1098
|
h('div', { className: 'capital-automation-runhead' },
|
|
1044
1099
|
h('div', { className: 'capital-automation-runmain' },
|
|
@@ -1050,27 +1105,15 @@ function RunRow(props) {
|
|
|
1050
1105
|
h('div', { className: 'capital-automation-runmetaline' },
|
|
1051
1106
|
h('span', { className: 'capital-automation-runmeta' }, `${formatShortTime(run.queuedAt, task?.trigger?.timezone)} · ${run.trigger === 'manual' ? zh.triggerManual : zh.triggerScheduled}`),
|
|
1052
1107
|
typeof run.durationMs === 'number' ? h('span', { className: 'capital-automation-runmeta' }, `${zh.duration} ${formatDuration(run.durationMs)}`) : null,
|
|
1053
|
-
h('span', { className: 'capital-automation-runmeta' }, `${zh.steps} ${run.steps} · ${zh.tools} ${run.toolCalls}`)
|
|
1108
|
+
h('span', { className: 'capital-automation-runmeta' }, `${zh.steps} ${run.steps} · ${zh.tools} ${run.toolCalls}`),
|
|
1109
|
+
errorBadge)),
|
|
1054
1110
|
h('div', { className: 'capital-automation-runactions' },
|
|
1055
|
-
errorCount > 0
|
|
1056
|
-
? h('button', {
|
|
1057
|
-
type: 'button',
|
|
1058
|
-
className: 'capital-automation-runerrorbadge',
|
|
1059
|
-
'data-tone': isFailureStatus(run.status) ? 'error' : 'warn',
|
|
1060
|
-
'aria-expanded': errorsOpen ? 'true' : 'false',
|
|
1061
|
-
'aria-controls': errorPanelId,
|
|
1062
|
-
'aria-label': `${zh.runErrors.replace('{n}', String(errorCount))},${errorsOpen ? zh.hideErrorDetails : zh.showErrorDetails}`,
|
|
1063
|
-
title: errorsOpen ? zh.hideErrorDetails : zh.showErrorDetails,
|
|
1064
|
-
onClick: () => setErrorsOpen((current) => !current),
|
|
1065
|
-
},
|
|
1066
|
-
h(IconWarningOutlineRegular, { size: 12 }),
|
|
1067
|
-
zh.runErrors.replace('{n}', String(errorCount)),
|
|
1068
|
-
h(IconChevronRightOutlineRegular, { size: 12 }))
|
|
1069
|
-
: null,
|
|
1070
1111
|
active && typeof onCancel === 'function'
|
|
1071
1112
|
? h('button', { type: 'button', className: 'capital-automation-btn', 'data-size': 'sm', 'data-variant': 'danger', disabled: busy, onClick: () => onCancel(run) }, zh.cancelRun)
|
|
1072
1113
|
: run.sessionId && onOpenSession
|
|
1073
|
-
? h('button', { type: 'button', className: 'capital-automation-btn', 'data-size': 'sm', onClick: () => onOpenSession(run.sessionId) },
|
|
1114
|
+
? h('button', { type: 'button', className: 'capital-automation-btn', 'data-size': 'sm', 'data-variant': 'primary', onClick: () => onOpenSession(run.sessionId) },
|
|
1115
|
+
h(IconRightUpOutlineRegular, { size: 13 }),
|
|
1116
|
+
zh.openSession)
|
|
1074
1117
|
: null)),
|
|
1075
1118
|
errorsOpen && errorCount > 0
|
|
1076
1119
|
? h('div', { id: errorPanelId, className: 'capital-automation-runerrors', role: 'region', 'aria-label': zh.errorDetailsLabel },
|
|
@@ -1266,7 +1309,7 @@ function TaskRow(props) {
|
|
|
1266
1309
|
const { task, onOpen, menuOpen, onMenuToggle, onMenuClose, onEdit, onAction, onRequestConfirm, canRun, busy, mutationsDisabled } = props
|
|
1267
1310
|
const run = task.lastRun
|
|
1268
1311
|
const running = isActiveRun(run)
|
|
1269
|
-
const
|
|
1312
|
+
const next = nextRunView(task)
|
|
1270
1313
|
return h('div', { className: 'capital-automation-trow' },
|
|
1271
1314
|
h('button', { type: 'button', className: 'capital-automation-trowmain', onClick: () => onOpen(task.id) },
|
|
1272
1315
|
h('span', { className: 'capital-automation-cell capital-automation-identity' },
|
|
@@ -1281,8 +1324,8 @@ function TaskRow(props) {
|
|
|
1281
1324
|
h('span', { className: 'capital-automation-schedule' }, scheduleSummary(task.trigger)),
|
|
1282
1325
|
h('span', { className: 'capital-automation-schedulesub' }, task.trigger?.timezone ?? '')),
|
|
1283
1326
|
h('span', { className: 'capital-automation-cell', 'data-cell': 'next' },
|
|
1284
|
-
h('span', { className: 'capital-automation-nextmain' },
|
|
1285
|
-
h('span', { className: 'capital-automation-nextsub' },
|
|
1327
|
+
h('span', { className: 'capital-automation-nextmain' }, next.value),
|
|
1328
|
+
h('span', { className: 'capital-automation-nextsub' }, next.sub)),
|
|
1286
1329
|
h('span', { className: 'capital-automation-cell' },
|
|
1287
1330
|
h(StateBadge, { state: task.state, running }))),
|
|
1288
1331
|
h('div', { className: 'capital-automation-trowmenu' },
|
|
@@ -1347,7 +1390,9 @@ function TemplateCard(props) {
|
|
|
1347
1390
|
h('span', { className: 'capital-automation-templatemeta' },
|
|
1348
1391
|
h(IconClockOutlineRegular, { size: 12 }),
|
|
1349
1392
|
`${zh.templateMeta} · ${scheduleSummary(task.trigger)}`),
|
|
1350
|
-
h('button', { type: 'button', className: 'capital-automation-btn', 'data-size': 'sm', 'data-variant': 'primary', onClick: () => onEnable(task), disabled: busy || disabled },
|
|
1393
|
+
h('button', { type: 'button', className: 'capital-automation-btn', 'data-size': 'sm', 'data-variant': 'primary', onClick: () => onEnable(task), disabled: busy || disabled },
|
|
1394
|
+
h(IconPlusOutlineRegular, { size: 12 }),
|
|
1395
|
+
busy ? zh.templateAdding : zh.templateAdd)))
|
|
1351
1396
|
}
|
|
1352
1397
|
|
|
1353
1398
|
function EmptyState(props) {
|
|
@@ -1617,14 +1662,19 @@ function TriggerFields(props) {
|
|
|
1617
1662
|
return h('div', { className: 'capital-automation-triggerbox' },
|
|
1618
1663
|
h('div', { className: 'capital-automation-triggerrow' },
|
|
1619
1664
|
h('span', { className: 'capital-automation-triggerclock', 'aria-hidden': 'true' }, h(IconAlarmClockOutlineRegular, { size: 16 })),
|
|
1620
|
-
h('
|
|
1665
|
+
h('div', { className: 'capital-automation-triggerfield' },
|
|
1621
1666
|
h('span', null, '重复'),
|
|
1622
|
-
h(
|
|
1623
|
-
|
|
1624
|
-
|
|
1667
|
+
h(Select, {
|
|
1668
|
+
value: trigger.cadence,
|
|
1669
|
+
options: Object.entries(zh.cadence).map(([value, label]) => ({ value, label })),
|
|
1670
|
+
onChange: setCadence,
|
|
1671
|
+
disabled,
|
|
1672
|
+
label: '重复',
|
|
1673
|
+
})),
|
|
1674
|
+
h('label', { className: 'capital-automation-triggerfield' },
|
|
1625
1675
|
h('span', null, zh.timeField),
|
|
1626
1676
|
h('input', { type: 'time', value: trigger.time, disabled, onChange: (event) => update({ time: event.target.value }) })),
|
|
1627
|
-
h('label',
|
|
1677
|
+
h('label', { className: 'capital-automation-triggerfield' },
|
|
1628
1678
|
h('span', null, zh.timezoneField),
|
|
1629
1679
|
h('input', {
|
|
1630
1680
|
type: 'text',
|
|
@@ -1647,13 +1697,18 @@ function TriggerFields(props) {
|
|
|
1647
1697
|
}, day.label)))
|
|
1648
1698
|
: null,
|
|
1649
1699
|
trigger.cadence === 'monthly'
|
|
1650
|
-
? h('
|
|
1700
|
+
? h('div', { className: 'capital-automation-triggerfield' },
|
|
1651
1701
|
h('span', null, zh.dayField),
|
|
1652
|
-
h(
|
|
1653
|
-
value: trigger.dayOfMonth ?? 1,
|
|
1702
|
+
h(Select, {
|
|
1703
|
+
value: String(trigger.dayOfMonth ?? 1),
|
|
1704
|
+
options: Array.from({ length: 28 }, (_, index) => {
|
|
1705
|
+
const day = index + 1
|
|
1706
|
+
return { value: String(day), label: zh.dayOfMonth.replace('{n}', String(day)) }
|
|
1707
|
+
}),
|
|
1708
|
+
onChange: (day) => update({ dayOfMonth: Number(day) }),
|
|
1654
1709
|
disabled,
|
|
1655
|
-
|
|
1656
|
-
}
|
|
1710
|
+
label: zh.dayField,
|
|
1711
|
+
}))
|
|
1657
1712
|
: null,
|
|
1658
1713
|
trigger.cadence === 'daily' ? h('span', { className: 'capital-automation-hint' }, trigger.tradingDaysOnly === true ? zh.triggerHint : zh.triggerHintNatural) : null,
|
|
1659
1714
|
h('label', { className: 'capital-automation-switch', style: { marginLeft: 'auto' } },
|
|
@@ -1685,6 +1740,67 @@ function Field(props) {
|
|
|
1685
1740
|
hint ? h('span', { className: 'capital-automation-hint' }, hint) : null)
|
|
1686
1741
|
}
|
|
1687
1742
|
|
|
1743
|
+
/**
|
|
1744
|
+
* DSH General-settings style selector: a filled pill plus the shared Menu surface.
|
|
1745
|
+
* Native <select> is intentionally avoided so light/dark themes follow host tokens.
|
|
1746
|
+
*/
|
|
1747
|
+
function Select(props) {
|
|
1748
|
+
const { value, options, onChange, disabled, label, block, size, align = 'start' } = props
|
|
1749
|
+
const [open, setOpen] = useState(false)
|
|
1750
|
+
const triggerRef = useRef(null)
|
|
1751
|
+
const items = options.map((option) => ({
|
|
1752
|
+
id: String(option.value),
|
|
1753
|
+
label: option.label,
|
|
1754
|
+
disabled: option.disabled === true,
|
|
1755
|
+
}))
|
|
1756
|
+
const currentValue = String(value ?? '')
|
|
1757
|
+
const current = items.find((item) => item.id === currentValue) ?? items[0]
|
|
1758
|
+
useEffect(() => {
|
|
1759
|
+
if (disabled === true && open) setOpen(false)
|
|
1760
|
+
}, [disabled, open])
|
|
1761
|
+
const closeMenu = () => setOpen(false)
|
|
1762
|
+
const selectValue = (id) => {
|
|
1763
|
+
setOpen(false)
|
|
1764
|
+
triggerRef.current?.focus?.({ preventScroll: true })
|
|
1765
|
+
if (id !== currentValue) onChange(id)
|
|
1766
|
+
}
|
|
1767
|
+
const trigger = h('button', {
|
|
1768
|
+
ref: triggerRef,
|
|
1769
|
+
type: 'button',
|
|
1770
|
+
className: 'capital-automation-select',
|
|
1771
|
+
'data-block': block === true ? 'true' : undefined,
|
|
1772
|
+
'data-size': size,
|
|
1773
|
+
disabled,
|
|
1774
|
+
'aria-label': current?.label ? `${label}:${current.label}` : label,
|
|
1775
|
+
'aria-haspopup': 'menu',
|
|
1776
|
+
'aria-expanded': open ? 'true' : 'false',
|
|
1777
|
+
onClick: () => setOpen((currentOpen) => !currentOpen),
|
|
1778
|
+
},
|
|
1779
|
+
h('span', {
|
|
1780
|
+
className: 'capital-automation-selectvalue',
|
|
1781
|
+
title: current?.label,
|
|
1782
|
+
}, current?.label ?? ''),
|
|
1783
|
+
h(IconChevronDownOutlineRegular, { size: size === 'sm' ? 12 : 14 }))
|
|
1784
|
+
return h(Menu, {
|
|
1785
|
+
open,
|
|
1786
|
+
anchor: trigger,
|
|
1787
|
+
items,
|
|
1788
|
+
selectedId: currentValue,
|
|
1789
|
+
onSelect: selectValue,
|
|
1790
|
+
onClose: closeMenu,
|
|
1791
|
+
align,
|
|
1792
|
+
portal: true,
|
|
1793
|
+
})
|
|
1794
|
+
}
|
|
1795
|
+
|
|
1796
|
+
function SelectField(props) {
|
|
1797
|
+
const { label, hint, ariaLabel, block = true, ...rest } = props
|
|
1798
|
+
return h('div', { className: 'capital-automation-field' },
|
|
1799
|
+
h('span', null, label),
|
|
1800
|
+
h(Select, { ...rest, label: ariaLabel ?? label, block }),
|
|
1801
|
+
hint ? h('span', { className: 'capital-automation-hint' }, hint) : null)
|
|
1802
|
+
}
|
|
1803
|
+
|
|
1688
1804
|
function NumberField(props) {
|
|
1689
1805
|
const { label, value, min, max, disabled, onChange } = props
|
|
1690
1806
|
return h(Field, { label },
|
|
@@ -1755,53 +1871,46 @@ function RunsPage(props) {
|
|
|
1755
1871
|
}
|
|
1756
1872
|
|
|
1757
1873
|
function OverviewTab(props) {
|
|
1758
|
-
const { detail, meta, onGoRuns } = props
|
|
1874
|
+
const { detail, meta, onGoRuns, onCancelRun, onOpenSession } = props
|
|
1759
1875
|
const latest = detail.runs[0]
|
|
1760
|
-
const next =
|
|
1876
|
+
const next = nextRunView(detail.task)
|
|
1877
|
+
const last = lastRunView(latest, detail.task.trigger.timezone)
|
|
1761
1878
|
const anyRunning = detail.runs.some((run) => isActiveRun(run))
|
|
1762
1879
|
const stateText = anyRunning ? zh.status.running : stateLabel(detail.task.state)
|
|
1880
|
+
const originLabel = detail.task.origin === 'builtin' ? zh.origin.builtin : zh.origin.custom
|
|
1881
|
+
const scheduleText = `${scheduleRangeSummary(detail.task.trigger)}${detail.task.trigger.tradingDaysOnly === true ? ` · ${zh.tradingDaysField}` : ''}`
|
|
1882
|
+
const scheduleHint = detail.task.trigger.tradingDaysOnly === true ? zh.triggerHint : zh.triggerHintNatural
|
|
1763
1883
|
return h('div', { className: 'capital-automation-overview' },
|
|
1764
1884
|
h('div', { className: 'capital-automation-statgrid' },
|
|
1765
1885
|
h('div', { className: 'capital-automation-stat' },
|
|
1766
1886
|
h('span', { className: 'capital-automation-statlabel' }, zh.stateLabel),
|
|
1767
1887
|
h('span', { className: 'capital-automation-statvalue', 'data-tone': anyRunning ? 'running' : undefined }, stateText),
|
|
1768
|
-
h('span', { className: 'capital-automation-statsub'
|
|
1888
|
+
h('span', { className: 'capital-automation-statsub', title: detail.task.origin === 'builtin' ? zh.configBuiltinHint : undefined }, originLabel)),
|
|
1769
1889
|
h('div', { className: 'capital-automation-stat' },
|
|
1770
1890
|
h('span', { className: 'capital-automation-statlabel' }, zh.nextRun),
|
|
1771
|
-
h('span', { className: 'capital-automation-statvalue' }, next),
|
|
1772
|
-
h('span', { className: 'capital-automation-statsub' },
|
|
1891
|
+
h('span', { className: 'capital-automation-statvalue' }, next.value),
|
|
1892
|
+
h('span', { className: 'capital-automation-statsub' }, next.sub)),
|
|
1773
1893
|
h('div', { className: 'capital-automation-stat' },
|
|
1774
1894
|
h('span', { className: 'capital-automation-statlabel' }, zh.lastResult),
|
|
1775
|
-
h('span', { className: 'capital-automation-statvalue', 'data-tone':
|
|
1776
|
-
h('span', { className: 'capital-automation-statsub' },
|
|
1777
|
-
h('div', { className: 'capital-automation-stat' },
|
|
1895
|
+
h('span', { className: 'capital-automation-statvalue', 'data-tone': last.tone }, last.value),
|
|
1896
|
+
h('span', { className: 'capital-automation-statsub' }, last.sub)),
|
|
1897
|
+
h('div', { className: 'capital-automation-stat', title: scheduleHint },
|
|
1778
1898
|
h('span', { className: 'capital-automation-statlabel' }, zh.triggerSummary),
|
|
1779
|
-
h('span', { className: 'capital-automation-statvalue' },
|
|
1899
|
+
h('span', { className: 'capital-automation-statvalue' }, scheduleText),
|
|
1780
1900
|
h('span', { className: 'capital-automation-statsub' }, `${detail.task.trigger.time} · ${detail.task.trigger.timezone}`))),
|
|
1781
1901
|
h('section', { className: 'capital-automation-card capital-automation-panel' },
|
|
1782
1902
|
h('div', { className: 'capital-automation-panelhead' },
|
|
1783
|
-
h('h3', null, zh.
|
|
1784
|
-
h('span', { className: 'capital-automation-hint' }, detail.task.trigger.tradingDaysOnly === true ? zh.triggerHint : zh.triggerHintNatural)),
|
|
1785
|
-
h('div', { className: 'capital-automation-kv' },
|
|
1786
|
-
h('div', { className: 'capital-automation-kvitem' },
|
|
1787
|
-
h('span', { className: 'capital-automation-kvlabel' }, zh.triggerField),
|
|
1788
|
-
h('span', { className: 'capital-automation-kvvalue' }, scheduleSummary(detail.task.trigger))),
|
|
1789
|
-
h('div', { className: 'capital-automation-kvitem' },
|
|
1790
|
-
h('span', { className: 'capital-automation-kvlabel' }, zh.timezoneField),
|
|
1791
|
-
h('span', { className: 'capital-automation-kvvalue' }, detail.task.trigger.timezone)),
|
|
1792
|
-
h('div', { className: 'capital-automation-kvitem' },
|
|
1793
|
-
h('span', { className: 'capital-automation-kvlabel' }, zh.nextRun),
|
|
1794
|
-
h('span', { className: 'capital-automation-kvvalue' }, `${next}${detail.task.nextRunAt ? ` · ${formatRelative(detail.task.nextRunAt)}` : ''}`)),
|
|
1795
|
-
h('div', { className: 'capital-automation-kvitem' },
|
|
1796
|
-
h('span', { className: 'capital-automation-kvlabel' }, zh.stateLabel),
|
|
1797
|
-
h('span', { className: 'capital-automation-kvvalue' }, `${stateText}${detail.task.trigger.tradingDaysOnly ? ` · ${zh.tradingDaysField}` : ''}`)))),
|
|
1798
|
-
h('section', { className: 'capital-automation-card capital-automation-panel' },
|
|
1799
|
-
h('div', { className: 'capital-automation-panelhead' },
|
|
1800
|
-
h('h3', null, zh.detailRecentRuns),
|
|
1903
|
+
h('h3', null, zh.detailRecentRuns.replace('{n}', String(DETAIL_RECENT_RUN_LIMIT))),
|
|
1801
1904
|
h('button', { type: 'button', className: 'capital-automation-btn', 'data-size': 'sm', 'data-variant': 'ghost', onClick: onGoRuns },
|
|
1802
1905
|
zh.detailAllRuns,
|
|
1803
1906
|
h(IconChevronRightOutlineRegular, { size: 13 }))),
|
|
1804
|
-
h(RunList, {
|
|
1907
|
+
h(RunList, {
|
|
1908
|
+
runs: detail.runs.slice(0, DETAIL_RECENT_RUN_LIMIT),
|
|
1909
|
+
tasks: [detail.task],
|
|
1910
|
+
onCancel: onCancelRun,
|
|
1911
|
+
onOpenSession,
|
|
1912
|
+
compact: true,
|
|
1913
|
+
})),
|
|
1805
1914
|
h('section', { className: 'capital-automation-card capital-automation-panel' },
|
|
1806
1915
|
h('div', { className: 'capital-automation-panelhead' },
|
|
1807
1916
|
h('h3', null, zh.environment)),
|
|
@@ -1818,26 +1927,21 @@ function OverviewTab(props) {
|
|
|
1818
1927
|
h('div', { className: 'capital-automation-kvitem' },
|
|
1819
1928
|
h('span', { className: 'capital-automation-kvlabel' }, zh.modeField),
|
|
1820
1929
|
h('span', { className: 'capital-automation-kvvalue' }, modeLabel(detail.task.mode)))),
|
|
1821
|
-
h('
|
|
1822
|
-
h('
|
|
1823
|
-
h('p', null, zh.budgetHint)),
|
|
1824
|
-
h('details', { className: 'capital-automation-technical' },
|
|
1825
|
-
h('summary', null, zh.techInfo),
|
|
1930
|
+
h('section', { className: 'capital-automation-technical' },
|
|
1931
|
+
h('h4', { className: 'capital-automation-technicaltitle' }, zh.techInfo),
|
|
1826
1932
|
h('dl', null,
|
|
1827
1933
|
h('dt', null, zh.profileKey),
|
|
1828
|
-
h('dd',
|
|
1934
|
+
h('dd', { title: 'profileKey 是 profile 名称的稳定哈希;与 session 标题里的 run id 无关。' }, meta?.profile?.key ?? '—'),
|
|
1829
1935
|
h('dt', null, zh.presetLabel),
|
|
1830
1936
|
h('dd', null, zh.presetValue),
|
|
1831
1937
|
h('dt', null, zh.policyField),
|
|
1832
1938
|
h('dd', null, meta?.execution?.policy ?? 'automation-v1'),
|
|
1833
1939
|
h('dt', null, zh.cwdKind),
|
|
1834
|
-
h('dd',
|
|
1835
|
-
h('dt', null, 'profile'),
|
|
1940
|
+
h('dd', { title: '当前固定为 profile(专属自动化工作区);没有 storage 等其他来源。' }, meta?.execution?.cwdKind ?? 'profile'),
|
|
1941
|
+
h('dt', null, 'profile 名称'),
|
|
1836
1942
|
h('dd', null, meta?.profile?.name ?? '—'),
|
|
1837
1943
|
h('dt', null, zh.calendarField),
|
|
1838
|
-
h('dd', null, calendarLabel(meta?.calendar))
|
|
1839
|
-
h('dt', null, zh.version),
|
|
1840
|
-
h('dd', null, meta?.version ? `v${meta.version}` : '—')))))
|
|
1944
|
+
h('dd', null, calendarLabel(meta?.calendar))))))
|
|
1841
1945
|
}
|
|
1842
1946
|
|
|
1843
1947
|
function ConfigTab(props) {
|
|
@@ -1855,18 +1959,21 @@ function ConfigTab(props) {
|
|
|
1855
1959
|
h('summary', null, zh.advanced),
|
|
1856
1960
|
h('div', { className: 'capital-automation-advancedbody' },
|
|
1857
1961
|
h('div', { className: 'capital-automation-formgrid' },
|
|
1858
|
-
h(
|
|
1859
|
-
|
|
1860
|
-
|
|
1861
|
-
|
|
1862
|
-
|
|
1863
|
-
|
|
1864
|
-
|
|
1865
|
-
|
|
1866
|
-
|
|
1867
|
-
|
|
1868
|
-
|
|
1869
|
-
|
|
1962
|
+
h(SelectField, {
|
|
1963
|
+
label: zh.workspaceField,
|
|
1964
|
+
value: task.workspaceId ?? '',
|
|
1965
|
+
options: workspaceOptions(meta, task.workspaceId).map((option) => ({ value: option.id, label: option.title })),
|
|
1966
|
+
disabled: busy || disabled,
|
|
1967
|
+
onChange: (workspaceId) => set({ workspaceId }),
|
|
1968
|
+
}),
|
|
1969
|
+
h(SelectField, {
|
|
1970
|
+
label: zh.modeField,
|
|
1971
|
+
hint: zh.modeHint,
|
|
1972
|
+
value: task.mode,
|
|
1973
|
+
options: Object.entries(zh.mode).map(([value, label]) => ({ value, label })),
|
|
1974
|
+
disabled: busy || disabled,
|
|
1975
|
+
onChange: (mode) => set({ mode }),
|
|
1976
|
+
})),
|
|
1870
1977
|
h('div', { className: 'capital-automation-formgrid' },
|
|
1871
1978
|
h(NumberField, { label: zh.runTimeout, value: task.limits.runTimeoutMinutes, min: timeoutRange[0], max: timeoutRange[1], disabled: busy || disabled, onChange: (value) => set((current) => ({ limits: { ...current.limits, runTimeoutMinutes: value } })) }),
|
|
1872
1979
|
h(NumberField, { label: zh.idleTimeout, value: task.limits.idleTimeoutMinutes, min: idleRange[0], max: idleRange[1], disabled: busy || disabled, onChange: (value) => set((current) => ({ limits: { ...current.limits, idleTimeoutMinutes: value } })) }),
|
|
@@ -1882,16 +1989,23 @@ function ConfigTab(props) {
|
|
|
1882
1989
|
h(SwitchRow, { label: zh.notifySuccess, checked: task.notifications.onSuccess, disabled: busy || disabled, onChange: (value) => set((current) => ({ notifications: { ...current.notifications, onSuccess: value } })) })),
|
|
1883
1990
|
h('p', { className: 'capital-automation-hint' }, zh.notifyHint))
|
|
1884
1991
|
return h('div', { className: 'capital-automation-form' },
|
|
1992
|
+
task.origin === 'builtin'
|
|
1993
|
+
? h('div', { className: 'capital-automation-formnote' },
|
|
1994
|
+
h(IconInfoOutlineRegular, { size: 13 }),
|
|
1995
|
+
h('span', null, zh.configBuiltinHint))
|
|
1996
|
+
: null,
|
|
1885
1997
|
h(Field, { label: zh.titleField },
|
|
1886
1998
|
h('input', { value: task.title, disabled: busy || disabled, onChange: (event) => set({ title: event.target.value }) })),
|
|
1887
1999
|
h(Field, { label: zh.descriptionField },
|
|
1888
2000
|
h('textarea', { value: task.description ?? '', disabled: busy || disabled, rows: 3, onChange: (event) => set({ description: event.target.value }) })),
|
|
1889
|
-
h(
|
|
1890
|
-
|
|
1891
|
-
|
|
1892
|
-
|
|
1893
|
-
|
|
1894
|
-
|
|
2001
|
+
h(SelectField, {
|
|
2002
|
+
label: zh.categoryField,
|
|
2003
|
+
hint: task.origin === 'builtin' ? zh.categoryFixed : undefined,
|
|
2004
|
+
value: task.category,
|
|
2005
|
+
options: Object.entries(zh.category).map(([value, label]) => ({ value, label })),
|
|
2006
|
+
disabled: busy || disabled || task.origin === 'builtin',
|
|
2007
|
+
onChange: (category) => set({ category }),
|
|
2008
|
+
}),
|
|
1895
2009
|
h(Field, { label: zh.instructionField },
|
|
1896
2010
|
h('textarea', {
|
|
1897
2011
|
value: task.instruction,
|
|
@@ -1957,7 +2071,7 @@ function DetailBar(props) {
|
|
|
1957
2071
|
}
|
|
1958
2072
|
|
|
1959
2073
|
function TaskDetailPage(props) {
|
|
1960
|
-
const { detail, meta, api, onChanged, openSession, tab, onTab, onRequestConfirm, onRequestCancelRun,
|
|
2074
|
+
const { detail, meta, api, onChanged, openSession, tab, onTab, onRequestConfirm, onRequestCancelRun, schedulerActive, storageReady } = props
|
|
1961
2075
|
const [draft, setDraft] = useState(null)
|
|
1962
2076
|
const [busy, setBusy] = useState('')
|
|
1963
2077
|
const [notice, setNotice] = useState('')
|
|
@@ -2063,7 +2177,7 @@ function TaskDetailPage(props) {
|
|
|
2063
2177
|
disabled: busy || !canRun,
|
|
2064
2178
|
title: schedulerActive === false ? zh.schedulerBlocked : running ? zh.runBlocked : undefined,
|
|
2065
2179
|
onClick: () => { void runNow() },
|
|
2066
|
-
}, zh.runNow)
|
|
2180
|
+
}, h(IconPlayOutlineRegular, { size: 14 }), zh.runNow)
|
|
2067
2181
|
|
|
2068
2182
|
const resetDraft = () => {
|
|
2069
2183
|
setDraft({
|
|
@@ -2084,13 +2198,7 @@ function TaskDetailPage(props) {
|
|
|
2084
2198
|
h('h2', null, detail.task.title),
|
|
2085
2199
|
h(StateBadge, { state: detail.task.state, running }),
|
|
2086
2200
|
unread > 0 ? h('span', { className: 'capital-automation-count', title: zh.unread }, String(unread)) : null),
|
|
2087
|
-
h('p', { className: 'capital-automation-herodesc' }, detail.task.description || zh.subtitle),
|
|
2088
|
-
h('div', { className: 'capital-automation-herometa' },
|
|
2089
|
-
h('span', null, h(IconClockOutlineRegular, { size: 13 }), scheduleSummary(detail.task.trigger)),
|
|
2090
|
-
h('span', null, `${zh.nextRun} ${detail.task.nextRunLocal ?? (detail.task.nextRunUnavailable ? zh.calendarUnavailable : zh.never)}`),
|
|
2091
|
-
h('span', null, `${zh.lastResult} ${detail.runs[0] ? statusLabel(detail.runs[0].status) : zh.never}`),
|
|
2092
|
-
h('span', null, categoryLabel(detail.task.category)),
|
|
2093
|
-
detail.task.origin === 'builtin' ? h('span', { className: 'capital-automation-tag' }, zh.origin.builtin) : h('span', { className: 'capital-automation-tag', 'data-tone': 'custom' }, zh.origin.custom))),
|
|
2201
|
+
h('p', { className: 'capital-automation-herodesc' }, detail.task.description || zh.subtitle)),
|
|
2094
2202
|
h('div', { className: 'capital-automation-heroactions' },
|
|
2095
2203
|
runButton,
|
|
2096
2204
|
running
|
|
@@ -2101,7 +2209,7 @@ function TaskDetailPage(props) {
|
|
|
2101
2209
|
'data-variant': detail.task.state === 'active' ? undefined : 'primary',
|
|
2102
2210
|
disabled: busy || !storageReadyNow,
|
|
2103
2211
|
onClick: () => { void toggleState() },
|
|
2104
|
-
}, activationLabel(detail.task)),
|
|
2212
|
+
}, h(activationIcon(detail.task), { size: 14 }), activationLabel(detail.task)),
|
|
2105
2213
|
h(TaskActionsMenu, {
|
|
2106
2214
|
task: detail.task,
|
|
2107
2215
|
open: menuOpen,
|
|
@@ -2135,9 +2243,14 @@ function TaskDetailPage(props) {
|
|
|
2135
2243
|
error.length > 0 ? h('p', { className: 'capital-automation-error', role: 'alert' }, error) : null)
|
|
2136
2244
|
: null,
|
|
2137
2245
|
running ? h('p', { className: 'capital-automation-hint', style: { paddingTop: 10 } }, zh.configWhileRunning) : null,
|
|
2138
|
-
detail.task.origin === 'builtin' ? h('p', { className: 'capital-automation-hint', style: { paddingTop: 8 } }, zh.configBuiltinHint) : null,
|
|
2139
2246
|
h('div', { className: 'capital-automation-detailbody' },
|
|
2140
|
-
tab === 'overview' ? h(OverviewTab, {
|
|
2247
|
+
tab === 'overview' ? h(OverviewTab, {
|
|
2248
|
+
detail,
|
|
2249
|
+
meta,
|
|
2250
|
+
onGoRuns: () => onTab('runs'),
|
|
2251
|
+
onCancelRun: onRequestCancelRun,
|
|
2252
|
+
onOpenSession: openSession,
|
|
2253
|
+
}) : null,
|
|
2141
2254
|
tab === 'config' ? h(ConfigTab, {
|
|
2142
2255
|
draft,
|
|
2143
2256
|
setDraft,
|
|
@@ -2244,25 +2357,37 @@ function NewTaskModal(props) {
|
|
|
2244
2357
|
onChange: (event) => set({ instruction: event.target.value }),
|
|
2245
2358
|
}),
|
|
2246
2359
|
h('div', { className: 'capital-automation-prompttoolbar' },
|
|
2247
|
-
h('
|
|
2360
|
+
h('div', { className: 'capital-automation-toolbarfield' },
|
|
2248
2361
|
h(IconFolderOpenOutlineRegular, { size: 13 }),
|
|
2249
2362
|
h('span', null, zh.workspaceField),
|
|
2250
|
-
h(
|
|
2363
|
+
h(Select, {
|
|
2251
2364
|
value: draft.workspaceId ?? '',
|
|
2252
|
-
|
|
2253
|
-
|
|
2254
|
-
|
|
2365
|
+
options: workspaceOptions(meta, draft.workspaceId).map((option) => ({ value: option.id, label: option.title })),
|
|
2366
|
+
onChange: (workspaceId) => set({ workspaceId }),
|
|
2367
|
+
label: zh.workspaceField,
|
|
2368
|
+
size: 'sm',
|
|
2369
|
+
align: 'end',
|
|
2370
|
+
})),
|
|
2371
|
+
h('div', { className: 'capital-automation-toolbarfield' },
|
|
2255
2372
|
h('span', null, zh.categoryField),
|
|
2256
|
-
h(
|
|
2373
|
+
h(Select, {
|
|
2257
2374
|
value: draft.category,
|
|
2258
|
-
|
|
2259
|
-
|
|
2260
|
-
|
|
2375
|
+
options: Object.entries(zh.category).map(([value, label]) => ({ value, label })),
|
|
2376
|
+
onChange: (category) => set({ category }),
|
|
2377
|
+
label: zh.categoryField,
|
|
2378
|
+
size: 'sm',
|
|
2379
|
+
align: 'end',
|
|
2380
|
+
})),
|
|
2381
|
+
h('div', { className: 'capital-automation-toolbarfield' },
|
|
2261
2382
|
h('span', null, zh.modeField),
|
|
2262
|
-
h(
|
|
2383
|
+
h(Select, {
|
|
2263
2384
|
value: draft.mode,
|
|
2264
|
-
|
|
2265
|
-
|
|
2385
|
+
options: Object.entries(zh.mode).map(([value, label]) => ({ value, label })),
|
|
2386
|
+
onChange: (mode) => set({ mode }),
|
|
2387
|
+
label: zh.modeField,
|
|
2388
|
+
size: 'sm',
|
|
2389
|
+
align: 'end',
|
|
2390
|
+
})),
|
|
2266
2391
|
h('span', { className: 'capital-automation-presetchip', title: zh.modeHint },
|
|
2267
2392
|
h(IconSparkleRegular, { size: 12 }),
|
|
2268
2393
|
zh.presetValue)))),
|
|
@@ -2631,7 +2756,6 @@ function AutomationPage(props) {
|
|
|
2631
2756
|
onTab: setDetailTab,
|
|
2632
2757
|
onRequestConfirm: requestConfirm,
|
|
2633
2758
|
onRequestCancelRun: (run) => requestConfirm('cancel-run', selectedTask ?? { id: run.taskId, title: run.taskTitle }, run),
|
|
2634
|
-
onOpenAllRuns: () => switchTab('runs'),
|
|
2635
2759
|
schedulerActive,
|
|
2636
2760
|
storageReady,
|
|
2637
2761
|
onChanged: async (taskId) => {
|