dsh-later 1.0.0 → 1.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/CHANGELOG.md +204 -0
- package/README.en.md +9 -2
- package/README.md +9 -2
- package/icon.svg +10 -0
- package/lib/bar-geometry.js +139 -0
- package/lib/client.js +1088 -386
- package/lib/command-outcome.js +15 -0
- package/lib/commands.js +56 -8
- package/lib/delivery.js +66 -0
- package/lib/domain.js +6 -0
- package/lib/index.js +152 -29
- package/lib/ownership-store.js +113 -15
- package/lib/presence.js +51 -3
- package/lib/projection.js +149 -20
- package/lib/runtime.js +160 -24
- package/lib/schedule-compat.js +179 -0
- package/lib/types/bar-geometry.d.ts +111 -0
- package/lib/types/command-outcome.d.ts +19 -0
- package/lib/types/delivery.d.ts +51 -0
- package/lib/types/domain.d.ts +32 -0
- package/lib/types/index.d.ts +28 -8
- package/lib/types/ownership-store.d.ts +42 -2
- package/lib/types/presence.d.ts +43 -4
- package/lib/types/projection.d.ts +68 -6
- package/lib/types/runtime.d.ts +58 -1
- package/lib/types/schedule-compat.d.ts +111 -0
- package/lib/types/upstream-compat.d.ts +123 -0
- package/lib/types/user-tools.d.ts +48 -7
- package/lib/upstream-compat.js +143 -0
- package/lib/user-tools.js +268 -44
- package/package.json +25 -22
package/lib/client.js
CHANGED
|
@@ -131,8 +131,51 @@ var COMPONENTS = [
|
|
|
131
131
|
".ss-dock-bar-fill {",
|
|
132
132
|
" position: relative; z-index: 1;",
|
|
133
133
|
" height: 100%; border-radius: 999px; background: var(--dsw-alias-brand-primary);",
|
|
134
|
-
|
|
134
|
+
/* 活动期的推进由 CSS 动画驱动(见 ScheduleDock 的 fillStyle):
|
|
135
|
+
旧实现是「每秒 tick 改一次宽度 + transition 补间」,1 分钟任务每秒跳约 8px,
|
|
136
|
+
肉眼可见锯齿。改为动画后由合成器逐帧插值,真 60fps 且零重渲染。
|
|
137
|
+
这里**不保留** transition: width —— 它与动画叠加会造成双重补间、反而更抖。 */
|
|
138
|
+
" /* \u6781\u77ED\u4EFB\u52A1/\u65E9\u671F\u6682\u505C\u65F6\u8FDB\u5EA6\u6BD4\u63A5\u8FD1 0\uFF1A\u7ED9\u6700\u5C0F\u53EF\u89C1\u5BBD\u5EA6\uFF0C\u4E14 active \u4E0E paused \u540C\u4E00\u89C4\u5219\uFF0C",
|
|
139
|
+
" \u907F\u514D\u6682\u505C\u524D\u540E\u4FDD\u5E95\u9608\u503C\u4E0D\u4E00\u81F4\u5BFC\u81F4\u6761\u957F\u8DF3\u53D8\u3002 */",
|
|
140
|
+
" min-width: 10px;",
|
|
135
141
|
"}",
|
|
142
|
+
"/* \u8FDB\u5EA6\u63A8\u8FDB\uFF1ACSS \u52A8\u753B\u7EBF\u6027\u63A8\u8FDB\uFF08\u66FF\u4EE3\u300C\u6BCF\u79D2 tick \u6539\u5BBD\u5EA6 + transition \u8865\u95F4\u300D\uFF09\u3002",
|
|
143
|
+
" \u53C2\u6570\u7531 JS \u6CE8\u5165 --ss-bar-duration / --ss-bar-delay\uFF1A",
|
|
144
|
+
" duration \u56FA\u5B9A\u4E3A\u5B8C\u6574\u7A97\u53E3\uFF08\u5426\u5219\u6BCF\u6B21 tick \u90FD\u6539\u53D8\u53C2\u6570\u3001\u6D4F\u89C8\u5668\u4F1A\u91CD\u542F\u52A8\u753B\uFF09\uFF1B",
|
|
145
|
+
" delay \u4E3A -(\u5DF2\u8FC7\u53BB) \u7684\u8D1F\u503C\uFF08\u628A\u64AD\u653E\u5934\u5B9A\u4F4D\u5230\u7EDD\u5BF9\u76F8\u4F4D\uFF0C\u91CD\u6302\u8F7D\u540E\u4E0D\u5F52\u96F6\uFF09\u3002",
|
|
146
|
+
" JS \u4FA7\u53EA\u4F20\u53D8\u91CF\u3001\u4E0D\u5199 animationName \u7B80\u5199\uFF0C\u907F\u514D\u8986\u76D6\u8FD9\u91CC\u7684\u58F0\u660E\u3002",
|
|
147
|
+
" \u6CE8\u610F\u6B64\u5904**\u4E0D\u5E26** :not(.ss-paused)\uFF1A\u6682\u505C\u6001\u53E6\u6709 animation: none \u8986\u76D6\u3002 */",
|
|
148
|
+
".ss-dock-bar-fill {",
|
|
149
|
+
" animation-name: ss-dock-bar-progress;",
|
|
150
|
+
" animation-duration: var(--ss-bar-duration, 3600s);",
|
|
151
|
+
" animation-delay: var(--ss-bar-delay, 0ms);",
|
|
152
|
+
" animation-timing-function: linear;",
|
|
153
|
+
" animation-fill-mode: forwards;",
|
|
154
|
+
" animation-iteration-count: 1;",
|
|
155
|
+
"}",
|
|
156
|
+
"@keyframes ss-dock-bar-progress { from { width: 0%; } to { width: 100%; } }",
|
|
157
|
+
"@media (prefers-reduced-motion: reduce) {",
|
|
158
|
+
" /* \u65E0\u969C\u788D\uFF1A\u5173\u6389\u9010\u5E27\u63A8\u8FDB\u3002\u6B64\u65F6 animation-fill-mode \u4F1A\u8BA9\u5BBD\u5EA6\u505C\u5728\u8D77\u59CB\u503C(0)\uFF0C",
|
|
159
|
+
" \u6545\u7531 JS \u4FA7\u6539\u8D70\u9759\u6001 width \u8DEF\u5F84\uFF08\u89C1 ScheduleDock \u7684 prefersReducedMotion\uFF09\u3002 */",
|
|
160
|
+
" .ss-dock-bar-fill { animation: none !important; }",
|
|
161
|
+
"}",
|
|
162
|
+
"/* \u6682\u505C\u6001\uFF08P1\uFF1A\u4E0D\u989D\u5916\u52A0\u6837\u5F0F\uFF09\u3002",
|
|
163
|
+
" \u6682\u505C = \u539F\u6761 + \u5B8C\u5168\u9759\u6B62\uFF1A\u4E0D\u53E0\u52A0\u659C\u7EB9/\u51B0\u5C01/\u963B\u585E\u5934\uFF0C\u4E5F\u4E0D\u6539\u5E95\u8272\u3001\u4E0D\u53D8\u8272\u3002",
|
|
164
|
+
" \u72B6\u6001\u7531\u300C\u52A8 / \u9759\u300D\u5BF9\u6BD4\u8868\u8FBE\u2014\u2014\u8FDB\u884C\u4E2D\u8FDB\u5EA6\u6761\u5728\u63A8\u8FDB\uFF0C\u6682\u505C\u65F6\u505C\u4F4F\u3002",
|
|
165
|
+
' \u6CE8\u610F\uFF1A**\u4E0D\u989D\u5916\u53E0\u6D41\u52A8\u7EB9\u7406**\u3002\u5148\u524D\u8BEF\u628A"\u8FDB\u884C\u4E2D\u52A0\u6D41\u5149"\u5F53\u4F5C P1 \u7684\u4E00\u90E8\u5206\u5B9E\u73B0\uFF0C',
|
|
166
|
+
" \u4F46\u90A3\u4E0D\u5728 P1 \u5B9A\u4E49\u5185\uFF08P1 \u539F\u6587\uFF1A\u6682\u505C = \u539F\u6761 + \u9759\u6B62\uFF0C\u4E0D\u52A0\u4EFB\u4F55\u7EB9\u7406\uFF09\uFF0C\u5DF2\u79FB\u9664\u3002",
|
|
167
|
+
" \u53EA\u4FDD\u7559\u4E0B\u9762\u8FD9\u884C\u9632\u5FA1\uFF1A\u4E07\u4E00\u52A8\u753B\u56E0\u6545\u6B8B\u7559\uFF0C\u6682\u505C\u65F6\u5FC5\u987B\u505C\u4F4F\u3002",
|
|
168
|
+
" \uFF08\u51E0\u4F55\u4E0E\u4FDD\u5E95\u5BBD\u5EA6\u6CBF\u7528 .ss-dock-bar-fill \u7684\u516C\u5171\u89C4\u5219\uFF0C\u6545\u6682\u505C\u524D\u540E\u957F\u5EA6\u4E00\u81F4\u3002\uFF09 */",
|
|
169
|
+
".ss-dock-row.ss-paused .ss-dock-bar-fill {",
|
|
170
|
+
" animation: none;",
|
|
171
|
+
"}",
|
|
172
|
+
"@media (prefers-reduced-motion: reduce) {",
|
|
173
|
+
" .ss-dock-row:not(.ss-paused) .ss-dock-bar-fill { animation: none; background: var(--dsw-alias-brand-primary); }",
|
|
174
|
+
"}",
|
|
175
|
+
".ss-dock-row.ss-paused .ss-dock-row-countdown { color: var(--dsw-alias-label-tertiary); }",
|
|
176
|
+
".ss-dock-row.ss-paused .ss-dock-row-time,",
|
|
177
|
+
".ss-dock-row.ss-paused .ss-dock-row-prompt { color: var(--dsw-alias-label-secondary); }",
|
|
178
|
+
".ss-dock-action.ss-paused-active { color: var(--dsw-alias-state-success-primary); }",
|
|
136
179
|
"/* \u5206\u9694\u7EBF\uFF1Aabsolute \u8DE8\u6574\u4E2A bar \u753B N-1 \u6761\u7B49\u6BD4\u7AD6\u7EBF\uFF0C\u6E32\u67D3\u5728 fill \u4E4B\u524D\uFF08fill \u7528 z-index:1 \u76D6\u4F4F\u300C\u5DF2\u586B\u5145\u6BB5\u300D\u4E0A\u7684\u523B\u5EA6\uFF09\u3002 */",
|
|
137
180
|
".ss-dock-bar-divider {",
|
|
138
181
|
" position: absolute; inset: 0; pointer-events: none;",
|
|
@@ -152,6 +195,29 @@ var COMPONENTS = [
|
|
|
152
195
|
".ss-dock-steer-err {",
|
|
153
196
|
" color: var(--dsw-alias-state-warn-secondary); font-size: 12px; line-height: 16px;",
|
|
154
197
|
"}",
|
|
198
|
+
"/*",
|
|
199
|
+
" * \u6295\u9012\u672A\u786E\u8BA4\u63D0\u793A\uFF1A\u6761\u76EE\u88AB\u5BBF\u4E3B\u4FDD\u7559\uFF08\u672A\u5199 dispatch\uFF09\uFF0C\u884C\u4ECD\u5728\u53F0\u4E0A\u3002",
|
|
200
|
+
' * \u4E0E\u666E\u901A\u9519\u8BEF\uFF08\u7EAF\u6587\u5B57\uFF09\u533A\u5206\uFF1A\u5B83\u4E0D\u662F\u4E00\u4E2A"\u5931\u8D25"\uFF0C\u800C\u662F"\u7ED3\u679C\u672A\u77E5\u4E14\u53EF\u633D\u56DE"\uFF0C',
|
|
201
|
+
" * \u8BED\u6C14\u5E94\u662F\u63D0\u793A\u800C\u975E\u62A5\u9519\uFF0C\u6545\u7ED9\u6D45\u5E95 + \u8FB9\u6846 + \u53EF\u70B9\u7684\u91CD\u8BD5\u3002",
|
|
202
|
+
" */",
|
|
203
|
+
".ss-dock-steer-warn {",
|
|
204
|
+
" display: flex; align-items: center; gap: 8px; flex-wrap: wrap;",
|
|
205
|
+
" margin-top: 4px; padding: 4px 8px; border-radius: 6px;",
|
|
206
|
+
" font-size: 12px; line-height: 16px;",
|
|
207
|
+
" color: var(--dsw-alias-state-warn-secondary);",
|
|
208
|
+
" background: color-mix(in srgb, var(--dsw-alias-state-warn-secondary) 12%, transparent);",
|
|
209
|
+
" border: 1px solid color-mix(in srgb, var(--dsw-alias-state-warn-secondary) 32%, transparent);",
|
|
210
|
+
"}",
|
|
211
|
+
".ss-dock-steer-retry {",
|
|
212
|
+
" margin-left: auto; padding: 1px 8px; border-radius: 5px; cursor: pointer;",
|
|
213
|
+
" font: inherit; font-size: 12px;",
|
|
214
|
+
" color: var(--dsw-alias-state-warn-secondary);",
|
|
215
|
+
" background: color-mix(in srgb, var(--dsw-alias-state-warn-secondary) 18%, transparent);",
|
|
216
|
+
" border: 1px solid color-mix(in srgb, var(--dsw-alias-state-warn-secondary) 38%, transparent);",
|
|
217
|
+
"}",
|
|
218
|
+
".ss-dock-steer-retry:hover {",
|
|
219
|
+
" background: color-mix(in srgb, var(--dsw-alias-state-warn-secondary) 28%, transparent);",
|
|
220
|
+
"}",
|
|
155
221
|
"/* \u884C\u5185\u7F16\u8F91\uFF08QueueDock .editor \u540C\u6B3E\u8F93\u5165\u6846\uFF09\u3002 */",
|
|
156
222
|
".ss-dock-edit-input {",
|
|
157
223
|
" box-sizing: border-box; flex: auto; min-width: 0; height: 28px; padding: 0 8px;",
|
|
@@ -170,23 +236,6 @@ var COMPONENTS = [
|
|
|
170
236
|
" flex-basis: 100%; color: var(--dsw-alias-state-error-secondary); font-size: 12px; line-height: 16px;",
|
|
171
237
|
"}",
|
|
172
238
|
".ss-dock-editing { flex-wrap: wrap; }",
|
|
173
|
-
".ss-toast-host {",
|
|
174
|
-
" position: fixed; right: 16px; bottom: 96px; z-index: 300;",
|
|
175
|
-
" display: flex; flex-direction: column; gap: 8px; pointer-events: none;",
|
|
176
|
-
"}",
|
|
177
|
-
".ss-toast {",
|
|
178
|
-
" pointer-events: auto; max-width: min(360px, calc(100vw - 32px));",
|
|
179
|
-
" display: flex; align-items: center; gap: 8px;",
|
|
180
|
-
" padding: 9px 12px; border-radius: 10px;",
|
|
181
|
-
" background: var(--dsw-specific-menu); color: var(--dsw-alias-label-primary);",
|
|
182
|
-
" border: 1px solid var(--dsw-alias-line-primary);",
|
|
183
|
-
" box-shadow: 0 6px 20px rgba(0, 0, 0, 0.18);",
|
|
184
|
-
" font-size: 13px; line-height: 18px;",
|
|
185
|
-
" animation: ss-toast-in 180ms var(--ds-ease-out);",
|
|
186
|
-
"}",
|
|
187
|
-
".ss-toast-icon { color: var(--dsw-alias-brand-primary); flex: none; }",
|
|
188
|
-
".ss-toast-text { min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }",
|
|
189
|
-
"@keyframes ss-toast-in { from { opacity: 0; transform: translateY(6px); } to { opacity: 1; transform: none; } }",
|
|
190
239
|
"",
|
|
191
240
|
"/* ==================== \u9762\u677F ==================== */",
|
|
192
241
|
"/* \u5BF9\u9F50\u5B98\u65B9 popover panel\uFF1Az-index 100\u3001border-inverted\u3001radius 12\u3001\u5B57\u53F7 12\u3001secondary \u6587\u5B57 */",
|
|
@@ -253,23 +302,22 @@ var COMPONENTS = [
|
|
|
253
302
|
".ss-tasklist-head { margin-top: 10px; }",
|
|
254
303
|
"",
|
|
255
304
|
"/* ==================== \u8868\u5355\u5B57\u6BB5 ==================== */",
|
|
256
|
-
"/* \u5BF9\u9F50\u5B98\u65B9 fields.module.css\uFF1Acolumn \u5E03\u5C40\u3001label \u5728\u4E0A 13px/500\
|
|
305
|
+
"/* \u5BF9\u9F50\u5B98\u65B9 fields.module.css\uFF1Acolumn \u5E03\u5C40\u3001label \u5728\u4E0A 13px/500\uFF0C\u5B57\u6BB5\u95F4\u65E0\u5206\u9694\u7EBF */",
|
|
257
306
|
".ss-field {",
|
|
258
307
|
" display: flex; flex-direction: column; gap: 6px; padding: 12px 0;",
|
|
259
308
|
"}",
|
|
260
|
-
".ss-field + .ss-field { border-top: 1px solid var(--dsw-alias-border-l2); }",
|
|
261
309
|
".ss-input {",
|
|
262
|
-
" height:
|
|
263
|
-
" border:
|
|
310
|
+
" min-height: 36px; padding: 0 12px;",
|
|
311
|
+
" border: .5px solid var(--dsw-alias-border-l4); border-radius: var(--dsw-radius-md);",
|
|
264
312
|
" background: var(--dsw-alias-bg-layer-3); color: var(--dsw-alias-label-primary);",
|
|
265
|
-
" font-size: 13px; line-height: 1.5;
|
|
313
|
+
" font: inherit; font-size: 13px; line-height: 1.5;",
|
|
266
314
|
" flex: 1; min-width: 0; width: 100%; box-sizing: border-box;",
|
|
267
315
|
"}",
|
|
268
316
|
".ss-input:focus-visible {",
|
|
269
|
-
" border-color: var(--dsw-alias-
|
|
317
|
+
" outline: none; border-color: var(--dsw-alias-state-business-primary);",
|
|
270
318
|
"}",
|
|
271
319
|
".ss-input:disabled { color: var(--dsw-alias-label-tertiary); cursor: default; }",
|
|
272
|
-
".ss-input.ss-inputInvalid { border-color: var(--dsw-alias-
|
|
320
|
+
".ss-input.ss-inputInvalid { border-color: var(--dsw-alias-state-error-primary); }",
|
|
273
321
|
"",
|
|
274
322
|
"/* ==================== \u4EFB\u52A1\u5217\u8868 ==================== */",
|
|
275
323
|
".ss-tasks { max-height: 160px; overflow-y: auto; margin-bottom: 8px; }",
|
|
@@ -362,46 +410,147 @@ var COMPONENTS = [
|
|
|
362
410
|
"/* \u7D2B\u4E3A\u5B9A\u65F6\u4E13\u5C5E\uFF08\u6D45\u6DF1\u901A\u7528\uFF0C\u5BF9\u767D/\u6DF1\u5E95\u5BF9\u6BD4\u5747 \u22653:1\uFF09\uFF1Burgent/overdue \u590D\u7528\u5BBF\u4E3B warn/error \u522B\u540D\u3002 */",
|
|
363
411
|
".ss-presence { display: inline-flex; flex: none; color: #8b5cf6; }",
|
|
364
412
|
".ss-presence-beside { margin-left: 4px; }",
|
|
413
|
+
"",
|
|
414
|
+
"/* \u2500\u2500 \u65E7\u7248\u70B9\u9635\u65F6\u949F\uFF08classic\uFF09 \u2500\u2500 */",
|
|
365
415
|
".ss-presence rect { fill: currentColor; }",
|
|
366
416
|
".ss-presence .ss-presence-ring { opacity: 0.8; animation: ss-presence-breathe 2.4s var(--ds-ease-in-out, ease-in-out) infinite; }",
|
|
367
417
|
".ss-presence .ss-presence-hand { opacity: 1; }",
|
|
368
|
-
'.ss-presence[data-state="urgent"] { color: var(--dsw-alias-state-warn-secondary); }',
|
|
369
418
|
'.ss-presence[data-state="urgent"] .ss-presence-ring { animation-name: ss-presence-pulse; animation-duration: 0.9s; }',
|
|
370
|
-
'.ss-presence[data-state="overdue"] { color: var(--dsw-alias-state-error-primary); }',
|
|
371
419
|
'.ss-presence[data-state="overdue"] .ss-presence-ring { animation: none; }',
|
|
420
|
+
"",
|
|
421
|
+
"/* \u65B0\u7248\u63CF\u8FB9\u65F6\u949F\uFF08modern\uFF09\u2014 \u5BF9\u9F50 DSH \u5B98\u65B9 spinner \u6837\u5F0F \u2500\u2500 */",
|
|
422
|
+
".ss-presence .ss-clock-face {",
|
|
423
|
+
" fill: none; stroke: currentColor; stroke-width: 2; stroke-linecap: round;",
|
|
424
|
+
" opacity: 0.25; animation: ss-clock-breathe 2.4s var(--ds-ease-in-out, ease-in-out) infinite;",
|
|
425
|
+
"}",
|
|
426
|
+
".ss-presence .ss-clock-hand { stroke: currentColor; stroke-width: 2; stroke-linecap: round; }",
|
|
427
|
+
".ss-presence .ss-clock-hand-h { opacity: 1; }",
|
|
428
|
+
".ss-presence .ss-clock-hand-m { opacity: 0.85; }",
|
|
429
|
+
'.ss-presence[data-state="urgent"] .ss-clock-face { animation-name: ss-clock-pulse; animation-duration: 0.9s; }',
|
|
430
|
+
'.ss-presence[data-state="overdue"] .ss-clock-face { animation: none; opacity: 1; }',
|
|
431
|
+
"",
|
|
432
|
+
"/* \u2500\u2500 \u4E09\u6001\u989C\u8272 \u2500\u2500 */",
|
|
433
|
+
'.ss-presence[data-state="urgent"] { color: var(--dsw-alias-state-warn-secondary); }',
|
|
434
|
+
'.ss-presence[data-state="overdue"] { color: var(--dsw-alias-state-error-primary); }',
|
|
435
|
+
"",
|
|
436
|
+
"/* \u2500\u2500 \u52A8\u753B\u5173\u952E\u5E27 \u2500\u2500 */",
|
|
372
437
|
"@keyframes ss-presence-breathe { 0%, 100% { opacity: 0.65; } 50% { opacity: 1; } }",
|
|
373
438
|
"@keyframes ss-presence-pulse { 0%, 100% { opacity: 0.5; } 50% { opacity: 1; } }",
|
|
374
|
-
"@
|
|
439
|
+
"@keyframes ss-clock-breathe { 0%, 100% { opacity: 0.65; } 50% { opacity: 1; } }",
|
|
440
|
+
"@keyframes ss-clock-pulse { 0%, 100% { opacity: 0.5; } 50% { opacity: 1; } }",
|
|
441
|
+
"@media (prefers-reduced-motion: reduce) {",
|
|
442
|
+
" .ss-presence .ss-presence-ring { animation: none; }",
|
|
443
|
+
" .ss-presence .ss-clock-face { animation: none; }",
|
|
444
|
+
"}",
|
|
375
445
|
"",
|
|
376
|
-
"/* ==================== \
|
|
377
|
-
"/* \
|
|
378
|
-
" \
|
|
379
|
-
"
|
|
380
|
-
"
|
|
381
|
-
"
|
|
382
|
-
"
|
|
383
|
-
"
|
|
384
|
-
"
|
|
385
|
-
"
|
|
386
|
-
"
|
|
387
|
-
"
|
|
388
|
-
"
|
|
389
|
-
"
|
|
390
|
-
"
|
|
391
|
-
"
|
|
392
|
-
"}",
|
|
393
|
-
"
|
|
394
|
-
"
|
|
395
|
-
"
|
|
396
|
-
".ss-
|
|
397
|
-
"
|
|
398
|
-
"
|
|
399
|
-
"
|
|
400
|
-
"
|
|
401
|
-
".ss-
|
|
402
|
-
"
|
|
403
|
-
|
|
404
|
-
"
|
|
446
|
+
"/* ==================== \u60AC\u6D6E\u5361\u7247\u72B6\u6001\u884C\u589E\u8865\uFF08issue #4\uFF09 ==================== */",
|
|
447
|
+
"/* \u4E0E\u5BBF\u4E3B .hoverStatus \u884C\u4E25\u683C\u540C\u6784\u3002\u5BBF\u4E3B StateDot \u5B9E\u6D4B\u7ED3\u6784\uFF08dsh-client-ui-primitives",
|
|
448
|
+
" \u7684 ._dot_* \u8FD0\u884C\u65F6\u6837\u5F0F\uFF0C10\xD710 relative + ::before 10px/inset:0 + ::after 6px/inset:2px\uFF0C",
|
|
449
|
+
" \u4E24\u5C42\u540C\u8272 \u2192 \u89C6\u89C9\u76F4\u5F84\u7EA6 8px\uFF09\uFF1A\u672C\u63D2\u4EF6\u6309\u4E0B\u8FF0\u540C\u6837\u7684\u53CC\u5C42\u5199\u6CD5\u81EA\u7ED8\uFF0C\u907F\u514D\u590D\u7528\u5176\u6784\u5EFA\u671F hash",
|
|
450
|
+
" \u7C7B\u540D\uFF08_dot_xxxxxx_n \u4E0D\u7A33\u5B9A\uFF0C\u5BBF\u4E3B\u5347\u7EA7\u4F1A\u9759\u9ED8\u5931\u6548\uFF09\u3002",
|
|
451
|
+
" \u989C\u8272\u8DDF\u968F\u5BBF\u4E3B\u8BED\u4E49\u8272\u677F\uFF0C\u4E0D\u5F15\u5165\u63D2\u4EF6\u4E13\u5C5E\u8272\u2014\u2014\u6587\u6848\u5DF2\u8BF4\u660E\u662F\u5B9A\u65F6\u63D0\u9192\uFF0C\u70B9\u4E0D\u5FC5\u518D\u627F\u62C5",
|
|
452
|
+
" \u300C\u533A\u5206\u6765\u6E90\u300D\u7684\u804C\u8D23\uFF1B\u6DF7\u5165\u7B2C\u4E94\u79CD\u989C\u8272\u53CD\u800C\u4E0E\u5BBF\u4E3B warning \u8BED\u4E49\u649E\u8F66\u3002",
|
|
453
|
+
"",
|
|
454
|
+
" \u26A0\uFE0F \u5DF2\u77E5\u9650\u5236\uFF08\u6D45\u8272\u9002\u914D\u5C1A\u672A\u5904\u7406\uFF09\uFF1A\u4EE5\u4E0B\u8272\u503C\u662F\u5728**\u5F53\u524D\u6DF1\u8272\u4E3B\u9898**\u4E0B\u4ECE\u5BBF\u4E3B",
|
|
455
|
+
" \u5B9E\u6D4B\u5F97\u5230\u7684\u8FD0\u884C\u65F6\u503C\uFF0C\u5BBF\u4E3B\u81EA\u8EAB\u5F15\u7528 --dsw-alias-* token\uFF0C\u4F1A\u968F\u4E3B\u9898\u53D8\u5316\uFF0C",
|
|
456
|
+
" \u800C\u6B64\u5904\u662F\u786C\u7F16\u7801\u5E38\u91CF\u3002\u56E0\u6B64\u5F53\u524D\u4EC5\u5728\u6DF1\u8272\u4E3B\u9898\u4E0B\u4E0E\u5BBF\u4E3B\u4E00\u81F4\uFF1B\u5207\u6362\u5230\u6D45\u8272\u4E3B\u9898/",
|
|
457
|
+
" \u5176\u4ED6\u914D\u8272\u65B9\u6848\u65F6\uFF0C\u672C\u884C\u4E0D\u4F1A\u8DDF\u968F\uFF0C\u53EF\u80FD\u4E0E\u8BE5\u5361\u7247\u5176\u4F59\u5185\u5BB9\u4E0D\u540C\u6B65\u3002",
|
|
458
|
+
" \u4FEE\u6CD5\uFF1A\u5B9E\u6D4B\u6D45\u8272\u4E3B\u9898\u4E0B\u8BE5\u5361\u7247\u7684\u5B9E\u9645\u5E95\u8272\u540E\uFF0C\u6539\u7528\u5BF9\u5E94 token\uFF08\u5F85\u529E\uFF09\u3002 */",
|
|
459
|
+
".ss-hover-status {",
|
|
460
|
+
" display: flex; align-items: center; gap: 8px;",
|
|
461
|
+
" color: #adb2b8; font-size: 12px; line-height: 20px;",
|
|
462
|
+
"}",
|
|
463
|
+
"/* \u72B6\u6001\u70B9\uFF1A\u5BBF\u4E3B\u540C\u6B3E\u53CC\u5C42\u7ED3\u6784\u3002\u5173\u952E\u2014\u2014::before \u662F 10% \u900F\u660E\u5EA6\u7684**\u5149\u6655**\uFF0C",
|
|
464
|
+
" \u4E0D\u662F\u5B9E\u5FC3\u5916\u73AF\uFF1B::after \u624D\u662F 6px \u5B9E\u5FC3\u6838\u5FC3\u3002\u82E5 ::before \u4E0D\u8BBE opacity\uFF0C",
|
|
465
|
+
" \u5B83\u4F1A\u76D6\u4F4F\u6838\u5FC3\u5E76\u6E32\u67D3\u6210 10px \u5B9E\u5FC3\u5706\uFF08\u6BD4\u5BBF\u4E3B\u660E\u663E\u504F\u5927\u504F\u5B9E\uFF09\u3002 */",
|
|
466
|
+
".ss-hover-status-dot {",
|
|
467
|
+
" position: relative; display: block; flex: none;",
|
|
468
|
+
" width: 10px; height: 10px;",
|
|
469
|
+
" color: #adb2b8;",
|
|
470
|
+
"}",
|
|
471
|
+
".ss-hover-status-dot::before,",
|
|
472
|
+
".ss-hover-status-dot::after {",
|
|
473
|
+
' content: ""; position: absolute; border-radius: 50%; background: currentColor;',
|
|
474
|
+
"}",
|
|
475
|
+
".ss-hover-status-dot::before { inset: 0; opacity: 0.1; }",
|
|
476
|
+
".ss-hover-status-dot::after { inset: 2px; }",
|
|
477
|
+
"/* \u8BED\u4E49\u6620\u5C04\uFF08\u5BF9\u9F50\u5BBF\u4E3B done/ongoing/warning/error \u56DB\u6001\u8272\u503C\uFF09\uFF1A",
|
|
478
|
+
" scheduled \u2192 ongoing \u7070\uFF08\u4E2D\u6027\uFF1A\u5DF2\u6392\u671F\uFF0C\u65E0\u7D27\u8FEB\u6027\uFF09",
|
|
479
|
+
" urgent \u2192 warning \u7425\u73C0\uFF08\u22645min \u5373\u5C06\u89E6\u53D1\uFF09",
|
|
480
|
+
" overdue \u2192 error \u7EA2\uFF08\u5DF2\u5230\u671F\uFF0C\u7B49\u5F85\u4F1A\u8BDD\u7A7A\u95F2\u53D1\u9001\uFF09 */",
|
|
481
|
+
'.ss-hover-status[data-state="urgent"] .ss-hover-status-dot { color: #f59e0b; }',
|
|
482
|
+
'.ss-hover-status[data-state="overdue"] .ss-hover-status-dot { color: #f25a5a; }',
|
|
483
|
+
"",
|
|
484
|
+
"/* ==================== \u8BBE\u7F6E\u9875\uFF08\u5B9A\u65F6\u63D0\u9192\u8868\u5355\uFF09 ==================== */",
|
|
485
|
+
"/* \u89C6\u89C9\u5BF9\u9F50\u5B98\u65B9 SettingsForm\uFF08dsh-client-ui-primitives\uFF09\uFF1A\u88F8\u8868\u5355\uFF0C\u65E0\u5361\u7247\u5BB9\u5668\uFF0C",
|
|
486
|
+
" \u5B57\u6BB5\u6309 section \u5206\u7EC4\uFF0C\u6BCF\u7EC4\u6709\u6807\u9898\uFF0C\u5E95\u90E8\u4FDD\u5B58\u6309\u94AE\u3002\u7C7B\u540D\u7EDF\u4E00 ss- \u524D\u7F00\u3002 */",
|
|
487
|
+
".ss-settings-form {",
|
|
488
|
+
" display: flex; flex-direction: column;",
|
|
489
|
+
"}",
|
|
490
|
+
"/* Section \u5206\u7EC4\uFF08\u5BF9\u9F50\u5B98\u65B9 AZSXYW_section \u7ED3\u6784\uFF09 */",
|
|
491
|
+
".ss-section {",
|
|
492
|
+
" padding: 16px 0;",
|
|
493
|
+
"}",
|
|
494
|
+
".ss-section-heading {",
|
|
495
|
+
" margin: 0; font-size: 13px; font-weight: 600; line-height: 1.5;",
|
|
496
|
+
" color: var(--dsw-alias-label-primary);",
|
|
497
|
+
"}",
|
|
498
|
+
".ss-section-fields {",
|
|
499
|
+
" display: flex; flex-direction: column;",
|
|
500
|
+
"}",
|
|
501
|
+
/* 紧凑字段并排(对齐官方 hF0LTq_limits 网格:两等宽列、间距 16px) */
|
|
502
|
+
".ss-section-fieldsGrid {",
|
|
503
|
+
" display: grid; grid-template-columns: repeat(2, minmax(0, 1fr)); gap: 16px;",
|
|
504
|
+
"}",
|
|
505
|
+
/* 帮助按钮(对齐官方 _helpButton_:24×24、radius 8px、12px 圆圈问号图标) */
|
|
506
|
+
".ss-help-btn {",
|
|
507
|
+
" width: 24px; height: 24px; padding: 0; flex: none;",
|
|
508
|
+
" display: inline-flex; align-items: center; justify-content: center;",
|
|
509
|
+
" background: none; border: none; border-radius: 8px; cursor: pointer;",
|
|
510
|
+
" color: var(--dsw-alias-label-tertiary);",
|
|
511
|
+
"}",
|
|
512
|
+
".ss-help-btn:hover, .ss-help-btnOpen { color: var(--dsw-alias-label-secondary); }",
|
|
513
|
+
".ss-help-btn:focus-visible {",
|
|
514
|
+
" outline: 2px solid var(--dsw-alias-state-business-primary); outline-offset: -1px;",
|
|
515
|
+
"}",
|
|
516
|
+
/* 展开后的说明区(对齐官方 _help_:12px / 1.6 行高、顶部 10px、次级文字色) */
|
|
517
|
+
".ss-help {",
|
|
518
|
+
" margin: 0; padding: 10px 0 0; font-size: 12px; line-height: 1.6;",
|
|
519
|
+
" color: var(--dsw-alias-label-secondary);",
|
|
520
|
+
"}",
|
|
521
|
+
".ss-help p { margin: 0; }",
|
|
522
|
+
/* Toggle 行(对齐官方子智能体插件的开关行:label 左 + switch 右) */
|
|
523
|
+
".ss-toggle-row {",
|
|
524
|
+
" display: flex; align-items: center; justify-content: space-between;",
|
|
525
|
+
" gap: 16px;",
|
|
526
|
+
"}",
|
|
527
|
+
".ss-toggle-label {",
|
|
528
|
+
" flex: 1; min-width: 0; font-size: 13px; font-weight: 500; line-height: 1.5;",
|
|
529
|
+
" color: var(--dsw-alias-label-primary);",
|
|
530
|
+
"}",
|
|
531
|
+
".ss-toggle-switch {",
|
|
532
|
+
" position: relative; width: 36px; height: 20px; flex: none;",
|
|
533
|
+
" background: var(--dsw-alias-bg-module-platform); border-radius: 999px;",
|
|
534
|
+
" cursor: pointer; transition: background var(--ds-transition-duration-fast) var(--ds-ease-in-out);",
|
|
535
|
+
" border: none; padding: 0;",
|
|
536
|
+
"}",
|
|
537
|
+
'.ss-toggle-switch[aria-checked="true"] { background: var(--dsw-alias-state-business-primary); }',
|
|
538
|
+
".ss-toggle-switch::after {",
|
|
539
|
+
' content: ""; position: absolute; top: 2px; left: 2px;',
|
|
540
|
+
" width: 16px; height: 16px; border-radius: 999px;",
|
|
541
|
+
" background: #fff; transition: transform var(--ds-transition-duration-fast) var(--ds-ease-in-out);",
|
|
542
|
+
"}",
|
|
543
|
+
'.ss-toggle-switch[aria-checked="true"]::after { transform: translateX(16px); }',
|
|
544
|
+
".ss-toggle-switch:disabled { opacity: 0.4; cursor: default; }",
|
|
545
|
+
".ss-toggle-switch:focus-visible {",
|
|
546
|
+
" outline: 2px solid var(--dsw-alias-state-business-primary); outline-offset: 2px;",
|
|
547
|
+
"}",
|
|
548
|
+
".ss-toggle-description {",
|
|
549
|
+
" margin: 0; padding: 0 0 12px; font-size: 12px; line-height: 1.6;",
|
|
550
|
+
" color: var(--dsw-alias-label-secondary);",
|
|
551
|
+
"}",
|
|
552
|
+
".ss-label-group {",
|
|
553
|
+
" display: flex; align-items: center; gap: 4px; flex: 1; min-width: 0;",
|
|
405
554
|
"}",
|
|
406
555
|
".ss-card-fieldHead { align-items: center; gap: 8px; display: flex; }",
|
|
407
556
|
".ss-card-label {",
|
|
@@ -420,11 +569,21 @@ var COMPONENTS = [
|
|
|
420
569
|
"}",
|
|
421
570
|
".ss-card-reset:hover:not(:disabled) { color: var(--dsw-alias-label-primary); }",
|
|
422
571
|
".ss-card-reset:disabled { cursor: default; }",
|
|
423
|
-
".ss-card-invalid { color: var(--dsw-alias-
|
|
572
|
+
".ss-card-invalid { color: var(--dsw-alias-state-error-primary); margin: 0; font-size: 12px; line-height: 1.5; }",
|
|
573
|
+
"/*",
|
|
574
|
+
" * \u9009\u9879\u98CE\u9669\u63D0\u793A\uFF08steer \u53EF\u80FD\u88AB\u56DE\u5408\u542F\u52A8\u541E\u6389 / discard \u4F1A\u8BA9\u9759\u9ED8\u4E22\u5931\u590D\u6D3B\uFF09\u3002",
|
|
575
|
+
' * \u5E38\u9A7B\u663E\u793A\u800C\u975E tooltip\uFF1A\u8FD9\u51E0\u9879\u914D\u7F6E\u7684\u540E\u679C\u662F"\u9759\u9ED8\u5931\u8D25"\uFF0C\u85CF\u5728\u60AC\u6D6E\u63D0\u793A\u91CC\u7B49\u4E8E\u6CA1\u6709\u3002',
|
|
576
|
+
" */",
|
|
577
|
+
".ss-card-risk {",
|
|
578
|
+
" margin: 6px 0 0; padding: 6px 9px; border-radius: 6px;",
|
|
579
|
+
" font-size: 12px; line-height: 1.55;",
|
|
580
|
+
" color: var(--dsw-alias-state-warn-secondary);",
|
|
581
|
+
" background: color-mix(in srgb, var(--dsw-alias-state-warn-secondary) 12%, transparent);",
|
|
582
|
+
" border: 1px solid color-mix(in srgb, var(--dsw-alias-state-warn-secondary) 30%, transparent);",
|
|
583
|
+
"}",
|
|
424
584
|
".ss-card-footer {",
|
|
425
|
-
" border-top: 1px solid var(--dsw-alias-border-l2);",
|
|
426
585
|
" justify-content: flex-end; align-items: center; gap: 8px;",
|
|
427
|
-
" padding:
|
|
586
|
+
" padding-top: 16px; display: flex;",
|
|
428
587
|
"}",
|
|
429
588
|
".ss-card-failed {",
|
|
430
589
|
" min-width: 0; color: var(--dsw-alias-label-error); flex: 1; margin: 0;",
|
|
@@ -432,7 +591,7 @@ var COMPONENTS = [
|
|
|
432
591
|
"}",
|
|
433
592
|
".ss-card-discard, .ss-card-save {",
|
|
434
593
|
" appearance: none; font: inherit; cursor: pointer;",
|
|
435
|
-
" border: 1px solid transparent; border-radius:
|
|
594
|
+
" border: 1px solid transparent; border-radius: var(--dsw-radius-md);",
|
|
436
595
|
" padding: 5px 14px; font-size: 13px; line-height: 1.5;",
|
|
437
596
|
"}",
|
|
438
597
|
".ss-card-discard { border-color: var(--dsw-alias-border-l2); color: var(--dsw-alias-label-secondary); background: none; }",
|
|
@@ -441,7 +600,7 @@ var COMPONENTS = [
|
|
|
441
600
|
".ss-card-save:hover:not(:disabled) { background: var(--dsw-alias-button-primary-hover); }",
|
|
442
601
|
".ss-card-discard:disabled, .ss-card-save:disabled { opacity: 0.4; cursor: default; }",
|
|
443
602
|
".ss-card-discard:focus-visible, .ss-card-save:focus-visible {",
|
|
444
|
-
" outline:
|
|
603
|
+
" outline: var(--dsw-focus-ring-width) solid var(--dsw-focus-ring-color, var(--dsw-alias-state-business-primary)); outline-offset: 1px;",
|
|
445
604
|
"}"
|
|
446
605
|
].join("\n");
|
|
447
606
|
function injectStyles() {
|
|
@@ -561,6 +720,16 @@ var zh = {
|
|
|
561
720
|
steerAlreadySent: "\u5DF2\u63D2\u8BDD",
|
|
562
721
|
steerFailed: "\u63D2\u8BDD\u5931\u8D25\uFF1A{message}",
|
|
563
722
|
steerUnsupportedKind: "\u5468\u671F\u63D0\u9192\u6682\u4E0D\u652F\u6301\u63D2\u8BDD",
|
|
723
|
+
/** 投递未确认(宿主保留条目,可重试) */
|
|
724
|
+
steerUnconfirmed: "\u6295\u9012\u672A\u786E\u8BA4\uFF0C\u63D0\u9192\u5DF2\u4FDD\u7559\uFF0C\u53EF\u91CD\u8BD5",
|
|
725
|
+
steerRetry: "\u91CD\u8BD5",
|
|
726
|
+
/** 暂停 / 恢复(仅 after;原地冻结进度条) */
|
|
727
|
+
pauseTask: "\u6682\u505C\u63D0\u9192",
|
|
728
|
+
resumeTask: "\u6062\u590D\u63D0\u9192",
|
|
729
|
+
pausedLabel: "\u5DF2\u6682\u505C",
|
|
730
|
+
pauseFailed: "\u6682\u505C\u5931\u8D25\uFF1A{message}",
|
|
731
|
+
resumeFailed: "\u6062\u590D\u5931\u8D25\uFF1A{message}",
|
|
732
|
+
pauseUnsupportedKind: "\u4EC5\u652F\u6301\u6682\u505C\u300C\u518D\u7B49 N \u5206\u949F\u300D\u7C7B\u63D0\u9192",
|
|
564
733
|
/** dock 折叠头计数(QueueDock「N 条排队消息」样式) */
|
|
565
734
|
panelCount: "{n} \u6761\u5B9A\u65F6\u63D0\u9192",
|
|
566
735
|
/** 精准倒计时(dock 行 + 折叠头) */
|
|
@@ -587,6 +756,13 @@ var zh = {
|
|
|
587
756
|
presenceOverdueAria: "\u6709 {n} \u6761\u5B9A\u65F6\u63D0\u9192\u5DF2\u5230\u671F\uFF0C\u7B49\u5F85\u53D1\u9001",
|
|
588
757
|
presenceTooltip: "\u4E0B\u6B21 {time} \xB7 {n} \u6761\u4EFB\u52A1",
|
|
589
758
|
presenceOverdueTooltip: "\u5DF2\u5230\u671F \xB7 {n} \u6761\u4EFB\u52A1\uFF08\u7B49\u5F85\u4F1A\u8BDD\u7A7A\u95F2\u53D1\u9001\uFF09",
|
|
759
|
+
/** 全部任务都处于暂停:没有排定的触发时刻,故不显示"下次"或"已到期"。 */
|
|
760
|
+
presencePausedAria: "\u6709 {n} \u6761\u5B9A\u65F6\u63D0\u9192\u5DF2\u6682\u505C",
|
|
761
|
+
presencePausedTooltip: "\u5DF2\u6682\u505C \xB7 {n} \u6761\u4EFB\u52A1",
|
|
762
|
+
/** 悬浮卡片状态区追加行(与宿主 hoverStatus 同构,纯追加不改写既有状态) */
|
|
763
|
+
hoverScheduleStatus: "\u6709 {n} \u6761\u5B9A\u65F6\u63D0\u9192\uFF0C\u4E0B\u6B21 {time}",
|
|
764
|
+
hoverScheduleOverdue: "\u6709 {n} \u6761\u5B9A\u65F6\u63D0\u9192\u5DF2\u5230\u671F\uFF0C\u7B49\u5F85\u53D1\u9001",
|
|
765
|
+
hoverSchedulePaused: "\u6709 {n} \u6761\u5B9A\u65F6\u63D0\u9192\u5DF2\u6682\u505C",
|
|
590
766
|
relMinutes: "{m} \u5206\u540E",
|
|
591
767
|
relHours: "{h} \u5C0F\u65F6\u540E",
|
|
592
768
|
relTomorrow: "\u660E\u5929 {time}",
|
|
@@ -623,6 +799,15 @@ var en = {
|
|
|
623
799
|
steerAlreadySent: "Steered",
|
|
624
800
|
steerFailed: "Steer failed: {message}",
|
|
625
801
|
steerUnsupportedKind: "Recurring reminders can't be steered",
|
|
802
|
+
/** Delivery unconfirmed (host kept the item; retryable) */
|
|
803
|
+
steerUnconfirmed: "Delivery unconfirmed \u2014 reminder kept, you can retry",
|
|
804
|
+
steerRetry: "Retry",
|
|
805
|
+
pauseTask: "Pause reminder",
|
|
806
|
+
resumeTask: "Resume reminder",
|
|
807
|
+
pausedLabel: "Paused",
|
|
808
|
+
pauseFailed: "Pause failed: {message}",
|
|
809
|
+
resumeFailed: "Resume failed: {message}",
|
|
810
|
+
pauseUnsupportedKind: 'Only "wait N minutes" (after) reminders can be paused',
|
|
626
811
|
panelCount: "{n} scheduled reminders",
|
|
627
812
|
countdownLeft: "in",
|
|
628
813
|
dueAnyMoment: "Sending soon",
|
|
@@ -641,6 +826,11 @@ var en = {
|
|
|
641
826
|
presenceOverdueAria: "{n} scheduled reminder(s) due, waiting to send",
|
|
642
827
|
presenceTooltip: "Next at {time} \xB7 {n} task(s)",
|
|
643
828
|
presenceOverdueTooltip: "Due \xB7 {n} task(s) (sends when the session is idle)",
|
|
829
|
+
presencePausedAria: "{n} paused reminder(s)",
|
|
830
|
+
presencePausedTooltip: "Paused \xB7 {n} task(s)",
|
|
831
|
+
hoverScheduleStatus: "{n} scheduled reminder(s), next {time}",
|
|
832
|
+
hoverScheduleOverdue: "{n} scheduled reminder(s) due, waiting to send",
|
|
833
|
+
hoverSchedulePaused: "{n} paused reminder(s)",
|
|
644
834
|
relMinutes: "in {m} min",
|
|
645
835
|
relHours: "in {h} h",
|
|
646
836
|
relTomorrow: "Tomorrow {time}",
|
|
@@ -860,11 +1050,11 @@ var import_jsx_runtime = require("react/jsx-runtime");
|
|
|
860
1050
|
function scheduleStateOf(item, now) {
|
|
861
1051
|
return Date.parse(item.scheduled_at) <= now ? "overdue" : "scheduled";
|
|
862
1052
|
}
|
|
863
|
-
function TaskList({ items
|
|
864
|
-
if (
|
|
1053
|
+
function TaskList({ items, now, deliveredIds, cancellingIds, onDelete, timeZone, t, lang }) {
|
|
1054
|
+
if (items.length === 0) {
|
|
865
1055
|
return /* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", { className: "ss-empty", "data-ss-empty": "", children: t.emptyTasks });
|
|
866
1056
|
}
|
|
867
|
-
return /* @__PURE__ */ (0, import_jsx_runtime.jsx)("ul", { className: "ss-tasks", "data-ss-tasks": "", children:
|
|
1057
|
+
return /* @__PURE__ */ (0, import_jsx_runtime.jsx)("ul", { className: "ss-tasks", "data-ss-tasks": "", children: items.map((item) => {
|
|
868
1058
|
const dotState = deliveredIds?.has(item.id) ? "delivered" : cancellingIds?.has(item.id) ? "cancelled" : scheduleStateOf(item, now);
|
|
869
1059
|
const isCancelled = dotState === "cancelled";
|
|
870
1060
|
return /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("li", { className: isCancelled ? "ss-task cancelled" : "ss-task", "data-ss-task": item.id, children: [
|
|
@@ -1237,12 +1427,12 @@ function useSchedules(inject2) {
|
|
|
1237
1427
|
if (pendingSync.length === 0 || !sessionId) return;
|
|
1238
1428
|
let cancelled = false;
|
|
1239
1429
|
const syncAll = async () => {
|
|
1240
|
-
const
|
|
1241
|
-
for (const item of
|
|
1430
|
+
const items = [...pendingSync];
|
|
1431
|
+
for (const item of items) {
|
|
1242
1432
|
if (cancelled) return;
|
|
1243
1433
|
try {
|
|
1244
1434
|
const accepted = await callCommand(sessionId, createLine(item.payload));
|
|
1245
|
-
if (accepted && !cancelled) {
|
|
1435
|
+
if (accepted.matched && !cancelled) {
|
|
1246
1436
|
removePending(item.clientSeq);
|
|
1247
1437
|
setPendingSync((prev) => prev.filter((p) => p.clientSeq !== item.clientSeq));
|
|
1248
1438
|
}
|
|
@@ -1268,7 +1458,7 @@ function useSchedules(inject2) {
|
|
|
1268
1458
|
setBusy(true);
|
|
1269
1459
|
try {
|
|
1270
1460
|
const accepted = await callCommand(sessionId, createLine(inputPayload));
|
|
1271
|
-
if (!accepted) {
|
|
1461
|
+
if (!accepted.matched) {
|
|
1272
1462
|
appendPending(inputPayload);
|
|
1273
1463
|
setPendingSync((prev) => [...prev, { clientSeq: Date.now(), createdAt: Date.now(), payload: inputPayload }]);
|
|
1274
1464
|
throw new Error(CLIENT_ERR.NOT_ACCEPTED);
|
|
@@ -1457,65 +1647,79 @@ function SchedButton(props) {
|
|
|
1457
1647
|
}
|
|
1458
1648
|
|
|
1459
1649
|
// src/client/components/ScheduleDock.tsx
|
|
1460
|
-
var import_react8 = require("react");
|
|
1461
|
-
|
|
1462
|
-
// src/client/toast.tsx
|
|
1463
|
-
var import_client = require("react-dom/client");
|
|
1464
1650
|
var import_react7 = require("react");
|
|
1465
|
-
|
|
1466
|
-
|
|
1467
|
-
var
|
|
1468
|
-
|
|
1469
|
-
|
|
1470
|
-
|
|
1471
|
-
|
|
1472
|
-
|
|
1473
|
-
|
|
1474
|
-
|
|
1475
|
-
|
|
1476
|
-
|
|
1477
|
-
|
|
1478
|
-
|
|
1479
|
-
|
|
1480
|
-
}
|
|
1481
|
-
|
|
1482
|
-
|
|
1483
|
-
|
|
1484
|
-
|
|
1485
|
-
|
|
1486
|
-
|
|
1487
|
-
|
|
1488
|
-
|
|
1489
|
-
|
|
1490
|
-
|
|
1491
|
-
|
|
1492
|
-
}
|
|
1493
|
-
|
|
1494
|
-
|
|
1495
|
-
|
|
1496
|
-
|
|
1497
|
-
|
|
1498
|
-
|
|
1499
|
-
|
|
1500
|
-
|
|
1501
|
-
|
|
1502
|
-
function
|
|
1503
|
-
|
|
1504
|
-
|
|
1505
|
-
|
|
1506
|
-
|
|
1507
|
-
|
|
1508
|
-
|
|
1509
|
-
|
|
1510
|
-
|
|
1511
|
-
|
|
1512
|
-
|
|
1513
|
-
|
|
1651
|
+
|
|
1652
|
+
// src/bar-geometry.ts
|
|
1653
|
+
var BAR_UNIT_MS = 36e5;
|
|
1654
|
+
function barWindow(item, end, now, firstSeen) {
|
|
1655
|
+
let start;
|
|
1656
|
+
if (item.kind === "after") {
|
|
1657
|
+
const windowSec = item.window_seconds ?? item.after_seconds;
|
|
1658
|
+
if (windowSec !== void 0) {
|
|
1659
|
+
start = end - windowSec * 1e3;
|
|
1660
|
+
} else if (item.created_at !== void 0) {
|
|
1661
|
+
const parsed = Date.parse(item.created_at);
|
|
1662
|
+
start = Number.isNaN(parsed) ? firstSeen.get(item.id) ?? now : parsed;
|
|
1663
|
+
} else {
|
|
1664
|
+
start = firstSeen.get(item.id) ?? now;
|
|
1665
|
+
}
|
|
1666
|
+
} else if (item.kind === "every" && item.every_seconds !== void 0) {
|
|
1667
|
+
start = end - item.every_seconds * 1e3;
|
|
1668
|
+
} else if (item.created_at !== void 0) {
|
|
1669
|
+
const parsed = Date.parse(item.created_at);
|
|
1670
|
+
start = Number.isNaN(parsed) ? firstSeen.get(item.id) ?? now : parsed;
|
|
1671
|
+
} else {
|
|
1672
|
+
start = firstSeen.get(item.id) ?? now;
|
|
1673
|
+
}
|
|
1674
|
+
return { start, totalMs: Math.max(1e3, end - start) };
|
|
1675
|
+
}
|
|
1676
|
+
function ratioAt(item, at, firstSeen) {
|
|
1677
|
+
const end = Date.parse(item.scheduled_at);
|
|
1678
|
+
const { start, totalMs } = barWindow(item, end, at, firstSeen);
|
|
1679
|
+
const elapsedMs = Math.min(Math.max(at - start, 0), totalMs);
|
|
1680
|
+
return {
|
|
1681
|
+
totalRatio: elapsedMs / totalMs,
|
|
1682
|
+
count: Math.max(1, Math.ceil(totalMs / BAR_UNIT_MS))
|
|
1683
|
+
};
|
|
1684
|
+
}
|
|
1685
|
+
function barSegments(item, now, firstSeen) {
|
|
1686
|
+
return ratioAt(item, now, firstSeen);
|
|
1687
|
+
}
|
|
1688
|
+
function frozenBarSegments(item, frozenLeftMs, firstSeen, renderedAt) {
|
|
1689
|
+
const windowSec = item.window_seconds ?? item.after_seconds;
|
|
1690
|
+
if (windowSec === void 0 || windowSec <= 0) {
|
|
1691
|
+
const end = Date.parse(item.scheduled_at);
|
|
1692
|
+
const pausedAt2 = Date.parse(item.paused_at ?? "");
|
|
1693
|
+
const exact = Number.isNaN(pausedAt2) ? end - Math.floor(frozenLeftMs / 1e3) * 1e3 : pausedAt2;
|
|
1694
|
+
return ratioAt(item, Number.isNaN(exact) ? end : exact, firstSeen);
|
|
1695
|
+
}
|
|
1696
|
+
const totalMs = Math.max(1e3, windowSec * 1e3);
|
|
1697
|
+
let leftMs = Math.min(Math.max(frozenLeftMs, 0), totalMs);
|
|
1698
|
+
const pausedAt = Date.parse(item.paused_at ?? "");
|
|
1699
|
+
if (renderedAt !== void 0 && !Number.isNaN(pausedAt) && pausedAt > renderedAt) {
|
|
1700
|
+
leftMs = Math.min(leftMs + (pausedAt - renderedAt), totalMs);
|
|
1701
|
+
}
|
|
1702
|
+
const elapsedMs = Math.min(Math.max(totalMs - leftMs, 0), totalMs);
|
|
1703
|
+
return {
|
|
1704
|
+
totalRatio: elapsedMs / totalMs,
|
|
1705
|
+
count: Math.max(1, Math.ceil(totalMs / BAR_UNIT_MS))
|
|
1706
|
+
};
|
|
1707
|
+
}
|
|
1708
|
+
function planBarAnimation(totalMs, elapsedMs) {
|
|
1709
|
+
if (!Number.isFinite(totalMs) || totalMs <= 0) return void 0;
|
|
1710
|
+
const raw = Number.isFinite(elapsedMs) ? elapsedMs : 0;
|
|
1711
|
+
const clamped = Math.min(Math.max(raw, 0), totalMs);
|
|
1712
|
+
const elapsed = clamped === 0 ? 0 : clamped;
|
|
1713
|
+
if (elapsed >= totalMs) return void 0;
|
|
1714
|
+
return {
|
|
1715
|
+
durationMs: totalMs,
|
|
1716
|
+
// -0 会在 CSS 里序列化成难看的 "-0ms",故显式归零
|
|
1717
|
+
delayMs: elapsed === 0 ? 0 : -elapsed
|
|
1514
1718
|
};
|
|
1515
1719
|
}
|
|
1516
1720
|
|
|
1517
1721
|
// src/client/components/ScheduleDock.tsx
|
|
1518
|
-
var
|
|
1722
|
+
var import_jsx_runtime4 = require("react/jsx-runtime");
|
|
1519
1723
|
function formatCountdown(ms) {
|
|
1520
1724
|
const total = Math.max(0, Math.round(ms / 1e3));
|
|
1521
1725
|
const h = Math.floor(total / 3600);
|
|
@@ -1525,53 +1729,151 @@ function formatCountdown(ms) {
|
|
|
1525
1729
|
const ss = String(s).padStart(2, "0");
|
|
1526
1730
|
return h > 0 ? `${h}:${mm}:${ss}` : `${mm}:${ss}`;
|
|
1527
1731
|
}
|
|
1528
|
-
|
|
1529
|
-
|
|
1530
|
-
|
|
1531
|
-
|
|
1532
|
-
|
|
1533
|
-
start = end - item.after_seconds * 1e3;
|
|
1534
|
-
} else if (item.kind === "every" && item.every_seconds !== void 0) {
|
|
1535
|
-
start = end - item.every_seconds * 1e3;
|
|
1536
|
-
} else if (item.created_at !== void 0) {
|
|
1537
|
-
const parsed = Date.parse(item.created_at);
|
|
1538
|
-
start = Number.isNaN(parsed) ? firstSeen.get(item.id) ?? now : parsed;
|
|
1539
|
-
} else {
|
|
1540
|
-
start = firstSeen.get(item.id) ?? now;
|
|
1732
|
+
function prefersReducedMotion() {
|
|
1733
|
+
try {
|
|
1734
|
+
return globalThis.matchMedia?.("(prefers-reduced-motion: reduce)").matches === true;
|
|
1735
|
+
} catch {
|
|
1736
|
+
return false;
|
|
1541
1737
|
}
|
|
1542
|
-
|
|
1543
|
-
|
|
1544
|
-
const
|
|
1545
|
-
|
|
1546
|
-
|
|
1738
|
+
}
|
|
1739
|
+
function planBarAnimationFor(item, now, firstSeen) {
|
|
1740
|
+
const end = Date.parse(item.scheduled_at);
|
|
1741
|
+
if (!Number.isFinite(end)) return void 0;
|
|
1742
|
+
const { start, totalMs } = barWindow(item, end, now, firstSeen);
|
|
1743
|
+
return planBarAnimation(totalMs, now - start);
|
|
1547
1744
|
}
|
|
1548
1745
|
var deleteLine2 = (id) => `/user-schedule-delete ${JSON.stringify({ id })}`;
|
|
1549
1746
|
var editLine = (id, prompt) => `/user-schedule-edit ${JSON.stringify({ id, prompt })}`;
|
|
1550
1747
|
var steerLine = (id) => `/user-schedule-steer-now ${JSON.stringify({ id })}`;
|
|
1748
|
+
var STEER_CONFIRM_WINDOW_MS = 2600;
|
|
1749
|
+
var pauseLine = (id) => `/user-schedule-pause ${JSON.stringify({ id })}`;
|
|
1750
|
+
var resumeLine = (uid) => `/user-schedule-resume ${JSON.stringify({ uid })}`;
|
|
1751
|
+
function canPause(item, now) {
|
|
1752
|
+
if (item.status === "paused") return false;
|
|
1753
|
+
if (item.kind !== "after") return false;
|
|
1754
|
+
const epoch = Date.parse(item.scheduled_at);
|
|
1755
|
+
return Number.isFinite(epoch) && epoch > now;
|
|
1756
|
+
}
|
|
1551
1757
|
function ScheduleDock({ callCommand, sessionId, useProjection, locale }) {
|
|
1552
1758
|
const now = useNow(1e3);
|
|
1553
1759
|
const { t } = useSchedT(locale);
|
|
1554
1760
|
const projection = typeof useProjection === "function" ? useProjection("userSchedules") : void 0;
|
|
1555
|
-
const
|
|
1556
|
-
|
|
1761
|
+
const [dismissedPaused, setDismissedPaused] = (0, import_react7.useState)(/* @__PURE__ */ new Set());
|
|
1762
|
+
(0, import_react7.useEffect)(() => {
|
|
1763
|
+
const live = projection?.schedules;
|
|
1764
|
+
if (live === void 0) return;
|
|
1765
|
+
setDismissedPaused((current) => {
|
|
1766
|
+
if (current.size === 0) return current;
|
|
1767
|
+
let changed = false;
|
|
1768
|
+
const nextSet = new Set(current);
|
|
1769
|
+
for (const item of live) {
|
|
1770
|
+
if (item.status !== "paused" && nextSet.delete(item.id)) changed = true;
|
|
1771
|
+
}
|
|
1772
|
+
return changed ? nextSet : current;
|
|
1773
|
+
});
|
|
1774
|
+
}, [projection]);
|
|
1775
|
+
const [promptOverrides, setPromptOverrides] = (0, import_react7.useState)(/* @__PURE__ */ new Map());
|
|
1776
|
+
(0, import_react7.useEffect)(() => {
|
|
1777
|
+
const live = projection?.schedules;
|
|
1778
|
+
if (live === void 0 || promptOverrides.size === 0) return;
|
|
1779
|
+
setPromptOverrides((current) => {
|
|
1780
|
+
if (current.size === 0) return current;
|
|
1781
|
+
let changed = false;
|
|
1782
|
+
const nextMap = new Map(current);
|
|
1783
|
+
for (const [id, text] of current) {
|
|
1784
|
+
const item = live.find((s) => s.id === id);
|
|
1785
|
+
if (item === void 0 || item.prompt === text) {
|
|
1786
|
+
nextMap.delete(id);
|
|
1787
|
+
changed = true;
|
|
1788
|
+
}
|
|
1789
|
+
}
|
|
1790
|
+
return changed ? nextMap : current;
|
|
1791
|
+
});
|
|
1792
|
+
}, [projection, promptOverrides]);
|
|
1793
|
+
const schedules = (0, import_react7.useMemo)(
|
|
1794
|
+
() => (projection?.schedules ?? []).filter((item) => !(item.status === "paused" && dismissedPaused.has(item.id))).map((item) => {
|
|
1795
|
+
const override = promptOverrides.get(item.id);
|
|
1796
|
+
return override === void 0 ? item : { ...item, prompt: override };
|
|
1797
|
+
}).sort(
|
|
1557
1798
|
(a, b) => Date.parse(a.scheduled_at) - Date.parse(b.scheduled_at)
|
|
1558
1799
|
),
|
|
1559
|
-
[projection]
|
|
1800
|
+
[projection, dismissedPaused, promptOverrides]
|
|
1560
1801
|
);
|
|
1561
|
-
const [collapsed, setCollapsed] = (0,
|
|
1562
|
-
const [cancelling, setCancelling] = (0,
|
|
1563
|
-
const [editingId, setEditingId] = (0,
|
|
1564
|
-
const [editingText, setEditingText] = (0,
|
|
1565
|
-
const [editErr, setEditErr] = (0,
|
|
1566
|
-
const [saving, setSaving] = (0,
|
|
1567
|
-
const [steering, setSteering] = (0,
|
|
1568
|
-
const [steerDone, setSteerDone] = (0,
|
|
1569
|
-
const [steerErr, setSteerErr] = (0,
|
|
1570
|
-
const
|
|
1571
|
-
|
|
1572
|
-
|
|
1573
|
-
|
|
1574
|
-
|
|
1802
|
+
const [collapsed, setCollapsed] = (0, import_react7.useState)(true);
|
|
1803
|
+
const [cancelling, setCancelling] = (0, import_react7.useState)(/* @__PURE__ */ new Set());
|
|
1804
|
+
const [editingId, setEditingId] = (0, import_react7.useState)(null);
|
|
1805
|
+
const [editingText, setEditingText] = (0, import_react7.useState)("");
|
|
1806
|
+
const [editErr, setEditErr] = (0, import_react7.useState)(null);
|
|
1807
|
+
const [saving, setSaving] = (0, import_react7.useState)(false);
|
|
1808
|
+
const [steering, setSteering] = (0, import_react7.useState)(/* @__PURE__ */ new Set());
|
|
1809
|
+
const [steerDone, setSteerDone] = (0, import_react7.useState)(/* @__PURE__ */ new Set());
|
|
1810
|
+
const [steerErr, setSteerErr] = (0, import_react7.useState)(/* @__PURE__ */ new Map());
|
|
1811
|
+
const [steerUnconfirmed, setSteerUnconfirmed] = (0, import_react7.useState)(/* @__PURE__ */ new Set());
|
|
1812
|
+
(0, import_react7.useEffect)(() => {
|
|
1813
|
+
const live = projection?.schedules;
|
|
1814
|
+
if (live === void 0) return;
|
|
1815
|
+
const present = new Set(live.filter((item) => item.status !== "paused").map((item) => item.id));
|
|
1816
|
+
setSteerDone((current) => {
|
|
1817
|
+
if (current.size === 0) return current;
|
|
1818
|
+
let changed = false;
|
|
1819
|
+
const next2 = new Set(current);
|
|
1820
|
+
for (const id of current) {
|
|
1821
|
+
if (!present.has(id)) {
|
|
1822
|
+
next2.delete(id);
|
|
1823
|
+
changed = true;
|
|
1824
|
+
}
|
|
1825
|
+
}
|
|
1826
|
+
return changed ? next2 : current;
|
|
1827
|
+
});
|
|
1828
|
+
}, [projection]);
|
|
1829
|
+
(0, import_react7.useEffect)(() => {
|
|
1830
|
+
if (steerDone.size === 0) return void 0;
|
|
1831
|
+
const timer = window.setTimeout(() => {
|
|
1832
|
+
const live = projection?.schedules;
|
|
1833
|
+
if (live === void 0) return;
|
|
1834
|
+
const present = new Set(live.filter((item) => item.status !== "paused").map((item) => item.id));
|
|
1835
|
+
setSteerUnconfirmed((current) => {
|
|
1836
|
+
let changed = false;
|
|
1837
|
+
const next2 = new Set(current);
|
|
1838
|
+
for (const id of steerDone) {
|
|
1839
|
+
if (present.has(id) && !next2.has(id)) {
|
|
1840
|
+
next2.add(id);
|
|
1841
|
+
changed = true;
|
|
1842
|
+
}
|
|
1843
|
+
if (!present.has(id) && next2.delete(id)) changed = true;
|
|
1844
|
+
}
|
|
1845
|
+
return changed ? next2 : current;
|
|
1846
|
+
});
|
|
1847
|
+
}, STEER_CONFIRM_WINDOW_MS);
|
|
1848
|
+
return () => window.clearTimeout(timer);
|
|
1849
|
+
}, [steerDone, projection]);
|
|
1850
|
+
const [pausing, setPausing] = (0, import_react7.useState)(/* @__PURE__ */ new Set());
|
|
1851
|
+
const [resuming, setResuming] = (0, import_react7.useState)(/* @__PURE__ */ new Set());
|
|
1852
|
+
const [pauseErr, setPauseErr] = (0, import_react7.useState)(/* @__PURE__ */ new Map());
|
|
1853
|
+
const firstSeenRef = (0, import_react7.useRef)(/* @__PURE__ */ new Map());
|
|
1854
|
+
const lastActiveAtRef = (0, import_react7.useRef)(/* @__PURE__ */ new Map());
|
|
1855
|
+
const wallClock = Date.now();
|
|
1856
|
+
{
|
|
1857
|
+
const next2 = new Map(lastActiveAtRef.current);
|
|
1858
|
+
let changed = false;
|
|
1859
|
+
for (const item of schedules) {
|
|
1860
|
+
if (item.status === "paused") continue;
|
|
1861
|
+
const prev = next2.get(item.id);
|
|
1862
|
+
if (prev === void 0 || wallClock > prev) {
|
|
1863
|
+
next2.set(item.id, wallClock);
|
|
1864
|
+
changed = true;
|
|
1865
|
+
}
|
|
1866
|
+
}
|
|
1867
|
+
for (const id of [...next2.keys()]) {
|
|
1868
|
+
if (!schedules.some((item) => item.id === id)) {
|
|
1869
|
+
next2.delete(id);
|
|
1870
|
+
changed = true;
|
|
1871
|
+
}
|
|
1872
|
+
}
|
|
1873
|
+
if (changed) lastActiveAtRef.current = next2;
|
|
1874
|
+
}
|
|
1875
|
+
const byId = (0, import_react7.useMemo)(() => new Map(schedules.map((item) => [item.id, item])), [schedules]);
|
|
1876
|
+
(0, import_react7.useEffect)(() => {
|
|
1575
1877
|
let changed = false;
|
|
1576
1878
|
const next2 = new Map(firstSeenRef.current);
|
|
1577
1879
|
for (const [id] of byId) {
|
|
@@ -1587,32 +1889,30 @@ function ScheduleDock({ callCommand, sessionId, useProjection, locale }) {
|
|
|
1587
1889
|
}
|
|
1588
1890
|
}
|
|
1589
1891
|
if (changed) firstSeenRef.current = next2;
|
|
1590
|
-
const prev = prevRef.current;
|
|
1591
|
-
if (prev.size > 0) {
|
|
1592
|
-
for (const [id, prevItem] of prev) {
|
|
1593
|
-
if (byId.has(id)) continue;
|
|
1594
|
-
if (suppressedRef.current.has(id)) continue;
|
|
1595
|
-
if (Date.parse(prevItem.scheduled_at) <= Date.now()) {
|
|
1596
|
-
showReminderToast(prevItem.prompt);
|
|
1597
|
-
}
|
|
1598
|
-
}
|
|
1599
|
-
}
|
|
1600
|
-
prevRef.current = byId;
|
|
1601
1892
|
}, [byId]);
|
|
1602
|
-
|
|
1603
|
-
suppressedRef.current = new Set(suppressedRef.current).add(id);
|
|
1604
|
-
};
|
|
1605
|
-
(0, import_react8.useEffect)(() => {
|
|
1893
|
+
(0, import_react7.useEffect)(() => {
|
|
1606
1894
|
if (schedules.length <= 1) setCollapsed(true);
|
|
1607
1895
|
}, [schedules.length]);
|
|
1608
1896
|
if (schedules.length === 0 || sessionId === void 0) return null;
|
|
1609
1897
|
const next = schedules[0];
|
|
1610
1898
|
if (next === void 0) return null;
|
|
1611
1899
|
const expanded = schedules.length === 1 || !collapsed;
|
|
1612
|
-
const handleCancel = (id) => {
|
|
1613
|
-
suppress(id);
|
|
1900
|
+
const handleCancel = (id, status) => {
|
|
1614
1901
|
setCancelling((current) => new Set(current).add(id));
|
|
1615
|
-
|
|
1902
|
+
const restore = () => {
|
|
1903
|
+
setDismissedPaused((current) => {
|
|
1904
|
+
if (!current.has(id)) return current;
|
|
1905
|
+
const nextSet = new Set(current);
|
|
1906
|
+
nextSet.delete(id);
|
|
1907
|
+
return nextSet;
|
|
1908
|
+
});
|
|
1909
|
+
};
|
|
1910
|
+
if (status === "paused") {
|
|
1911
|
+
setDismissedPaused((current) => new Set(current).add(id));
|
|
1912
|
+
}
|
|
1913
|
+
void callCommand(sessionId, deleteLine2(id)).then((outcome) => {
|
|
1914
|
+
if (!outcome.matched) restore();
|
|
1915
|
+
}).catch(restore).finally(() => {
|
|
1616
1916
|
window.setTimeout(() => {
|
|
1617
1917
|
setCancelling((current) => {
|
|
1618
1918
|
const nextSet = new Set(current);
|
|
@@ -1624,16 +1924,19 @@ function ScheduleDock({ callCommand, sessionId, useProjection, locale }) {
|
|
|
1624
1924
|
};
|
|
1625
1925
|
const handleSteer = (item) => {
|
|
1626
1926
|
const id = item.id;
|
|
1627
|
-
|
|
1927
|
+
const wasPaused = item.status === "paused";
|
|
1628
1928
|
setSteering((current) => new Set(current).add(id));
|
|
1629
1929
|
setSteerErr((current) => {
|
|
1630
1930
|
const next2 = new Map(current);
|
|
1631
1931
|
next2.delete(id);
|
|
1632
1932
|
return next2;
|
|
1633
1933
|
});
|
|
1634
|
-
void callCommand(sessionId, steerLine(id)).then((
|
|
1635
|
-
if (
|
|
1934
|
+
void callCommand(sessionId, steerLine(id)).then((outcome) => {
|
|
1935
|
+
if (outcome.matched) {
|
|
1636
1936
|
setSteerDone((current) => new Set(current).add(id));
|
|
1937
|
+
if (wasPaused) {
|
|
1938
|
+
setDismissedPaused((current) => new Set(current).add(id));
|
|
1939
|
+
}
|
|
1637
1940
|
} else {
|
|
1638
1941
|
setSteerErr((current) => new Map(current).set(id, t.editErrNotAccepted));
|
|
1639
1942
|
}
|
|
@@ -1647,6 +1950,67 @@ function ScheduleDock({ callCommand, sessionId, useProjection, locale }) {
|
|
|
1647
1950
|
});
|
|
1648
1951
|
});
|
|
1649
1952
|
};
|
|
1953
|
+
const handleSteerRetry = (item) => {
|
|
1954
|
+
const id = item.id;
|
|
1955
|
+
setSteerUnconfirmed((current) => {
|
|
1956
|
+
if (!current.has(id)) return current;
|
|
1957
|
+
const next2 = new Set(current);
|
|
1958
|
+
next2.delete(id);
|
|
1959
|
+
return next2;
|
|
1960
|
+
});
|
|
1961
|
+
setSteerDone((current) => {
|
|
1962
|
+
if (!current.has(id)) return current;
|
|
1963
|
+
const next2 = new Set(current);
|
|
1964
|
+
next2.delete(id);
|
|
1965
|
+
return next2;
|
|
1966
|
+
});
|
|
1967
|
+
handleSteer(item);
|
|
1968
|
+
};
|
|
1969
|
+
const handlePause = (item) => {
|
|
1970
|
+
const id = item.id;
|
|
1971
|
+
if (!canPause(item, now)) return;
|
|
1972
|
+
setPausing((current) => new Set(current).add(id));
|
|
1973
|
+
setPauseErr((current) => {
|
|
1974
|
+
const next2 = new Map(current);
|
|
1975
|
+
next2.delete(id);
|
|
1976
|
+
return next2;
|
|
1977
|
+
});
|
|
1978
|
+
void callCommand(sessionId, pauseLine(id)).then((outcome) => {
|
|
1979
|
+
if (!outcome.matched) {
|
|
1980
|
+
setPauseErr((current) => new Map(current).set(id, t.editErrNotAccepted));
|
|
1981
|
+
}
|
|
1982
|
+
}).catch(() => {
|
|
1983
|
+
setPauseErr((current) => new Map(current).set(id, t.editErrCommandFailed));
|
|
1984
|
+
}).finally(() => {
|
|
1985
|
+
setPausing((current) => {
|
|
1986
|
+
const next2 = new Set(current);
|
|
1987
|
+
next2.delete(id);
|
|
1988
|
+
return next2;
|
|
1989
|
+
});
|
|
1990
|
+
});
|
|
1991
|
+
};
|
|
1992
|
+
const handleResume = (item) => {
|
|
1993
|
+
const uid = item.id;
|
|
1994
|
+
setResuming((current) => new Set(current).add(uid));
|
|
1995
|
+
setPauseErr((current) => {
|
|
1996
|
+
const next2 = new Map(current);
|
|
1997
|
+
next2.delete(uid);
|
|
1998
|
+
return next2;
|
|
1999
|
+
});
|
|
2000
|
+
void callCommand(sessionId, resumeLine(uid)).then((outcome) => {
|
|
2001
|
+
if (!outcome.matched) {
|
|
2002
|
+
setPauseErr((current) => new Map(current).set(uid, t.editErrNotAccepted));
|
|
2003
|
+
}
|
|
2004
|
+
}).catch(() => {
|
|
2005
|
+
setPauseErr((current) => new Map(current).set(uid, t.editErrCommandFailed));
|
|
2006
|
+
}).finally(() => {
|
|
2007
|
+
setResuming((current) => {
|
|
2008
|
+
const next2 = new Set(current);
|
|
2009
|
+
next2.delete(uid);
|
|
2010
|
+
return next2;
|
|
2011
|
+
});
|
|
2012
|
+
});
|
|
2013
|
+
};
|
|
1650
2014
|
const startEdit = (item) => {
|
|
1651
2015
|
setEditingId(item.id);
|
|
1652
2016
|
setEditingText(item.prompt);
|
|
@@ -1663,12 +2027,15 @@ function ScheduleDock({ callCommand, sessionId, useProjection, locale }) {
|
|
|
1663
2027
|
setEditErr(t.editErrEmpty);
|
|
1664
2028
|
return;
|
|
1665
2029
|
}
|
|
1666
|
-
suppress(id);
|
|
1667
2030
|
setSaving(true);
|
|
1668
2031
|
setEditErr(null);
|
|
1669
|
-
void callCommand(sessionId, editLine(id, trimmed)).then((
|
|
1670
|
-
if (!
|
|
1671
|
-
|
|
2032
|
+
void callCommand(sessionId, editLine(id, trimmed)).then((outcome) => {
|
|
2033
|
+
if (!outcome.matched) {
|
|
2034
|
+
setEditErr(format(t.editErrFailed, { message: t.editErrNotAccepted }));
|
|
2035
|
+
return;
|
|
2036
|
+
}
|
|
2037
|
+
setPromptOverrides((current) => new Map(current).set(id, trimmed));
|
|
2038
|
+
cancelEdit();
|
|
1672
2039
|
}).catch(() => {
|
|
1673
2040
|
setEditErr(format(t.editErrFailed, { message: t.editErrCommandFailed }));
|
|
1674
2041
|
}).finally(() => setSaving(false));
|
|
@@ -1677,8 +2044,8 @@ function ScheduleDock({ callCommand, sessionId, useProjection, locale }) {
|
|
|
1677
2044
|
const epoch = Date.parse(item.scheduled_at);
|
|
1678
2045
|
const state = epoch <= now ? "overdue" : "scheduled";
|
|
1679
2046
|
if (editingId === item.id) {
|
|
1680
|
-
return /* @__PURE__ */ (0,
|
|
1681
|
-
/* @__PURE__ */ (0,
|
|
2047
|
+
return /* @__PURE__ */ (0, import_jsx_runtime4.jsxs)("li", { className: "ss-dock-row ss-editing", "data-ss-dock-row": item.id, children: [
|
|
2048
|
+
/* @__PURE__ */ (0, import_jsx_runtime4.jsx)(
|
|
1682
2049
|
"input",
|
|
1683
2050
|
{
|
|
1684
2051
|
className: "ss-dock-edit-input",
|
|
@@ -1695,7 +2062,7 @@ function ScheduleDock({ callCommand, sessionId, useProjection, locale }) {
|
|
|
1695
2062
|
"aria-label": `${t.editTask}: ${item.prompt}`
|
|
1696
2063
|
}
|
|
1697
2064
|
),
|
|
1698
|
-
/* @__PURE__ */ (0,
|
|
2065
|
+
/* @__PURE__ */ (0, import_jsx_runtime4.jsx)(
|
|
1699
2066
|
"button",
|
|
1700
2067
|
{
|
|
1701
2068
|
type: "button",
|
|
@@ -1705,60 +2072,98 @@ function ScheduleDock({ callCommand, sessionId, useProjection, locale }) {
|
|
|
1705
2072
|
children: saving ? "\u2026" : t.editSave
|
|
1706
2073
|
}
|
|
1707
2074
|
),
|
|
1708
|
-
/* @__PURE__ */ (0,
|
|
1709
|
-
editErr !== null && /* @__PURE__ */ (0,
|
|
2075
|
+
/* @__PURE__ */ (0, import_jsx_runtime4.jsx)("button", { type: "button", className: "ss-dock-action", onClick: cancelEdit, "aria-label": t.editCancel, children: "\u2715" }),
|
|
2076
|
+
editErr !== null && /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("span", { className: "ss-dock-edit-err", children: editErr })
|
|
1710
2077
|
] }, item.id);
|
|
1711
2078
|
}
|
|
1712
|
-
|
|
1713
|
-
|
|
1714
|
-
|
|
1715
|
-
|
|
1716
|
-
|
|
1717
|
-
|
|
1718
|
-
|
|
1719
|
-
|
|
1720
|
-
|
|
1721
|
-
|
|
1722
|
-
|
|
1723
|
-
|
|
1724
|
-
|
|
1725
|
-
|
|
1726
|
-
|
|
1727
|
-
|
|
1728
|
-
|
|
1729
|
-
"
|
|
1730
|
-
|
|
1731
|
-
|
|
1732
|
-
|
|
1733
|
-
|
|
1734
|
-
|
|
1735
|
-
|
|
1736
|
-
|
|
1737
|
-
|
|
1738
|
-
|
|
1739
|
-
|
|
1740
|
-
|
|
1741
|
-
|
|
1742
|
-
|
|
1743
|
-
|
|
1744
|
-
|
|
1745
|
-
|
|
1746
|
-
|
|
1747
|
-
|
|
1748
|
-
|
|
1749
|
-
|
|
1750
|
-
|
|
1751
|
-
|
|
1752
|
-
|
|
1753
|
-
|
|
1754
|
-
|
|
1755
|
-
|
|
1756
|
-
|
|
1757
|
-
|
|
1758
|
-
|
|
2079
|
+
const isPaused = item.status === "paused";
|
|
2080
|
+
const frozenLeft = isPaused ? (item.remaining_seconds ?? 0) * 1e3 : epoch - now;
|
|
2081
|
+
const countdownText = isPaused ? t.pausedLabel : state === "overdue" ? t.dueAnyMoment : `${t.countdownLeft} ${formatCountdown(Math.max(0, frozenLeft))}`;
|
|
2082
|
+
return /* @__PURE__ */ (0, import_jsx_runtime4.jsxs)(
|
|
2083
|
+
"li",
|
|
2084
|
+
{
|
|
2085
|
+
className: `ss-dock-row${isPaused ? " ss-paused" : ""}`,
|
|
2086
|
+
"data-ss-dock-row": item.id,
|
|
2087
|
+
children: [
|
|
2088
|
+
/* @__PURE__ */ (0, import_jsx_runtime4.jsxs)("div", { className: "ss-dock-preview", children: [
|
|
2089
|
+
/* @__PURE__ */ (0, import_jsx_runtime4.jsxs)("div", { className: "ss-dock-row-line", children: [
|
|
2090
|
+
/* @__PURE__ */ (0, import_jsx_runtime4.jsx)("span", { className: "ss-dock-row-time", children: formatHhmm(epoch, detectTimeZone()) }),
|
|
2091
|
+
/* @__PURE__ */ (0, import_jsx_runtime4.jsx)("span", { className: `ss-dock-row-countdown${!isPaused && state === "overdue" ? " ss-due" : ""}${isPaused ? " ss-paused-label" : ""}`, children: countdownText }),
|
|
2092
|
+
/* @__PURE__ */ (0, import_jsx_runtime4.jsx)("span", { className: "ss-dock-row-prompt", title: item.prompt, children: item.prompt })
|
|
2093
|
+
] }),
|
|
2094
|
+
/* @__PURE__ */ (0, import_jsx_runtime4.jsx)(MultiBar, { item, now: wallClock, firstSeen: firstSeenRef.current, t, frozen: isPaused, frozenLeftMs: frozenLeft, renderedAt: lastActiveAtRef.current.get(item.id) ?? wallClock }),
|
|
2095
|
+
(steerErr.get(item.id) ?? pauseErr.get(item.id)) !== void 0 && /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("span", { className: "ss-dock-steer-err", children: steerErr.get(item.id) ?? pauseErr.get(item.id) }),
|
|
2096
|
+
steerUnconfirmed.has(item.id) && /* @__PURE__ */ (0, import_jsx_runtime4.jsxs)("span", { className: "ss-dock-steer-warn", role: "status", children: [
|
|
2097
|
+
/* @__PURE__ */ (0, import_jsx_runtime4.jsx)("span", { children: t.steerUnconfirmed }),
|
|
2098
|
+
/* @__PURE__ */ (0, import_jsx_runtime4.jsx)("button", { type: "button", className: "ss-dock-steer-retry", onClick: () => handleSteerRetry(item), children: t.steerRetry })
|
|
2099
|
+
] })
|
|
2100
|
+
] }),
|
|
2101
|
+
/* @__PURE__ */ (0, import_jsx_runtime4.jsxs)("div", { className: "ss-dock-actions", children: [
|
|
2102
|
+
/* @__PURE__ */ (0, import_jsx_runtime4.jsx)(
|
|
2103
|
+
"button",
|
|
2104
|
+
{
|
|
2105
|
+
type: "button",
|
|
2106
|
+
className: "ss-dock-action",
|
|
2107
|
+
title: t.editTask,
|
|
2108
|
+
"aria-label": t.editTask,
|
|
2109
|
+
onClick: () => startEdit(item),
|
|
2110
|
+
children: /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(QueueEditIcon, {})
|
|
2111
|
+
}
|
|
2112
|
+
),
|
|
2113
|
+
isPaused ? /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(
|
|
2114
|
+
"button",
|
|
2115
|
+
{
|
|
2116
|
+
type: "button",
|
|
2117
|
+
className: `ss-dock-action ss-paused-active${resuming.has(item.id) ? " ss-pending" : ""}`,
|
|
2118
|
+
title: t.resumeTask,
|
|
2119
|
+
"aria-label": t.resumeTask,
|
|
2120
|
+
disabled: resuming.has(item.id),
|
|
2121
|
+
onClick: () => handleResume(item),
|
|
2122
|
+
children: /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(QueueResumeIcon, {})
|
|
2123
|
+
}
|
|
2124
|
+
) : /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(
|
|
2125
|
+
"button",
|
|
2126
|
+
{
|
|
2127
|
+
type: "button",
|
|
2128
|
+
className: `ss-dock-action${pausing.has(item.id) ? " ss-pending" : ""}`,
|
|
2129
|
+
title: canPause(item, now) ? t.pauseTask : t.pauseUnsupportedKind,
|
|
2130
|
+
"aria-label": canPause(item, now) ? t.pauseTask : t.pauseUnsupportedKind,
|
|
2131
|
+
disabled: !canPause(item, now) || pausing.has(item.id),
|
|
2132
|
+
onClick: () => handlePause(item),
|
|
2133
|
+
children: /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(QueuePauseIcon, {})
|
|
2134
|
+
}
|
|
2135
|
+
),
|
|
2136
|
+
/* @__PURE__ */ (0, import_jsx_runtime4.jsx)(
|
|
2137
|
+
"button",
|
|
2138
|
+
{
|
|
2139
|
+
type: "button",
|
|
2140
|
+
className: "ss-dock-action",
|
|
2141
|
+
title: t.deleteTask,
|
|
2142
|
+
"aria-label": t.deleteTask,
|
|
2143
|
+
onClick: () => handleCancel(item.id, isPaused ? "paused" : "active"),
|
|
2144
|
+
children: /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(QueueDeleteIcon, {})
|
|
2145
|
+
}
|
|
2146
|
+
),
|
|
2147
|
+
item.kind !== "every" && /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(
|
|
2148
|
+
"button",
|
|
2149
|
+
{
|
|
2150
|
+
type: "button",
|
|
2151
|
+
className: `ss-dock-action ss-dock-action-steer${steering.has(item.id) ? " ss-pending" : ""}${steerDone.has(item.id) ? " ss-done" : ""}`,
|
|
2152
|
+
title: steerDone.has(item.id) ? t.steerAlreadySent : t.steerTask,
|
|
2153
|
+
"aria-label": steerDone.has(item.id) ? t.steerAlreadySent : t.steerTask,
|
|
2154
|
+
disabled: steering.has(item.id) || steerDone.has(item.id),
|
|
2155
|
+
onClick: () => handleSteer(item),
|
|
2156
|
+
children: /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(QueueSendIcon, {})
|
|
2157
|
+
}
|
|
2158
|
+
)
|
|
2159
|
+
] })
|
|
2160
|
+
]
|
|
2161
|
+
},
|
|
2162
|
+
item.id
|
|
2163
|
+
);
|
|
1759
2164
|
};
|
|
1760
|
-
return /* @__PURE__ */ (0,
|
|
1761
|
-
schedules.length > 1 && /* @__PURE__ */ (0,
|
|
2165
|
+
return /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("div", { className: "ss-dock-root", "data-ss-dock": "", children: /* @__PURE__ */ (0, import_jsx_runtime4.jsxs)("div", { className: "ss-dock-body", children: [
|
|
2166
|
+
schedules.length > 1 && /* @__PURE__ */ (0, import_jsx_runtime4.jsxs)(
|
|
1762
2167
|
"button",
|
|
1763
2168
|
{
|
|
1764
2169
|
type: "button",
|
|
@@ -1766,23 +2171,48 @@ function ScheduleDock({ callCommand, sessionId, useProjection, locale }) {
|
|
|
1766
2171
|
"aria-expanded": !collapsed,
|
|
1767
2172
|
onClick: () => setCollapsed((value) => !value),
|
|
1768
2173
|
children: [
|
|
1769
|
-
/* @__PURE__ */ (0,
|
|
1770
|
-
/* @__PURE__ */ (0,
|
|
1771
|
-
/* @__PURE__ */ (0,
|
|
2174
|
+
/* @__PURE__ */ (0, import_jsx_runtime4.jsx)("span", { className: "ss-dock-lead", "aria-hidden": "true", children: /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(QueueClockIcon, {}) }),
|
|
2175
|
+
/* @__PURE__ */ (0, import_jsx_runtime4.jsx)("span", { className: "ss-dock-count", children: format(t.panelCount, { n: schedules.length }) }),
|
|
2176
|
+
/* @__PURE__ */ (0, import_jsx_runtime4.jsx)("span", { className: expanded ? "ss-dock-chevron ss-open" : "ss-dock-chevron", "aria-hidden": "true", children: /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(QueueChevronIcon, {}) })
|
|
1772
2177
|
]
|
|
1773
2178
|
}
|
|
1774
2179
|
),
|
|
1775
|
-
expanded && /* @__PURE__ */ (0,
|
|
2180
|
+
expanded && /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("ul", { className: "ss-dock-list", children: schedules.map(renderRow) })
|
|
1776
2181
|
] }) });
|
|
1777
2182
|
}
|
|
1778
2183
|
function MultiBar({
|
|
1779
2184
|
item,
|
|
1780
2185
|
now,
|
|
1781
2186
|
firstSeen,
|
|
1782
|
-
t
|
|
2187
|
+
t,
|
|
2188
|
+
frozen = false,
|
|
2189
|
+
frozenLeftMs,
|
|
2190
|
+
renderedAt
|
|
1783
2191
|
}) {
|
|
1784
|
-
const
|
|
1785
|
-
|
|
2192
|
+
const frozenSeg = frozen ? frozenBarSegments(item, frozenLeftMs ?? 0, firstSeen, renderedAt) : void 0;
|
|
2193
|
+
const activeSeg = frozen ? void 0 : barSegments(item, now, firstSeen);
|
|
2194
|
+
const { totalRatio, count } = frozenSeg ?? activeSeg ?? { totalRatio: 0, count: 1 };
|
|
2195
|
+
const phaseAtRef = (0, import_react7.useRef)(null);
|
|
2196
|
+
if (frozen || prefersReducedMotion()) {
|
|
2197
|
+
phaseAtRef.current = null;
|
|
2198
|
+
} else if (phaseAtRef.current === null) {
|
|
2199
|
+
phaseAtRef.current = now;
|
|
2200
|
+
}
|
|
2201
|
+
const anim = frozen || prefersReducedMotion() ? void 0 : planBarAnimationFor(item, phaseAtRef.current ?? now, firstSeen);
|
|
2202
|
+
const fillStyle = anim === void 0 ? { width: `${totalRatio * 100}%` } : {
|
|
2203
|
+
/**
|
|
2204
|
+
* 只注入**参数**(CSS 变量),动画的组装交给 CSS(见 styles.ts)。
|
|
2205
|
+
*
|
|
2206
|
+
* 这样做的原因:动画声明留在 CSS 里,JS 不碰 `animationName` 等简写属性
|
|
2207
|
+
* ——否则会整条覆盖 CSS 的声明。当前只有进度推进一个动画,但保持这个
|
|
2208
|
+
* 分工,将来若再加纹理/状态动效不必回头改 JS。
|
|
2209
|
+
*/
|
|
2210
|
+
["--ss-bar-duration"]: `${anim.durationMs}ms`,
|
|
2211
|
+
// 负 delay 把播放头定位到挂载时刻的绝对相位;此后恒定不变
|
|
2212
|
+
// (重算会让动画多跳——见上方 phaseAtRef 注释)。
|
|
2213
|
+
["--ss-bar-delay"]: `${anim.delayMs}ms`
|
|
2214
|
+
};
|
|
2215
|
+
return /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(
|
|
1786
2216
|
"div",
|
|
1787
2217
|
{
|
|
1788
2218
|
className: `ss-dock-bars${count > 4 ? " ss-dock-bars-compact" : ""}`,
|
|
@@ -1791,8 +2221,8 @@ function MultiBar({
|
|
|
1791
2221
|
"aria-valuemax": 100,
|
|
1792
2222
|
"aria-valuenow": Math.round(totalRatio * 100),
|
|
1793
2223
|
"aria-label": t.panelTitle,
|
|
1794
|
-
children: /* @__PURE__ */ (0,
|
|
1795
|
-
count > 1 && /* @__PURE__ */ (0,
|
|
2224
|
+
children: /* @__PURE__ */ (0, import_jsx_runtime4.jsxs)("div", { className: "ss-dock-bar", children: [
|
|
2225
|
+
count > 1 && /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(
|
|
1796
2226
|
"div",
|
|
1797
2227
|
{
|
|
1798
2228
|
className: "ss-dock-bar-divider",
|
|
@@ -1801,55 +2231,120 @@ function MultiBar({
|
|
|
1801
2231
|
}
|
|
1802
2232
|
}
|
|
1803
2233
|
),
|
|
1804
|
-
/* @__PURE__ */ (0,
|
|
2234
|
+
/* @__PURE__ */ (0, import_jsx_runtime4.jsx)("div", { className: "ss-dock-bar-fill", style: fillStyle })
|
|
1805
2235
|
] })
|
|
1806
2236
|
}
|
|
1807
2237
|
);
|
|
1808
2238
|
}
|
|
1809
2239
|
function QueueClockIcon() {
|
|
1810
|
-
return /* @__PURE__ */ (0,
|
|
2240
|
+
return /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("svg", { width: "14", height: "14", viewBox: "0 0 14 14", fill: "none", xmlns: "http://www.w3.org/2000/svg", "aria-hidden": "true", children: /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("path", { d: "M7.00049 0.199829C3.24488 0.199829 0.199952 3.24408 0.199707 6.99963C0.199707 8.0414 0.434087 9.03061 0.854004 9.91467L1.11279 10.4576L2.19775 9.94202L1.94092 9.39905L1.81787 9.12268C1.5498 8.46885 1.40186 7.75171 1.40186 6.99963C1.4021 3.90808 3.90888 1.40198 7.00049 1.40198C10.0919 1.40219 12.5979 3.90821 12.5981 6.99963C12.5981 10.0913 10.0921 12.5981 7.00049 12.5983C6.36734 12.5983 5.90348 12.5535 5.49268 12.4401C5.08803 12.3283 4.7041 12.1414 4.24463 11.8209C3.57111 11.3511 2.60588 11.1855 1.81006 11.6881L1.79736 11.6959L1.78467 11.7047L1.25537 12.0778L1.65381 13.2672L2.46045 12.6989C2.75029 12.5214 3.18004 12.5442 3.55615 12.8063C4.10063 13.1861 4.60863 13.4423 5.17334 13.5983C5.73194 13.7525 6.31665 13.8004 7.00049 13.8004C10.7561 13.8002 13.8003 10.7553 13.8003 6.99963C13.8 3.24421 10.7559 0.200041 7.00049 0.199829ZM3.81201 7.47327V8.67542H7.11572V7.47327H3.81201ZM3.81201 6.34924H10.2173V5.14709H3.81201V6.34924Z", fill: "currentColor" }) });
|
|
1811
2241
|
}
|
|
1812
2242
|
function QueueChevronIcon() {
|
|
1813
|
-
return /* @__PURE__ */ (0,
|
|
2243
|
+
return /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("svg", { width: "14", height: "14", viewBox: "0 0 14 14", fill: "none", xmlns: "http://www.w3.org/2000/svg", "aria-hidden": "true", children: /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("path", { d: "M11.8486 5.5L11.4238 5.92383L8.69727 8.65137C8.44157 8.90706 8.21562 9.13382 8.01172 9.29785C7.79912 9.46883 7.55595 9.61756 7.25 9.66602C7.08435 9.69222 6.91565 9.69222 6.75 9.66602C6.44405 9.61756 6.20088 9.46883 5.98828 9.29785C5.78438 9.13382 5.55843 8.90706 5.30273 8.65137L2.57617 5.92383L2.15137 5.5L3 4.65137L3.42383 5.07617L6.15137 7.80273C6.42595 8.07732 6.59876 8.24849 6.74023 8.3623C6.87291 8.46904 6.92272 8.47813 6.9375 8.48047C6.97895 8.48703 7.02105 8.48703 7.0625 8.48047C7.07728 8.47813 7.12709 8.46904 7.25977 8.3623C7.40124 8.24849 7.57405 8.07732 7.84863 7.80273L10.5762 5.07617L11 4.65137L11.8486 5.5Z", fill: "currentColor" }) });
|
|
1814
2244
|
}
|
|
1815
2245
|
function QueueEditIcon() {
|
|
1816
|
-
return /* @__PURE__ */ (0,
|
|
2246
|
+
return /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("svg", { width: "16", height: "16", viewBox: "0 0 16 16", fill: "none", xmlns: "http://www.w3.org/2000/svg", "aria-hidden": "true", children: /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("path", { d: "M9.94076 1.34942C10.7047 0.90231 11.6503 0.902415 12.4143 1.34942C12.7061 1.52015 12.9688 1.79118 13.3104 2.13284C13.6521 2.47448 13.9231 2.73721 14.0939 3.02894C14.5408 3.79294 14.5409 4.73856 14.0939 5.50251C13.9231 5.79415 13.652 6.05704 13.3104 6.39861L6.65932 13.0497C6.28068 13.4284 6.00695 13.7108 5.66543 13.9097C5.32391 14.1085 4.94315 14.2074 4.42705 14.3498L3.24394 14.6761C2.77527 14.8054 2.34538 14.9262 2.00131 14.9684C1.65196 15.0112 1.17964 15.0013 0.810764 14.6325C0.441921 14.2637 0.432107 13.7913 0.47486 13.442C0.517035 13.0979 0.6379 12.668 0.767181 12.1993L1.09352 11.0162C1.23588 10.5001 1.33481 10.1193 1.5336 9.77784C1.7325 9.43632 2.0149 9.1626 2.39355 8.78395L9.04466 2.13284C9.38625 1.79126 9.64911 1.52016 9.94076 1.34942ZM15.5427 14.8398H7.55223L8.96707 13.425H15.5427V14.8398ZM3.39382 9.78422C2.965 10.213 2.84244 10.3436 2.75709 10.49C2.67183 10.6366 2.61862 10.8079 2.45733 11.3925L2.13099 12.5756C2.00183 13.0439 1.92194 13.3419 1.88863 13.5536C2.10041 13.5204 2.39872 13.4416 2.86764 13.3123L4.05075 12.9859C4.63544 12.8246 4.80669 12.7715 4.95323 12.6862C5.09968 12.6008 5.23022 12.4783 5.65905 12.0494L10.721 6.98644L8.45577 4.72121L3.39382 9.78422ZM11.7 2.57079C11.3774 2.38198 10.9777 2.38198 10.6551 2.57079C10.5602 2.62647 10.4487 2.72931 10.0449 3.13311L9.45604 3.72094L11.7213 5.98617L12.3102 5.39833C12.7139 4.99457 12.8168 4.88307 12.8725 4.78818C13.0613 4.46561 13.0612 4.06585 12.8725 3.74326C12.8169 3.64827 12.7146 3.53752 12.3102 3.13311C11.9057 2.72863 11.795 2.6264 11.7 2.57079Z", fill: "currentColor" }) });
|
|
1817
2247
|
}
|
|
1818
2248
|
function QueueDeleteIcon() {
|
|
1819
|
-
return /* @__PURE__ */ (0,
|
|
2249
|
+
return /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("svg", { width: "16", height: "16", viewBox: "0 0 16 16", fill: "none", xmlns: "http://www.w3.org/2000/svg", "aria-hidden": "true", children: /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("path", { d: "M14.4782 4.84067L14.2138 10.1152C14.1102 12.1872 14.067 13.0115 13.3866 13.9607C13.1044 14.3546 12.7498 14.6912 12.3424 14.9535C11.8239 15.2872 11.2415 15.4316 10.5585 15.4998C9.88727 15.5668 9.04946 15.5656 7.99998 15.5656C6.95051 15.5656 6.1127 15.5668 5.44142 15.4998C4.75851 15.4316 4.17602 15.2872 3.65753 14.9535C3.25012 14.6912 2.89559 14.3546 2.61332 13.9607C1.93296 13.0115 1.88979 12.1872 1.78619 10.1152L1.52179 4.84067L2.89006 4.77277L3.15343 10.0463C3.26221 12.2218 3.32452 12.6015 3.72646 13.1624C3.90825 13.4161 4.13686 13.6334 4.39927 13.8023C4.66204 13.9714 5.00263 14.0792 5.57825 14.1367C6.16562 14.1953 6.92298 14.1963 7.99998 14.1963C9.07699 14.1963 9.83434 14.1953 10.4217 14.1367C10.9973 14.0792 11.3379 13.9714 11.6007 13.8023C11.8631 13.6334 12.0917 13.4161 12.2735 13.1624C12.6755 12.6015 12.7378 12.2218 12.8465 10.0463L13.1099 4.77277L14.4782 4.84067ZM5.43011 6.22849H6.7994V11.3909H5.43011V6.22849ZM9.20056 6.22849H10.5699V11.3909H9.20056V6.22849ZM8.53597 0.434431C9.17976 0.434431 9.6522 0.426926 10.0966 0.571258C10.2357 0.616451 10.3717 0.672554 10.502 0.738948C10.9182 0.951107 11.2464 1.29099 11.7015 1.74612L12.4978 2.54136H15.3742V3.91169H0.625732V2.54136H3.50218L4.29845 1.74612C4.75358 1.29099 5.08174 0.951107 5.49801 0.738948C5.62831 0.672554 5.76425 0.616451 5.90334 0.571258C6.34776 0.426926 6.82021 0.434431 7.46399 0.434431H8.53597ZM7.46399 1.80476C6.73208 1.80476 6.51641 1.81187 6.32617 1.87369C6.25545 1.89667 6.18668 1.92533 6.12041 1.95907C5.96398 2.03878 5.82348 2.16253 5.44142 2.54136H10.5585C10.1765 2.16253 10.036 2.03878 9.87955 1.95907C9.81329 1.92533 9.74452 1.89667 9.6738 1.87369C9.48356 1.81187 9.26789 1.80476 8.53597 1.80476H7.46399Z", fill: "currentColor" }) });
|
|
1820
2250
|
}
|
|
1821
2251
|
function QueueSendIcon() {
|
|
1822
|
-
return /* @__PURE__ */ (0,
|
|
2252
|
+
return /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("svg", { width: "14", height: "14", viewBox: "0 0 14 14", fill: "none", xmlns: "http://www.w3.org/2000/svg", "aria-hidden": "true", children: /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("path", { d: "M7.24707 1.01771C7.52897 1.07653 7.77619 1.19694 8.00391 1.38001C8.19202 1.53136 8.39884 1.73784 8.61914 1.95814L12.6396 5.9806L11.6299 6.99134L7.71484 3.0763V13.0001H6.28516V3.0763L2.36914 6.99134L1.35938 5.9806L5.38086 1.95814C5.60116 1.73784 5.80798 1.53136 5.99609 1.38001C6.19476 1.22027 6.4385 1.06739 6.75195 1.01771C6.91296 0.992304 7.07471 0.997504 7.24707 1.01771Z", fill: "currentColor" }) });
|
|
2253
|
+
}
|
|
2254
|
+
function QueuePauseIcon() {
|
|
2255
|
+
return /* @__PURE__ */ (0, import_jsx_runtime4.jsxs)("svg", { width: "16", height: "16", viewBox: "0 0 16 16", fill: "none", xmlns: "http://www.w3.org/2000/svg", "aria-hidden": "true", children: [
|
|
2256
|
+
/* @__PURE__ */ (0, import_jsx_runtime4.jsx)("rect", { x: "3.6", y: "2.6", width: "3.2", height: "10.8", rx: "1.1", fill: "currentColor" }),
|
|
2257
|
+
/* @__PURE__ */ (0, import_jsx_runtime4.jsx)("rect", { x: "9.2", y: "2.6", width: "3.2", height: "10.8", rx: "1.1", fill: "currentColor" })
|
|
2258
|
+
] });
|
|
2259
|
+
}
|
|
2260
|
+
function QueueResumeIcon() {
|
|
2261
|
+
return /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("svg", { width: "16", height: "16", viewBox: "0 0 16 16", fill: "none", xmlns: "http://www.w3.org/2000/svg", "aria-hidden": "true", children: /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("path", { d: "M4.4 2.9c0-.6.66-1 1.18-.68l7.1 4.1c.52.3.52 1.06 0 1.36l-7.1 4.1A.8.8 0 0 1 4.4 11.1V2.9Z", fill: "currentColor" }) });
|
|
1823
2262
|
}
|
|
1824
2263
|
|
|
1825
2264
|
// src/client/components/SchedulerSettingsCard.tsx
|
|
1826
|
-
var
|
|
1827
|
-
var
|
|
1828
|
-
var
|
|
1829
|
-
{
|
|
1830
|
-
|
|
1831
|
-
|
|
1832
|
-
|
|
1833
|
-
|
|
1834
|
-
|
|
1835
|
-
|
|
2265
|
+
var import_react8 = require("react");
|
|
2266
|
+
var import_jsx_runtime5 = require("react/jsx-runtime");
|
|
2267
|
+
var SECTIONS = [
|
|
2268
|
+
{
|
|
2269
|
+
id: "display",
|
|
2270
|
+
titleKey: "sectionDisplay",
|
|
2271
|
+
layout: "stack",
|
|
2272
|
+
fields: [
|
|
2273
|
+
{
|
|
2274
|
+
kind: "boolean",
|
|
2275
|
+
key: "showButton",
|
|
2276
|
+
labelKey: "showButtonLabel",
|
|
2277
|
+
hintKey: "showButtonHint",
|
|
2278
|
+
defaultValue: true
|
|
2279
|
+
},
|
|
2280
|
+
{
|
|
2281
|
+
kind: "enum",
|
|
2282
|
+
key: "clockIconStyle",
|
|
2283
|
+
labelKey: "clockIconStyleLabel",
|
|
2284
|
+
hintKey: "clockIconStyleHint",
|
|
2285
|
+
options: ["auto", "modern", "classic"],
|
|
2286
|
+
defaultValue: "auto"
|
|
2287
|
+
},
|
|
2288
|
+
{ kind: "number", key: "maxSchedules", labelKey: "maxSchedulesLabel", hintKey: "maxSchedulesHint", defaultValue: 100 }
|
|
2289
|
+
]
|
|
2290
|
+
},
|
|
2291
|
+
{
|
|
2292
|
+
id: "time",
|
|
2293
|
+
titleKey: "sectionTime",
|
|
2294
|
+
layout: "grid",
|
|
2295
|
+
fields: [
|
|
2296
|
+
{ kind: "time", key: "workStart", labelKey: "workStartLabel", hintKey: "smartWindowHint" },
|
|
2297
|
+
{ kind: "time", key: "workEnd", labelKey: "workEndLabel" },
|
|
2298
|
+
{ kind: "time", key: "lunchStart", labelKey: "lunchStartLabel" },
|
|
2299
|
+
{ kind: "time", key: "lunchEnd", labelKey: "lunchEndLabel" },
|
|
2300
|
+
{ kind: "time", key: "eveningEnd", labelKey: "eveningEndLabel" }
|
|
2301
|
+
]
|
|
2302
|
+
},
|
|
2303
|
+
{
|
|
2304
|
+
id: "delivery",
|
|
2305
|
+
titleKey: "sectionDelivery",
|
|
2306
|
+
layout: "stack",
|
|
2307
|
+
fields: [
|
|
2308
|
+
{
|
|
2309
|
+
kind: "enum",
|
|
2310
|
+
key: "steerDelivery",
|
|
2311
|
+
labelKey: "steerDeliveryLabel",
|
|
2312
|
+
hintKey: "steerDeliveryHint",
|
|
2313
|
+
options: ["followup", "steer"],
|
|
2314
|
+
defaultValue: "followup"
|
|
2315
|
+
},
|
|
2316
|
+
{
|
|
2317
|
+
kind: "boolean",
|
|
2318
|
+
key: "confirmDelivery",
|
|
2319
|
+
labelKey: "confirmDeliveryLabel",
|
|
2320
|
+
hintKey: "confirmDeliveryHint",
|
|
2321
|
+
defaultValue: true
|
|
2322
|
+
},
|
|
2323
|
+
{
|
|
2324
|
+
kind: "enum",
|
|
2325
|
+
key: "onUnconfirmed",
|
|
2326
|
+
labelKey: "onUnconfirmedLabel",
|
|
2327
|
+
hintKey: "onUnconfirmedHint",
|
|
2328
|
+
options: ["keep", "discard"],
|
|
2329
|
+
defaultValue: "keep"
|
|
2330
|
+
}
|
|
2331
|
+
]
|
|
2332
|
+
}
|
|
1836
2333
|
];
|
|
1837
|
-
|
|
1838
|
-
return /* @__PURE__ */ (0, import_jsx_runtime6.jsx)("svg", { width: "14", height: "14", viewBox: "0 0 14 14", fill: "none", className, "aria-hidden": "true", children: /* @__PURE__ */ (0, import_jsx_runtime6.jsx)("path", { d: "M3.5 5.25 7 8.75l3.5-3.5", stroke: "currentColor", strokeWidth: "1.2", strokeLinecap: "round", strokeLinejoin: "round" }) });
|
|
1839
|
-
}
|
|
2334
|
+
var FIELDS = SECTIONS.flatMap((s) => s.fields);
|
|
1840
2335
|
function SchedulerSettingsCard({ scope, t }) {
|
|
1841
|
-
const [snapshot, setSnapshot] = (0,
|
|
1842
|
-
const [pending, setPending] = (0,
|
|
1843
|
-
const [saving, setSaving] = (0,
|
|
1844
|
-
const [failed, setFailed] = (0,
|
|
1845
|
-
const [
|
|
1846
|
-
(0,
|
|
2336
|
+
const [snapshot, setSnapshot] = (0, import_react8.useState)(() => scope.getSnapshot());
|
|
2337
|
+
const [pending, setPending] = (0, import_react8.useState)({});
|
|
2338
|
+
const [saving, setSaving] = (0, import_react8.useState)(false);
|
|
2339
|
+
const [failed, setFailed] = (0, import_react8.useState)(false);
|
|
2340
|
+
const [helpOpen, setHelpOpen] = (0, import_react8.useState)({});
|
|
2341
|
+
(0, import_react8.useEffect)(() => {
|
|
1847
2342
|
const initial = scope.getSnapshot();
|
|
1848
2343
|
setSnapshot(initial);
|
|
1849
2344
|
setPending({});
|
|
1850
2345
|
if (initial.status === "ready") setFailed(false);
|
|
1851
2346
|
}, [scope]);
|
|
1852
|
-
(0,
|
|
2347
|
+
(0, import_react8.useEffect)(() => {
|
|
1853
2348
|
return scope.subscribe(() => {
|
|
1854
2349
|
const snap = scope.getSnapshot();
|
|
1855
2350
|
setSnapshot(snap);
|
|
@@ -1858,10 +2353,10 @@ function SchedulerSettingsCard({ scope, t }) {
|
|
|
1858
2353
|
}
|
|
1859
2354
|
});
|
|
1860
2355
|
}, [scope]);
|
|
1861
|
-
if (snapshot.status === "unavailable") return /* @__PURE__ */ (0,
|
|
2356
|
+
if (snapshot.status === "unavailable") return /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(import_jsx_runtime5.Fragment, {});
|
|
1862
2357
|
if (snapshot.status !== "ready") {
|
|
1863
|
-
if (snapshot.status === "loading") return /* @__PURE__ */ (0,
|
|
1864
|
-
return /* @__PURE__ */ (0,
|
|
2358
|
+
if (snapshot.status === "loading") return /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("div", { className: "ss-hint", children: t("loading") });
|
|
2359
|
+
return /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("div", { className: "ss-hint", children: t("unavailable") });
|
|
1865
2360
|
}
|
|
1866
2361
|
const value = snapshot.value ?? {};
|
|
1867
2362
|
const base = snapshot.base ?? {};
|
|
@@ -1879,6 +2374,10 @@ function SchedulerSettingsCard({ scope, t }) {
|
|
|
1879
2374
|
const v2 = value[field.key];
|
|
1880
2375
|
return v2 === false ? "false" : "true";
|
|
1881
2376
|
}
|
|
2377
|
+
if (field.kind === "enum") {
|
|
2378
|
+
const v2 = value[field.key];
|
|
2379
|
+
return typeof v2 === "string" ? v2 : field.defaultValue;
|
|
2380
|
+
}
|
|
1882
2381
|
const v = value[field.key];
|
|
1883
2382
|
return v ?? "";
|
|
1884
2383
|
};
|
|
@@ -1891,6 +2390,10 @@ function SchedulerSettingsCard({ scope, t }) {
|
|
|
1891
2390
|
const v2 = base[field.key];
|
|
1892
2391
|
return v2 === false ? "false" : "true";
|
|
1893
2392
|
}
|
|
2393
|
+
if (field.kind === "enum") {
|
|
2394
|
+
const v2 = base[field.key];
|
|
2395
|
+
return typeof v2 === "string" ? v2 : field.defaultValue;
|
|
2396
|
+
}
|
|
1894
2397
|
const v = base[field.key];
|
|
1895
2398
|
return v ?? "";
|
|
1896
2399
|
};
|
|
@@ -1903,6 +2406,7 @@ function SchedulerSettingsCard({ scope, t }) {
|
|
|
1903
2406
|
return null;
|
|
1904
2407
|
}
|
|
1905
2408
|
if (field.kind === "boolean") return null;
|
|
2409
|
+
if (field.kind === "enum") return field.options.includes(raw) ? null : t("invalidLabel");
|
|
1906
2410
|
if (raw.trim().length === 0) return null;
|
|
1907
2411
|
if (!isValidHhmm(raw)) return t("invalidTimeLabel");
|
|
1908
2412
|
return null;
|
|
@@ -1918,11 +2422,11 @@ function SchedulerSettingsCard({ scope, t }) {
|
|
|
1918
2422
|
setFieldPending(field.key, baselineValue(field), true);
|
|
1919
2423
|
setFailed(false);
|
|
1920
2424
|
};
|
|
1921
|
-
const handleDiscard = (0,
|
|
2425
|
+
const handleDiscard = (0, import_react8.useCallback)(() => {
|
|
1922
2426
|
setPending({});
|
|
1923
2427
|
setFailed(false);
|
|
1924
2428
|
}, []);
|
|
1925
|
-
const handleSave = (0,
|
|
2429
|
+
const handleSave = (0, import_react8.useCallback)(async () => {
|
|
1926
2430
|
if (!dirty || saving || !writable) return;
|
|
1927
2431
|
setSaving(true);
|
|
1928
2432
|
setFailed(false);
|
|
@@ -1955,66 +2459,91 @@ function SchedulerSettingsCard({ scope, t }) {
|
|
|
1955
2459
|
};
|
|
1956
2460
|
const anyInvalid = FIELDS.some((field) => invalidField(field) !== null);
|
|
1957
2461
|
const saveDisabled = !dirty || saving || !writable || anyInvalid;
|
|
1958
|
-
|
|
1959
|
-
|
|
1960
|
-
|
|
1961
|
-
|
|
1962
|
-
|
|
1963
|
-
|
|
1964
|
-
"aria-expanded": open,
|
|
1965
|
-
"aria-label": `${t(open ? "collapse" : "expand")}: ${t("title")}`,
|
|
1966
|
-
onClick: () => setOpen(!open),
|
|
1967
|
-
children: [
|
|
1968
|
-
/* @__PURE__ */ (0, import_jsx_runtime6.jsxs)("span", { className: "ss-card-headText", children: [
|
|
1969
|
-
/* @__PURE__ */ (0, import_jsx_runtime6.jsx)("span", { className: "ss-card-name", children: t("title") }),
|
|
1970
|
-
/* @__PURE__ */ (0, import_jsx_runtime6.jsx)("span", { className: "ss-card-description", children: t("description") })
|
|
1971
|
-
] }),
|
|
1972
|
-
dirty && /* @__PURE__ */ (0, import_jsx_runtime6.jsx)("span", { className: "ss-card-pending", children: t("pendingBadge") }),
|
|
1973
|
-
/* @__PURE__ */ (0, import_jsx_runtime6.jsx)(ChevronDown, { className: open ? "ss-card-chevron ss-card-chevronOpen" : "ss-card-chevron" })
|
|
1974
|
-
]
|
|
1975
|
-
}
|
|
1976
|
-
),
|
|
1977
|
-
open ? /* @__PURE__ */ (0, import_jsx_runtime6.jsxs)("div", { className: "ss-card-body", children: [
|
|
1978
|
-
!writable && /* @__PURE__ */ (0, import_jsx_runtime6.jsx)("p", { className: "ss-card-readOnly", role: "status", children: t("readOnly") }),
|
|
1979
|
-
FIELDS.map((field) => {
|
|
2462
|
+
const confirmEnabled = (pending.confirmDelivery?.value ?? (value.confirmDelivery === false ? "false" : "true")) !== "false";
|
|
2463
|
+
return /* @__PURE__ */ (0, import_jsx_runtime5.jsxs)("div", { className: "ss-settings-form", children: [
|
|
2464
|
+
!writable && /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("p", { className: "ss-hint", role: "status", children: t("readOnly") }),
|
|
2465
|
+
SECTIONS.map((section) => /* @__PURE__ */ (0, import_jsx_runtime5.jsxs)("section", { className: "ss-section", "aria-labelledby": `ss-section-${section.id}`, children: [
|
|
2466
|
+
/* @__PURE__ */ (0, import_jsx_runtime5.jsx)("h3", { className: "ss-section-heading", id: `ss-section-${section.id}`, children: t(section.titleKey) }),
|
|
2467
|
+
/* @__PURE__ */ (0, import_jsx_runtime5.jsx)("div", { className: section.layout === "grid" ? "ss-section-fields ss-section-fieldsGrid" : "ss-section-fields", children: section.fields.map((field) => {
|
|
1980
2468
|
const invalid = invalidField(field);
|
|
1981
2469
|
const isTime = field.kind === "time";
|
|
1982
2470
|
const labelKey = field.labelKey;
|
|
1983
2471
|
const hintKey = field.hintKey;
|
|
1984
2472
|
const userHas = isUserOverridden(field.key);
|
|
1985
2473
|
const fieldId = `ss-${field.key}`;
|
|
1986
|
-
|
|
1987
|
-
|
|
1988
|
-
|
|
1989
|
-
|
|
1990
|
-
|
|
1991
|
-
|
|
2474
|
+
const helpHint = hintKey !== void 0 && t(hintKey).length > 0;
|
|
2475
|
+
const badges = userHas ? /* @__PURE__ */ (0, import_jsx_runtime5.jsxs)("span", { className: "ss-card-badges", children: [
|
|
2476
|
+
/* @__PURE__ */ (0, import_jsx_runtime5.jsx)("span", { className: "ss-card-badge", children: t("overriddenLabel") }),
|
|
2477
|
+
/* @__PURE__ */ (0, import_jsx_runtime5.jsx)(
|
|
2478
|
+
"button",
|
|
2479
|
+
{
|
|
2480
|
+
type: "button",
|
|
2481
|
+
className: "ss-card-reset",
|
|
2482
|
+
disabled: !writable || saving,
|
|
2483
|
+
onClick: () => handleResetField(field),
|
|
2484
|
+
children: t("resetLabel")
|
|
2485
|
+
}
|
|
2486
|
+
)
|
|
2487
|
+
] }) : null;
|
|
2488
|
+
if (field.kind === "boolean") {
|
|
2489
|
+
const checked = displayValue(field) !== "false";
|
|
2490
|
+
return /* @__PURE__ */ (0, import_jsx_runtime5.jsxs)("div", { className: "ss-field ss-fieldToggle", children: [
|
|
2491
|
+
/* @__PURE__ */ (0, import_jsx_runtime5.jsxs)("div", { className: "ss-toggle-row", children: [
|
|
2492
|
+
/* @__PURE__ */ (0, import_jsx_runtime5.jsx)("div", { className: "ss-label-group", children: /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("label", { htmlFor: fieldId, className: "ss-toggle-label", children: t(labelKey) }) }),
|
|
2493
|
+
badges,
|
|
2494
|
+
/* @__PURE__ */ (0, import_jsx_runtime5.jsx)(
|
|
1992
2495
|
"button",
|
|
1993
2496
|
{
|
|
1994
2497
|
type: "button",
|
|
1995
|
-
|
|
2498
|
+
id: fieldId,
|
|
2499
|
+
role: "switch",
|
|
2500
|
+
"aria-checked": checked,
|
|
2501
|
+
"aria-label": t(labelKey),
|
|
2502
|
+
className: "ss-toggle-switch",
|
|
1996
2503
|
disabled: !writable || saving,
|
|
1997
|
-
onClick: () =>
|
|
1998
|
-
children: t("resetLabel")
|
|
2504
|
+
onClick: () => handleFieldEdit(field, checked ? "false" : "true")
|
|
1999
2505
|
}
|
|
2000
2506
|
)
|
|
2001
|
-
] })
|
|
2507
|
+
] }),
|
|
2508
|
+
helpHint ? /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("p", { className: "ss-toggle-description", children: t(hintKey) }) : null,
|
|
2509
|
+
invalid !== null ? /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("p", { className: "ss-card-invalid", role: "status", children: invalid }) : null
|
|
2510
|
+
] }, field.key);
|
|
2511
|
+
}
|
|
2512
|
+
return /* @__PURE__ */ (0, import_jsx_runtime5.jsxs)("div", { className: "ss-field", children: [
|
|
2513
|
+
/* @__PURE__ */ (0, import_jsx_runtime5.jsxs)("div", { className: "ss-card-fieldHead", children: [
|
|
2514
|
+
/* @__PURE__ */ (0, import_jsx_runtime5.jsxs)("div", { className: "ss-label-group", children: [
|
|
2515
|
+
/* @__PURE__ */ (0, import_jsx_runtime5.jsx)("label", { htmlFor: fieldId, className: "ss-card-label", children: t(labelKey) }),
|
|
2516
|
+
helpHint && /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(
|
|
2517
|
+
"button",
|
|
2518
|
+
{
|
|
2519
|
+
type: "button",
|
|
2520
|
+
className: helpOpen[field.key] === true ? "ss-help-btn ss-help-btnOpen" : "ss-help-btn",
|
|
2521
|
+
"aria-label": `${t(labelKey)}\u8BF4\u660E`,
|
|
2522
|
+
"aria-expanded": helpOpen[field.key] === true,
|
|
2523
|
+
"aria-controls": `ss-help-${field.key}`,
|
|
2524
|
+
onClick: () => setHelpOpen((prev) => ({ ...prev, [field.key]: !prev[field.key] })),
|
|
2525
|
+
children: /* @__PURE__ */ (0, import_jsx_runtime5.jsxs)("svg", { width: "12", height: "12", viewBox: "0 0 14 14", fill: "none", "aria-hidden": "true", strokeWidth: "1", children: [
|
|
2526
|
+
/* @__PURE__ */ (0, import_jsx_runtime5.jsx)("path", { d: "M12.5757 7.00012C12.5757 3.92085 10.0794 1.42463 7.00012 1.42456C3.9208 1.42456 1.42456 3.9208 1.42456 7.00012C1.42463 10.0794 3.92085 12.5757 7.00012 12.5757C10.0793 12.5756 12.5756 10.0793 12.5757 7.00012ZM13.8002 7.00012C13.8001 10.7559 10.7559 13.8001 7.00012 13.8002C3.2443 13.8002 0.199291 10.7559 0.199219 7.00012C0.199219 3.24426 3.24426 0.199219 7.00012 0.199219C10.7559 0.199291 13.8002 3.2443 13.8002 7.00012Z", fill: "currentColor" }),
|
|
2527
|
+
/* @__PURE__ */ (0, import_jsx_runtime5.jsx)("path", { d: "M7.6127 3.18921V4.55986H6.38735V3.18921H7.6127Z", fill: "currentColor" }),
|
|
2528
|
+
/* @__PURE__ */ (0, import_jsx_runtime5.jsx)("path", { d: "M7.6127 5.68921V10.8109H6.38735V5.68921H7.6127Z", fill: "currentColor" })
|
|
2529
|
+
] })
|
|
2530
|
+
}
|
|
2531
|
+
)
|
|
2532
|
+
] }),
|
|
2533
|
+
badges
|
|
2002
2534
|
] }),
|
|
2003
|
-
field.kind === "
|
|
2535
|
+
field.kind === "enum" ? /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(
|
|
2004
2536
|
"select",
|
|
2005
2537
|
{
|
|
2006
2538
|
id: fieldId,
|
|
2007
2539
|
className: invalid !== null ? "ss-input ss-inputInvalid" : "ss-input",
|
|
2008
2540
|
"aria-invalid": invalid !== null || void 0,
|
|
2009
|
-
value: displayValue(field)
|
|
2541
|
+
value: displayValue(field),
|
|
2010
2542
|
disabled: !writable || saving,
|
|
2011
2543
|
onChange: (event) => handleFieldEdit(field, event.target.value),
|
|
2012
|
-
children:
|
|
2013
|
-
/* @__PURE__ */ (0, import_jsx_runtime6.jsx)("option", { value: "true", children: t("optionOn") }),
|
|
2014
|
-
/* @__PURE__ */ (0, import_jsx_runtime6.jsx)("option", { value: "false", children: t("optionOff") })
|
|
2015
|
-
]
|
|
2544
|
+
children: field.options.map((option) => /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("option", { value: option, children: t(`${field.key}Option_${option}`) }, option))
|
|
2016
2545
|
}
|
|
2017
|
-
) : /* @__PURE__ */ (0,
|
|
2546
|
+
) : /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(
|
|
2018
2547
|
"input",
|
|
2019
2548
|
{
|
|
2020
2549
|
id: fieldId,
|
|
@@ -2028,33 +2557,36 @@ function SchedulerSettingsCard({ scope, t }) {
|
|
|
2028
2557
|
onChange: (event) => handleFieldEdit(field, event.target.value)
|
|
2029
2558
|
}
|
|
2030
2559
|
),
|
|
2031
|
-
invalid !== null
|
|
2560
|
+
invalid !== null ? /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("p", { className: "ss-card-invalid", role: "status", children: invalid }) : null,
|
|
2561
|
+
helpOpen[field.key] === true && hintKey !== void 0 && t(hintKey).length > 0 ? /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("div", { id: `ss-help-${field.key}`, role: "region", "aria-label": `${t(labelKey)}\u8BF4\u660E`, className: "ss-help", children: /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("p", { children: t(hintKey) }) }) : null,
|
|
2562
|
+
field.key === "steerDelivery" && displayValue(field) === "steer" ? /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("p", { className: "ss-card-risk", role: "status", children: confirmEnabled ? t("steerRiskGuarded") : t("steerRiskUnguarded") }) : null,
|
|
2563
|
+
field.key === "onUnconfirmed" && displayValue(field) === "discard" ? /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("p", { className: "ss-card-risk", role: "status", children: t("discardRisk") }) : null
|
|
2032
2564
|
] }, field.key);
|
|
2033
|
-
})
|
|
2034
|
-
|
|
2035
|
-
|
|
2036
|
-
|
|
2037
|
-
|
|
2038
|
-
|
|
2039
|
-
|
|
2040
|
-
|
|
2041
|
-
|
|
2042
|
-
|
|
2043
|
-
|
|
2044
|
-
|
|
2045
|
-
|
|
2046
|
-
|
|
2047
|
-
|
|
2048
|
-
|
|
2049
|
-
|
|
2050
|
-
|
|
2051
|
-
|
|
2052
|
-
|
|
2053
|
-
|
|
2054
|
-
|
|
2055
|
-
|
|
2056
|
-
|
|
2057
|
-
] })
|
|
2565
|
+
}) })
|
|
2566
|
+
] }, section.id)),
|
|
2567
|
+
/* @__PURE__ */ (0, import_jsx_runtime5.jsxs)("div", { className: "ss-card-footer", children: [
|
|
2568
|
+
failed && /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("p", { className: "ss-card-failed", role: "status", children: t("saveFailed") }),
|
|
2569
|
+
dirty && /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(
|
|
2570
|
+
"button",
|
|
2571
|
+
{
|
|
2572
|
+
type: "button",
|
|
2573
|
+
className: "ss-card-discard",
|
|
2574
|
+
disabled: saving,
|
|
2575
|
+
onClick: handleDiscard,
|
|
2576
|
+
children: t("discard")
|
|
2577
|
+
}
|
|
2578
|
+
),
|
|
2579
|
+
/* @__PURE__ */ (0, import_jsx_runtime5.jsx)(
|
|
2580
|
+
"button",
|
|
2581
|
+
{
|
|
2582
|
+
type: "button",
|
|
2583
|
+
className: "ss-card-save",
|
|
2584
|
+
disabled: saveDisabled,
|
|
2585
|
+
onClick: () => void handleSave(),
|
|
2586
|
+
children: saving ? t("saving") : t("save")
|
|
2587
|
+
}
|
|
2588
|
+
)
|
|
2589
|
+
] })
|
|
2058
2590
|
] });
|
|
2059
2591
|
}
|
|
2060
2592
|
|
|
@@ -2063,15 +2595,21 @@ var PRESENCE_URGENT_WINDOW_MS = 5 * 6e4;
|
|
|
2063
2595
|
function summarizeSchedules(schedules) {
|
|
2064
2596
|
let nextAt;
|
|
2065
2597
|
let count = 0;
|
|
2598
|
+
let pausedCount = 0;
|
|
2066
2599
|
for (const item of schedules ?? []) {
|
|
2067
2600
|
const raw = item.scheduled_at ?? item.scheduledAt;
|
|
2068
2601
|
if (raw === void 0) continue;
|
|
2069
2602
|
const epoch = Date.parse(raw);
|
|
2070
2603
|
if (!Number.isFinite(epoch)) continue;
|
|
2071
2604
|
count += 1;
|
|
2605
|
+
if (item.status === "paused") {
|
|
2606
|
+
pausedCount += 1;
|
|
2607
|
+
continue;
|
|
2608
|
+
}
|
|
2072
2609
|
if (nextAt === void 0 || epoch < nextAt) nextAt = epoch;
|
|
2073
2610
|
}
|
|
2074
|
-
|
|
2611
|
+
if (count === 0) return { count: 0, pausedCount: 0 };
|
|
2612
|
+
return nextAt === void 0 ? { count, pausedCount } : { count, nextAt, pausedCount };
|
|
2075
2613
|
}
|
|
2076
2614
|
function badgeStateFor(nextAt, now) {
|
|
2077
2615
|
if (nextAt === void 0) return "scheduled";
|
|
@@ -2080,6 +2618,24 @@ function badgeStateFor(nextAt, now) {
|
|
|
2080
2618
|
if (diff <= PRESENCE_URGENT_WINDOW_MS) return "urgent";
|
|
2081
2619
|
return "scheduled";
|
|
2082
2620
|
}
|
|
2621
|
+
function hoverScheduleStatus(entry, now, labels, strings, formatHhmm3, formatDate2) {
|
|
2622
|
+
const tone = badgeStateFor(entry.nextAt, now);
|
|
2623
|
+
if (entry.nextAt === void 0 && entry.pausedCount > 0) {
|
|
2624
|
+
const paused = strings.hoverSchedulePaused ?? strings.hoverScheduleOverdue;
|
|
2625
|
+
return { label: formatTemplate(paused, { n: entry.count }), tone };
|
|
2626
|
+
}
|
|
2627
|
+
if (tone === "overdue" || entry.nextAt === void 0) {
|
|
2628
|
+
return { label: formatTemplate(strings.hoverScheduleOverdue, { n: entry.count }), tone };
|
|
2629
|
+
}
|
|
2630
|
+
const time = relativeFireLabel(entry.nextAt, now, labels, formatHhmm3, formatDate2);
|
|
2631
|
+
return { label: formatTemplate(strings.hoverScheduleStatus, { n: entry.count, time }), tone };
|
|
2632
|
+
}
|
|
2633
|
+
function formatTemplate(template, params) {
|
|
2634
|
+
return template.replace(
|
|
2635
|
+
/\{(\w+)\}/g,
|
|
2636
|
+
(match, key) => key in params ? String(params[key]) : match
|
|
2637
|
+
);
|
|
2638
|
+
}
|
|
2083
2639
|
function startOfDay(epoch) {
|
|
2084
2640
|
const d = new Date(epoch);
|
|
2085
2641
|
d.setHours(0, 0, 0, 0);
|
|
@@ -2099,17 +2655,25 @@ function relativeFireLabel(nextAt, now, labels, formatHhmm3, formatDate2) {
|
|
|
2099
2655
|
|
|
2100
2656
|
// src/client/session-presence.ts
|
|
2101
2657
|
var BADGE_CLASS = "ss-presence";
|
|
2658
|
+
var HOVER_ROW_CLASS = "ss-hover-status";
|
|
2102
2659
|
var FIBER_MAX_DEPTH = 8;
|
|
2103
2660
|
var SCAN_DEBOUNCE_MS = 60;
|
|
2104
2661
|
var STATE_TICK_MS = 3e4;
|
|
2105
2662
|
var REFRESH_INTERVAL_MS = 6e4;
|
|
2106
|
-
var
|
|
2663
|
+
var CLOCK_SVG_CLASSIC = '<svg width="10" height="10" viewBox="0 0 10 10" shape-rendering="crispEdges" aria-hidden="true"><g class="ss-presence-ring"><rect x="0" y="0" width="2" height="2"/><rect x="4" y="0" width="2" height="2"/><rect x="8" y="0" width="2" height="2"/><rect x="8" y="4" width="2" height="2"/><rect x="8" y="8" width="2" height="2"/><rect x="4" y="8" width="2" height="2"/><rect x="0" y="8" width="2" height="2"/><rect x="0" y="4" width="2" height="2"/></g><g class="ss-presence-hand"><rect x="4" y="2" width="2" height="2"/><rect x="6" y="4" width="2" height="2"/></g></svg>';
|
|
2664
|
+
var CLOCK_SVG_MODERN = '<svg width="14" height="14" viewBox="0 0 24 24" aria-hidden="true"><circle class="ss-clock-face" cx="12" cy="12" r="9.5"/><g class="ss-clock-hand"><line class="ss-clock-hand-h" x1="12" y1="12" x2="12" y2="6.5"/><line class="ss-clock-hand-m" x1="12" y1="12" x2="17" y2="12"/></g></svg>';
|
|
2107
2665
|
var hhmmFormatter = new Intl.DateTimeFormat(void 0, { hour: "2-digit", minute: "2-digit", hour12: false });
|
|
2108
2666
|
var dateFormatter = new Intl.DateTimeFormat(void 0, { month: "short", day: "numeric" });
|
|
2109
2667
|
var formatHhmm2 = (epoch) => hhmmFormatter.format(epoch);
|
|
2110
2668
|
var formatDate = (epoch) => dateFormatter.format(epoch);
|
|
2111
2669
|
function sessionIdOfRow(row) {
|
|
2112
|
-
|
|
2670
|
+
return sessionIdOfNode(row);
|
|
2671
|
+
}
|
|
2672
|
+
function sessionIdOfHoverCard(card) {
|
|
2673
|
+
return sessionIdOfNode(card);
|
|
2674
|
+
}
|
|
2675
|
+
function sessionIdOfNode(element) {
|
|
2676
|
+
const host = element;
|
|
2113
2677
|
const fiberKey = Object.keys(host).find((key) => key.startsWith("__reactFiber$"));
|
|
2114
2678
|
if (fiberKey === void 0) return void 0;
|
|
2115
2679
|
let fiber = host[fiberKey];
|
|
@@ -2148,10 +2712,14 @@ function labelsFor(dict) {
|
|
|
2148
2712
|
};
|
|
2149
2713
|
}
|
|
2150
2714
|
function mountSessionPresence(options) {
|
|
2151
|
-
const { sessions, locale } = options;
|
|
2715
|
+
const { sessions, locale, getClockIconStyle } = options;
|
|
2152
2716
|
if (typeof document === "undefined" || typeof MutationObserver === "undefined") {
|
|
2153
2717
|
return () => void 0;
|
|
2154
2718
|
}
|
|
2719
|
+
const getClockSvg = () => {
|
|
2720
|
+
const style = getClockIconStyle?.() ?? "auto";
|
|
2721
|
+
return style === "classic" ? CLOCK_SVG_CLASSIC : CLOCK_SVG_MODERN;
|
|
2722
|
+
};
|
|
2155
2723
|
let index = /* @__PURE__ */ new Map();
|
|
2156
2724
|
let scanTimer;
|
|
2157
2725
|
let disposed = false;
|
|
@@ -2165,6 +2733,7 @@ function mountSessionPresence(options) {
|
|
|
2165
2733
|
if (row.hasAttribute("aria-expanded")) continue;
|
|
2166
2734
|
applyBadge(row, now, dict);
|
|
2167
2735
|
}
|
|
2736
|
+
applyHoverCard(now, dict);
|
|
2168
2737
|
};
|
|
2169
2738
|
const scheduleScan = () => {
|
|
2170
2739
|
if (disposed || scanTimer !== void 0) return;
|
|
@@ -2184,8 +2753,9 @@ function mountSessionPresence(options) {
|
|
|
2184
2753
|
}
|
|
2185
2754
|
const state = badgeStateFor(entry.nextAt, now);
|
|
2186
2755
|
const time = entry.nextAt === void 0 ? "" : relativeFireLabel(entry.nextAt, now, labelsFor(dict), formatHhmm2, formatDate);
|
|
2187
|
-
const
|
|
2188
|
-
const
|
|
2756
|
+
const allPaused = entry.nextAt === void 0 && entry.pausedCount > 0;
|
|
2757
|
+
const aria = allPaused ? format(dict.presencePausedAria, { n: entry.count }) : state === "overdue" ? format(dict.presenceOverdueAria, { n: entry.count }) : format(dict.presenceBadgeAria, { n: entry.count, time });
|
|
2758
|
+
const tooltip = allPaused ? format(dict.presencePausedTooltip, { n: entry.count }) : state === "overdue" ? format(dict.presenceOverdueTooltip, { n: entry.count }) : format(dict.presenceTooltip, { n: entry.count, time });
|
|
2189
2759
|
if (existing !== null) {
|
|
2190
2760
|
if (existing.dataset.state !== state) existing.dataset.state = state;
|
|
2191
2761
|
if (existing.getAttribute("aria-label") !== aria) existing.setAttribute("aria-label", aria);
|
|
@@ -2201,10 +2771,55 @@ function mountSessionPresence(options) {
|
|
|
2201
2771
|
badge.setAttribute("role", "img");
|
|
2202
2772
|
badge.setAttribute("aria-label", aria);
|
|
2203
2773
|
badge.setAttribute("title", tooltip);
|
|
2204
|
-
badge.innerHTML =
|
|
2774
|
+
badge.innerHTML = getClockSvg();
|
|
2205
2775
|
if (beside) slot.after(badge);
|
|
2206
2776
|
else slot.append(badge);
|
|
2207
2777
|
}
|
|
2778
|
+
function findHoverCard() {
|
|
2779
|
+
for (const card of Array.from(document.body.children)) {
|
|
2780
|
+
if (!(card instanceof HTMLElement)) continue;
|
|
2781
|
+
const statusHost = card.firstElementChild;
|
|
2782
|
+
if (!(statusHost instanceof HTMLElement)) continue;
|
|
2783
|
+
const hasStatusRow = Array.from(statusHost.children).some((child) => {
|
|
2784
|
+
const dot = child.firstElementChild;
|
|
2785
|
+
return child.children.length >= 2 && dot !== null && dot.tagName === "SPAN" && dot.getAttribute("aria-hidden") === "true";
|
|
2786
|
+
});
|
|
2787
|
+
if (!hasStatusRow) continue;
|
|
2788
|
+
const sessionId = sessionIdOfHoverCard(card);
|
|
2789
|
+
if (sessionId === void 0) continue;
|
|
2790
|
+
return { card, statusHost, sessionId };
|
|
2791
|
+
}
|
|
2792
|
+
return null;
|
|
2793
|
+
}
|
|
2794
|
+
function applyHoverCard(now, dict) {
|
|
2795
|
+
const found = findHoverCard();
|
|
2796
|
+
if (found === null) return;
|
|
2797
|
+
const { statusHost, sessionId } = found;
|
|
2798
|
+
const existing = statusHost.querySelector(`:scope > .${HOVER_ROW_CLASS}`);
|
|
2799
|
+
const entry = index.get(sessionId);
|
|
2800
|
+
if (entry === void 0) {
|
|
2801
|
+
existing?.remove();
|
|
2802
|
+
return;
|
|
2803
|
+
}
|
|
2804
|
+
const { label } = hoverScheduleStatus(entry, now, labelsFor(dict), dict, formatHhmm2, formatDate);
|
|
2805
|
+
const state = badgeStateFor(entry.nextAt, now);
|
|
2806
|
+
if (existing !== null) {
|
|
2807
|
+
const text2 = existing.lastElementChild;
|
|
2808
|
+
if (text2 !== null && text2.textContent !== label) text2.textContent = label;
|
|
2809
|
+
if (existing.dataset.state !== state) existing.dataset.state = state;
|
|
2810
|
+
return;
|
|
2811
|
+
}
|
|
2812
|
+
const row = document.createElement("div");
|
|
2813
|
+
row.className = HOVER_ROW_CLASS;
|
|
2814
|
+
row.dataset.state = state;
|
|
2815
|
+
const dot = document.createElement("span");
|
|
2816
|
+
dot.setAttribute("aria-hidden", "true");
|
|
2817
|
+
dot.className = "ss-hover-status-dot";
|
|
2818
|
+
const text = document.createElement("span");
|
|
2819
|
+
text.textContent = label;
|
|
2820
|
+
row.append(dot, text);
|
|
2821
|
+
statusHost.append(row);
|
|
2822
|
+
}
|
|
2208
2823
|
const unsubscribeList = sessions.list.subscribe(scheduleScan);
|
|
2209
2824
|
const unsubscribeLocale = locale?.subscribe(scheduleScan);
|
|
2210
2825
|
const observer = new MutationObserver(scheduleScan);
|
|
@@ -2241,26 +2856,33 @@ function mountSessionPresence(options) {
|
|
|
2241
2856
|
document.removeEventListener("visibilitychange", onVisible);
|
|
2242
2857
|
window.removeEventListener("online", onVisible);
|
|
2243
2858
|
for (const badge of Array.from(document.querySelectorAll(`.${BADGE_CLASS}`))) badge.remove();
|
|
2859
|
+
for (const row of Array.from(document.querySelectorAll(`.${HOVER_ROW_CLASS}`))) row.remove();
|
|
2244
2860
|
};
|
|
2245
2861
|
}
|
|
2246
2862
|
|
|
2247
2863
|
// src/client/index.tsx
|
|
2248
2864
|
var INPUT_RIGHT_SLOT = "conversation.input.right";
|
|
2249
|
-
var inject = ["slots", "sessions", "conversation", "
|
|
2865
|
+
var inject = ["slots", "sessions", "conversation", "locale"];
|
|
2250
2866
|
var NS = "settings.plugins.later";
|
|
2251
2867
|
var SETTINGS_NS = "dsh-later";
|
|
2868
|
+
var ENTRY_ID = "later";
|
|
2252
2869
|
function apply(ctx) {
|
|
2253
2870
|
const slots = ctx.get("slots");
|
|
2254
2871
|
const sessions = ctx.get("sessions");
|
|
2255
|
-
const settingsScope = ctx.get("settingsScope");
|
|
2256
2872
|
const locale = ctx.get("locale");
|
|
2257
2873
|
if (slots === void 0 || sessions === void 0) return;
|
|
2258
2874
|
ctx.effect(() => injectStyles(), "dsh-later: styles");
|
|
2259
|
-
|
|
2875
|
+
let detectedVersion = "classic";
|
|
2876
|
+
let getClockIconStyle = () => "auto";
|
|
2260
2877
|
ctx.effect(
|
|
2261
2878
|
() => mountSessionPresence({
|
|
2262
2879
|
sessions,
|
|
2263
|
-
...locale === void 0 ? {} : { locale }
|
|
2880
|
+
...locale === void 0 ? {} : { locale },
|
|
2881
|
+
getClockIconStyle: () => {
|
|
2882
|
+
const style = getClockIconStyle();
|
|
2883
|
+
if (style === "auto") return detectedVersion;
|
|
2884
|
+
return style;
|
|
2885
|
+
}
|
|
2264
2886
|
}),
|
|
2265
2887
|
"dsh-later: presence"
|
|
2266
2888
|
);
|
|
@@ -2273,10 +2895,11 @@ function apply(ctx) {
|
|
|
2273
2895
|
expand: "\u5C55\u5F00\u8BBE\u7F6E",
|
|
2274
2896
|
collapse: "\u6536\u8D77\u8BBE\u7F6E",
|
|
2275
2897
|
readOnly: "\u672C\u90E8\u7F72\u7684\u8BBE\u7F6E\u4E3A\u53EA\u8BFB\u3002",
|
|
2898
|
+
sectionDisplay: "\u663E\u793A\u8BBE\u7F6E",
|
|
2899
|
+
sectionTime: "\u65F6\u95F4\u8BBE\u7F6E",
|
|
2900
|
+
sectionDelivery: "\u6295\u9012\u8BBE\u7F6E",
|
|
2276
2901
|
showButtonLabel: "\u663E\u793A\u5B9A\u65F6\u6309\u94AE",
|
|
2277
2902
|
showButtonHint: "\u5173\u95ED\u540E\u8F93\u5165\u6846\u53F3\u4FA7\u4E0D\u518D\u663E\u793A\u65F6\u949F\u6309\u94AE\uFF1B\u5DF2\u521B\u5EFA\u7684\u63D0\u9192\u4ECD\u4F1A\u7167\u5E38\u89E6\u53D1\uFF0C\u5E76\u5728\u8F93\u5165\u6846\u4E0B\u65B9\u7684\u5F85\u53D1\u9001\u5217\u8868\u4E2D\u663E\u793A\u3002",
|
|
2278
|
-
optionOn: "\u663E\u793A",
|
|
2279
|
-
optionOff: "\u9690\u85CF",
|
|
2280
2903
|
maxSchedulesLabel: "\u5355\u4F1A\u8BDD\u4EFB\u52A1\u4E0A\u9650",
|
|
2281
2904
|
maxSchedulesHint: "\u5355\u4E2A\u4F1A\u8BDD\u5185\u5141\u8BB8\u521B\u5EFA\u7684\u6700\u5927\u5B9A\u65F6\u4EFB\u52A1\u6570\u91CF\u3002",
|
|
2282
2905
|
smartWindowHint: "\u7528\u4E8E\u300C\u5DE5\u4F5C\u65F6\u95F4\u300D\u82AF\u7247\u4E0E\u667A\u80FD\u6A21\u5F0F\u81EA\u52A8\u6392\u671F\u3002",
|
|
@@ -2285,6 +2908,24 @@ function apply(ctx) {
|
|
|
2285
2908
|
lunchStartLabel: "\u5348\u4F11\u5F00\u59CB",
|
|
2286
2909
|
lunchEndLabel: "\u5348\u4F11\u7ED3\u675F",
|
|
2287
2910
|
eveningEndLabel: "\u591C\u95F4\u9759\u9ED8\u8D77\u70B9",
|
|
2911
|
+
steerDeliveryLabel: "\u63D2\u8BDD\u6295\u9012\u65B9\u5F0F",
|
|
2912
|
+
steerDeliveryHint: "\u300C\u63D2\u8BDD\u53D1\u9001\u300D\u628A\u63D0\u9192\u5185\u5BB9\u63A8\u7ED9\u4F1A\u8BDD\u65F6\u8FDB\u5165\u7684\u961F\u5217\u3002",
|
|
2913
|
+
steerDeliveryOption_followup: "\u72EC\u7ACB\u6210\u4E00\u8F6E\uFF08\u63A8\u8350\uFF09",
|
|
2914
|
+
steerDeliveryOption_steer: "\u63D2\u5165\u5F53\u524D\u56DE\u5408\uFF08\u66F4\u5FEB\uFF09",
|
|
2915
|
+
confirmDeliveryLabel: "\u6295\u9012\u786E\u8BA4",
|
|
2916
|
+
confirmDeliveryHint: "\u6295\u9012\u540E\u6838\u5BF9\u4F1A\u8BDD\u65E5\u5FD7\uFF0C\u786E\u8BA4\u6D88\u606F\u771F\u6B63\u8FDB\u5165\u8BF7\u6C42\u3002\u5173\u95ED\u5219\u4E0D\u518D\u6838\u5BF9\uFF0C\u4E5F\u4E0D\u4FDD\u8BC1\u9001\u8FBE\u3002",
|
|
2917
|
+
onUnconfirmedLabel: "\u672A\u786E\u8BA4\u65F6",
|
|
2918
|
+
onUnconfirmedHint: "\u6295\u9012\u672A\u80FD\u786E\u8BA4\u65F6\u7684\u5904\u7406\u65B9\u5F0F\u3002",
|
|
2919
|
+
onUnconfirmedOption_keep: "\u4FDD\u7559\u6761\u76EE\u53EF\u91CD\u8BD5\uFF08\u63A8\u8350\uFF09",
|
|
2920
|
+
onUnconfirmedOption_discard: "\u4E22\u5F03",
|
|
2921
|
+
clockIconStyleLabel: "\u65F6\u949F\u56FE\u6807\u98CE\u683C",
|
|
2922
|
+
clockIconStyleHint: "\u4FA7\u680F\u4F1A\u8BDD\u884C\u5B9A\u65F6\u72B6\u6001\u56FE\u6807\u7684\u663E\u793A\u98CE\u683C\u3002",
|
|
2923
|
+
clockIconStyleOption_auto: "\u81EA\u52A8\uFF08\u63A8\u8350\uFF09",
|
|
2924
|
+
clockIconStyleOption_modern: "\u65B0\u7248\u63CF\u8FB9\u98CE\u683C",
|
|
2925
|
+
clockIconStyleOption_classic: "\u65E7\u7248\u70B9\u9635\u98CE\u683C",
|
|
2926
|
+
steerRiskGuarded: "\u26A0 \u649E\u4E0A\u56DE\u5408\u542F\u52A8\u65F6\u53EF\u80FD\u88AB\u541E\u6389\uFF1B\u5DF2\u5F00\u542F\u6295\u9012\u786E\u8BA4\uFF0C\u672A\u9001\u8FBE\u4F1A\u4FDD\u7559\u6761\u76EE\u5E76\u53EF\u91CD\u8BD5\u3002",
|
|
2927
|
+
steerRiskUnguarded: "\u26A0 \u649E\u4E0A\u56DE\u5408\u542F\u52A8\u65F6\u53EF\u80FD\u88AB\u541E\u6389\uFF0C\u4E14\u4E0D\u4F1A\u4FDD\u7559\u6761\u76EE\uFF08\u6295\u9012\u786E\u8BA4\u5DF2\u5173\u95ED\uFF09\u3002",
|
|
2928
|
+
discardRisk: "\u26A0 \u672A\u786E\u8BA4\u7684\u63D0\u9192\u4F1A\u88AB\u79FB\u51FA\u5217\u8868 \u2014\u2014 \u9759\u9ED8\u4E22\u5931\u5C06\u91CD\u65B0\u53D8\u5F97\u53EF\u80FD\u3002",
|
|
2288
2929
|
overriddenLabel: "\u5DF2\u8986\u76D6",
|
|
2289
2930
|
resetLabel: "\u91CD\u7F6E",
|
|
2290
2931
|
invalidLabel: "\u8BF7\u8F93\u5165\u6709\u6548\u7684\u6570\u5B57\u3002",
|
|
@@ -2303,10 +2944,11 @@ function apply(ctx) {
|
|
|
2303
2944
|
expand: "Show settings",
|
|
2304
2945
|
collapse: "Hide settings",
|
|
2305
2946
|
readOnly: "Settings for this deployment are read-only.",
|
|
2947
|
+
sectionDisplay: "Display",
|
|
2948
|
+
sectionTime: "Time windows",
|
|
2949
|
+
sectionDelivery: "Delivery",
|
|
2306
2950
|
showButtonLabel: "Show schedule button",
|
|
2307
2951
|
showButtonHint: "Hide the clock button on the input bar. Existing reminders keep firing and stay visible in the dock below the composer.",
|
|
2308
|
-
optionOn: "Show",
|
|
2309
|
-
optionOff: "Hide",
|
|
2310
2952
|
maxSchedulesLabel: "Max schedules per session",
|
|
2311
2953
|
maxSchedulesHint: "Maximum number of scheduled reminders allowed per session.",
|
|
2312
2954
|
smartWindowHint: "Used by the Work-hours chip and smart auto-scheduling.",
|
|
@@ -2315,6 +2957,24 @@ function apply(ctx) {
|
|
|
2315
2957
|
lunchStartLabel: "Lunch break start",
|
|
2316
2958
|
lunchEndLabel: "Lunch break end",
|
|
2317
2959
|
eveningEndLabel: "Night quiet starts at",
|
|
2960
|
+
steerDeliveryLabel: "Interject delivery",
|
|
2961
|
+
steerDeliveryHint: 'Which queue the reminder content enters when you press "Send interjection".',
|
|
2962
|
+
steerDeliveryOption_followup: "Own turn (recommended)",
|
|
2963
|
+
steerDeliveryOption_steer: "Current turn (faster)",
|
|
2964
|
+
confirmDeliveryLabel: "Confirm delivery",
|
|
2965
|
+
confirmDeliveryHint: "After sending, check the session log to confirm the message actually entered a request. Turning this off skips the check and no longer guarantees delivery.",
|
|
2966
|
+
onUnconfirmedLabel: "When unconfirmed",
|
|
2967
|
+
onUnconfirmedHint: "What to do when delivery cannot be confirmed.",
|
|
2968
|
+
onUnconfirmedOption_keep: "Keep for retry (recommended)",
|
|
2969
|
+
onUnconfirmedOption_discard: "Discard",
|
|
2970
|
+
clockIconStyleLabel: "Clock icon style",
|
|
2971
|
+
clockIconStyleHint: "Display style of the schedule status icon in the sidebar.",
|
|
2972
|
+
clockIconStyleOption_auto: "Auto (recommended)",
|
|
2973
|
+
clockIconStyleOption_modern: "Modern stroke style",
|
|
2974
|
+
clockIconStyleOption_classic: "Classic dot-matrix style",
|
|
2975
|
+
steerRiskGuarded: "\u26A0 May be swallowed when it collides with turn start; delivery confirmation is on, so an undelivered reminder is kept and can be retried.",
|
|
2976
|
+
steerRiskUnguarded: "\u26A0 May be swallowed when it collides with turn start, and the reminder will NOT be kept (delivery confirmation is off).",
|
|
2977
|
+
discardRisk: "\u26A0 Unconfirmed reminders are removed from the list \u2014 silent loss becomes possible again.",
|
|
2318
2978
|
overriddenLabel: "Overridden",
|
|
2319
2979
|
resetLabel: "Reset",
|
|
2320
2980
|
invalidLabel: "Please enter a valid number.",
|
|
@@ -2331,27 +2991,14 @@ function apply(ctx) {
|
|
|
2331
2991
|
const callCommand = async (sessionId, line) => {
|
|
2332
2992
|
const actx = sessions.scope(sessionId);
|
|
2333
2993
|
const face = actx === void 0 ? void 0 : sessions.sessionOf(actx);
|
|
2334
|
-
if (face === void 0) return false;
|
|
2994
|
+
if (face === void 0) return { matched: false };
|
|
2335
2995
|
try {
|
|
2336
2996
|
const result = await face.command(line);
|
|
2337
|
-
return result?.ok === true && result.value?.matched === true;
|
|
2997
|
+
return { matched: result?.ok === true && result.value?.matched === true };
|
|
2338
2998
|
} catch {
|
|
2339
|
-
return false;
|
|
2999
|
+
return { matched: false };
|
|
2340
3000
|
}
|
|
2341
3001
|
};
|
|
2342
|
-
const schedulerScope = settingsScope === void 0 ? void 0 : settingsScope.bind({ namespace: SETTINGS_NS });
|
|
2343
|
-
ctx.slots.inject(
|
|
2344
|
-
INPUT_RIGHT_SLOT,
|
|
2345
|
-
() => ctx.slots.register(
|
|
2346
|
-
{
|
|
2347
|
-
name: INPUT_RIGHT_SLOT,
|
|
2348
|
-
id: "later",
|
|
2349
|
-
order: 50,
|
|
2350
|
-
inject: () => ({ callCommand, locale, schedulerScope })
|
|
2351
|
-
},
|
|
2352
|
-
SchedButton
|
|
2353
|
-
)
|
|
2354
|
-
);
|
|
2355
3002
|
ctx.slots.inject(
|
|
2356
3003
|
"conversation.input.dock",
|
|
2357
3004
|
() => ctx.slots.register(
|
|
@@ -2364,19 +3011,74 @@ function apply(ctx) {
|
|
|
2364
3011
|
ScheduleDock
|
|
2365
3012
|
)
|
|
2366
3013
|
);
|
|
2367
|
-
|
|
2368
|
-
|
|
2369
|
-
|
|
2370
|
-
|
|
2371
|
-
|
|
2372
|
-
|
|
2373
|
-
|
|
2374
|
-
|
|
2375
|
-
|
|
2376
|
-
|
|
2377
|
-
|
|
2378
|
-
|
|
2379
|
-
|
|
3014
|
+
let composerMounted = false;
|
|
3015
|
+
const mountComposer = (scope) => {
|
|
3016
|
+
if (composerMounted) return;
|
|
3017
|
+
composerMounted = true;
|
|
3018
|
+
ctx.slots.inject(
|
|
3019
|
+
INPUT_RIGHT_SLOT,
|
|
3020
|
+
() => ctx.slots.register(
|
|
3021
|
+
{
|
|
3022
|
+
name: INPUT_RIGHT_SLOT,
|
|
3023
|
+
id: "later",
|
|
3024
|
+
order: 50,
|
|
3025
|
+
inject: () => ({ callCommand, locale, schedulerScope: scope })
|
|
3026
|
+
},
|
|
3027
|
+
SchedButton
|
|
3028
|
+
)
|
|
3029
|
+
);
|
|
3030
|
+
};
|
|
3031
|
+
const cardT = locale === void 0 ? void 0 : locale.bind(NS);
|
|
3032
|
+
const cardDeclaration = (slot, scope) => ({
|
|
3033
|
+
name: slot,
|
|
3034
|
+
key: SETTINGS_NS,
|
|
3035
|
+
locale: NS,
|
|
3036
|
+
inject: () => ({ scope, t: cardT })
|
|
3037
|
+
});
|
|
3038
|
+
ctx.inject(["settingsScope"], () => {
|
|
3039
|
+
const binder = ctx.get("settingsScope");
|
|
3040
|
+
if (binder === void 0) return;
|
|
3041
|
+
detectedVersion = "classic";
|
|
3042
|
+
const scope = binder.bind({ namespace: SETTINGS_NS });
|
|
3043
|
+
getClockIconStyle = () => {
|
|
3044
|
+
const snap = scope.getSnapshot();
|
|
3045
|
+
if (snap.status !== "ready") return "auto";
|
|
3046
|
+
const value = snap.value ?? {};
|
|
3047
|
+
const style = value["clockIconStyle"];
|
|
3048
|
+
return style === "modern" || style === "classic" ? style : "auto";
|
|
3049
|
+
};
|
|
3050
|
+
mountComposer(scope);
|
|
3051
|
+
if (cardT === void 0) return;
|
|
3052
|
+
ctx.slots.inject(
|
|
3053
|
+
"settings.plugin.item",
|
|
3054
|
+
() => ctx.slots.register(cardDeclaration("settings.plugin.item", scope), SchedulerSettingsCard)
|
|
3055
|
+
);
|
|
3056
|
+
});
|
|
3057
|
+
ctx.inject(["configForms"], () => {
|
|
3058
|
+
const forms = ctx.get("configForms");
|
|
3059
|
+
if (forms === void 0 || typeof forms.get !== "function" || typeof forms.whileServed !== "function") return;
|
|
3060
|
+
detectedVersion = "modern";
|
|
3061
|
+
const scope = forms.get(ENTRY_ID);
|
|
3062
|
+
getClockIconStyle = () => {
|
|
3063
|
+
const snap = scope.getSnapshot();
|
|
3064
|
+
if (snap.status !== "ready") return "auto";
|
|
3065
|
+
const value = snap.value ?? {};
|
|
3066
|
+
const style = value["clockIconStyle"];
|
|
3067
|
+
return style === "modern" || style === "classic" ? style : "auto";
|
|
3068
|
+
};
|
|
3069
|
+
mountComposer(scope);
|
|
3070
|
+
if (cardT === void 0) return;
|
|
3071
|
+
ctx.effect(
|
|
3072
|
+
() => forms.whileServed(
|
|
3073
|
+
[ENTRY_ID],
|
|
3074
|
+
() => ctx.slots.inject(
|
|
3075
|
+
"plugins.bundle.config",
|
|
3076
|
+
() => ctx.slots.register(cardDeclaration("plugins.bundle.config", scope), SchedulerSettingsCard)
|
|
3077
|
+
)
|
|
3078
|
+
),
|
|
3079
|
+
"dsh-later: plugins-page card"
|
|
3080
|
+
);
|
|
3081
|
+
});
|
|
2380
3082
|
}
|
|
2381
3083
|
|
|
2382
3084
|
return module.exports;
|