@qihongmu/dsh-client-ui-scheduled-task 0.1.0

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/lib/client.js ADDED
@@ -0,0 +1,1563 @@
1
+ window.__ModuleLoader__.load({
2
+ id: "@qihongmu/dsh-client-ui-scheduled-task",
3
+ factory: (require) => {
4
+ var module = { exports: {} };
5
+ var exports = module.exports;
6
+ Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
7
+ let react = require("react");
8
+ let _deepseek_ai_dsh_client_ui_primitives = require("@deepseek-ai/dsh-client-ui-primitives");
9
+ let react_jsx_runtime = require("react/jsx-runtime");
10
+ //#region src/client/locales.ts
11
+ /** Scheduled-tasks panel UI dictionaries. */
12
+ const NS = "scheduled-tasks";
13
+ /** Simplified Chinese scheduled-tasks UI messages. */
14
+ const zh = {
15
+ "trigger.label": "定时任务",
16
+ "trigger.aria": "定时任务",
17
+ "panel.title": "已安排的任务",
18
+ "panel.subtitle": "让助手安排任务、设置提醒或监测更新",
19
+ "panel.empty": "还没有任何任务",
20
+ "panel.loading": "读取中…",
21
+ "panel.readFailed": "读取任务列表失败:{message}",
22
+ "search.placeholder": "搜索已安排任务",
23
+ "filter.all": "全部",
24
+ "filter.active": "已开启",
25
+ "filter.paused": "已暂停",
26
+ "drawer.close": "关闭",
27
+ "row.schedule.every": "每 {duration}",
28
+ "row.schedule.after": "{duration} 后执行一次",
29
+ "row.schedule.at": "定时:{time}",
30
+ "row.schedule.hourly": "每小时的第 {minute} 分",
31
+ "row.schedule.daily": "每天 {time}",
32
+ "row.schedule.weekly": "每周{weekdays} {time}",
33
+ "row.schedule.monthly": "每月 {day} 号 {time}",
34
+ "row.next": "下次运行 {time}",
35
+ "row.status.active": "进行中",
36
+ "row.status.paused": "已暂停",
37
+ "row.status.completed": "已完成",
38
+ "row.state.overdue": "已逾期",
39
+ "row.lastError": "上次触发失败",
40
+ "action.create": "创建",
41
+ "action.pause": "暂停",
42
+ "action.resume": "恢复",
43
+ "action.edit": "编辑",
44
+ "action.delete": "删除",
45
+ "action.markRead": "标记已读",
46
+ "create.title": "新建定时任务",
47
+ "create.editTitle": "编辑定时任务",
48
+ "create.subtitle": "配置任务的执行时间、指令和运行方式。",
49
+ "create.submit": "创建定时任务",
50
+ "create.save": "保存修改",
51
+ "form.title.label": "任务标题",
52
+ "form.title.placeholder": "未命名定时任务",
53
+ "form.prompt.label": "指令",
54
+ "form.prompt.placeholder": "例如:Review 最近 24 小时的提交,总结可能引入的 bug 和修复建议",
55
+ "form.prompt.required": "请填写任务指令",
56
+ "form.schedule.label": "调度",
57
+ "form.schedule.required": "请先选择调度频率",
58
+ "form.schedule.invalid": "调度信息不完整,请补全后重试",
59
+ "form.schedule.add": "+ 添加计划",
60
+ "schedule.hourly": "每小时",
61
+ "schedule.daily": "每天",
62
+ "schedule.weekly": "每周",
63
+ "schedule.monthly": "每月",
64
+ "schedule.custom": "自定义",
65
+ "schedule.hourlyAtMinute": "第",
66
+ "schedule.minuteUnit": "分",
67
+ "schedule.at": "于",
68
+ "schedule.dayUnit": "号",
69
+ "schedule.clear": "删除调度",
70
+ "schedule.pickWeekdays": "选择星期",
71
+ "schedule.wd.1": "一",
72
+ "schedule.wd.2": "二",
73
+ "schedule.wd.3": "三",
74
+ "schedule.wd.4": "四",
75
+ "schedule.wd.5": "五",
76
+ "schedule.wd.6": "六",
77
+ "schedule.wd.7": "日",
78
+ "schedule.wd.separator": "、",
79
+ "schedule.preview.hourly": "每小时的第 {minute} 分",
80
+ "schedule.preview.daily": "每天 {time}",
81
+ "schedule.preview.weekly": "每周{weekdays} {time}",
82
+ "schedule.preview.monthly": "每月 {day} 号 {time}",
83
+ "form.kind.once": "指定时间",
84
+ "form.kind.delay": "延迟执行",
85
+ "form.kind.interval": "周期执行",
86
+ "form.date": "日期",
87
+ "form.time": "时间",
88
+ "form.timeZone": "时区",
89
+ "form.afterSeconds": "延迟秒数",
90
+ "form.everySeconds": "间隔秒数",
91
+ "form.project.label": "项目",
92
+ "form.project.none": "默认目录(不选择项目)",
93
+ "form.project.loading": "读取项目…",
94
+ "form.project.failed": "读取项目失败:{message}",
95
+ "form.model.label": "模型",
96
+ "form.model.default": "默认模型",
97
+ "form.model.loading": "读取模型…",
98
+ "form.model.empty": "没有打开的会话,无法列出模型;将使用默认模型。",
99
+ "form.model.failed": "读取模型失败:{message}",
100
+ "form.confirm.label": "变更前确认",
101
+ "form.confirm.hint": "运行中执行写入等敏感操作前先征求确认",
102
+ "form.cancel": "取消",
103
+ "form.submitBusy": "提交中…",
104
+ "duration.seconds": "{count} 秒",
105
+ "duration.minutes": "{count} 分钟",
106
+ "duration.hours": "{count} 小时",
107
+ "duration.days": "{count} 天"
108
+ };
109
+ /** English scheduled-tasks UI messages. */
110
+ const en = {
111
+ "trigger.label": "Scheduled Tasks",
112
+ "trigger.aria": "Scheduled tasks",
113
+ "panel.title": "Scheduled Tasks",
114
+ "panel.subtitle": "Let the assistant run tasks, set reminders, or monitor updates",
115
+ "panel.empty": "No tasks yet",
116
+ "panel.loading": "Reading…",
117
+ "panel.readFailed": "Reading the task list failed: {message}",
118
+ "search.placeholder": "Search scheduled tasks",
119
+ "filter.all": "All",
120
+ "filter.active": "Active",
121
+ "filter.paused": "Paused",
122
+ "drawer.close": "Close",
123
+ "row.schedule.every": "Every {duration}",
124
+ "row.schedule.after": "Once after {duration}",
125
+ "row.schedule.at": "At: {time}",
126
+ "row.schedule.hourly": "Hourly at minute {minute}",
127
+ "row.schedule.daily": "Daily at {time}",
128
+ "row.schedule.weekly": "Weekly {weekdays} {time}",
129
+ "row.schedule.monthly": "Monthly on day {day} at {time}",
130
+ "row.next": "Next run {time}",
131
+ "row.status.active": "Active",
132
+ "row.status.paused": "Paused",
133
+ "row.status.completed": "Completed",
134
+ "row.state.overdue": "Overdue",
135
+ "row.lastError": "Last run failed",
136
+ "action.create": "Create",
137
+ "action.pause": "Pause",
138
+ "action.resume": "Resume",
139
+ "action.edit": "Edit",
140
+ "action.delete": "Delete",
141
+ "action.markRead": "Mark as read",
142
+ "create.title": "New Scheduled Task",
143
+ "create.editTitle": "Edit Scheduled Task",
144
+ "create.subtitle": "Configure when the task runs, its instruction, and how it runs.",
145
+ "create.submit": "Create Task",
146
+ "create.save": "Save Changes",
147
+ "form.title.label": "Title",
148
+ "form.title.placeholder": "Untitled task",
149
+ "form.prompt.label": "Instruction",
150
+ "form.prompt.placeholder": "e.g. Review the last 24 hours of commits and summarize likely bugs and fixes",
151
+ "form.prompt.required": "The task instruction is required",
152
+ "form.schedule.label": "Schedule",
153
+ "form.schedule.required": "Pick a schedule frequency first",
154
+ "form.schedule.invalid": "Schedule details are incomplete",
155
+ "form.schedule.add": "+ Add schedule",
156
+ "schedule.hourly": "Hourly",
157
+ "schedule.daily": "Daily",
158
+ "schedule.weekly": "Weekly",
159
+ "schedule.monthly": "Monthly",
160
+ "schedule.custom": "Custom",
161
+ "schedule.hourlyAtMinute": "Minute",
162
+ "schedule.minuteUnit": "",
163
+ "schedule.at": "at",
164
+ "schedule.dayUnit": "",
165
+ "schedule.clear": "Clear schedule",
166
+ "schedule.pickWeekdays": "Pick weekdays",
167
+ "schedule.wd.1": "Mon",
168
+ "schedule.wd.2": "Tue",
169
+ "schedule.wd.3": "Wed",
170
+ "schedule.wd.4": "Thu",
171
+ "schedule.wd.5": "Fri",
172
+ "schedule.wd.6": "Sat",
173
+ "schedule.wd.7": "Sun",
174
+ "schedule.wd.separator": ", ",
175
+ "schedule.preview.hourly": "Hourly at minute {minute}",
176
+ "schedule.preview.daily": "Daily at {time}",
177
+ "schedule.preview.weekly": "Weekly {weekdays} {time}",
178
+ "schedule.preview.monthly": "Monthly on day {day} at {time}",
179
+ "form.kind.once": "At a time",
180
+ "form.kind.delay": "After a delay",
181
+ "form.kind.interval": "Every interval",
182
+ "form.date": "Date",
183
+ "form.time": "Time",
184
+ "form.timeZone": "Time zone",
185
+ "form.afterSeconds": "Delay seconds",
186
+ "form.everySeconds": "Interval seconds",
187
+ "form.project.label": "Project",
188
+ "form.project.none": "Default directory (no project)",
189
+ "form.project.loading": "Loading projects…",
190
+ "form.project.failed": "Loading projects failed: {message}",
191
+ "form.model.label": "Model",
192
+ "form.model.default": "Default model",
193
+ "form.model.loading": "Loading models…",
194
+ "form.model.empty": "No open conversation to list models; the default model will be used.",
195
+ "form.model.failed": "Loading models failed: {message}",
196
+ "form.confirm.label": "Confirm before changes",
197
+ "form.confirm.hint": "Ask for confirmation before sensitive actions like writes while running",
198
+ "form.cancel": "Cancel",
199
+ "form.submitBusy": "Submitting…",
200
+ "duration.seconds": "{count}s",
201
+ "duration.minutes": "{count}m",
202
+ "duration.hours": "{count}h",
203
+ "duration.days": "{count}d"
204
+ };
205
+ //#endregion
206
+ //#region src/client/format.ts
207
+ /** Format a wire ISO timestamp in the browser's default zone. */
208
+ function localizedDate(value) {
209
+ if (value === void 0) return "";
210
+ return new Intl.DateTimeFormat(void 0, {
211
+ dateStyle: "medium",
212
+ timeStyle: "short"
213
+ }).format(new Date(value));
214
+ }
215
+ /** Humanize a whole-second duration through the duration dictionary keys. */
216
+ function humanizeDuration(t, seconds) {
217
+ if (seconds % 86400 === 0) return t("duration.days", { count: seconds / 86400 });
218
+ if (seconds % 3600 === 0) return t("duration.hours", { count: seconds / 3600 });
219
+ if (seconds % 60 === 0) return t("duration.minutes", { count: seconds / 60 });
220
+ return t("duration.seconds", { count: seconds });
221
+ }
222
+ /** Join localized weekday names with the locale's list separator. */
223
+ function weekdaySummary(t, days) {
224
+ return days.map((day) => t(`schedule.wd.${day}`)).join(t("schedule.wd.separator"));
225
+ }
226
+ /** Localize one schedule rule into a one-line summary (list rows, previews). */
227
+ function ruleSummary(rule, t) {
228
+ switch (rule.kind) {
229
+ case "every": return t("row.schedule.every", { duration: humanizeDuration(t, rule.everySeconds) });
230
+ case "after": return t("row.schedule.after", { duration: humanizeDuration(t, rule.afterSeconds) });
231
+ case "at": return t("row.schedule.at", { time: localizedDate(rule.scheduledAt) });
232
+ case "hourly": return t("row.schedule.hourly", { minute: String(rule.minute).padStart(2, "0") });
233
+ case "daily": return t("row.schedule.daily", { time: rule.time });
234
+ case "weekly": return t("row.schedule.weekly", {
235
+ weekdays: weekdaySummary(t, rule.weekdays),
236
+ time: rule.time
237
+ });
238
+ case "monthly": return t("row.schedule.monthly", {
239
+ day: String(rule.dayOfMonth),
240
+ time: rule.time
241
+ });
242
+ }
243
+ }
244
+ //#endregion
245
+ //#region \0dsh-plugin-css:src/client/ScheduledTasksPanel.module.css.dshcss.js
246
+ const classes = {
247
+ "drawer": "D-0Mgq_drawer",
248
+ "weekPicker": "D-0Mgq_weekPicker",
249
+ "rowTitle": "D-0Mgq_rowTitle",
250
+ "scheduleEditor": "D-0Mgq_scheduleEditor",
251
+ "tabs": "D-0Mgq_tabs",
252
+ "note": "D-0Mgq_note",
253
+ "drawer-in": "D-0Mgq_drawer-in",
254
+ "switchRow": "D-0Mgq_switchRow",
255
+ "weekOption": "D-0Mgq_weekOption",
256
+ "closeButton": "D-0Mgq_closeButton",
257
+ "subtitle": "D-0Mgq_subtitle",
258
+ "rowLastError": "D-0Mgq_rowLastError",
259
+ "toolbar": "D-0Mgq_toolbar",
260
+ "readError": "D-0Mgq_readError",
261
+ "rowHead": "D-0Mgq_rowHead",
262
+ "bottomBar": "D-0Mgq_bottomBar",
263
+ "rowMain": "D-0Mgq_rowMain",
264
+ "timeZoneChip": "D-0Mgq_timeZoneChip",
265
+ "segmentButton": "D-0Mgq_segmentButton",
266
+ "switchCopy": "D-0Mgq_switchCopy",
267
+ "rail": "D-0Mgq_rail",
268
+ "headActions": "D-0Mgq_headActions",
269
+ "scheduleRow": "D-0Mgq_scheduleRow",
270
+ "drawerError": "D-0Mgq_drawerError",
271
+ "textArea": "D-0Mgq_textArea",
272
+ "head": "D-0Mgq_head",
273
+ "unreadDot": "D-0Mgq_unreadDot",
274
+ "rowActions": "D-0Mgq_rowActions",
275
+ "searchBox": "D-0Mgq_searchBox",
276
+ "actionButton": "D-0Mgq_actionButton",
277
+ "backdrop": "D-0Mgq_backdrop",
278
+ "switch": "D-0Mgq_switch",
279
+ "segmentText": "D-0Mgq_segmentText",
280
+ "customGroup": "D-0Mgq_customGroup",
281
+ "rowSchedule": "D-0Mgq_rowSchedule",
282
+ "weekMenu": "D-0Mgq_weekMenu",
283
+ "footerButtons": "D-0Mgq_footerButtons",
284
+ "tab": "D-0Mgq_tab",
285
+ "rowStatus": "D-0Mgq_rowStatus",
286
+ "rowOverdue": "D-0Mgq_rowOverdue",
287
+ "ghostButton": "D-0Mgq_ghostButton",
288
+ "rowNext": "D-0Mgq_rowNext",
289
+ "formBody": "D-0Mgq_formBody",
290
+ "fieldLine": "D-0Mgq_fieldLine",
291
+ "timeZoneInput": "D-0Mgq_timeZoneInput",
292
+ "rows": "D-0Mgq_rows",
293
+ "searchInput": "D-0Mgq_searchInput",
294
+ "rowMeta": "D-0Mgq_rowMeta",
295
+ "textInput": "D-0Mgq_textInput",
296
+ "primaryButton": "D-0Mgq_primaryButton",
297
+ "badgeCount": "D-0Mgq_badgeCount",
298
+ "hint": "D-0Mgq_hint",
299
+ "badgeLabel": "D-0Mgq_badgeLabel",
300
+ "segmentSelect": "D-0Mgq_segmentSelect",
301
+ "clearButton": "D-0Mgq_clearButton",
302
+ "segmentTime": "D-0Mgq_segmentTime",
303
+ "fieldHint": "D-0Mgq_fieldHint",
304
+ "title": "D-0Mgq_title",
305
+ "body": "D-0Mgq_body",
306
+ "badge": "D-0Mgq_badge",
307
+ "schedulePreview": "D-0Mgq_schedulePreview",
308
+ "row": "D-0Mgq_row",
309
+ "statusDot": "D-0Mgq_statusDot",
310
+ "layer": "D-0Mgq_layer"
311
+ };
312
+ if (typeof document !== "undefined" && !document.querySelector("style[data-dsh-plugin-css=\"ScheduledTasksPanel.module.css\"]")) {
313
+ const style = document.createElement("style");
314
+ style.setAttribute("data-dsh-plugin-css", "ScheduledTasksPanel.module.css");
315
+ style.textContent = ".D-0Mgq_layer {\n flex: none;\n align-items: center;\n width: 100%;\n height: 49px;\n margin: 8px 0 0;\n display: flex;\n position: relative;\n}\n\n.D-0Mgq_footerButtons {\n align-items: center;\n width: 100%;\n display: flex;\n}\n\n.D-0Mgq_badge {\n width: 100%;\n height: 49px;\n color: var(--dsw-alias-label-primary);\n cursor: pointer;\n background: none;\n border: none;\n border-radius: 12px;\n align-items: center;\n gap: 8px;\n padding: 0 8px 0 6px;\n font-family: inherit;\n font-size: 14px;\n display: inline-flex;\n overflow: hidden;\n}\n\n.D-0Mgq_badge:hover {\n background: var(--dsw-alias-interactive-bg-hover-solid);\n}\n\n.D-0Mgq_badge[data-active] {\n background: var(--dsw-alias-interactive-bg-hover);\n}\n\n.D-0Mgq_badgeLabel {\n text-overflow: ellipsis;\n white-space: nowrap;\n min-width: 0;\n overflow: hidden;\n}\n\n.D-0Mgq_badgeCount {\n background: var(--dsw-alias-state-business-primary);\n min-width: 18px;\n color: var(--dsw-alias-label-primary-inverted);\n text-align: center;\n font-variant-numeric: tabular-nums;\n border-radius: 999px;\n flex: none;\n margin-left: auto;\n padding: 0 5px;\n font-size: 11px;\n line-height: 18px;\n}\n\n.D-0Mgq_layer.D-0Mgq_rail {\n width: 36px;\n height: 36px;\n margin: 0;\n}\n\n.D-0Mgq_rail .D-0Mgq_badge {\n border-radius: 50%;\n justify-content: center;\n gap: 0;\n width: 36px;\n height: 36px;\n padding: 0;\n}\n\n.D-0Mgq_rail .D-0Mgq_footerButtons {\n flex-direction: column;\n}\n\n@keyframes D-0Mgq_drawer-in {\n from {\n opacity: 0;\n transform: translateX(24px);\n }\n\n to {\n opacity: 1;\n transform: translateX(0);\n }\n}\n\n.D-0Mgq_backdrop {\n z-index: 40;\n background: #00000052;\n position: fixed;\n inset: 0;\n}\n\n.D-0Mgq_drawer {\n z-index: 41;\n border-left: 1px solid var(--dsw-alias-border-l1);\n background: var(--dsw-alias-bg-base);\n width: 640px;\n max-width: calc(100vw - 24px);\n box-shadow: var(--dsw-shadow-lv2);\n --dsh-scrollbar-thumb: var(--dsw-alias-scrollbar-bg-l2);\n --dsh-scrollbar-thumb-hover: var(--dsw-alias-scrollbar-hover-l2);\n flex-direction: column;\n animation: .16s ease-out D-0Mgq_drawer-in;\n display: flex;\n position: fixed;\n top: 0;\n bottom: 0;\n right: 0;\n overflow: hidden;\n}\n\n.D-0Mgq_drawerError {\n border: 1px solid var(--dsw-alias-border-l2);\n background: var(--dsw-alias-bg-base);\n box-shadow: var(--dsw-shadow-lv2);\n border-radius: 8px;\n margin: 0;\n padding: 8px 10px;\n position: absolute;\n bottom: 16px;\n left: 20px;\n right: 20px;\n}\n\n.D-0Mgq_head {\n flex: none;\n justify-content: space-between;\n align-items: center;\n gap: 12px;\n padding: 20px 20px 0;\n display: flex;\n}\n\n.D-0Mgq_title {\n min-width: 0;\n color: var(--dsw-alias-label-primary);\n text-overflow: ellipsis;\n white-space: nowrap;\n margin: 0;\n font-size: 20px;\n font-weight: 600;\n line-height: 28px;\n overflow: hidden;\n}\n\n.D-0Mgq_headActions {\n flex: none;\n align-items: center;\n gap: 8px;\n display: flex;\n}\n\n.D-0Mgq_subtitle {\n color: var(--dsw-alias-label-tertiary);\n flex: none;\n margin: 4px 0 0;\n padding: 0 20px;\n font-size: 12px;\n line-height: 18px;\n}\n\n.D-0Mgq_toolbar {\n flex: none;\n align-items: center;\n gap: 8px;\n padding: 14px 20px 0;\n display: flex;\n}\n\n.D-0Mgq_searchBox {\n border: 1px solid var(--dsw-alias-border-l2);\n height: 32px;\n color: var(--dsw-alias-label-tertiary);\n border-radius: 8px;\n flex: 1;\n align-items: center;\n gap: 6px;\n padding: 0 10px;\n display: flex;\n}\n\n.D-0Mgq_searchBox:focus-within {\n border-color: var(--dsw-alias-border-l3);\n}\n\n.D-0Mgq_searchInput {\n min-width: 0;\n color: var(--dsw-alias-label-primary);\n font: inherit;\n background: none;\n border: none;\n outline: none;\n flex: 1;\n font-size: 13px;\n}\n\n.D-0Mgq_searchInput::placeholder {\n color: var(--dsw-alias-label-tertiary);\n}\n\n.D-0Mgq_primaryButton {\n background: var(--dsw-alias-button-primary-fill);\n height: 32px;\n color: var(--dsw-alias-label-primary-inverted);\n font: inherit;\n cursor: pointer;\n border: none;\n border-radius: 8px;\n flex: none;\n align-items: center;\n gap: 6px;\n padding: 0 14px;\n font-size: 13px;\n display: inline-flex;\n}\n\n.D-0Mgq_primaryButton:hover:not(:disabled) {\n background: var(--dsw-alias-button-primary-hover);\n}\n\n.D-0Mgq_ghostButton {\n border: 1px solid var(--dsw-alias-border-l2);\n height: 32px;\n color: var(--dsw-alias-label-secondary);\n font: inherit;\n cursor: pointer;\n background: none;\n border-radius: 8px;\n flex: none;\n padding: 0 12px;\n font-size: 13px;\n}\n\n.D-0Mgq_ghostButton:hover:not(:disabled) {\n background: var(--dsw-alias-interactive-bg-hover);\n}\n\n.D-0Mgq_closeButton {\n width: 28px;\n height: 28px;\n color: var(--dsw-alias-label-tertiary);\n cursor: pointer;\n background: none;\n border: none;\n border-radius: 999px;\n flex: none;\n justify-content: center;\n align-items: center;\n padding: 0;\n display: inline-flex;\n}\n\n.D-0Mgq_closeButton:hover {\n background: var(--dsw-alias-interactive-bg-hover);\n color: var(--dsw-alias-label-secondary);\n}\n\n.D-0Mgq_primaryButton:disabled, .D-0Mgq_ghostButton:disabled {\n opacity: .4;\n cursor: default;\n}\n\n.D-0Mgq_tabs {\n border-bottom: 1px solid var(--dsw-alias-border-l2);\n flex: none;\n gap: 16px;\n margin: 10px 20px 0;\n display: flex;\n}\n\n.D-0Mgq_tab {\n color: var(--dsw-alias-label-secondary);\n font: inherit;\n cursor: pointer;\n background: none;\n border: none;\n border-bottom: 2px solid #0000;\n padding: 8px 2px;\n font-size: 13px;\n}\n\n.D-0Mgq_tab:hover {\n color: var(--dsw-alias-label-primary);\n}\n\n.D-0Mgq_tab[data-active] {\n border-bottom-color: var(--dsw-alias-state-business-primary);\n color: var(--dsw-alias-label-primary);\n font-weight: 500;\n}\n\n.D-0Mgq_body {\n flex: 1;\n min-height: 0;\n padding: 12px 20px 20px;\n overflow-y: auto;\n}\n\n.D-0Mgq_note, .D-0Mgq_readError {\n color: var(--dsw-alias-label-tertiary);\n margin: 4px 0;\n font-size: 12px;\n line-height: 18px;\n}\n\n.D-0Mgq_readError {\n color: var(--dsw-alias-state-error-primary);\n}\n\n.D-0Mgq_rows {\n flex-direction: column;\n gap: 8px;\n margin: 0;\n padding: 0;\n list-style: none;\n display: flex;\n}\n\n.D-0Mgq_row {\n border-radius: 10px;\n align-items: flex-start;\n gap: 10px;\n padding: 12px;\n display: flex;\n}\n\n.D-0Mgq_row:hover {\n background: var(--dsw-alias-interactive-bg-hover);\n}\n\n.D-0Mgq_statusDot {\n border: 1.5px solid var(--dsw-alias-label-tertiary);\n border-radius: 50%;\n flex: none;\n width: 14px;\n height: 14px;\n margin-top: 3px;\n}\n\n.D-0Mgq_statusDot[data-status=\"active\"] {\n border-color: var(--dsw-alias-state-business-primary);\n background: var(--dsw-alias-state-business-primary);\n}\n\n.D-0Mgq_statusDot[data-status=\"paused\"] {\n border-color: var(--dsw-alias-label-tertiary);\n background: none;\n}\n\n.D-0Mgq_statusDot[data-status=\"completed\"] {\n border-color: var(--dsw-alias-label-tertiary);\n background: var(--dsw-alias-label-tertiary);\n}\n\n.D-0Mgq_rowMain {\n flex-direction: column;\n flex: 1;\n gap: 2px;\n min-width: 0;\n display: flex;\n}\n\n.D-0Mgq_rowMain[data-unread] {\n cursor: pointer;\n}\n\n.D-0Mgq_rowMain[data-unread]:hover {\n opacity: .85;\n}\n\n.D-0Mgq_rowHead {\n align-items: center;\n gap: 8px;\n display: flex;\n}\n\n.D-0Mgq_unreadDot {\n background: var(--dsw-alias-state-business-primary);\n border-radius: 50%;\n flex: none;\n width: 7px;\n height: 7px;\n}\n\n.D-0Mgq_rowTitle {\n min-width: 0;\n color: var(--dsw-alias-label-primary);\n text-overflow: ellipsis;\n white-space: nowrap;\n flex: 1;\n font-size: 14px;\n font-weight: 500;\n line-height: 20px;\n overflow: hidden;\n}\n\n.D-0Mgq_rowMeta {\n align-items: center;\n gap: 8px;\n min-width: 0;\n display: flex;\n}\n\n.D-0Mgq_rowSchedule, .D-0Mgq_rowNext {\n min-width: 0;\n color: var(--dsw-alias-label-tertiary);\n text-overflow: ellipsis;\n white-space: nowrap;\n font-size: 12px;\n line-height: 18px;\n overflow: hidden;\n}\n\n.D-0Mgq_rowNext {\n flex-shrink: 1;\n}\n\n.D-0Mgq_rowSchedule {\n flex-shrink: 0;\n}\n\n.D-0Mgq_rowOverdue {\n color: var(--dsw-alias-state-warn-label);\n flex: none;\n font-size: 11px;\n line-height: 16px;\n}\n\n.D-0Mgq_rowLastError {\n color: var(--dsw-alias-state-error-primary, var(--dsw-alias-state-warn-label));\n cursor: help;\n flex: none;\n font-size: 11px;\n line-height: 16px;\n}\n\n.D-0Mgq_fieldHint {\n color: var(--dsw-alias-state-error-primary, var(--dsw-alias-state-warn-label));\n font-size: 11px;\n line-height: 16px;\n}\n\n.D-0Mgq_rowStatus {\n background: var(--dsw-alias-button-ghost-active-fill);\n height: 20px;\n color: var(--dsw-alias-label-caption);\n border-radius: 10px;\n flex: none;\n align-items: center;\n padding: 0 6px;\n font-size: 11px;\n line-height: 20px;\n display: inline-flex;\n}\n\n.D-0Mgq_rowStatus[data-state=\"overdue\"] {\n background: var(--dsw-alias-state-warn-tertiary);\n color: var(--dsw-alias-state-warn-label);\n}\n\n.D-0Mgq_rowActions {\n opacity: 0;\n flex: none;\n align-items: center;\n gap: 6px;\n transition: opacity .12s;\n display: flex;\n}\n\n.D-0Mgq_row:hover .D-0Mgq_rowActions, .D-0Mgq_row:focus-within .D-0Mgq_rowActions {\n opacity: 1;\n}\n\n.D-0Mgq_actionButton {\n width: 28px;\n height: 28px;\n color: var(--dsw-alias-label-tertiary);\n cursor: pointer;\n background: none;\n border: none;\n border-radius: 999px;\n justify-content: center;\n align-items: center;\n padding: 0;\n display: inline-flex;\n}\n\n.D-0Mgq_actionButton:hover:not(:disabled) {\n background: var(--dsw-alias-interactive-bg-hover);\n color: var(--dsw-alias-label-secondary);\n}\n\n.D-0Mgq_actionButton:disabled {\n opacity: .4;\n cursor: default;\n}\n\n.D-0Mgq_formBody {\n flex-direction: column;\n gap: 14px;\n display: flex;\n}\n\n.D-0Mgq_fieldLine {\n color: var(--dsw-alias-label-caption);\n flex-direction: column;\n gap: 6px;\n font-size: 12px;\n line-height: 16px;\n display: flex;\n}\n\n.D-0Mgq_textInput {\n border: 1px solid var(--dsw-alias-border-l2);\n background: var(--dsw-alias-bg-base);\n height: 32px;\n color: var(--dsw-alias-label-primary);\n font: inherit;\n border-radius: 8px;\n padding: 0 10px;\n font-size: 13px;\n}\n\n.D-0Mgq_textInput:focus {\n border-color: var(--dsw-alias-border-l3);\n outline: none;\n}\n\n.D-0Mgq_textArea {\n border: 1px solid var(--dsw-alias-border-l2);\n background: var(--dsw-alias-bg-base);\n min-height: 96px;\n color: var(--dsw-alias-label-primary);\n font: inherit;\n resize: vertical;\n border-radius: 8px;\n padding: 8px 10px;\n font-size: 13px;\n line-height: 20px;\n}\n\n.D-0Mgq_textArea:focus {\n border-color: var(--dsw-alias-border-l3);\n outline: none;\n}\n\n.D-0Mgq_bottomBar {\n border-top: 1px solid var(--dsw-alias-border-l2);\n grid-template-columns: minmax(0, 1fr);\n gap: 14px;\n margin-top: 2px;\n padding-top: 14px;\n display: grid;\n}\n\n.D-0Mgq_switchRow {\n justify-content: space-between;\n align-items: center;\n gap: 12px;\n display: flex;\n}\n\n.D-0Mgq_switchCopy {\n color: var(--dsw-alias-label-secondary);\n flex-direction: column;\n gap: 2px;\n font-size: 12px;\n line-height: 16px;\n display: flex;\n}\n\n.D-0Mgq_hint {\n color: var(--dsw-alias-label-tertiary);\n font-size: 11px;\n line-height: 16px;\n}\n\n.D-0Mgq_switch {\n background: var(--dsw-alias-interactive-bg-hover-solid);\n cursor: pointer;\n border: none;\n border-radius: 999px;\n flex: none;\n width: 36px;\n height: 20px;\n padding: 0;\n transition: background .12s;\n position: relative;\n}\n\n.D-0Mgq_switch:after {\n content: \"\";\n background: var(--dsw-alias-label-primary-inverted);\n border-radius: 50%;\n width: 16px;\n height: 16px;\n transition: transform .12s;\n position: absolute;\n top: 2px;\n left: 2px;\n}\n\n.D-0Mgq_switch[data-on] {\n background: var(--dsw-alias-state-business-primary);\n}\n\n.D-0Mgq_switch[data-on]:after {\n transform: translateX(16px);\n}\n\n.D-0Mgq_scheduleEditor {\n width: 100%;\n}\n\n.D-0Mgq_scheduleRow {\n border: 1px solid var(--dsw-alias-border-l2);\n background: var(--dsw-alias-bg-base);\n border-radius: 10px;\n flex-wrap: wrap;\n align-items: center;\n gap: 6px;\n padding: 8px 10px;\n display: flex;\n}\n\n.D-0Mgq_segmentSelect, .D-0Mgq_segmentTime {\n background: var(--dsw-alias-button-ghost-active-fill);\n height: 30px;\n color: var(--dsw-alias-label-primary);\n font: inherit;\n border: 1px solid #0000;\n border-radius: 8px;\n padding: 0 8px;\n font-size: 13px;\n}\n\n.D-0Mgq_segmentSelect:focus, .D-0Mgq_segmentTime:focus {\n border-color: var(--dsw-alias-border-l3);\n outline: none;\n}\n\n.D-0Mgq_segmentTime {\n width: auto;\n}\n\n.D-0Mgq_segmentText {\n color: var(--dsw-alias-label-secondary);\n white-space: nowrap;\n font-size: 13px;\n line-height: 20px;\n}\n\n.D-0Mgq_timeZoneChip {\n background: var(--dsw-alias-button-ghost-active-fill, transparent);\n color: var(--dsw-alias-label-primary);\n cursor: pointer;\n border: none;\n border-radius: 6px;\n padding: 2px 6px;\n font-size: 12px;\n line-height: 18px;\n}\n\n.D-0Mgq_timeZoneChip:hover {\n background: var(--dsw-alias-interactive-bg-hover);\n}\n\n.D-0Mgq_timeZoneInput {\n background: var(--dsw-alias-fill-secondary, transparent);\n width: 9em;\n color: var(--dsw-alias-label-primary);\n border: none;\n border-radius: 6px;\n padding: 2px 6px;\n font-size: 12px;\n line-height: 18px;\n}\n\n.D-0Mgq_timeZoneInput:focus {\n outline: 1px solid var(--dsw-alias-border-focus, currentColor);\n}\n\n.D-0Mgq_schedulePreview {\n color: var(--dsw-alias-label-tertiary);\n text-overflow: ellipsis;\n white-space: nowrap;\n margin-left: auto;\n font-size: 12px;\n line-height: 18px;\n overflow: hidden;\n}\n\n.D-0Mgq_clearButton {\n width: 26px;\n height: 26px;\n color: var(--dsw-alias-label-tertiary);\n cursor: pointer;\n background: none;\n border: none;\n border-radius: 999px;\n flex: none;\n justify-content: center;\n align-items: center;\n padding: 0;\n display: inline-flex;\n}\n\n.D-0Mgq_clearButton:hover {\n background: var(--dsw-alias-interactive-bg-hover);\n color: var(--dsw-alias-state-error-primary);\n}\n\n.D-0Mgq_weekPicker {\n position: relative;\n}\n\n.D-0Mgq_segmentButton {\n background: var(--dsw-alias-button-ghost-active-fill);\n height: 30px;\n color: var(--dsw-alias-label-primary);\n font: inherit;\n cursor: pointer;\n border: 1px solid #0000;\n border-radius: 8px;\n align-items: center;\n gap: 4px;\n padding: 0 8px;\n font-size: 13px;\n display: inline-flex;\n}\n\n.D-0Mgq_segmentButton:focus {\n border-color: var(--dsw-alias-border-l3);\n outline: none;\n}\n\n.D-0Mgq_weekMenu {\n z-index: 60;\n border: 1px solid var(--dsw-alias-border-l1);\n background: var(--dsw-alias-bg-base);\n width: 96px;\n max-height: 240px;\n box-shadow: var(--dsw-shadow-lv2);\n border-radius: 10px;\n flex-direction: column;\n padding: 4px;\n display: flex;\n position: absolute;\n top: calc(100% + 4px);\n left: 0;\n overflow-y: auto;\n}\n\n.D-0Mgq_weekOption {\n color: var(--dsw-alias-label-primary);\n cursor: pointer;\n border-radius: 7px;\n align-items: center;\n gap: 8px;\n padding: 6px 8px;\n font-size: 13px;\n display: flex;\n}\n\n.D-0Mgq_weekOption:hover {\n background: var(--dsw-alias-interactive-bg-hover);\n}\n\n.D-0Mgq_weekOption input {\n margin: 0;\n}\n\n.D-0Mgq_customGroup {\n gap: 12px;\n}\n";
316
+ document.head.append(style);
317
+ }
318
+ var ScheduledTasksPanel_module_css_dshcss_default = new Proxy(classes, { get(target, key) {
319
+ return target[key] ?? "ScheduledTasksPanel.module.css_" + String(key);
320
+ } });
321
+ //#endregion
322
+ //#region src/client/ScheduleEditor.tsx
323
+ /**
324
+ * Inline schedule editor (图 of 调度): a preset dropdown (每小时/每天/每周/每月/自定义)
325
+ * followed per preset by compact sub-selectors, a live summary line, and a
326
+ * clear (trash) action. Controlled by the parent create form, which owns the
327
+ * state and turns the chosen preset into a wire rule selector. The wall-clock
328
+ * presets carry an editable IANA time-zone field; the custom presets keep
329
+ * their own at/after/every fields in the parent.
330
+ */
331
+ /** Locale key per weekday (1=Mon..7=Sun). */
332
+ const WEEKDAY_KEYS = {
333
+ 1: "schedule.wd.1",
334
+ 2: "schedule.wd.2",
335
+ 3: "schedule.wd.3",
336
+ 4: "schedule.wd.4",
337
+ 5: "schedule.wd.5",
338
+ 6: "schedule.wd.6",
339
+ 7: "schedule.wd.7"
340
+ };
341
+ const MINUTES = Array.from({ length: 60 }, (_, index) => String(index).padStart(2, "0"));
342
+ const DAYS = Array.from({ length: 31 }, (_, index) => String(index + 1));
343
+ /** Render the current schedule as the summary line under/next to the segments. */
344
+ function previewLine(t, preset, minute, time, weekdays, dayOfMonth) {
345
+ switch (preset) {
346
+ case "hourly": return t("schedule.preview.hourly", { minute });
347
+ case "daily": return t("schedule.preview.daily", { time });
348
+ case "weekly": return t("schedule.preview.weekly", {
349
+ weekdays: weekdaySummary(t, weekdays),
350
+ time
351
+ });
352
+ case "monthly": return t("schedule.preview.monthly", {
353
+ day: dayOfMonth,
354
+ time
355
+ });
356
+ default: return "";
357
+ }
358
+ }
359
+ /** Compact GMT offset (e.g. `GMT+8`, `GMT+5:30`, `GMT-4`); falls back to the IANA name. */
360
+ function gmtOffset(timeZone) {
361
+ if (timeZone.trim() === "") return "";
362
+ try {
363
+ return new Intl.DateTimeFormat("en-US", {
364
+ timeZone,
365
+ timeZoneName: "shortOffset"
366
+ }).formatToParts(/* @__PURE__ */ new Date()).find((piece) => piece.type === "timeZoneName")?.value ?? timeZone;
367
+ } catch {
368
+ return timeZone;
369
+ }
370
+ }
371
+ /**
372
+ * Timezone field: displays the GMT offset (e.g. `GMT+8`) and hides the IANA
373
+ * region name; clicking the chip swaps to a short IANA editor (the wire value
374
+ * must stay an IANA name), and Enter / blur / Escape return to the offset chip.
375
+ */
376
+ function TimezoneField({ t, value, onChange }) {
377
+ const [editing, setEditing] = (0, react.useState)(false);
378
+ const inputRef = (0, react.useRef)(null);
379
+ (0, react.useEffect)(() => {
380
+ if (editing && inputRef.current !== null) inputRef.current.focus();
381
+ }, [editing]);
382
+ if (!editing) return /* @__PURE__ */ (0, react_jsx_runtime.jsx)("button", {
383
+ type: "button",
384
+ className: ScheduledTasksPanel_module_css_dshcss_default.timeZoneChip,
385
+ title: value,
386
+ "aria-label": t("form.timeZone"),
387
+ onClick: () => {
388
+ setEditing(true);
389
+ },
390
+ children: gmtOffset(value)
391
+ });
392
+ return /* @__PURE__ */ (0, react_jsx_runtime.jsx)("input", {
393
+ ref: inputRef,
394
+ className: ScheduledTasksPanel_module_css_dshcss_default.timeZoneInput,
395
+ value,
396
+ spellCheck: false,
397
+ "aria-label": t("form.timeZone"),
398
+ onChange: (event) => {
399
+ onChange(event.target.value);
400
+ },
401
+ onBlur: () => {
402
+ setEditing(false);
403
+ },
404
+ onKeyDown: (event) => {
405
+ if (event.key === "Enter" || event.key === "Escape") event.currentTarget.blur();
406
+ }
407
+ });
408
+ }
409
+ /** A compact weekday multi-select (toggle chips in a popover). */
410
+ function WeekdayPicker({ t, value, onChange }) {
411
+ const [open, setOpen] = (0, react.useState)(false);
412
+ const rootRef = (0, react.useRef)(null);
413
+ const toggle = (day, present) => {
414
+ onChange(present ? value.filter((item) => item !== day) : [...value, day].sort((a, b) => a - b));
415
+ };
416
+ const summary = value.length === 0 ? t("schedule.pickWeekdays") : weekdaySummary(t, value);
417
+ (0, react.useEffect)(() => {
418
+ if (!open) return;
419
+ const onMouseDown = (event) => {
420
+ if (rootRef.current !== null && !rootRef.current.contains(event.target)) setOpen(false);
421
+ };
422
+ const onKeyDown = (event) => {
423
+ if (event.key !== "Escape") return;
424
+ setOpen(false);
425
+ event.stopImmediatePropagation();
426
+ };
427
+ document.addEventListener("mousedown", onMouseDown);
428
+ document.addEventListener("keydown", onKeyDown, true);
429
+ return () => {
430
+ document.removeEventListener("mousedown", onMouseDown);
431
+ document.removeEventListener("keydown", onKeyDown, true);
432
+ };
433
+ }, [open]);
434
+ return /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
435
+ ref: rootRef,
436
+ className: ScheduledTasksPanel_module_css_dshcss_default.weekPicker,
437
+ children: [/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("button", {
438
+ type: "button",
439
+ className: ScheduledTasksPanel_module_css_dshcss_default.segmentButton,
440
+ "aria-expanded": open,
441
+ "aria-haspopup": "listbox",
442
+ onClick: () => {
443
+ setOpen((current) => !current);
444
+ },
445
+ children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", { children: summary }), /* @__PURE__ */ (0, react_jsx_runtime.jsx)(_deepseek_ai_dsh_client_ui_primitives.IconChevronDownOutline14, { size: 12 })]
446
+ }), open && /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
447
+ className: ScheduledTasksPanel_module_css_dshcss_default.weekMenu,
448
+ role: "listbox",
449
+ "aria-multiselectable": "true",
450
+ children: [
451
+ 1,
452
+ 2,
453
+ 3,
454
+ 4,
455
+ 5,
456
+ 6,
457
+ 7
458
+ ].map((day) => {
459
+ const checked = value.includes(day);
460
+ return /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("label", {
461
+ className: ScheduledTasksPanel_module_css_dshcss_default.weekOption,
462
+ children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("input", {
463
+ type: "checkbox",
464
+ checked,
465
+ onChange: () => {
466
+ toggle(day, checked);
467
+ }
468
+ }), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", { children: t(WEEKDAY_KEYS[day]) })]
469
+ }, day);
470
+ })
471
+ })]
472
+ });
473
+ }
474
+ /** Render the inline schedule editor field. */
475
+ function ScheduleEditor({ t, preset, minute, time, timeZone, weekdays, dayOfMonth, onPresetChange, onMinuteChange, onTimeChange, onWeekdaysChange, onDayOfMonthChange, onTimeZoneChange, onClear }) {
476
+ const preview = previewLine(t, preset, minute, time, weekdays, dayOfMonth);
477
+ return /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
478
+ className: ScheduledTasksPanel_module_css_dshcss_default.scheduleEditor,
479
+ children: /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
480
+ className: ScheduledTasksPanel_module_css_dshcss_default.scheduleRow,
481
+ children: [
482
+ /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("select", {
483
+ className: ScheduledTasksPanel_module_css_dshcss_default.segmentSelect,
484
+ value: preset,
485
+ onChange: (event) => {
486
+ onPresetChange(event.target.value);
487
+ },
488
+ "aria-label": t("form.schedule.label"),
489
+ children: [
490
+ /* @__PURE__ */ (0, react_jsx_runtime.jsx)("option", {
491
+ value: "",
492
+ children: t("form.schedule.add")
493
+ }),
494
+ /* @__PURE__ */ (0, react_jsx_runtime.jsx)("option", {
495
+ value: "hourly",
496
+ children: t("schedule.hourly")
497
+ }),
498
+ /* @__PURE__ */ (0, react_jsx_runtime.jsx)("option", {
499
+ value: "daily",
500
+ children: t("schedule.daily")
501
+ }),
502
+ /* @__PURE__ */ (0, react_jsx_runtime.jsx)("option", {
503
+ value: "weekly",
504
+ children: t("schedule.weekly")
505
+ }),
506
+ /* @__PURE__ */ (0, react_jsx_runtime.jsx)("option", {
507
+ value: "monthly",
508
+ children: t("schedule.monthly")
509
+ }),
510
+ /* @__PURE__ */ (0, react_jsx_runtime.jsx)("option", {
511
+ value: "custom",
512
+ children: t("schedule.custom")
513
+ })
514
+ ]
515
+ }),
516
+ preset === "hourly" && /* @__PURE__ */ (0, react_jsx_runtime.jsxs)(react_jsx_runtime.Fragment, { children: [
517
+ /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
518
+ className: ScheduledTasksPanel_module_css_dshcss_default.segmentText,
519
+ children: t("schedule.hourlyAtMinute")
520
+ }),
521
+ /* @__PURE__ */ (0, react_jsx_runtime.jsx)("select", {
522
+ className: ScheduledTasksPanel_module_css_dshcss_default.segmentSelect,
523
+ value: minute,
524
+ onChange: (event) => {
525
+ onMinuteChange(event.target.value);
526
+ },
527
+ children: MINUTES.map((value) => /* @__PURE__ */ (0, react_jsx_runtime.jsx)("option", {
528
+ value,
529
+ children: value
530
+ }, value))
531
+ }),
532
+ /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
533
+ className: ScheduledTasksPanel_module_css_dshcss_default.segmentText,
534
+ children: t("schedule.minuteUnit")
535
+ })
536
+ ] }),
537
+ (preset === "daily" || preset === "weekly" || preset === "monthly") && /* @__PURE__ */ (0, react_jsx_runtime.jsxs)(react_jsx_runtime.Fragment, { children: [
538
+ preset === "daily" && /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
539
+ className: ScheduledTasksPanel_module_css_dshcss_default.segmentText,
540
+ children: t("schedule.at")
541
+ }),
542
+ preset === "weekly" && /* @__PURE__ */ (0, react_jsx_runtime.jsx)(WeekdayPicker, {
543
+ t,
544
+ value: weekdays,
545
+ onChange: onWeekdaysChange
546
+ }),
547
+ preset === "weekly" && /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
548
+ className: ScheduledTasksPanel_module_css_dshcss_default.segmentText,
549
+ children: t("schedule.at")
550
+ }),
551
+ preset === "monthly" && /* @__PURE__ */ (0, react_jsx_runtime.jsxs)(react_jsx_runtime.Fragment, { children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("select", {
552
+ className: ScheduledTasksPanel_module_css_dshcss_default.segmentSelect,
553
+ value: dayOfMonth,
554
+ onChange: (event) => {
555
+ onDayOfMonthChange(event.target.value);
556
+ },
557
+ children: DAYS.map((value) => /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("option", {
558
+ value,
559
+ children: [
560
+ value,
561
+ " ",
562
+ t("schedule.dayUnit")
563
+ ]
564
+ }, value))
565
+ }), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
566
+ className: ScheduledTasksPanel_module_css_dshcss_default.segmentText,
567
+ children: t("schedule.at")
568
+ })] }),
569
+ /* @__PURE__ */ (0, react_jsx_runtime.jsx)("input", {
570
+ className: ScheduledTasksPanel_module_css_dshcss_default.segmentTime,
571
+ type: "time",
572
+ value: time,
573
+ onChange: (event) => {
574
+ onTimeChange(event.target.value);
575
+ }
576
+ }),
577
+ /* @__PURE__ */ (0, react_jsx_runtime.jsx)(TimezoneField, {
578
+ t,
579
+ value: timeZone,
580
+ onChange: onTimeZoneChange
581
+ })
582
+ ] }),
583
+ preview !== "" && /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
584
+ className: ScheduledTasksPanel_module_css_dshcss_default.schedulePreview,
585
+ children: preview
586
+ }),
587
+ /* @__PURE__ */ (0, react_jsx_runtime.jsx)("button", {
588
+ type: "button",
589
+ className: ScheduledTasksPanel_module_css_dshcss_default.clearButton,
590
+ "aria-label": t("schedule.clear"),
591
+ onClick: onClear,
592
+ children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)(_deepseek_ai_dsh_client_ui_primitives.IconTrashOutline16, { size: 14 })
593
+ })
594
+ ]
595
+ })
596
+ });
597
+ }
598
+ //#endregion
599
+ //#region src/client/ScheduledTaskCreate.tsx
600
+ /**
601
+ * 新建定时任务 create/edit view (the drawer body): the inline schedule editor
602
+ * (每小时/每天/每周/每月/自定义), title, the instruction Prompt, project (DSH
603
+ * workspace), confirm-before-change toggle, and model selection.
604
+ */
605
+ /** Local zone used as the default for daily/weekly/monthly. */
606
+ function localTimeZone() {
607
+ return Intl.DateTimeFormat().resolvedOptions().timeZone;
608
+ }
609
+ /** Neutral editor state shared by every preset before its own overrides. */
610
+ const DEFAULT_SCHEDULE = {
611
+ customKind: "at",
612
+ minute: "00",
613
+ time: "09:00",
614
+ timeZone: localTimeZone(),
615
+ weekdays: [...[
616
+ 1,
617
+ 2,
618
+ 3,
619
+ 4,
620
+ 5
621
+ ]],
622
+ dayOfMonth: "1"
623
+ };
624
+ /** Resolve the editor state from an edit task (or create defaults). */
625
+ function initialSchedule(task) {
626
+ const base = {
627
+ ...DEFAULT_SCHEDULE,
628
+ timeZone: localTimeZone()
629
+ };
630
+ if (task === void 0) return {
631
+ ...base,
632
+ preset: ""
633
+ };
634
+ const rule = task.rule;
635
+ switch (rule.kind) {
636
+ case "hourly": return {
637
+ ...base,
638
+ preset: "hourly",
639
+ minute: String(rule.minute).padStart(2, "0")
640
+ };
641
+ case "daily": return {
642
+ ...base,
643
+ preset: "daily",
644
+ time: rule.time,
645
+ timeZone: rule.time_zone
646
+ };
647
+ case "weekly": return {
648
+ ...base,
649
+ preset: "weekly",
650
+ time: rule.time,
651
+ timeZone: rule.time_zone,
652
+ weekdays: [...rule.weekdays]
653
+ };
654
+ case "monthly": return {
655
+ ...base,
656
+ preset: "monthly",
657
+ time: rule.time,
658
+ timeZone: rule.time_zone,
659
+ dayOfMonth: String(rule.dayOfMonth)
660
+ };
661
+ case "every": return {
662
+ ...base,
663
+ preset: "custom",
664
+ customKind: "every"
665
+ };
666
+ case "after": return {
667
+ ...base,
668
+ preset: "custom",
669
+ customKind: "after"
670
+ };
671
+ case "at": return {
672
+ ...base,
673
+ preset: "custom",
674
+ customKind: "at"
675
+ };
676
+ }
677
+ }
678
+ /** Validate an `HH:mm` string. */
679
+ function isTime(time) {
680
+ return /^([01]\d|2[0-3]):([0-5]\d)$/.test(time);
681
+ }
682
+ /**
683
+ * Split a `<providerId>/<modelId>` option key at the FIRST slash — model ids may
684
+ * themselves contain slashes (e.g. openrouter's `stealth/ox-alpha`), so a naive
685
+ * `split('/')` would truncate the model id.
686
+ */
687
+ function parseModelKey(key) {
688
+ const at = key.indexOf("/");
689
+ if (at <= 0 || at === key.length - 1) return void 0;
690
+ return {
691
+ provider: key.slice(0, at),
692
+ model: key.slice(at + 1)
693
+ };
694
+ }
695
+ const IDLE_OPTIONS = {
696
+ status: "loading",
697
+ items: [],
698
+ error: ""
699
+ };
700
+ /** Render the create/edit scheduled-task form. */
701
+ function ScheduledTaskCreate({ t, busy, task, listProjects, listModels, onCancel, onSubmit }) {
702
+ const [title, setTitle] = (0, react.useState)(task?.title ?? "");
703
+ const [prompt, setPrompt] = (0, react.useState)(task?.prompt ?? "");
704
+ const [schedule, setSchedule] = (0, react.useState)(() => initialSchedule(task));
705
+ const [date, setDate] = (0, react.useState)("");
706
+ const [atTime, setAtTime] = (0, react.useState)("");
707
+ const [afterSeconds, setAfterSeconds] = (0, react.useState)("60");
708
+ const [everySeconds, setEverySeconds] = (0, react.useState)("300");
709
+ const [projectKey, setProjectKey] = (0, react.useState)(task?.workspaceId ?? "");
710
+ const [modelKey, setModelKey] = (0, react.useState)(task?.model === void 0 ? "" : `${task.model.provider}/${task.model.model}`);
711
+ const [confirmBeforeChange, setConfirmBeforeChange] = (0, react.useState)(task?.confirmBeforeChange ?? false);
712
+ const [projects, setProjects] = (0, react.useState)(IDLE_OPTIONS);
713
+ const [models, setModels] = (0, react.useState)(IDLE_OPTIONS);
714
+ const [formError, setFormError] = (0, react.useState)(null);
715
+ const { preset, customKind, minute, time, timeZone, weekdays, dayOfMonth } = schedule;
716
+ (0, react.useEffect)(() => {
717
+ if (task?.rule.kind !== "at") return;
718
+ const at = new Date(task.rule.scheduledAt);
719
+ setDate([
720
+ at.getFullYear(),
721
+ String(at.getMonth() + 1).padStart(2, "0"),
722
+ String(at.getDate()).padStart(2, "0")
723
+ ].join("-"));
724
+ setAtTime(`${String(at.getHours()).padStart(2, "0")}:${String(at.getMinutes()).padStart(2, "0")}`);
725
+ }, [task]);
726
+ (0, react.useEffect)(() => {
727
+ let alive = true;
728
+ listProjects().then((items) => {
729
+ if (alive) setProjects({
730
+ status: "ready",
731
+ items
732
+ });
733
+ }, (error) => {
734
+ if (alive) setProjects({
735
+ status: "failed",
736
+ items: [],
737
+ error: error instanceof Error ? error.message : String(error)
738
+ });
739
+ });
740
+ listModels().then((items) => {
741
+ if (alive) setModels({
742
+ status: "ready",
743
+ items
744
+ });
745
+ }, (error) => {
746
+ if (alive) setModels({
747
+ status: "failed",
748
+ items: [],
749
+ error: error instanceof Error ? error.message : String(error)
750
+ });
751
+ });
752
+ return () => {
753
+ alive = false;
754
+ };
755
+ }, [listProjects, listModels]);
756
+ const patchSchedule = (patch) => {
757
+ setSchedule((current) => ({
758
+ ...current,
759
+ ...patch
760
+ }));
761
+ };
762
+ const setPreset = (next) => {
763
+ patchSchedule({ preset: next });
764
+ };
765
+ const selectorValid = (() => {
766
+ switch (preset) {
767
+ case "": return false;
768
+ case "hourly": return /^\d{1,2}$/.test(minute) && Number(minute) >= 0 && Number(minute) <= 59;
769
+ case "daily": return isTime(time) && timeZone.trim() !== "";
770
+ case "weekly": return weekdays.length > 0 && isTime(time) && timeZone.trim() !== "";
771
+ case "monthly": return isTime(time) && timeZone.trim() !== "" && Number(dayOfMonth) >= 1 && Number(dayOfMonth) <= 31;
772
+ case "custom": switch (customKind) {
773
+ case "at": return date !== "" && atTime !== "" && timeZone.trim() !== "";
774
+ case "after": return Number.isInteger(Number(afterSeconds)) && Number(afterSeconds) > 0;
775
+ case "every": return Number.isInteger(Number(everySeconds)) && Number(everySeconds) >= 300;
776
+ }
777
+ }
778
+ })();
779
+ /** Build the wire selector object (not including title/prompt/carry). */
780
+ const buildSelector = () => {
781
+ switch (preset) {
782
+ case "": return;
783
+ case "hourly": return { hourly: { minute: Number(minute) } };
784
+ case "daily": return { daily: {
785
+ time,
786
+ time_zone: timeZone.trim()
787
+ } };
788
+ case "weekly": return { weekly: {
789
+ weekdays,
790
+ time,
791
+ time_zone: timeZone.trim()
792
+ } };
793
+ case "monthly": return { monthly: {
794
+ dayOfMonth: Number(dayOfMonth),
795
+ time,
796
+ time_zone: timeZone.trim()
797
+ } };
798
+ case "custom":
799
+ if (customKind === "at") return { at: {
800
+ date,
801
+ time: atTime,
802
+ time_zone: timeZone.trim()
803
+ } };
804
+ if (customKind === "after") return { after_seconds: Number(afterSeconds) };
805
+ return { every_seconds: Number(everySeconds) };
806
+ }
807
+ };
808
+ /** Assemble the wire input from the form state. */
809
+ const buildInput = () => {
810
+ if (!selectorValid) return void 0;
811
+ const trimmedPrompt = prompt.trim();
812
+ const effectiveTitle = title.trim() !== "" ? title.trim() : trimmedPrompt.slice(0, 40);
813
+ const project = projects.items.find((item) => item.workspaceId === projectKey);
814
+ const model = modelKey === "" ? void 0 : parseModelKey(modelKey);
815
+ const base = {
816
+ title: effectiveTitle,
817
+ prompt: trimmedPrompt,
818
+ confirmBeforeChange,
819
+ ...project === void 0 ? {} : {
820
+ workspaceId: project.workspaceId,
821
+ cwd: project.path
822
+ }
823
+ };
824
+ if (model !== void 0) base.model = model;
825
+ const selector = buildSelector();
826
+ return {
827
+ ...base,
828
+ ...selector === void 0 ? {} : selector
829
+ };
830
+ };
831
+ const submit = async () => {
832
+ if (prompt.trim() === "") {
833
+ setFormError(t("form.prompt.required"));
834
+ return;
835
+ }
836
+ const input = buildInput();
837
+ if (input === void 0) return;
838
+ setFormError(null);
839
+ const result = await onSubmit(input);
840
+ if (!result.ok) setFormError(result.message);
841
+ };
842
+ return /* @__PURE__ */ (0, react_jsx_runtime.jsxs)(react_jsx_runtime.Fragment, { children: [
843
+ /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("header", {
844
+ className: ScheduledTasksPanel_module_css_dshcss_default.head,
845
+ children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("h2", {
846
+ className: ScheduledTasksPanel_module_css_dshcss_default.title,
847
+ children: task === void 0 ? t("create.title") : t("create.editTitle")
848
+ }), /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
849
+ className: ScheduledTasksPanel_module_css_dshcss_default.headActions,
850
+ children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("button", {
851
+ type: "button",
852
+ className: ScheduledTasksPanel_module_css_dshcss_default.ghostButton,
853
+ disabled: busy,
854
+ onClick: onCancel,
855
+ children: t("form.cancel")
856
+ }), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("button", {
857
+ type: "button",
858
+ className: ScheduledTasksPanel_module_css_dshcss_default.primaryButton,
859
+ disabled: busy || prompt.trim() === "" || !selectorValid,
860
+ onClick: () => {
861
+ submit();
862
+ },
863
+ children: busy ? t("form.submitBusy") : task === void 0 ? t("create.submit") : t("create.save")
864
+ })]
865
+ })]
866
+ }),
867
+ /* @__PURE__ */ (0, react_jsx_runtime.jsx)("p", {
868
+ className: ScheduledTasksPanel_module_css_dshcss_default.subtitle,
869
+ children: t("create.subtitle")
870
+ }),
871
+ /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
872
+ className: `${ScheduledTasksPanel_module_css_dshcss_default.body} ${ScheduledTasksPanel_module_css_dshcss_default.formBody}`,
873
+ children: [
874
+ /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("label", {
875
+ className: ScheduledTasksPanel_module_css_dshcss_default.fieldLine,
876
+ children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", { children: t("form.title.label") }), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("input", {
877
+ className: ScheduledTasksPanel_module_css_dshcss_default.textInput,
878
+ value: title,
879
+ onChange: (event) => {
880
+ setTitle(event.target.value);
881
+ },
882
+ placeholder: t("form.title.placeholder")
883
+ })]
884
+ }),
885
+ /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
886
+ className: ScheduledTasksPanel_module_css_dshcss_default.fieldLine,
887
+ children: [
888
+ /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", { children: t("form.schedule.label") }),
889
+ /* @__PURE__ */ (0, react_jsx_runtime.jsx)(ScheduleEditor, {
890
+ t,
891
+ preset,
892
+ minute,
893
+ time,
894
+ timeZone,
895
+ weekdays,
896
+ dayOfMonth,
897
+ onPresetChange: setPreset,
898
+ onMinuteChange: (value) => {
899
+ patchSchedule({ minute: value });
900
+ },
901
+ onTimeChange: (value) => {
902
+ patchSchedule({ time: value });
903
+ },
904
+ onWeekdaysChange: (value) => {
905
+ patchSchedule({ weekdays: value });
906
+ },
907
+ onDayOfMonthChange: (value) => {
908
+ patchSchedule({ dayOfMonth: value });
909
+ },
910
+ onTimeZoneChange: (value) => {
911
+ patchSchedule({ timeZone: value });
912
+ },
913
+ onClear: () => {
914
+ patchSchedule({ preset: "" });
915
+ }
916
+ }),
917
+ !selectorValid && /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
918
+ className: ScheduledTasksPanel_module_css_dshcss_default.fieldHint,
919
+ children: preset === "" ? t("form.schedule.required") : t("form.schedule.invalid")
920
+ })
921
+ ]
922
+ }),
923
+ preset === "custom" && /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
924
+ className: `${ScheduledTasksPanel_module_css_dshcss_default.formBody} ${ScheduledTasksPanel_module_css_dshcss_default.customGroup}`,
925
+ children: [
926
+ /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("label", {
927
+ className: ScheduledTasksPanel_module_css_dshcss_default.fieldLine,
928
+ children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", { children: t("form.schedule.label") }), /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("select", {
929
+ className: ScheduledTasksPanel_module_css_dshcss_default.textInput,
930
+ value: customKind,
931
+ onChange: (event) => {
932
+ patchSchedule({ customKind: event.target.value });
933
+ },
934
+ children: [
935
+ /* @__PURE__ */ (0, react_jsx_runtime.jsx)("option", {
936
+ value: "at",
937
+ children: t("form.kind.once")
938
+ }),
939
+ /* @__PURE__ */ (0, react_jsx_runtime.jsx)("option", {
940
+ value: "after",
941
+ children: t("form.kind.delay")
942
+ }),
943
+ customKind === "every" && /* @__PURE__ */ (0, react_jsx_runtime.jsx)("option", {
944
+ value: "every",
945
+ disabled: true,
946
+ children: t("form.kind.interval")
947
+ })
948
+ ]
949
+ })]
950
+ }),
951
+ customKind === "at" && /* @__PURE__ */ (0, react_jsx_runtime.jsxs)(react_jsx_runtime.Fragment, { children: [
952
+ /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("label", {
953
+ className: ScheduledTasksPanel_module_css_dshcss_default.fieldLine,
954
+ children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", { children: t("form.date") }), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("input", {
955
+ className: ScheduledTasksPanel_module_css_dshcss_default.textInput,
956
+ type: "date",
957
+ value: date,
958
+ onChange: (event) => {
959
+ setDate(event.target.value);
960
+ }
961
+ })]
962
+ }),
963
+ /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("label", {
964
+ className: ScheduledTasksPanel_module_css_dshcss_default.fieldLine,
965
+ children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", { children: t("form.time") }), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("input", {
966
+ className: ScheduledTasksPanel_module_css_dshcss_default.textInput,
967
+ type: "time",
968
+ value: atTime,
969
+ onChange: (event) => {
970
+ setAtTime(event.target.value);
971
+ }
972
+ })]
973
+ }),
974
+ /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("label", {
975
+ className: ScheduledTasksPanel_module_css_dshcss_default.fieldLine,
976
+ children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", { children: t("form.timeZone") }), /* @__PURE__ */ (0, react_jsx_runtime.jsx)(TimezoneField, {
977
+ t,
978
+ value: timeZone,
979
+ onChange: (value) => {
980
+ patchSchedule({ timeZone: value });
981
+ }
982
+ })]
983
+ })
984
+ ] }),
985
+ customKind === "after" && /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("label", {
986
+ className: ScheduledTasksPanel_module_css_dshcss_default.fieldLine,
987
+ children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", { children: t("form.afterSeconds") }), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("input", {
988
+ className: ScheduledTasksPanel_module_css_dshcss_default.textInput,
989
+ type: "number",
990
+ min: 1,
991
+ value: afterSeconds,
992
+ onChange: (event) => {
993
+ setAfterSeconds(event.target.value);
994
+ }
995
+ })]
996
+ }),
997
+ customKind === "every" && /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("label", {
998
+ className: ScheduledTasksPanel_module_css_dshcss_default.fieldLine,
999
+ children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", { children: t("form.everySeconds") }), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("input", {
1000
+ className: ScheduledTasksPanel_module_css_dshcss_default.textInput,
1001
+ type: "number",
1002
+ min: 300,
1003
+ value: everySeconds,
1004
+ onChange: (event) => {
1005
+ setEverySeconds(event.target.value);
1006
+ }
1007
+ })]
1008
+ })
1009
+ ]
1010
+ }),
1011
+ /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("label", {
1012
+ className: ScheduledTasksPanel_module_css_dshcss_default.fieldLine,
1013
+ children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", { children: t("form.prompt.label") }), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("textarea", {
1014
+ className: ScheduledTasksPanel_module_css_dshcss_default.textArea,
1015
+ value: prompt,
1016
+ onChange: (event) => {
1017
+ setPrompt(event.target.value);
1018
+ },
1019
+ placeholder: t("form.prompt.placeholder")
1020
+ })]
1021
+ }),
1022
+ /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
1023
+ className: ScheduledTasksPanel_module_css_dshcss_default.bottomBar,
1024
+ children: [
1025
+ /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("label", {
1026
+ className: ScheduledTasksPanel_module_css_dshcss_default.fieldLine,
1027
+ children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", { children: t("form.project.label") }), /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("select", {
1028
+ className: ScheduledTasksPanel_module_css_dshcss_default.textInput,
1029
+ value: projectKey,
1030
+ disabled: projects.status !== "ready",
1031
+ onChange: (event) => {
1032
+ setProjectKey(event.target.value);
1033
+ },
1034
+ children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("option", {
1035
+ value: "",
1036
+ children: projects.status === "loading" ? t("form.project.loading") : projects.status === "failed" ? t("form.project.failed", { message: projects.error ?? "" }) : t("form.project.none")
1037
+ }), projects.items.map((item) => /* @__PURE__ */ (0, react_jsx_runtime.jsx)("option", {
1038
+ value: item.workspaceId,
1039
+ children: item.title
1040
+ }, item.workspaceId))]
1041
+ })]
1042
+ }),
1043
+ /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
1044
+ className: ScheduledTasksPanel_module_css_dshcss_default.switchRow,
1045
+ children: [/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
1046
+ className: ScheduledTasksPanel_module_css_dshcss_default.switchCopy,
1047
+ children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", { children: t("form.confirm.label") }), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
1048
+ className: ScheduledTasksPanel_module_css_dshcss_default.hint,
1049
+ children: t("form.confirm.hint")
1050
+ })]
1051
+ }), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("button", {
1052
+ type: "button",
1053
+ className: ScheduledTasksPanel_module_css_dshcss_default.switch,
1054
+ "data-on": confirmBeforeChange || void 0,
1055
+ role: "switch",
1056
+ "aria-checked": confirmBeforeChange,
1057
+ "aria-label": t("form.confirm.label"),
1058
+ onClick: () => {
1059
+ setConfirmBeforeChange((value) => !value);
1060
+ }
1061
+ })]
1062
+ }),
1063
+ /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("label", {
1064
+ className: ScheduledTasksPanel_module_css_dshcss_default.fieldLine,
1065
+ children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", { children: t("form.model.label") }), /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("select", {
1066
+ className: ScheduledTasksPanel_module_css_dshcss_default.textInput,
1067
+ value: modelKey,
1068
+ disabled: models.status !== "ready",
1069
+ onChange: (event) => {
1070
+ setModelKey(event.target.value);
1071
+ },
1072
+ children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("option", {
1073
+ value: "",
1074
+ children: models.status === "loading" ? t("form.model.loading") : models.status === "failed" ? t("form.model.failed", { message: models.error ?? "" }) : models.items.length === 0 ? t("form.model.empty") : t("form.model.default")
1075
+ }), models.items.map((item) => /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("option", {
1076
+ value: `${item.providerId}/${item.modelId}`,
1077
+ children: [
1078
+ item.providerName,
1079
+ "/",
1080
+ item.modelName
1081
+ ]
1082
+ }, `${item.providerId}/${item.modelId}`))]
1083
+ })]
1084
+ })
1085
+ ]
1086
+ }),
1087
+ formError !== null && /* @__PURE__ */ (0, react_jsx_runtime.jsx)("p", {
1088
+ className: ScheduledTasksPanel_module_css_dshcss_default.readError,
1089
+ role: "alert",
1090
+ children: formError
1091
+ })
1092
+ ]
1093
+ })
1094
+ ] });
1095
+ }
1096
+ //#endregion
1097
+ //#region src/client/ScheduledTasksList.tsx
1098
+ /**
1099
+ * 已安排的任务 list view (the drawer body): search box, status filter tabs, and
1100
+ * the task rows with hover-revealed actions over the Remote.
1101
+ */
1102
+ const FILTER_LABELS = {
1103
+ all: "filter.all",
1104
+ active: "filter.active",
1105
+ paused: "filter.paused"
1106
+ };
1107
+ const STATUS_LABELS = {
1108
+ active: "row.status.active",
1109
+ paused: "row.status.paused",
1110
+ completed: "row.status.completed"
1111
+ };
1112
+ /** Row action wrapper: a tooltip over a compact icon button. */
1113
+ function RowAction({ label, children, ...props }) {
1114
+ return /* @__PURE__ */ (0, react_jsx_runtime.jsx)(_deepseek_ai_dsh_client_ui_primitives.Tooltip, {
1115
+ label,
1116
+ side: "bottom",
1117
+ delayMs: 500,
1118
+ children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)("button", {
1119
+ type: "button",
1120
+ className: ScheduledTasksPanel_module_css_dshcss_default.actionButton,
1121
+ "aria-label": label,
1122
+ ...props,
1123
+ children
1124
+ })
1125
+ });
1126
+ }
1127
+ /** Render the scheduled-tasks list view. */
1128
+ function ScheduledTasksList({ t, tasks, busy, onCreate, onClose, onEdit, onSetStatus, onDelete, onMarkRead }) {
1129
+ const [search, setSearch] = (0, react.useState)("");
1130
+ const [filter, setFilter] = (0, react.useState)("all");
1131
+ const query = search.trim().toLowerCase();
1132
+ const filtered = tasks.filter((task) => {
1133
+ if (filter === "active" && task.status !== "active") return false;
1134
+ if (filter === "paused" && task.status !== "paused") return false;
1135
+ if (query !== "" && !task.title.toLowerCase().includes(query)) return false;
1136
+ return true;
1137
+ });
1138
+ return /* @__PURE__ */ (0, react_jsx_runtime.jsxs)(react_jsx_runtime.Fragment, { children: [
1139
+ /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("header", {
1140
+ className: ScheduledTasksPanel_module_css_dshcss_default.head,
1141
+ children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("h2", {
1142
+ className: ScheduledTasksPanel_module_css_dshcss_default.title,
1143
+ children: t("panel.title")
1144
+ }), /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
1145
+ className: ScheduledTasksPanel_module_css_dshcss_default.headActions,
1146
+ children: [/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("button", {
1147
+ type: "button",
1148
+ className: ScheduledTasksPanel_module_css_dshcss_default.primaryButton,
1149
+ onClick: onCreate,
1150
+ children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)(_deepseek_ai_dsh_client_ui_primitives.IconPlusOutline16, { size: 14 }), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", { children: t("action.create") })]
1151
+ }), /* @__PURE__ */ (0, react_jsx_runtime.jsx)(_deepseek_ai_dsh_client_ui_primitives.Tooltip, {
1152
+ label: t("drawer.close"),
1153
+ side: "bottom",
1154
+ delayMs: 500,
1155
+ children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)("button", {
1156
+ type: "button",
1157
+ className: ScheduledTasksPanel_module_css_dshcss_default.closeButton,
1158
+ "aria-label": t("drawer.close"),
1159
+ onClick: onClose,
1160
+ children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)(_deepseek_ai_dsh_client_ui_primitives.IconCloseOutline16, { size: 16 })
1161
+ })
1162
+ })]
1163
+ })]
1164
+ }),
1165
+ /* @__PURE__ */ (0, react_jsx_runtime.jsx)("p", {
1166
+ className: ScheduledTasksPanel_module_css_dshcss_default.subtitle,
1167
+ children: t("panel.subtitle")
1168
+ }),
1169
+ /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
1170
+ className: ScheduledTasksPanel_module_css_dshcss_default.toolbar,
1171
+ children: /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("label", {
1172
+ className: ScheduledTasksPanel_module_css_dshcss_default.searchBox,
1173
+ children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)(_deepseek_ai_dsh_client_ui_primitives.IconSearchOutline16, { size: 14 }), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("input", {
1174
+ className: ScheduledTasksPanel_module_css_dshcss_default.searchInput,
1175
+ value: search,
1176
+ onChange: (event) => {
1177
+ setSearch(event.target.value);
1178
+ },
1179
+ placeholder: t("search.placeholder")
1180
+ })]
1181
+ })
1182
+ }),
1183
+ /* @__PURE__ */ (0, react_jsx_runtime.jsx)("nav", {
1184
+ className: ScheduledTasksPanel_module_css_dshcss_default.tabs,
1185
+ "aria-label": t("panel.title"),
1186
+ children: Object.keys(FILTER_LABELS).map((item) => /* @__PURE__ */ (0, react_jsx_runtime.jsx)("button", {
1187
+ type: "button",
1188
+ className: ScheduledTasksPanel_module_css_dshcss_default.tab,
1189
+ "data-active": filter === item || void 0,
1190
+ onClick: () => {
1191
+ setFilter(item);
1192
+ },
1193
+ children: t(FILTER_LABELS[item])
1194
+ }, item))
1195
+ }),
1196
+ /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
1197
+ className: ScheduledTasksPanel_module_css_dshcss_default.body,
1198
+ children: [filtered.length === 0 && /* @__PURE__ */ (0, react_jsx_runtime.jsx)("p", {
1199
+ className: ScheduledTasksPanel_module_css_dshcss_default.note,
1200
+ children: t("panel.empty")
1201
+ }), filtered.length > 0 && /* @__PURE__ */ (0, react_jsx_runtime.jsx)("ul", {
1202
+ className: ScheduledTasksPanel_module_css_dshcss_default.rows,
1203
+ children: filtered.map((task) => /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("li", {
1204
+ className: ScheduledTasksPanel_module_css_dshcss_default.row,
1205
+ children: [
1206
+ /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
1207
+ className: ScheduledTasksPanel_module_css_dshcss_default.statusDot,
1208
+ "data-status": task.status,
1209
+ role: "img",
1210
+ "aria-label": t(STATUS_LABELS[task.status])
1211
+ }),
1212
+ /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
1213
+ className: ScheduledTasksPanel_module_css_dshcss_default.rowMain,
1214
+ "data-unread": task.unread || void 0,
1215
+ role: task.unread ? "button" : void 0,
1216
+ tabIndex: task.unread ? 0 : void 0,
1217
+ "aria-label": task.unread ? t("action.markRead") : void 0,
1218
+ onClick: () => {
1219
+ if (task.unread && !busy) onMarkRead(task);
1220
+ },
1221
+ onKeyDown: (event) => {
1222
+ if (task.unread && !busy && (event.key === "Enter" || event.key === " ")) {
1223
+ event.preventDefault();
1224
+ onMarkRead(task);
1225
+ }
1226
+ },
1227
+ children: [/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
1228
+ className: ScheduledTasksPanel_module_css_dshcss_default.rowHead,
1229
+ children: [task.unread && /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", { className: ScheduledTasksPanel_module_css_dshcss_default.unreadDot }), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
1230
+ className: ScheduledTasksPanel_module_css_dshcss_default.rowTitle,
1231
+ children: task.title
1232
+ })]
1233
+ }), /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
1234
+ className: ScheduledTasksPanel_module_css_dshcss_default.rowMeta,
1235
+ children: [
1236
+ /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
1237
+ className: ScheduledTasksPanel_module_css_dshcss_default.rowSchedule,
1238
+ children: ruleSummary(task.rule, t)
1239
+ }),
1240
+ task.nextRunAt !== void 0 && task.status !== "completed" && /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
1241
+ className: ScheduledTasksPanel_module_css_dshcss_default.rowNext,
1242
+ children: t("row.next", { time: localizedDate(task.nextRunAt) })
1243
+ }),
1244
+ task.state === "overdue" && /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
1245
+ className: ScheduledTasksPanel_module_css_dshcss_default.rowOverdue,
1246
+ children: t("row.state.overdue")
1247
+ }),
1248
+ task.lastError !== void 0 && /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
1249
+ className: ScheduledTasksPanel_module_css_dshcss_default.rowLastError,
1250
+ title: `${task.lastError.at} — ${task.lastError.message}`,
1251
+ children: t("row.lastError")
1252
+ }),
1253
+ /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
1254
+ className: ScheduledTasksPanel_module_css_dshcss_default.rowStatus,
1255
+ "data-state": task.state,
1256
+ children: t(STATUS_LABELS[task.status])
1257
+ })
1258
+ ]
1259
+ })]
1260
+ }),
1261
+ /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
1262
+ className: ScheduledTasksPanel_module_css_dshcss_default.rowActions,
1263
+ children: [
1264
+ task.status === "active" && /* @__PURE__ */ (0, react_jsx_runtime.jsx)(RowAction, {
1265
+ label: t("action.pause"),
1266
+ disabled: busy,
1267
+ onClick: () => {
1268
+ onSetStatus(task, "paused");
1269
+ },
1270
+ children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)(_deepseek_ai_dsh_client_ui_primitives.IconPauseOutline16, { size: 14 })
1271
+ }),
1272
+ task.status === "paused" && /* @__PURE__ */ (0, react_jsx_runtime.jsx)(RowAction, {
1273
+ label: t("action.resume"),
1274
+ disabled: busy,
1275
+ onClick: () => {
1276
+ onSetStatus(task, "active");
1277
+ },
1278
+ children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)(_deepseek_ai_dsh_client_ui_primitives.IconPlayOutline16, { size: 14 })
1279
+ }),
1280
+ /* @__PURE__ */ (0, react_jsx_runtime.jsx)(RowAction, {
1281
+ label: t("action.edit"),
1282
+ disabled: busy,
1283
+ onClick: () => {
1284
+ onEdit(task);
1285
+ },
1286
+ children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)(_deepseek_ai_dsh_client_ui_primitives.IconEditOutline16, { size: 14 })
1287
+ }),
1288
+ /* @__PURE__ */ (0, react_jsx_runtime.jsx)(RowAction, {
1289
+ label: t("action.delete"),
1290
+ disabled: busy,
1291
+ onClick: () => {
1292
+ onDelete(task);
1293
+ },
1294
+ children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)(_deepseek_ai_dsh_client_ui_primitives.IconTrashOutline16, { size: 14 })
1295
+ })
1296
+ ]
1297
+ })
1298
+ ]
1299
+ }, task.id))
1300
+ })]
1301
+ })
1302
+ ] });
1303
+ }
1304
+ //#endregion
1305
+ //#region src/client/ScheduledTasksPanel.tsx
1306
+ /**
1307
+ * Global scheduled-task panel shell (external plugin): the sidebar footer
1308
+ * trigger opens a right-docked drawer hosting two views — the 已安排的任务
1309
+ * history list (search/filter/create) and the 新建定时任务 form — over the
1310
+ * Remote's list/create/update/setStatus/delete/markRead surface.
1311
+ */
1312
+ /** Unwrap one Typert envelope; a falsey `ok` keeps the inner error message. */
1313
+ function unwrap(answered) {
1314
+ if (!answered.ok) return {
1315
+ ok: false,
1316
+ message: `${answered.error.code}: ${answered.error.message}`
1317
+ };
1318
+ return {
1319
+ ok: true,
1320
+ value: answered.value
1321
+ };
1322
+ }
1323
+ /** Render the scheduled-tasks trigger and its right-side drawer. */
1324
+ function ScheduledTasksPanel({ wide, remote, listProjects, listModels, t }) {
1325
+ const [open, setOpen] = (0, react.useState)(false);
1326
+ const [view, setView] = (0, react.useState)("list");
1327
+ const [tasks, setTasks] = (0, react.useState)([]);
1328
+ const [read, setRead] = (0, react.useState)(false);
1329
+ const [error, setError] = (0, react.useState)(null);
1330
+ const [busy, setBusy] = (0, react.useState)(false);
1331
+ const [editingId, setEditingId] = (0, react.useState)(null);
1332
+ const unread = tasks.filter((task) => task.unread).length;
1333
+ const refresh = async () => {
1334
+ try {
1335
+ const envelope = unwrap(await remote.list());
1336
+ if (!envelope.ok) {
1337
+ setRead(true);
1338
+ setError(envelope.message);
1339
+ setTasks([]);
1340
+ return;
1341
+ }
1342
+ setRead(true);
1343
+ setError(null);
1344
+ setTasks(envelope.value);
1345
+ } catch (caught) {
1346
+ setRead(true);
1347
+ setError(t("panel.readFailed", { message: caught instanceof Error ? caught.message : String(caught) }));
1348
+ setTasks([]);
1349
+ }
1350
+ };
1351
+ (0, react.useEffect)(() => {
1352
+ if (open) refresh();
1353
+ }, [open]);
1354
+ (0, react.useEffect)(() => {
1355
+ if (!open) return;
1356
+ const onKey = (event) => {
1357
+ if (event.key === "Escape") setOpen(false);
1358
+ };
1359
+ window.addEventListener("keydown", onKey);
1360
+ return () => {
1361
+ window.removeEventListener("keydown", onKey);
1362
+ };
1363
+ }, [open]);
1364
+ const openList = () => {
1365
+ setEditingId(null);
1366
+ setView("list");
1367
+ };
1368
+ const runMutation = async (action) => {
1369
+ if (busy) return;
1370
+ setBusy(true);
1371
+ try {
1372
+ await action();
1373
+ setError(null);
1374
+ } catch (caught) {
1375
+ setError(caught instanceof Error ? caught.message : String(caught));
1376
+ } finally {
1377
+ setBusy(false);
1378
+ try {
1379
+ await refresh();
1380
+ } catch {}
1381
+ }
1382
+ };
1383
+ const setStatus = (task, status) => {
1384
+ runMutation(async () => {
1385
+ const next = unwrap(await remote.setStatus(task.id, status));
1386
+ if (!next.ok) throw new Error(next.message);
1387
+ if (!next.value.ok) throw new Error(`${next.value.code}: ${next.value.message}`);
1388
+ });
1389
+ };
1390
+ const removeTask = (task) => {
1391
+ runMutation(async () => {
1392
+ const next = unwrap(await remote.delete(task.id));
1393
+ if (!next.ok) throw new Error(next.message);
1394
+ if (!next.value.ok) throw new Error(`${next.value.code}: ${next.value.message}`);
1395
+ });
1396
+ };
1397
+ const markRead = (task) => {
1398
+ runMutation(async () => {
1399
+ const next = unwrap(await remote.markRead(task.id));
1400
+ if (!next.ok) throw new Error(next.message);
1401
+ });
1402
+ };
1403
+ /** Create or update from the create view; errors surface inside the form. */
1404
+ const submit = async (input) => {
1405
+ let answered;
1406
+ try {
1407
+ answered = editingId === null ? await remote.create(input) : await remote.update(editingId, input);
1408
+ } catch (caught) {
1409
+ return {
1410
+ ok: false,
1411
+ message: caught instanceof Error ? caught.message : String(caught)
1412
+ };
1413
+ }
1414
+ const envelope = unwrap(answered);
1415
+ if (!envelope.ok) return {
1416
+ ok: false,
1417
+ message: envelope.message
1418
+ };
1419
+ if (!envelope.value.ok) return {
1420
+ ok: false,
1421
+ message: `${envelope.value.code}: ${envelope.value.message}`
1422
+ };
1423
+ openList();
1424
+ refresh();
1425
+ return { ok: true };
1426
+ };
1427
+ const editing = editingId === null ? void 0 : tasks.find((task) => task.id === editingId);
1428
+ return /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
1429
+ className: wide ? ScheduledTasksPanel_module_css_dshcss_default.layer : `${ScheduledTasksPanel_module_css_dshcss_default.layer} ${ScheduledTasksPanel_module_css_dshcss_default.rail}`,
1430
+ children: [open && /* @__PURE__ */ (0, react_jsx_runtime.jsxs)(react_jsx_runtime.Fragment, { children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
1431
+ className: ScheduledTasksPanel_module_css_dshcss_default.backdrop,
1432
+ onClick: () => {
1433
+ setOpen(false);
1434
+ }
1435
+ }), /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("section", {
1436
+ className: ScheduledTasksPanel_module_css_dshcss_default.drawer,
1437
+ "aria-label": t("panel.title"),
1438
+ children: [
1439
+ view === "list" ? /* @__PURE__ */ (0, react_jsx_runtime.jsx)(ScheduledTasksList, {
1440
+ t,
1441
+ tasks,
1442
+ busy,
1443
+ onCreate: () => {
1444
+ setEditingId(null);
1445
+ setView("create");
1446
+ },
1447
+ onClose: () => {
1448
+ setOpen(false);
1449
+ },
1450
+ onEdit: (task) => {
1451
+ setEditingId(task.id);
1452
+ setView("create");
1453
+ },
1454
+ onSetStatus: setStatus,
1455
+ onDelete: removeTask,
1456
+ onMarkRead: markRead
1457
+ }) : /* @__PURE__ */ (0, react_jsx_runtime.jsx)(ScheduledTaskCreate, {
1458
+ t,
1459
+ busy,
1460
+ task: editing,
1461
+ listProjects,
1462
+ listModels,
1463
+ onCancel: openList,
1464
+ onSubmit: submit
1465
+ }, editingId ?? "new"),
1466
+ error !== null && /* @__PURE__ */ (0, react_jsx_runtime.jsx)("p", {
1467
+ className: `${ScheduledTasksPanel_module_css_dshcss_default.readError} ${ScheduledTasksPanel_module_css_dshcss_default.drawerError}`,
1468
+ role: "alert",
1469
+ children: t("panel.readFailed", { message: error })
1470
+ }),
1471
+ !read && /* @__PURE__ */ (0, react_jsx_runtime.jsx)("p", {
1472
+ className: `${ScheduledTasksPanel_module_css_dshcss_default.note} ${ScheduledTasksPanel_module_css_dshcss_default.drawerError}`,
1473
+ children: t("panel.loading")
1474
+ })
1475
+ ]
1476
+ })] }), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
1477
+ className: ScheduledTasksPanel_module_css_dshcss_default.footerButtons,
1478
+ children: /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("button", {
1479
+ type: "button",
1480
+ className: ScheduledTasksPanel_module_css_dshcss_default.badge,
1481
+ "data-active": open || void 0,
1482
+ "aria-label": t("trigger.aria"),
1483
+ "aria-expanded": open,
1484
+ onClick: () => {
1485
+ setOpen((current) => !current);
1486
+ },
1487
+ children: [
1488
+ /* @__PURE__ */ (0, react_jsx_runtime.jsx)(_deepseek_ai_dsh_client_ui_primitives.IconRefreshOutline16, {}),
1489
+ wide && /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
1490
+ className: ScheduledTasksPanel_module_css_dshcss_default.badgeLabel,
1491
+ children: t("trigger.label")
1492
+ }),
1493
+ unread > 0 && /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
1494
+ className: ScheduledTasksPanel_module_css_dshcss_default.badgeCount,
1495
+ children: unread
1496
+ })
1497
+ ]
1498
+ })
1499
+ })]
1500
+ });
1501
+ }
1502
+ //#endregion
1503
+ //#region src/client/index.ts
1504
+ /**
1505
+ * Required services: the slot system, locale, the Remote key, the
1506
+ * `remote.scheduledTasks` namespace provided by the remotes assembly entry,
1507
+ * and the connection/session runtimes backing the create form's option lists.
1508
+ */
1509
+ const inject = [
1510
+ "slots",
1511
+ "locale",
1512
+ "remote",
1513
+ "remote.scheduledTasks",
1514
+ "connection",
1515
+ "sessions"
1516
+ ];
1517
+ /** Register the scheduled-tasks sidebar panel over the mounted Remote namespace. */
1518
+ function apply(ctx) {
1519
+ ctx.effect(() => ctx.locale.register(NS, {
1520
+ zh,
1521
+ en
1522
+ }), "ui-scheduled-task: dictionaries");
1523
+ const sessions = ctx.get("sessions");
1524
+ const connection = ctx.get("connection");
1525
+ ctx.slots.inject("sidebar.footer.action", () => ctx.slots.register({
1526
+ name: "sidebar.footer.action",
1527
+ id: "scheduled-tasks",
1528
+ locale: NS,
1529
+ inject: () => ({
1530
+ remote: ctx.remote.scheduledTasks,
1531
+ listProjects: async () => {
1532
+ const response = await connection.api.workspace.list({});
1533
+ if (!response.result.ok) throw new Error(`${response.result.error.code}: ${response.result.error.message}`);
1534
+ return response.result.value.items.map((item) => ({
1535
+ workspaceId: String(item.workspaceId),
1536
+ title: item.title,
1537
+ path: item.path
1538
+ }));
1539
+ },
1540
+ listModels: async () => {
1541
+ const sessionId = sessions.list.getSnapshot().current;
1542
+ if (sessionId === void 0) return [];
1543
+ const response = await connection.api.sessions.models({ sessionId });
1544
+ if (!response.result.ok) throw new Error(`${response.result.error.code}: ${response.result.error.message}`);
1545
+ const rows = [];
1546
+ for (const group of response.result.value.groups) for (const model of group.models) rows.push({
1547
+ providerId: group.id,
1548
+ providerName: group.name,
1549
+ modelId: model.id,
1550
+ modelName: model.name
1551
+ });
1552
+ return rows;
1553
+ }
1554
+ })
1555
+ }, ScheduledTasksPanel));
1556
+ }
1557
+ //#endregion
1558
+ exports.ScheduledTasksPanel = ScheduledTasksPanel;
1559
+ exports.apply = apply;
1560
+ exports.inject = inject;
1561
+ return module.exports;
1562
+ }
1563
+ });