@goodandready/dsh-goal 0.1.4 → 0.1.6
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/docs/design/DESIGN.md +16 -0
- package/lib/client.js +439 -216
- package/lib/goal-engine.js +643 -536
- package/lib/index.js +122 -6
- package/package.json +1 -1
package/lib/client.js
CHANGED
|
@@ -3,7 +3,7 @@ window.__ModuleLoader__.load({
|
|
|
3
3
|
factory: (require) => {
|
|
4
4
|
const module = { exports: {} };
|
|
5
5
|
const React = require('react');
|
|
6
|
-
const { useState, useEffect, useRef, useCallback } = React;
|
|
6
|
+
const { useState, useEffect, useRef, useCallback, useMemo } = React;
|
|
7
7
|
|
|
8
8
|
const NS = 'dsh-goal';
|
|
9
9
|
|
|
@@ -108,7 +108,6 @@ window.__ModuleLoader__.load({
|
|
|
108
108
|
strokeWidth: 2.5,
|
|
109
109
|
strokeLinecap: 'round',
|
|
110
110
|
strokeLinejoin: 'round',
|
|
111
|
-
style: { color: 'var(--dsw-alias-status-success)' },
|
|
112
111
|
className,
|
|
113
112
|
},
|
|
114
113
|
React.createElement('polyline', { points: '20 6 9 17 4 12' }),
|
|
@@ -173,7 +172,7 @@ window.__ModuleLoader__.load({
|
|
|
173
172
|
);
|
|
174
173
|
}
|
|
175
174
|
|
|
176
|
-
// --- СТИЛИ И CSS ПРАВИЛА (
|
|
175
|
+
// --- СТИЛИ И CSS ПРАВИЛА (СТАНДАРТ DSH-CLINEBOT & ДИЗАЙН-СИСТЕМА DSH) ---
|
|
177
176
|
const CSS_STYLES = `
|
|
178
177
|
.dsh-goal-dock {
|
|
179
178
|
box-sizing: border-box;
|
|
@@ -189,16 +188,23 @@ window.__ModuleLoader__.load({
|
|
|
189
188
|
display: flex;
|
|
190
189
|
align-items: center;
|
|
191
190
|
justify-content: space-between;
|
|
192
|
-
background: var(--dsw-alias-bg-layer-
|
|
191
|
+
background: var(--dsw-alias-bg-layer-3);
|
|
193
192
|
border: 1px solid var(--dsw-alias-border-l2);
|
|
194
193
|
border-radius: 12px;
|
|
195
|
-
padding:
|
|
194
|
+
padding: 7px 14px;
|
|
196
195
|
font-family: inherit;
|
|
197
196
|
font-size: 13px;
|
|
198
197
|
color: var(--dsw-alias-label-primary);
|
|
199
198
|
user-select: none;
|
|
200
199
|
box-shadow: 0 1px 4px rgba(0, 0, 0, 0.08);
|
|
201
|
-
transition: all 0.
|
|
200
|
+
transition: all 0.15s ease;
|
|
201
|
+
}
|
|
202
|
+
.dsh-goal-banner:hover {
|
|
203
|
+
border-color: var(--dsw-alias-label-tertiary);
|
|
204
|
+
}
|
|
205
|
+
.dsh-goal-banner.completed {
|
|
206
|
+
border-color: var(--dsw-alias-state-success-primary);
|
|
207
|
+
background: var(--dsw-alias-bg-layer-3);
|
|
202
208
|
}
|
|
203
209
|
.dsh-goal-left {
|
|
204
210
|
display: flex;
|
|
@@ -213,13 +219,36 @@ window.__ModuleLoader__.load({
|
|
|
213
219
|
display: flex;
|
|
214
220
|
align-items: center;
|
|
215
221
|
}
|
|
222
|
+
.dsh-goal-badge {
|
|
223
|
+
font-size: 11px;
|
|
224
|
+
padding: 2px 8px;
|
|
225
|
+
border-radius: 999px;
|
|
226
|
+
border: 1px solid var(--dsw-alias-border-l2);
|
|
227
|
+
display: inline-flex;
|
|
228
|
+
align-items: center;
|
|
229
|
+
gap: 4px;
|
|
230
|
+
font-weight: 600;
|
|
231
|
+
white-space: nowrap;
|
|
232
|
+
background: var(--dsw-alias-bg-layer-2);
|
|
233
|
+
color: var(--dsw-alias-label-primary);
|
|
234
|
+
}
|
|
235
|
+
.dsh-goal-badge-ok {
|
|
236
|
+
border-color: var(--dsw-alias-state-success-primary);
|
|
237
|
+
color: var(--dsw-alias-state-success-primary);
|
|
238
|
+
background: rgba(16, 185, 129, 0.08);
|
|
239
|
+
}
|
|
240
|
+
.dsh-goal-badge-warn {
|
|
241
|
+
border-color: var(--dsw-alias-state-warning-primary);
|
|
242
|
+
color: var(--dsw-alias-state-warning-primary);
|
|
243
|
+
background: rgba(245, 158, 11, 0.08);
|
|
244
|
+
}
|
|
216
245
|
.dsh-goal-label {
|
|
217
246
|
font-weight: 600;
|
|
218
247
|
color: var(--dsw-alias-label-primary);
|
|
219
248
|
white-space: nowrap;
|
|
220
249
|
}
|
|
221
250
|
.dsh-goal-label.completed {
|
|
222
|
-
color: var(--dsw-alias-
|
|
251
|
+
color: var(--dsw-alias-state-success-primary);
|
|
223
252
|
}
|
|
224
253
|
.dsh-goal-title {
|
|
225
254
|
color: var(--dsw-alias-label-secondary);
|
|
@@ -249,21 +278,38 @@ window.__ModuleLoader__.load({
|
|
|
249
278
|
flex-shrink: 0;
|
|
250
279
|
}
|
|
251
280
|
.dsh-goal-btn {
|
|
252
|
-
|
|
253
|
-
|
|
254
|
-
|
|
281
|
+
appearance: none;
|
|
282
|
+
font: inherit;
|
|
283
|
+
background: var(--dsw-alias-bg-layer-2);
|
|
284
|
+
border: 1px solid var(--dsw-alias-border-l2);
|
|
285
|
+
padding: 5px 8px;
|
|
255
286
|
margin: 0;
|
|
256
|
-
color: var(--dsw-alias-label-
|
|
287
|
+
color: var(--dsw-alias-label-primary);
|
|
257
288
|
cursor: pointer;
|
|
258
|
-
display: flex;
|
|
289
|
+
display: inline-flex;
|
|
259
290
|
align-items: center;
|
|
260
291
|
justify-content: center;
|
|
261
|
-
|
|
292
|
+
gap: 5px;
|
|
293
|
+
border-radius: 8px;
|
|
294
|
+
font-size: 12px;
|
|
295
|
+
font-weight: 500;
|
|
262
296
|
transition: all 0.15s ease;
|
|
263
297
|
}
|
|
264
|
-
.dsh-goal-btn:hover {
|
|
298
|
+
.dsh-goal-btn:hover:not(:disabled) {
|
|
299
|
+
background: var(--dsw-alias-bg-layer-4, var(--dsw-alias-bg-layer-2));
|
|
300
|
+
border-color: var(--dsw-alias-label-dimmed, var(--dsw-alias-border-l2));
|
|
301
|
+
}
|
|
302
|
+
.dsh-goal-btn.icon-only {
|
|
303
|
+
padding: 4px 6px;
|
|
304
|
+
border-radius: 6px;
|
|
305
|
+
border-color: transparent;
|
|
306
|
+
background: transparent;
|
|
307
|
+
color: var(--dsw-alias-label-tertiary);
|
|
308
|
+
}
|
|
309
|
+
.dsh-goal-btn.icon-only:hover {
|
|
265
310
|
color: var(--dsw-alias-label-primary);
|
|
266
|
-
background: var(--dsw-alias-bg-layer-
|
|
311
|
+
background: var(--dsw-alias-bg-layer-2);
|
|
312
|
+
border-color: var(--dsw-alias-border-l2);
|
|
267
313
|
}
|
|
268
314
|
.dsh-goal-btn.close {
|
|
269
315
|
font-size: 13px;
|
|
@@ -271,10 +317,23 @@ window.__ModuleLoader__.load({
|
|
|
271
317
|
padding: 3px 6px;
|
|
272
318
|
}
|
|
273
319
|
.dsh-goal-btn.close:hover {
|
|
274
|
-
color: var(--dsw-alias-
|
|
320
|
+
color: var(--dsw-alias-state-error-primary);
|
|
321
|
+
}
|
|
322
|
+
.dsh-goal-btn-primary {
|
|
323
|
+
background: var(--dsw-alias-label-primary);
|
|
324
|
+
color: var(--dsw-alias-bg-layer-3);
|
|
325
|
+
border-color: transparent;
|
|
326
|
+
}
|
|
327
|
+
.dsh-goal-btn-primary:hover:not(:disabled) {
|
|
328
|
+
opacity: 0.88;
|
|
329
|
+
}
|
|
330
|
+
.dsh-goal-btn-danger {
|
|
331
|
+
color: var(--dsw-alias-state-error-primary);
|
|
332
|
+
border-color: rgba(239, 68, 68, 0.3);
|
|
275
333
|
}
|
|
276
|
-
.dsh-goal-btn
|
|
277
|
-
|
|
334
|
+
.dsh-goal-btn-danger:hover:not(:disabled) {
|
|
335
|
+
background: rgba(239, 68, 68, 0.12) !important;
|
|
336
|
+
border-color: rgba(239, 68, 68, 0.5);
|
|
278
337
|
}
|
|
279
338
|
|
|
280
339
|
/* Modal Details */
|
|
@@ -292,7 +351,7 @@ window.__ModuleLoader__.load({
|
|
|
292
351
|
background: var(--dsw-alias-bg-layer-3);
|
|
293
352
|
border: 1px solid var(--dsw-alias-border-l2);
|
|
294
353
|
border-radius: 12px;
|
|
295
|
-
width:
|
|
354
|
+
width: 560px;
|
|
296
355
|
max-width: 90vw;
|
|
297
356
|
max-height: 80vh;
|
|
298
357
|
display: flex;
|
|
@@ -300,48 +359,81 @@ window.__ModuleLoader__.load({
|
|
|
300
359
|
box-shadow: 0 16px 36px rgba(0, 0, 0, 0.4);
|
|
301
360
|
}
|
|
302
361
|
.dsh-goal-modal-head {
|
|
303
|
-
padding:
|
|
362
|
+
padding: 16px 20px;
|
|
304
363
|
border-bottom: 1px solid var(--dsw-alias-border-l2);
|
|
305
364
|
display: flex;
|
|
306
365
|
align-items: center;
|
|
307
366
|
justify-content: space-between;
|
|
308
367
|
}
|
|
309
368
|
.dsh-goal-modal-title {
|
|
310
|
-
font-size:
|
|
369
|
+
font-size: 16px;
|
|
311
370
|
font-weight: 600;
|
|
312
371
|
color: var(--dsw-alias-label-primary);
|
|
372
|
+
display: flex;
|
|
373
|
+
align-items: center;
|
|
374
|
+
gap: 8px;
|
|
313
375
|
}
|
|
314
376
|
.dsh-goal-modal-body {
|
|
315
|
-
padding:
|
|
377
|
+
padding: 18px 20px;
|
|
316
378
|
overflow-y: auto;
|
|
317
379
|
display: flex;
|
|
318
380
|
flex-direction: column;
|
|
319
|
-
gap:
|
|
381
|
+
gap: 14px;
|
|
382
|
+
}
|
|
383
|
+
.dsh-goal-stat-grid {
|
|
384
|
+
display: grid;
|
|
385
|
+
grid-template-columns: repeat(auto-fit, minmax(130px, 1fr));
|
|
386
|
+
gap: 10px;
|
|
387
|
+
}
|
|
388
|
+
.dsh-goal-stat-box {
|
|
389
|
+
padding: 10px 12px;
|
|
390
|
+
border: 1px solid var(--dsw-alias-border-l2);
|
|
391
|
+
border-radius: 8px;
|
|
392
|
+
background: var(--dsw-alias-bg-layer-2);
|
|
393
|
+
display: flex;
|
|
394
|
+
flex-direction: column;
|
|
395
|
+
gap: 2px;
|
|
396
|
+
}
|
|
397
|
+
.dsh-goal-stat-val {
|
|
398
|
+
font-size: 16px;
|
|
399
|
+
font-weight: 700;
|
|
400
|
+
color: var(--dsw-alias-label-primary);
|
|
401
|
+
}
|
|
402
|
+
.dsh-goal-stat-lbl {
|
|
403
|
+
font-size: 11px;
|
|
404
|
+
color: var(--dsw-alias-label-secondary);
|
|
320
405
|
}
|
|
321
406
|
.dsh-goal-milestone-item {
|
|
322
407
|
display: flex;
|
|
323
408
|
align-items: flex-start;
|
|
324
409
|
gap: 10px;
|
|
325
|
-
padding:
|
|
410
|
+
padding: 10px 12px;
|
|
326
411
|
border-radius: 8px;
|
|
327
412
|
background: var(--dsw-alias-bg-layer-2);
|
|
413
|
+
border: 1px solid var(--dsw-alias-border-l2);
|
|
328
414
|
font-size: 13px;
|
|
415
|
+
transition: all 0.15s ease;
|
|
329
416
|
}
|
|
330
417
|
.dsh-goal-modal-foot {
|
|
331
|
-
padding:
|
|
418
|
+
padding: 14px 20px;
|
|
332
419
|
border-top: 1px solid var(--dsw-alias-border-l2);
|
|
333
420
|
display: flex;
|
|
334
421
|
justify-content: flex-end;
|
|
335
|
-
|
|
422
|
+
align-items: center;
|
|
423
|
+
gap: 10px;
|
|
336
424
|
}
|
|
337
425
|
|
|
338
|
-
/* Settings Card */
|
|
426
|
+
/* Settings Card (clinebot pattern) */
|
|
339
427
|
.dsh-goal-card {
|
|
340
428
|
border: 1px solid var(--dsw-alias-border-l2);
|
|
341
429
|
background: var(--dsw-alias-bg-layer-3);
|
|
342
430
|
border-radius: 12px;
|
|
343
431
|
list-style: none;
|
|
344
|
-
margin-bottom:
|
|
432
|
+
margin-bottom: 12px;
|
|
433
|
+
transition: border-color 0.15s ease;
|
|
434
|
+
}
|
|
435
|
+
.dsh-goal-card:hover {
|
|
436
|
+
border-color: var(--dsw-alias-label-tertiary);
|
|
345
437
|
}
|
|
346
438
|
.dsh-goal-card-head {
|
|
347
439
|
appearance: none;
|
|
@@ -350,13 +442,13 @@ window.__ModuleLoader__.load({
|
|
|
350
442
|
color: inherit;
|
|
351
443
|
text-align: left;
|
|
352
444
|
cursor: pointer;
|
|
353
|
-
background:
|
|
445
|
+
background: transparent;
|
|
354
446
|
border: 0;
|
|
355
447
|
border-radius: 12px;
|
|
356
448
|
display: flex;
|
|
357
449
|
align-items: center;
|
|
358
450
|
gap: 12px;
|
|
359
|
-
padding:
|
|
451
|
+
padding: 16px 20px;
|
|
360
452
|
}
|
|
361
453
|
.dsh-goal-card-title {
|
|
362
454
|
color: var(--dsw-alias-label-primary);
|
|
@@ -370,14 +462,16 @@ window.__ModuleLoader__.load({
|
|
|
370
462
|
}
|
|
371
463
|
.dsh-goal-card-body {
|
|
372
464
|
border-top: 1px solid var(--dsw-alias-border-l2);
|
|
373
|
-
margin: 0
|
|
374
|
-
padding
|
|
465
|
+
margin: 0 20px;
|
|
466
|
+
padding: 16px 0 16px;
|
|
467
|
+
display: flex;
|
|
468
|
+
flex-direction: column;
|
|
469
|
+
gap: 14px;
|
|
375
470
|
}
|
|
376
471
|
.dsh-goal-card-field {
|
|
377
472
|
display: flex;
|
|
378
473
|
flex-direction: column;
|
|
379
474
|
gap: 6px;
|
|
380
|
-
padding: 12px 0;
|
|
381
475
|
}
|
|
382
476
|
.dsh-goal-field-label-row {
|
|
383
477
|
display: flex;
|
|
@@ -385,6 +479,7 @@ window.__ModuleLoader__.load({
|
|
|
385
479
|
justify-content: space-between;
|
|
386
480
|
font-size: 13px;
|
|
387
481
|
font-weight: 500;
|
|
482
|
+
color: var(--dsw-alias-label-primary);
|
|
388
483
|
}
|
|
389
484
|
.dsh-goal-field-meta {
|
|
390
485
|
display: flex;
|
|
@@ -395,28 +490,35 @@ window.__ModuleLoader__.load({
|
|
|
395
490
|
}
|
|
396
491
|
.dsh-goal-override-tag {
|
|
397
492
|
font-size: 11px;
|
|
398
|
-
padding:
|
|
493
|
+
padding: 2px 6px;
|
|
399
494
|
border-radius: 4px;
|
|
400
495
|
background: var(--dsw-alias-bg-layer-2);
|
|
401
496
|
color: var(--dsw-alias-label-secondary);
|
|
497
|
+
border: 1px solid var(--dsw-alias-border-l2);
|
|
402
498
|
}
|
|
403
499
|
.dsh-goal-card-input {
|
|
404
|
-
height:
|
|
500
|
+
height: 36px;
|
|
405
501
|
border: 1px solid var(--dsw-alias-border-l2);
|
|
406
|
-
background: var(--dsw-alias-bg-layer-
|
|
502
|
+
background: var(--dsw-alias-bg-layer-2);
|
|
407
503
|
color: var(--dsw-alias-label-primary);
|
|
408
504
|
border-radius: 8px;
|
|
409
505
|
padding: 0 12px;
|
|
410
506
|
font-size: 13px;
|
|
507
|
+
width: 100%;
|
|
508
|
+
box-sizing: border-box;
|
|
509
|
+
}
|
|
510
|
+
.dsh-goal-card-input:focus {
|
|
511
|
+
outline: none;
|
|
512
|
+
border-color: var(--dsw-alias-state-brand-primary);
|
|
411
513
|
}
|
|
412
514
|
.dsh-goal-card-input[aria-invalid="true"] {
|
|
413
|
-
border-color: var(--dsw-alias-
|
|
515
|
+
border-color: var(--dsw-alias-state-error-primary);
|
|
414
516
|
}
|
|
415
517
|
.dsh-goal-chev {
|
|
416
518
|
margin-left: auto;
|
|
417
519
|
flex: none;
|
|
418
520
|
color: var(--dsw-alias-label-tertiary);
|
|
419
|
-
transition: transform .16s;
|
|
521
|
+
transition: transform .16s ease;
|
|
420
522
|
}
|
|
421
523
|
.dsh-goal-chev-open {
|
|
422
524
|
transform: rotate(180deg);
|
|
@@ -425,7 +527,7 @@ window.__ModuleLoader__.load({
|
|
|
425
527
|
display: flex;
|
|
426
528
|
align-items: center;
|
|
427
529
|
justify-content: space-between;
|
|
428
|
-
padding:
|
|
530
|
+
padding: 6px 0;
|
|
429
531
|
}
|
|
430
532
|
.dsh-goal-check {
|
|
431
533
|
display: flex;
|
|
@@ -440,11 +542,11 @@ window.__ModuleLoader__.load({
|
|
|
440
542
|
display: flex;
|
|
441
543
|
justify-content: flex-end;
|
|
442
544
|
align-items: center;
|
|
443
|
-
gap:
|
|
444
|
-
padding:
|
|
545
|
+
gap: 10px;
|
|
546
|
+
padding: 14px 0 4px;
|
|
445
547
|
}
|
|
446
548
|
.dsh-goal-foot-note {
|
|
447
|
-
color: var(--dsw-alias-
|
|
549
|
+
color: var(--dsw-alias-state-error-primary);
|
|
448
550
|
font-size: 12px;
|
|
449
551
|
margin-right: auto;
|
|
450
552
|
}
|
|
@@ -452,7 +554,7 @@ window.__ModuleLoader__.load({
|
|
|
452
554
|
background: transparent;
|
|
453
555
|
border: 0;
|
|
454
556
|
cursor: pointer;
|
|
455
|
-
padding: 2px
|
|
557
|
+
padding: 2px 6px;
|
|
456
558
|
display: flex;
|
|
457
559
|
align-items: center;
|
|
458
560
|
gap: 4px;
|
|
@@ -470,19 +572,19 @@ window.__ModuleLoader__.load({
|
|
|
470
572
|
cursor: pointer;
|
|
471
573
|
border: 1px solid var(--dsw-alias-border-l2);
|
|
472
574
|
border-radius: 8px;
|
|
473
|
-
padding:
|
|
575
|
+
padding: 6px 14px;
|
|
474
576
|
font-size: 13px;
|
|
475
|
-
background:
|
|
476
|
-
color: var(--dsw-alias-label-
|
|
577
|
+
background: var(--dsw-alias-bg-layer-2);
|
|
578
|
+
color: var(--dsw-alias-label-primary);
|
|
477
579
|
transition: all 0.15s ease;
|
|
478
580
|
}
|
|
479
581
|
.dsh-goal-discard:hover:not(:disabled) {
|
|
480
|
-
|
|
481
|
-
|
|
582
|
+
background: var(--dsw-alias-bg-layer-4, var(--dsw-alias-bg-layer-2));
|
|
583
|
+
border-color: var(--dsw-alias-label-dimmed, var(--dsw-alias-border-l2));
|
|
482
584
|
}
|
|
483
585
|
.dsh-goal-discard:disabled {
|
|
484
586
|
opacity: 0.4;
|
|
485
|
-
cursor:
|
|
587
|
+
cursor: not-allowed;
|
|
486
588
|
}
|
|
487
589
|
.dsh-goal-save {
|
|
488
590
|
appearance: none;
|
|
@@ -490,16 +592,19 @@ window.__ModuleLoader__.load({
|
|
|
490
592
|
cursor: pointer;
|
|
491
593
|
border: 1px solid transparent;
|
|
492
594
|
border-radius: 8px;
|
|
493
|
-
padding:
|
|
595
|
+
padding: 6px 16px;
|
|
494
596
|
font-size: 13px;
|
|
495
597
|
background: var(--dsw-alias-label-primary);
|
|
496
598
|
color: var(--dsw-alias-bg-layer-3);
|
|
497
599
|
font-weight: 500;
|
|
498
600
|
transition: opacity 0.15s ease;
|
|
499
601
|
}
|
|
602
|
+
.dsh-goal-save:hover:not(:disabled) {
|
|
603
|
+
opacity: 0.88;
|
|
604
|
+
}
|
|
500
605
|
.dsh-goal-save:disabled {
|
|
501
606
|
opacity: 0.4;
|
|
502
|
-
cursor:
|
|
607
|
+
cursor: not-allowed;
|
|
503
608
|
}
|
|
504
609
|
`;
|
|
505
610
|
|
|
@@ -508,10 +613,51 @@ window.__ModuleLoader__.load({
|
|
|
508
613
|
if (document.getElementById('dsh-goal-styles')) return;
|
|
509
614
|
const style = document.createElement('style');
|
|
510
615
|
style.id = 'dsh-goal-styles';
|
|
616
|
+
style.dataset.dshPlugin = NS;
|
|
511
617
|
style.textContent = CSS_STYLES;
|
|
512
618
|
document.head.appendChild(style);
|
|
513
619
|
}
|
|
514
620
|
|
|
621
|
+
|
|
622
|
+
// Синтез приятных звуковых колокольчиков через Web Audio API (Item 6)
|
|
623
|
+
function playGoalChime(isSuccess = true) {
|
|
624
|
+
if (typeof window === 'undefined') return;
|
|
625
|
+
try {
|
|
626
|
+
const AudioCtx = window.AudioContext || window.webkitAudioContext;
|
|
627
|
+
if (!AudioCtx) return;
|
|
628
|
+
const actx = new AudioCtx();
|
|
629
|
+
if (actx.state === 'suspended') {
|
|
630
|
+
actx.resume().catch(() => {});
|
|
631
|
+
}
|
|
632
|
+
const now = actx.currentTime;
|
|
633
|
+
// Пентатонические аккорды: успех — восходящий C5-E5-G5-C6; сбой/ошибка — нисходящий G4-Eb4-C4
|
|
634
|
+
const notes = isSuccess
|
|
635
|
+
? [523.25, 659.25, 783.99, 1046.50]
|
|
636
|
+
: [392.00, 311.13, 261.63];
|
|
637
|
+
|
|
638
|
+
notes.forEach((freq, idx) => {
|
|
639
|
+
const osc = actx.createOscillator();
|
|
640
|
+
const gain = actx.createGain();
|
|
641
|
+
osc.type = 'sine';
|
|
642
|
+
osc.frequency.setValueAtTime(freq, now + idx * 0.12);
|
|
643
|
+
|
|
644
|
+
gain.gain.setValueAtTime(0.001, now + idx * 0.12);
|
|
645
|
+
gain.gain.exponentialRampToValueAtTime(0.15, now + idx * 0.12 + 0.02);
|
|
646
|
+
gain.gain.exponentialRampToValueAtTime(0.0001, now + idx * 0.12 + 0.4);
|
|
647
|
+
|
|
648
|
+
osc.connect(gain);
|
|
649
|
+
gain.connect(actx.destination);
|
|
650
|
+
|
|
651
|
+
osc.start(now + idx * 0.12);
|
|
652
|
+
osc.stop(now + idx * 0.12 + 0.45);
|
|
653
|
+
});
|
|
654
|
+
|
|
655
|
+
setTimeout(() => {
|
|
656
|
+
try { actx.close(); } catch (_) {}
|
|
657
|
+
}, 2000);
|
|
658
|
+
} catch (_) {}
|
|
659
|
+
}
|
|
660
|
+
|
|
515
661
|
// --- МОДАЛЬНОЕ ОКНО ДЕТАЛЕЙ (MODAL DETAILS) ---
|
|
516
662
|
function GoalDetailsModal({ state, onClose, onAction, t }) {
|
|
517
663
|
if (!state) return null;
|
|
@@ -521,31 +667,31 @@ window.__ModuleLoader__.load({
|
|
|
521
667
|
|
|
522
668
|
return React.createElement(
|
|
523
669
|
'div',
|
|
524
|
-
{
|
|
525
|
-
className: 'dsh-goal-modal-overlay',
|
|
526
|
-
onClick: (e) => {
|
|
527
|
-
if (e.target === e.currentTarget) onClose();
|
|
528
|
-
},
|
|
529
|
-
},
|
|
670
|
+
{ className: 'dsh-goal-modal-overlay', onClick: onClose },
|
|
530
671
|
React.createElement(
|
|
531
672
|
'div',
|
|
532
|
-
{
|
|
673
|
+
{
|
|
674
|
+
className: 'dsh-goal-modal',
|
|
675
|
+
onClick: (e) => e.stopPropagation(),
|
|
676
|
+
},
|
|
533
677
|
React.createElement(
|
|
534
678
|
'div',
|
|
535
679
|
{ className: 'dsh-goal-modal-head' },
|
|
536
680
|
React.createElement(
|
|
537
681
|
'div',
|
|
538
|
-
{
|
|
539
|
-
isCompleted
|
|
540
|
-
|
|
541
|
-
|
|
542
|
-
|
|
543
|
-
isCompleted ? (t('modalTitleCompleted') || 'Цель выполнена: план и результаты') : (t('modalTitle') || 'План и статус цели'),
|
|
544
|
-
),
|
|
682
|
+
{ className: 'dsh-goal-modal-title' },
|
|
683
|
+
isCompleted
|
|
684
|
+
? React.createElement(IconCheck, { size: 18, className: 'cb-badge-ok' })
|
|
685
|
+
: React.createElement(IconTarget, { size: 18 }),
|
|
686
|
+
isCompleted ? (t('modalTitleCompleted') || 'Цель выполнена: план и результаты') : (t('modalTitle') || 'План и статус цели'),
|
|
545
687
|
),
|
|
546
688
|
React.createElement(
|
|
547
689
|
'button',
|
|
548
|
-
{
|
|
690
|
+
{
|
|
691
|
+
className: 'dsh-goal-btn icon-only close',
|
|
692
|
+
onClick: onClose,
|
|
693
|
+
title: t('close') || 'Закрыть',
|
|
694
|
+
},
|
|
549
695
|
'✕',
|
|
550
696
|
),
|
|
551
697
|
),
|
|
@@ -555,25 +701,42 @@ window.__ModuleLoader__.load({
|
|
|
555
701
|
React.createElement(
|
|
556
702
|
'div',
|
|
557
703
|
null,
|
|
558
|
-
React.createElement('div', { style: { fontWeight: 600, fontSize:
|
|
559
|
-
state.description ? React.createElement('div', { style: { color: 'var(--dsw-alias-label-secondary)', fontSize: 13, marginBottom: 4 } }, state.description) : null,
|
|
704
|
+
React.createElement('div', { style: { fontWeight: 600, fontSize: 16, marginBottom: 4, color: 'var(--dsw-alias-label-primary)' } }, state.title),
|
|
705
|
+
state.description ? React.createElement('div', { style: { color: 'var(--dsw-alias-label-secondary)', fontSize: 13, marginBottom: 6, lineHeight: 1.4 } }, state.description) : null,
|
|
560
706
|
),
|
|
561
707
|
React.createElement(
|
|
562
708
|
'div',
|
|
563
|
-
{
|
|
564
|
-
React.createElement(
|
|
709
|
+
{ className: 'dsh-goal-stat-grid' },
|
|
710
|
+
React.createElement(
|
|
711
|
+
'div',
|
|
712
|
+
{ className: 'dsh-goal-stat-box' },
|
|
713
|
+
React.createElement('span', { className: 'dsh-goal-stat-val' }, state.formattedElapsed || '0s'),
|
|
714
|
+
React.createElement('span', { className: 'dsh-goal-stat-lbl' }, t('time') || 'Время работы'),
|
|
715
|
+
),
|
|
716
|
+
React.createElement(
|
|
717
|
+
'div',
|
|
718
|
+
{ className: 'dsh-goal-stat-box' },
|
|
719
|
+
React.createElement('span', { className: 'dsh-goal-stat-val' }, `${state.iterationsCount || 0}/${state.maxIterations || 25}`),
|
|
720
|
+
React.createElement('span', { className: 'dsh-goal-stat-lbl' }, 'Итерации'),
|
|
721
|
+
),
|
|
722
|
+
React.createElement(
|
|
723
|
+
'div',
|
|
724
|
+
{ className: 'dsh-goal-stat-box' },
|
|
725
|
+
React.createElement('span', { className: 'dsh-goal-stat-val' }, `${state.progressPercent || 0}%`),
|
|
726
|
+
React.createElement('span', { className: 'dsh-goal-stat-lbl' }, 'Прогресс'),
|
|
727
|
+
),
|
|
565
728
|
),
|
|
566
729
|
React.createElement(
|
|
567
730
|
'div',
|
|
568
731
|
{ style: { display: 'flex', flexDirection: 'column', gap: 8, marginTop: 4 } },
|
|
569
|
-
React.createElement('div', { style: { fontWeight: 600, fontSize: 13 } }, t('milestones') || 'План работ:'),
|
|
732
|
+
React.createElement('div', { style: { fontWeight: 600, fontSize: 13, color: 'var(--dsw-alias-label-primary)' } }, t('milestones') || 'План работ:'),
|
|
570
733
|
milestones.length === 0
|
|
571
734
|
? React.createElement('div', { style: { color: 'var(--dsw-alias-label-tertiary)', fontSize: 12, padding: '8px 0' } }, t('noMilestones') || 'Агент формирует план работ...')
|
|
572
735
|
: milestones.map((m, i) =>
|
|
573
736
|
React.createElement(
|
|
574
737
|
'div',
|
|
575
738
|
{ key: m.id || i, className: 'dsh-goal-milestone-item' },
|
|
576
|
-
React.createElement('span', { style: { fontSize:
|
|
739
|
+
React.createElement('span', { style: { fontSize: 15 } }, m.status === 'completed' ? '✅' : m.status === 'in_progress' ? '🔄' : '⏳'),
|
|
577
740
|
React.createElement(
|
|
578
741
|
'div',
|
|
579
742
|
{ style: { flex: 1, minWidth: 0 } },
|
|
@@ -601,12 +764,11 @@ window.__ModuleLoader__.load({
|
|
|
601
764
|
? React.createElement(
|
|
602
765
|
'button',
|
|
603
766
|
{
|
|
604
|
-
className: 'dsh-goal-btn danger',
|
|
767
|
+
className: 'dsh-goal-btn dsh-goal-btn-danger',
|
|
605
768
|
onClick: () => {
|
|
606
769
|
onAction('clear');
|
|
607
770
|
onClose();
|
|
608
771
|
},
|
|
609
|
-
style: { padding: '6px 12px', fontSize: 13 },
|
|
610
772
|
},
|
|
611
773
|
t('closeBanner') || 'Закрыть плашку цели',
|
|
612
774
|
)
|
|
@@ -614,9 +776,8 @@ window.__ModuleLoader__.load({
|
|
|
614
776
|
React.createElement(
|
|
615
777
|
'button',
|
|
616
778
|
{
|
|
617
|
-
className: 'dsh-goal-
|
|
779
|
+
className: 'dsh-goal-btn dsh-goal-btn-primary',
|
|
618
780
|
onClick: onClose,
|
|
619
|
-
style: { padding: '6px 16px' },
|
|
620
781
|
},
|
|
621
782
|
t('close') || 'Закрыть',
|
|
622
783
|
),
|
|
@@ -625,7 +786,7 @@ window.__ModuleLoader__.load({
|
|
|
625
786
|
);
|
|
626
787
|
}
|
|
627
788
|
|
|
628
|
-
|
|
789
|
+
function sessionIdOf(ctx, props) {
|
|
629
790
|
try {
|
|
630
791
|
if (props?.session?.id) return String(props.session.id);
|
|
631
792
|
if (props?.session?.sessionId) return String(props.session.sessionId);
|
|
@@ -651,6 +812,7 @@ window.__ModuleLoader__.load({
|
|
|
651
812
|
const [now, setNow] = useState(() => Date.now());
|
|
652
813
|
const stateRef = useRef(null);
|
|
653
814
|
stateRef.current = state;
|
|
815
|
+
const lastStateRef = useRef(null);
|
|
654
816
|
|
|
655
817
|
const t = (key) => {
|
|
656
818
|
if (ctx?.locale?.getSnapshot) {
|
|
@@ -681,18 +843,37 @@ window.__ModuleLoader__.load({
|
|
|
681
843
|
});
|
|
682
844
|
if (res.ok) {
|
|
683
845
|
const data = await res.json();
|
|
684
|
-
|
|
846
|
+
updateStateWithAudio(data);
|
|
847
|
+
return data;
|
|
685
848
|
}
|
|
686
849
|
} catch (_) {}
|
|
687
850
|
}, [sid]);
|
|
688
851
|
|
|
689
|
-
//
|
|
852
|
+
// Звуковое оповещение при переходе в COMPLETED или FAILED
|
|
853
|
+
const updateStateWithAudio = useCallback((nextState) => {
|
|
854
|
+
if (nextState && lastStateRef.current) {
|
|
855
|
+
const prev = lastStateRef.current;
|
|
856
|
+
if (prev.state !== nextState.state && nextState.enableSound !== false) {
|
|
857
|
+
if (nextState.state === 'COMPLETED') {
|
|
858
|
+
playGoalChime(true);
|
|
859
|
+
} else if (nextState.state === 'FAILED') {
|
|
860
|
+
playGoalChime(false);
|
|
861
|
+
}
|
|
862
|
+
}
|
|
863
|
+
}
|
|
864
|
+
lastStateRef.current = nextState;
|
|
865
|
+
setState(nextState);
|
|
866
|
+
}, []);
|
|
867
|
+
|
|
868
|
+
// Realtime Server-Sent Events (SSE) с автоматическим адаптивным fallback-поллингом
|
|
690
869
|
useEffect(() => {
|
|
870
|
+
let es = null;
|
|
691
871
|
let timer = null;
|
|
692
872
|
let isDisposed = false;
|
|
873
|
+
let sseActive = false;
|
|
693
874
|
|
|
694
875
|
const scheduleNextPoll = () => {
|
|
695
|
-
if (isDisposed) return;
|
|
876
|
+
if (isDisposed || sseActive) return;
|
|
696
877
|
const currentState = stateRef.current;
|
|
697
878
|
const isDocHidden = typeof document !== 'undefined' && document.hidden;
|
|
698
879
|
const isRunning = currentState?.hasActiveGoal && currentState?.state === 'RUNNING';
|
|
@@ -710,16 +891,58 @@ window.__ModuleLoader__.load({
|
|
|
710
891
|
}, delay);
|
|
711
892
|
};
|
|
712
893
|
|
|
713
|
-
|
|
894
|
+
// Запуск SSE соединения
|
|
895
|
+
if (typeof window !== 'undefined' && typeof window.EventSource !== 'undefined') {
|
|
896
|
+
try {
|
|
897
|
+
const query = sid && sid !== 'default' ? `?sessionId=${encodeURIComponent(sid)}` : '';
|
|
898
|
+
es = new window.EventSource(`/dsh-goal/events${query}`);
|
|
899
|
+
|
|
900
|
+
es.onopen = () => {
|
|
901
|
+
sseActive = true;
|
|
902
|
+
if (timer) {
|
|
903
|
+
clearTimeout(timer);
|
|
904
|
+
timer = null;
|
|
905
|
+
}
|
|
906
|
+
};
|
|
907
|
+
|
|
908
|
+
es.onmessage = (event) => {
|
|
909
|
+
if (isDisposed) return;
|
|
910
|
+
try {
|
|
911
|
+
const data = JSON.parse(event.data);
|
|
912
|
+
if (data && typeof data === 'object') {
|
|
913
|
+
updateStateWithAudio(data);
|
|
914
|
+
}
|
|
915
|
+
} catch (_) {}
|
|
916
|
+
};
|
|
917
|
+
|
|
918
|
+
es.onerror = () => {
|
|
919
|
+
// При сбое соединения SSE переключаемся на адаптивный fallback поллинг
|
|
920
|
+
sseActive = false;
|
|
921
|
+
if (!isDisposed && !timer) {
|
|
922
|
+
scheduleNextPoll();
|
|
923
|
+
}
|
|
924
|
+
};
|
|
925
|
+
} catch (_) {
|
|
926
|
+
sseActive = false;
|
|
927
|
+
scheduleNextPoll();
|
|
928
|
+
}
|
|
929
|
+
} else {
|
|
714
930
|
scheduleNextPoll();
|
|
931
|
+
}
|
|
932
|
+
|
|
933
|
+
// Первоначальная загрузка состояния
|
|
934
|
+
fetchState().then((data) => {
|
|
935
|
+
if (!sseActive) scheduleNextPoll();
|
|
715
936
|
});
|
|
716
937
|
|
|
717
938
|
const onVisibilityChange = () => {
|
|
718
939
|
if (typeof document !== 'undefined' && !document.hidden) {
|
|
719
|
-
if (
|
|
720
|
-
|
|
721
|
-
|
|
722
|
-
|
|
940
|
+
if (!sseActive) {
|
|
941
|
+
if (timer) clearTimeout(timer);
|
|
942
|
+
fetchState().then(() => {
|
|
943
|
+
scheduleNextPoll();
|
|
944
|
+
});
|
|
945
|
+
}
|
|
723
946
|
}
|
|
724
947
|
};
|
|
725
948
|
|
|
@@ -729,12 +952,16 @@ window.__ModuleLoader__.load({
|
|
|
729
952
|
|
|
730
953
|
return () => {
|
|
731
954
|
isDisposed = true;
|
|
955
|
+
if (es) {
|
|
956
|
+
es.close();
|
|
957
|
+
es = null;
|
|
958
|
+
}
|
|
732
959
|
if (timer) clearTimeout(timer);
|
|
733
960
|
if (typeof document !== 'undefined' && document.removeEventListener) {
|
|
734
961
|
document.removeEventListener('visibilitychange', onVisibilityChange);
|
|
735
962
|
}
|
|
736
963
|
};
|
|
737
|
-
}, [fetchState]);
|
|
964
|
+
}, [sid, fetchState, updateStateWithAudio]);
|
|
738
965
|
|
|
739
966
|
const handleAction = async (action, extra = {}) => {
|
|
740
967
|
try {
|
|
@@ -748,7 +975,7 @@ window.__ModuleLoader__.load({
|
|
|
748
975
|
});
|
|
749
976
|
if (res.ok) {
|
|
750
977
|
const data = await res.json();
|
|
751
|
-
if (data.state)
|
|
978
|
+
if (data.state) updateStateWithAudio(data.state);
|
|
752
979
|
}
|
|
753
980
|
} catch (_) {}
|
|
754
981
|
};
|
|
@@ -789,8 +1016,10 @@ window.__ModuleLoader__.load({
|
|
|
789
1016
|
),
|
|
790
1017
|
React.createElement(
|
|
791
1018
|
'span',
|
|
792
|
-
{
|
|
793
|
-
|
|
1019
|
+
{
|
|
1020
|
+
className: `dsh-goal-badge ${isCompleted ? 'dsh-goal-badge-ok' : isPaused ? 'dsh-goal-badge-warn' : ''}`,
|
|
1021
|
+
},
|
|
1022
|
+
isCompleted ? (t('goalCompleted') || 'Цель выполнена') : isPaused ? (t('pause') || 'На паузе') : (t('goalLabel') || 'Текущая цель'),
|
|
794
1023
|
),
|
|
795
1024
|
React.createElement('span', { className: 'dsh-goal-title', title: state.title }, state.title),
|
|
796
1025
|
),
|
|
@@ -806,7 +1035,7 @@ window.__ModuleLoader__.load({
|
|
|
806
1035
|
? React.createElement(
|
|
807
1036
|
'button',
|
|
808
1037
|
{
|
|
809
|
-
className: 'dsh-goal-btn',
|
|
1038
|
+
className: 'dsh-goal-btn icon-only',
|
|
810
1039
|
title: isPaused ? (t('resume') || 'Возобновить') : (t('pause') || 'Приостановить'),
|
|
811
1040
|
onClick: () => handleAction(isPaused ? 'resume' : 'pause'),
|
|
812
1041
|
},
|
|
@@ -816,7 +1045,7 @@ window.__ModuleLoader__.load({
|
|
|
816
1045
|
React.createElement(
|
|
817
1046
|
'button',
|
|
818
1047
|
{
|
|
819
|
-
className: 'dsh-goal-btn',
|
|
1048
|
+
className: 'dsh-goal-btn icon-only',
|
|
820
1049
|
title: t('details') || 'Развернуть детали цели',
|
|
821
1050
|
onClick: () => setIsModalOpen(true),
|
|
822
1051
|
},
|
|
@@ -826,7 +1055,7 @@ window.__ModuleLoader__.load({
|
|
|
826
1055
|
? React.createElement(
|
|
827
1056
|
'button',
|
|
828
1057
|
{
|
|
829
|
-
className: 'dsh-goal-btn close',
|
|
1058
|
+
className: 'dsh-goal-btn icon-only close',
|
|
830
1059
|
title: t('closeBanner') || 'Закрыть плашку цели',
|
|
831
1060
|
onClick: () => handleAction('clear'),
|
|
832
1061
|
},
|
|
@@ -848,12 +1077,6 @@ window.__ModuleLoader__.load({
|
|
|
848
1077
|
}
|
|
849
1078
|
|
|
850
1079
|
// --- ЛОГИКА ФОРМЫ НАСТРОЕК ---
|
|
851
|
-
// Архитектурное решение (Issue #23):
|
|
852
|
-
// Чистая логика состояния формы настроек вынесена в `lib/card-form-state.js` для запуска
|
|
853
|
-
// быстрых изолированных unit-тестов через `node --test`. В `lib/client.js` эти функции
|
|
854
|
-
// продублированы встроенным образом, поскольку клиентский бандл загружается браузерным
|
|
855
|
-
// загрузчиком DSH (`window.__ModuleLoader__`) как самодостаточный автономный скрипт
|
|
856
|
-
// без этапа сборки (bundler / webpack) и не может динамически импортировать локальные файлы.
|
|
857
1080
|
const DEFAULT_SETTINGS = {
|
|
858
1081
|
maxIterations: 25,
|
|
859
1082
|
autoDrive: true,
|
|
@@ -899,7 +1122,7 @@ window.__ModuleLoader__.load({
|
|
|
899
1122
|
}
|
|
900
1123
|
} else {
|
|
901
1124
|
if (draftValue !== undefined) {
|
|
902
|
-
isDirty = draftValue !== (userVal !== undefined ? userVal : baseVal);
|
|
1125
|
+
isDirty = Boolean(draftValue) !== (userVal !== undefined ? Boolean(userVal) : Boolean(baseVal));
|
|
903
1126
|
}
|
|
904
1127
|
}
|
|
905
1128
|
|
|
@@ -916,8 +1139,8 @@ window.__ModuleLoader__.load({
|
|
|
916
1139
|
function computeSavePlan(draft, snap) {
|
|
917
1140
|
if (!draft) return [];
|
|
918
1141
|
|
|
919
|
-
const writes = [];
|
|
920
1142
|
const fields = ['maxIterations', 'autoDrive', 'enableSound'];
|
|
1143
|
+
const writes = [];
|
|
921
1144
|
|
|
922
1145
|
for (const f of fields) {
|
|
923
1146
|
if (draft[f] === undefined) continue;
|
|
@@ -1066,124 +1289,124 @@ window.__ModuleLoader__.load({
|
|
|
1066
1289
|
React.createElement(
|
|
1067
1290
|
'div',
|
|
1068
1291
|
{ className: 'dsh-goal-card-field' },
|
|
1069
|
-
|
|
1070
|
-
|
|
1071
|
-
|
|
1072
|
-
|
|
1073
|
-
|
|
1074
|
-
|
|
1075
|
-
|
|
1076
|
-
|
|
1077
|
-
|
|
1078
|
-
|
|
1079
|
-
|
|
1080
|
-
|
|
1292
|
+
React.createElement(
|
|
1293
|
+
'div',
|
|
1294
|
+
{ className: 'dsh-goal-field-label-row' },
|
|
1295
|
+
React.createElement('label', { htmlFor: 'dsh-goal-max-iter' }, t('maxIterLabel') || 'Максимум итераций (Safety Limit):'),
|
|
1296
|
+
React.createElement(
|
|
1297
|
+
'div',
|
|
1298
|
+
{ className: 'dsh-goal-field-meta' },
|
|
1299
|
+
maxIterStatus.isOverridden
|
|
1300
|
+
? React.createElement('span', { className: 'dsh-goal-override-tag' }, t('overridden') || 'изменено')
|
|
1301
|
+
: null,
|
|
1302
|
+
maxIterStatus.isOverridden
|
|
1303
|
+
? React.createElement(
|
|
1304
|
+
'button',
|
|
1305
|
+
{
|
|
1306
|
+
type: 'button',
|
|
1307
|
+
className: 'dsh-goal-btn-inline-reset',
|
|
1308
|
+
title: t('resetField') || 'Сбросить к значению по умолчанию',
|
|
1309
|
+
onClick: () => resetFieldToDefault('maxIterations'),
|
|
1310
|
+
},
|
|
1311
|
+
React.createElement(IconRotateCcw, { size: 12 }),
|
|
1312
|
+
t('resetField') || 'По умолчанию',
|
|
1313
|
+
)
|
|
1314
|
+
: null,
|
|
1315
|
+
),
|
|
1316
|
+
),
|
|
1317
|
+
React.createElement('input', {
|
|
1318
|
+
id: 'dsh-goal-max-iter',
|
|
1319
|
+
type: 'number',
|
|
1320
|
+
min: 1,
|
|
1321
|
+
placeholder: String(maxIterStatus.baseValue),
|
|
1322
|
+
className: 'dsh-goal-card-input',
|
|
1323
|
+
value: maxIterStatus.value !== undefined ? maxIterStatus.value : '',
|
|
1324
|
+
disabled,
|
|
1325
|
+
'aria-invalid': invalid,
|
|
1326
|
+
onChange: (e) => edit('maxIterations', e.target.value),
|
|
1327
|
+
}),
|
|
1328
|
+
),
|
|
1329
|
+
React.createElement(
|
|
1330
|
+
'div',
|
|
1331
|
+
{ className: 'dsh-goal-check-row' },
|
|
1332
|
+
React.createElement(
|
|
1333
|
+
'label',
|
|
1334
|
+
{ className: 'dsh-goal-check' },
|
|
1335
|
+
React.createElement('input', {
|
|
1336
|
+
type: 'checkbox',
|
|
1337
|
+
checked: autoDriveStatus.value === true,
|
|
1338
|
+
disabled,
|
|
1339
|
+
onChange: (e) => edit('autoDrive', e.target.checked),
|
|
1340
|
+
}),
|
|
1341
|
+
t('autoDriveLabel') || 'Авто-драйв: продолжать цикл автоматически',
|
|
1342
|
+
),
|
|
1343
|
+
autoDriveStatus.isOverridden
|
|
1344
|
+
? React.createElement(
|
|
1345
|
+
'button',
|
|
1346
|
+
{
|
|
1347
|
+
type: 'button',
|
|
1348
|
+
className: 'dsh-goal-btn-inline-reset',
|
|
1349
|
+
title: t('resetField') || 'Сбросить к значению по умолчанию',
|
|
1350
|
+
onClick: () => resetFieldToDefault('autoDrive'),
|
|
1351
|
+
},
|
|
1352
|
+
React.createElement(IconRotateCcw, { size: 12 }),
|
|
1353
|
+
)
|
|
1354
|
+
: null,
|
|
1355
|
+
),
|
|
1356
|
+
React.createElement(
|
|
1357
|
+
'div',
|
|
1358
|
+
{ className: 'dsh-goal-check-row' },
|
|
1359
|
+
React.createElement(
|
|
1360
|
+
'label',
|
|
1361
|
+
{ className: 'dsh-goal-check' },
|
|
1362
|
+
React.createElement('input', {
|
|
1363
|
+
type: 'checkbox',
|
|
1364
|
+
checked: enableSoundStatus.value === true,
|
|
1365
|
+
disabled,
|
|
1366
|
+
onChange: (e) => edit('enableSound', e.target.checked),
|
|
1367
|
+
}),
|
|
1368
|
+
t('soundLabel') || 'Звук по завершении цели',
|
|
1369
|
+
),
|
|
1370
|
+
enableSoundStatus.isOverridden
|
|
1371
|
+
? React.createElement(
|
|
1372
|
+
'button',
|
|
1373
|
+
{
|
|
1374
|
+
type: 'button',
|
|
1375
|
+
className: 'dsh-goal-btn-inline-reset',
|
|
1376
|
+
title: t('resetField') || 'Сбросить к значению по умолчанию',
|
|
1377
|
+
onClick: () => resetFieldToDefault('enableSound'),
|
|
1378
|
+
},
|
|
1379
|
+
React.createElement(IconRotateCcw, { size: 12 }),
|
|
1380
|
+
)
|
|
1381
|
+
: null,
|
|
1382
|
+
),
|
|
1383
|
+
React.createElement(
|
|
1384
|
+
'div',
|
|
1385
|
+
{ className: 'dsh-goal-foot' },
|
|
1386
|
+
failed
|
|
1387
|
+
? React.createElement('span', { className: 'dsh-goal-foot-note' }, t('saveFailed') || 'Не сохранено — исправьте и повторите')
|
|
1388
|
+
: null,
|
|
1389
|
+
React.createElement(
|
|
1081
1390
|
'button',
|
|
1082
1391
|
{
|
|
1083
|
-
|
|
1084
|
-
|
|
1085
|
-
|
|
1086
|
-
|
|
1392
|
+
className: 'dsh-goal-discard',
|
|
1393
|
+
disabled: !dirty || disabled,
|
|
1394
|
+
onClick: () => {
|
|
1395
|
+
setFailed(false);
|
|
1396
|
+
setDraft(null);
|
|
1397
|
+
},
|
|
1087
1398
|
},
|
|
1088
|
-
|
|
1089
|
-
|
|
1090
|
-
|
|
1091
|
-
|
|
1092
|
-
|
|
1093
|
-
|
|
1094
|
-
|
|
1095
|
-
|
|
1096
|
-
|
|
1097
|
-
min: 1,
|
|
1098
|
-
placeholder: String(maxIterStatus.baseValue),
|
|
1099
|
-
className: 'dsh-goal-card-input',
|
|
1100
|
-
value: maxIterStatus.value !== undefined ? maxIterStatus.value : '',
|
|
1101
|
-
disabled,
|
|
1102
|
-
'aria-invalid': invalid,
|
|
1103
|
-
onChange: (e) => edit('maxIterations', e.target.value),
|
|
1104
|
-
}),
|
|
1105
|
-
),
|
|
1106
|
-
React.createElement(
|
|
1107
|
-
'div',
|
|
1108
|
-
{ className: 'dsh-goal-check-row' },
|
|
1109
|
-
React.createElement(
|
|
1110
|
-
'label',
|
|
1111
|
-
{ className: 'dsh-goal-check' },
|
|
1112
|
-
React.createElement('input', {
|
|
1113
|
-
type: 'checkbox',
|
|
1114
|
-
checked: autoDriveStatus.value === true,
|
|
1115
|
-
disabled,
|
|
1116
|
-
onChange: (e) => edit('autoDrive', e.target.checked),
|
|
1117
|
-
}),
|
|
1118
|
-
t('autoDriveLabel') || 'Авто-драйв: продолжать цикл автоматически',
|
|
1119
|
-
),
|
|
1120
|
-
autoDriveStatus.isOverridden
|
|
1121
|
-
? React.createElement(
|
|
1122
|
-
'button',
|
|
1123
|
-
{
|
|
1124
|
-
type: 'button',
|
|
1125
|
-
className: 'dsh-goal-btn-inline-reset',
|
|
1126
|
-
title: t('resetField') || 'Сбросить к значению по умолчанию',
|
|
1127
|
-
onClick: () => resetFieldToDefault('autoDrive'),
|
|
1128
|
-
},
|
|
1129
|
-
React.createElement(IconRotateCcw, { size: 12 }),
|
|
1130
|
-
)
|
|
1131
|
-
: null,
|
|
1132
|
-
),
|
|
1133
|
-
React.createElement(
|
|
1134
|
-
'div',
|
|
1135
|
-
{ className: 'dsh-goal-check-row' },
|
|
1136
|
-
React.createElement(
|
|
1137
|
-
'label',
|
|
1138
|
-
{ className: 'dsh-goal-check' },
|
|
1139
|
-
React.createElement('input', {
|
|
1140
|
-
type: 'checkbox',
|
|
1141
|
-
checked: enableSoundStatus.value === true,
|
|
1142
|
-
disabled,
|
|
1143
|
-
onChange: (e) => edit('enableSound', e.target.checked),
|
|
1144
|
-
}),
|
|
1145
|
-
t('soundLabel') || 'Звук по завершении цели',
|
|
1146
|
-
),
|
|
1147
|
-
enableSoundStatus.isOverridden
|
|
1148
|
-
? React.createElement(
|
|
1149
|
-
'button',
|
|
1150
|
-
{
|
|
1151
|
-
type: 'button',
|
|
1152
|
-
className: 'dsh-goal-btn-inline-reset',
|
|
1153
|
-
title: t('resetField') || 'Сбросить к значению по умолчанию',
|
|
1154
|
-
onClick: () => resetFieldToDefault('enableSound'),
|
|
1155
|
-
},
|
|
1156
|
-
React.createElement(IconRotateCcw, { size: 12 }),
|
|
1157
|
-
)
|
|
1158
|
-
: null,
|
|
1159
|
-
),
|
|
1160
|
-
React.createElement(
|
|
1161
|
-
'div',
|
|
1162
|
-
{ className: 'dsh-goal-foot' },
|
|
1163
|
-
failed
|
|
1164
|
-
? React.createElement('span', { className: 'dsh-goal-foot-note' }, t('saveFailed') || 'Не сохранено — исправьте и повторите')
|
|
1165
|
-
: null,
|
|
1166
|
-
React.createElement(
|
|
1167
|
-
'button',
|
|
1168
|
-
{
|
|
1169
|
-
className: 'dsh-goal-discard',
|
|
1170
|
-
disabled: !dirty || disabled,
|
|
1171
|
-
onClick: () => {
|
|
1172
|
-
setFailed(false);
|
|
1173
|
-
setDraft(null);
|
|
1174
|
-
},
|
|
1175
|
-
},
|
|
1176
|
-
t('discard') || 'Отменить правки',
|
|
1177
|
-
),
|
|
1178
|
-
React.createElement(
|
|
1179
|
-
'button',
|
|
1180
|
-
{ className: 'dsh-goal-save', disabled: !dirty || disabled || invalid, onClick: save },
|
|
1181
|
-
saving ? t('saving') || 'Сохранение…' : t('save') || 'Сохранить',
|
|
1182
|
-
),
|
|
1183
|
-
),
|
|
1399
|
+
t('discard') || 'Отменить правки',
|
|
1400
|
+
),
|
|
1401
|
+
React.createElement(
|
|
1402
|
+
'button',
|
|
1403
|
+
{ className: 'dsh-goal-save', disabled: !dirty || disabled || invalid, onClick: save },
|
|
1404
|
+
saving ? t('saving') || 'Сохранение…' : t('save') || 'Сохранить',
|
|
1405
|
+
),
|
|
1406
|
+
),
|
|
1407
|
+
),
|
|
1184
1408
|
)
|
|
1185
|
-
|
|
1186
|
-
: null,
|
|
1409
|
+
: null,
|
|
1187
1410
|
);
|
|
1188
1411
|
}
|
|
1189
1412
|
|
|
@@ -1199,7 +1422,7 @@ window.__ModuleLoader__.load({
|
|
|
1199
1422
|
details: 'Развернуть детали цели',
|
|
1200
1423
|
modalTitle: 'План и статус цели',
|
|
1201
1424
|
modalTitleCompleted: 'Цель выполнена: план и результаты',
|
|
1202
|
-
time: 'Время',
|
|
1425
|
+
time: 'Время работы',
|
|
1203
1426
|
milestones: 'План работ:',
|
|
1204
1427
|
noMilestones: 'Агент формирует план работ...',
|
|
1205
1428
|
close: 'Закрыть',
|
|
@@ -1227,7 +1450,7 @@ window.__ModuleLoader__.load({
|
|
|
1227
1450
|
details: 'Expand Goal Details',
|
|
1228
1451
|
modalTitle: 'Goal Plan & Status',
|
|
1229
1452
|
modalTitleCompleted: 'Goal Completed: Plan & Results',
|
|
1230
|
-
time: '
|
|
1453
|
+
time: 'Running time',
|
|
1231
1454
|
milestones: 'Plan of work:',
|
|
1232
1455
|
noMilestones: 'Agent is preparing the plan of work...',
|
|
1233
1456
|
close: 'Close',
|