@things-factory/worklist 10.1.5 → 10.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/dist-client/components/activity-approval-ribon.js +17 -2
- package/dist-client/components/activity-approval-ribon.js.map +1 -1
- package/dist-client/components/decision-slots.d.ts +89 -0
- package/dist-client/components/decision-slots.js +111 -0
- package/dist-client/components/decision-slots.js.map +1 -0
- package/dist-client/pages/activity-approval/activity-approval-page.d.ts +72 -0
- package/dist-client/pages/activity-approval/activity-approval-page.js +425 -43
- package/dist-client/pages/activity-approval/activity-approval-page.js.map +1 -1
- package/dist-client/pages/activity-catalog/activity-catalog-page.d.ts +11 -0
- package/dist-client/pages/activity-catalog/activity-catalog-page.js +48 -1
- package/dist-client/pages/activity-catalog/activity-catalog-page.js.map +1 -1
- package/dist-client/pages/installable-activity/installable-activity-list-page.d.ts +27 -0
- package/dist-client/pages/installable-activity/installable-activity-list-page.js +70 -11
- package/dist-client/pages/installable-activity/installable-activity-list-page.js.map +1 -1
- package/dist-client/route.d.ts +1 -1
- package/dist-client/tsconfig.tsbuildinfo +1 -1
- package/dist-server/controllers/activity-approval/approval-line.d.ts +32 -0
- package/dist-server/controllers/activity-approval/approval-line.js +35 -0
- package/dist-server/controllers/activity-approval/approval-line.js.map +1 -1
- package/dist-server/controllers/activity-approval/approve.js +17 -0
- package/dist-server/controllers/activity-approval/approve.js.map +1 -1
- package/dist-server/controllers/activity-approval/reject.js +21 -1
- package/dist-server/controllers/activity-approval/reject.js.map +1 -1
- package/dist-server/controllers/activity-installation/activity-installation-controller.js +5 -9
- package/dist-server/controllers/activity-installation/activity-installation-controller.js.map +1 -1
- package/dist-server/controllers/activity-installation/installable-to-activity.d.ts +49 -0
- package/dist-server/controllers/activity-installation/installable-to-activity.js +40 -0
- package/dist-server/controllers/activity-installation/installable-to-activity.js.map +1 -0
- package/dist-server/controllers/activity-installation/registry-conflict.d.ts +32 -0
- package/dist-server/controllers/activity-installation/registry-conflict.js +21 -0
- package/dist-server/controllers/activity-installation/registry-conflict.js.map +1 -0
- package/dist-server/service/activity/activity-decision-key-item-type.d.ts +160 -0
- package/dist-server/service/activity/activity-decision-key-item-type.js +176 -0
- package/dist-server/service/activity/activity-decision-key-item-type.js.map +1 -0
- package/dist-server/service/activity/activity-type.d.ts +3 -0
- package/dist-server/service/activity/activity-type.js +8 -0
- package/dist-server/service/activity/activity-type.js.map +1 -1
- package/dist-server/service/activity/activity.d.ts +30 -0
- package/dist-server/service/activity/activity.js +14 -0
- package/dist-server/service/activity/activity.js.map +1 -1
- package/dist-server/service/activity/decision-key-declaration.d.ts +33 -0
- package/dist-server/service/activity/decision-key-declaration.js +67 -0
- package/dist-server/service/activity/decision-key-declaration.js.map +1 -0
- package/dist-server/service/activity/{credential-guard-subscriber.d.ts → declaration-guard-subscriber.d.ts} +6 -1
- package/dist-server/service/activity/declaration-guard-subscriber.js +46 -0
- package/dist-server/service/activity/declaration-guard-subscriber.js.map +1 -0
- package/dist-server/service/activity/index.d.ts +3 -3
- package/dist-server/service/activity/index.js +2 -2
- package/dist-server/service/activity/index.js.map +1 -1
- package/dist-server/service/activity/search-key-declaration.d.ts +38 -0
- package/dist-server/service/activity/search-key-declaration.js +49 -0
- package/dist-server/service/activity/search-key-declaration.js.map +1 -0
- package/dist-server/service/activity-instance/activity-instance-type.js.map +1 -1
- package/dist-server/service/activity-instance/index.d.ts +1 -1
- package/dist-server/service/activity-template/index.d.ts +1 -1
- package/dist-server/service/activity-thread/index.d.ts +1 -1
- package/dist-server/service/index.d.ts +3 -3
- package/dist-server/service/installable-activity/installable-activity-mutation.js +24 -0
- package/dist-server/service/installable-activity/installable-activity-mutation.js.map +1 -1
- package/dist-server/service/installable-activity/installable-activity.d.ts +9 -0
- package/dist-server/service/installable-activity/installable-activity.js +5 -0
- package/dist-server/service/installable-activity/installable-activity.js.map +1 -1
- package/dist-server/tsconfig.tsbuildinfo +1 -1
- package/package.json +9 -9
- package/translations/en.json +28 -6
- package/translations/ja.json +22 -0
- package/translations/ko.json +28 -6
- package/translations/ms.json +22 -0
- package/translations/zh.json +22 -0
- package/dist-server/service/activity/credential-guard-subscriber.js +0 -35
- package/dist-server/service/activity/credential-guard-subscriber.js.map +0 -1
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import { __decorate, __metadata } from "tslib";
|
|
2
|
+
import '@material/web/icon/icon.js';
|
|
2
3
|
import '@operato/property-editor/ox-properties-dynamic-view.js';
|
|
3
4
|
import '@operato/board/ox-board-viewer.js';
|
|
4
5
|
import '../../components/activity-approval-ribon.js';
|
|
@@ -13,7 +14,9 @@ import { i18next, localize } from '@operato/i18n';
|
|
|
13
14
|
import { PageView } from '@operato/shell';
|
|
14
15
|
import { CommonButtonStyles, ScrollbarStyles } from '@operato/styles';
|
|
15
16
|
import { provider } from '@things-factory/board-ui/dist-client/board-provider.js';
|
|
16
|
-
import {
|
|
17
|
+
import { isReferenceStep } from '@things-factory/organization/dist-client';
|
|
18
|
+
import { ActivityFieldsStyles, fieldValue, inputSpecOf, outputSpecOf, renderGiven } from '../../components/activity-fields.js';
|
|
19
|
+
import { decisionSlots, reversibilityOf, slotOfRole, slotsOfRole } from '../../components/decision-slots.js';
|
|
17
20
|
const ActivityApprovalFetchResult = `\
|
|
18
21
|
{ id
|
|
19
22
|
judgment
|
|
@@ -57,6 +60,12 @@ const ActivityApprovalFetchResult = `\
|
|
|
57
60
|
description
|
|
58
61
|
state
|
|
59
62
|
activity { id
|
|
63
|
+
label
|
|
64
|
+
decisionKeys { role
|
|
65
|
+
inputPath
|
|
66
|
+
tKey
|
|
67
|
+
unit
|
|
68
|
+
}
|
|
60
69
|
model { name
|
|
61
70
|
description
|
|
62
71
|
active
|
|
@@ -72,6 +81,7 @@ const ActivityApprovalFetchResult = `\
|
|
|
72
81
|
}
|
|
73
82
|
approvalLine { type
|
|
74
83
|
value
|
|
84
|
+
participation
|
|
75
85
|
approver { id
|
|
76
86
|
name
|
|
77
87
|
description
|
|
@@ -214,8 +224,154 @@ let ActivityApprovalPage = class ActivityApprovalPage extends localize(i18next)(
|
|
|
214
224
|
color: var(--ui-faint, #8a959c);
|
|
215
225
|
word-break: keep-all;
|
|
216
226
|
}
|
|
227
|
+
|
|
228
|
+
/*
|
|
229
|
+
* The decision, drawn from the activity's declaration.
|
|
230
|
+
*
|
|
231
|
+
* The order is the declaration's and the weight descends with it: what is being asked reads
|
|
232
|
+
* first at title size, then what it is about, then the words a person wrote, then what changes
|
|
233
|
+
* on approval, and last why it came up at all.
|
|
234
|
+
*/
|
|
235
|
+
section[decision] .headline {
|
|
236
|
+
font-size: var(--ui-t-headline, 19px);
|
|
237
|
+
font-weight: 600;
|
|
238
|
+
line-height: 1.35;
|
|
239
|
+
color: var(--ui-ink, #17242c);
|
|
240
|
+
word-break: keep-all;
|
|
241
|
+
}
|
|
242
|
+
|
|
243
|
+
section[decision] .subject {
|
|
244
|
+
margin-top: 3px;
|
|
245
|
+
font-family: var(--ui-mono, ui-monospace, Menlo, monospace);
|
|
246
|
+
font-size: var(--ui-t-body, 13px);
|
|
247
|
+
color: var(--ui-muted, #57676f);
|
|
248
|
+
}
|
|
249
|
+
|
|
250
|
+
section[decision] .block {
|
|
251
|
+
margin-top: 14px;
|
|
252
|
+
}
|
|
253
|
+
|
|
254
|
+
section[decision] .block > .label {
|
|
255
|
+
margin-bottom: 4px;
|
|
256
|
+
font-size: var(--ui-t-small, 11.5px);
|
|
257
|
+
color: var(--ui-muted, #57676f);
|
|
258
|
+
}
|
|
259
|
+
|
|
260
|
+
/* What a person wrote is set apart, because it is the only part nobody computed. */
|
|
261
|
+
section[decision] .said {
|
|
262
|
+
padding: 9px 11px;
|
|
263
|
+
border-left: 3px solid var(--ui-line, #d5dce0);
|
|
264
|
+
background: var(--ui-line-soft, #f2f5f7);
|
|
265
|
+
color: var(--ui-ink, #17242c);
|
|
266
|
+
word-break: break-word;
|
|
267
|
+
}
|
|
268
|
+
|
|
269
|
+
section[decision] .none {
|
|
270
|
+
color: var(--ui-faint, #8a959c);
|
|
271
|
+
}
|
|
272
|
+
|
|
273
|
+
section[decision] .consequence {
|
|
274
|
+
margin-top: 8px;
|
|
275
|
+
padding: 9px 11px;
|
|
276
|
+
border: 1px solid var(--ui-line, #d5dce0);
|
|
277
|
+
border-radius: var(--ui-r-small, 6px);
|
|
278
|
+
}
|
|
279
|
+
|
|
280
|
+
section[decision] .consequence > .label {
|
|
281
|
+
margin-bottom: 3px;
|
|
282
|
+
font-size: var(--ui-t-small, 11.5px);
|
|
283
|
+
color: var(--ui-muted, #57676f);
|
|
284
|
+
}
|
|
285
|
+
|
|
286
|
+
/*
|
|
287
|
+
* Whether approving can be undone reads as the frame around the decision, not as one of its
|
|
288
|
+
* consequences. Among them it carries the same weight as "four orders get pushed back", and
|
|
289
|
+
* on an approval that moves equipment it is the heaviest line on the screen.
|
|
290
|
+
*/
|
|
291
|
+
section[decision] .reversibility {
|
|
292
|
+
display: flex;
|
|
293
|
+
align-items: center;
|
|
294
|
+
gap: 6px;
|
|
295
|
+
|
|
296
|
+
margin-top: 12px;
|
|
297
|
+
padding: 8px 11px;
|
|
298
|
+
border-radius: var(--ui-r-small, 6px);
|
|
299
|
+
|
|
300
|
+
background: var(--ui-line-soft, #f2f5f7);
|
|
301
|
+
color: var(--ui-muted, #57676f);
|
|
302
|
+
font-size: var(--ui-t-small, 11.5px);
|
|
303
|
+
}
|
|
304
|
+
|
|
305
|
+
section[decision] .reversibility[irreversible] {
|
|
306
|
+
background: var(--md-sys-color-error-container, #ffdad6);
|
|
307
|
+
color: var(--md-sys-color-on-error-container, #410002);
|
|
308
|
+
font-weight: 600;
|
|
309
|
+
}
|
|
310
|
+
|
|
311
|
+
section[decision] .reversibility md-icon {
|
|
312
|
+
font-size: 1.15em;
|
|
313
|
+
}
|
|
314
|
+
|
|
315
|
+
/*
|
|
316
|
+
* What the decision was made from. Set flatter than the consequences — it is the record the
|
|
317
|
+
* approver checks, not something the approval brings about.
|
|
318
|
+
*/
|
|
319
|
+
section[decision] .evidence {
|
|
320
|
+
margin-top: 8px;
|
|
321
|
+
padding: 7px 0 7px 11px;
|
|
322
|
+
border-left: 2px solid var(--ui-line, #d5dce0);
|
|
323
|
+
}
|
|
324
|
+
|
|
325
|
+
section[decision] .evidence > .label {
|
|
326
|
+
margin-bottom: 2px;
|
|
327
|
+
font-size: var(--ui-t-small, 11.5px);
|
|
328
|
+
color: var(--ui-muted, #57676f);
|
|
329
|
+
}
|
|
330
|
+
|
|
331
|
+
/*
|
|
332
|
+
* What is true right now sits apart from what the approval would change. Sharing the box the
|
|
333
|
+
* consequences use would say the approval causes these readings.
|
|
334
|
+
*/
|
|
335
|
+
section[decision] .current-state {
|
|
336
|
+
margin-top: 14px;
|
|
337
|
+
padding: 9px 11px;
|
|
338
|
+
border: 1px dashed var(--ui-line, #d5dce0);
|
|
339
|
+
border-radius: var(--ui-r-small, 6px);
|
|
340
|
+
}
|
|
341
|
+
|
|
342
|
+
section[decision] .current-state > .label {
|
|
343
|
+
margin-bottom: 3px;
|
|
344
|
+
font-size: var(--ui-t-small, 11.5px);
|
|
345
|
+
color: var(--ui-muted, #57676f);
|
|
346
|
+
}
|
|
347
|
+
|
|
348
|
+
section[decision] .policy {
|
|
349
|
+
margin-top: 14px;
|
|
350
|
+
padding-top: 11px;
|
|
351
|
+
border-top: 1px solid var(--ui-line, #d5dce0);
|
|
352
|
+
font-size: var(--ui-t-small, 11.5px);
|
|
353
|
+
color: var(--ui-muted, #57676f);
|
|
354
|
+
}
|
|
217
355
|
`
|
|
218
356
|
]; }
|
|
357
|
+
/**
|
|
358
|
+
* Is the reader seated here as a reference — someone who comments and does not decide?
|
|
359
|
+
*
|
|
360
|
+
* The rule comes from organization's client types, the same function its own approval-line editor
|
|
361
|
+
* and list use, so the two wire spellings of the enum are handled in one place. The approval line
|
|
362
|
+
* answers rather than ActivityApproval.participation, matching what the server refuses on
|
|
363
|
+
* (isReferenceOrder in approval-line.ts): the line decides who comes next, so letting the row
|
|
364
|
+
* decide who may judge would leave two authorities with nothing to settle a disagreement.
|
|
365
|
+
*
|
|
366
|
+
* The value comes back false while the query is still out. That is the same answer as for an
|
|
367
|
+
* approver, so the buttons show for a moment on a reference's screen — pressing one is refused by
|
|
368
|
+
* the server, which is why the server closed first.
|
|
369
|
+
*/
|
|
370
|
+
get isReference() {
|
|
371
|
+
const approvalLine = this.activityThread?.activityInstance?.approvalLine;
|
|
372
|
+
const order = Number(this.activityApproval?.order ?? 0);
|
|
373
|
+
return isReferenceStep(approvalLine?.[order - 1]);
|
|
374
|
+
}
|
|
219
375
|
get context() {
|
|
220
376
|
const judgment = this.activityApproval?.judgment;
|
|
221
377
|
return { title: this.lifecycle?.params?.['title'] || i18next.t('title.activity approval'),
|
|
@@ -227,6 +383,17 @@ let ActivityApprovalPage = class ActivityApprovalPage extends localize(i18next)(
|
|
|
227
383
|
* 어느 목록에서 열리는지는 이 화면이 안다. 그것을 적어 둔다.
|
|
228
384
|
*/
|
|
229
385
|
menu: 'approval-pending-list',
|
|
386
|
+
/*
|
|
387
|
+
* A reference is offered neither approve nor reject.
|
|
388
|
+
*
|
|
389
|
+
* ActivityApprovalJudgment has carried Closed for this seat from the start — "the case ended"
|
|
390
|
+
* rather than a judgment — so a reference row was never meant to end in approved or rejected.
|
|
391
|
+
* The buttons were offered anyway, and the server accepted them until 2026-09-09.
|
|
392
|
+
*
|
|
393
|
+
* What stays is the note, because a comment is the whole point of the seat, and close. The
|
|
394
|
+
* hint under the textarea says which seat this is; buttons that simply vanish leave the
|
|
395
|
+
* reader looking for them.
|
|
396
|
+
*/
|
|
230
397
|
actions: judgment
|
|
231
398
|
? [
|
|
232
399
|
{ title: i18next.t('button.close'),
|
|
@@ -236,48 +403,16 @@ let ActivityApprovalPage = class ActivityApprovalPage extends localize(i18next)(
|
|
|
236
403
|
...CommonButtonStyles.back
|
|
237
404
|
}
|
|
238
405
|
]
|
|
239
|
-
:
|
|
240
|
-
|
|
241
|
-
|
|
242
|
-
|
|
243
|
-
*
|
|
244
|
-
* 승인이 주 동작이다 — 채운 단추 하나. 반려는 대등한 선택이지만 예외 경로라 테두리
|
|
245
|
-
* 단추로 그 옆에 둔다.
|
|
246
|
-
*
|
|
247
|
-
* 「저장」은 이름이 뜻을 말하지 않았다. 이 단추가 저장하는 것은 **의견 하나**이고
|
|
248
|
-
* (saveActivityApproval 은 id 와 comment 만 보낸다), 판단은 미뤄 둔다. 그리고 그 결과는
|
|
249
|
-
* 목록에서 「메모 있음」 표식으로 나타난다(activity-cells 의 approvalMarks). 목록이
|
|
250
|
-
* 부르는 이름과 같은 낱말로 맞춘다.
|
|
251
|
-
*/
|
|
252
|
-
[
|
|
253
|
-
{ title: i18next.t('button.approve'),
|
|
254
|
-
action: this.approveActivityApproval.bind(this),
|
|
255
|
-
icon: 'approval',
|
|
256
|
-
emphasis: { raised: true,
|
|
257
|
-
outlined: false,
|
|
258
|
-
dense: false,
|
|
259
|
-
danger: false
|
|
260
|
-
}
|
|
261
|
-
},
|
|
262
|
-
{ title: i18next.t('button.reject'),
|
|
263
|
-
action: this.rejectActivityApproval.bind(this),
|
|
264
|
-
icon: 'assignment_return',
|
|
265
|
-
emphasis: { raised: false,
|
|
266
|
-
outlined: true,
|
|
267
|
-
dense: false,
|
|
268
|
-
danger: false
|
|
269
|
-
}
|
|
270
|
-
},
|
|
271
|
-
{ title: i18next.t('button.save-note'),
|
|
406
|
+
: this.isReference
|
|
407
|
+
? [
|
|
408
|
+
{
|
|
409
|
+
title: i18next.t('button.save-note'),
|
|
272
410
|
action: this.saveActivityApproval.bind(this),
|
|
273
411
|
icon: 'edit_note',
|
|
274
|
-
emphasis: { raised: false,
|
|
275
|
-
outlined: true,
|
|
276
|
-
dense: false,
|
|
277
|
-
danger: false
|
|
278
|
-
}
|
|
412
|
+
emphasis: { raised: true, outlined: false, dense: false, danger: false }
|
|
279
413
|
},
|
|
280
|
-
{
|
|
414
|
+
{
|
|
415
|
+
title: i18next.t('button.close'),
|
|
281
416
|
action: () => {
|
|
282
417
|
history.back();
|
|
283
418
|
},
|
|
@@ -285,6 +420,55 @@ let ActivityApprovalPage = class ActivityApprovalPage extends localize(i18next)(
|
|
|
285
420
|
icon: 'close'
|
|
286
421
|
}
|
|
287
422
|
]
|
|
423
|
+
: /*
|
|
424
|
+
* ── 세 단추의 순서와 무게 (2026-09-06) ──────────────────────────
|
|
425
|
+
* 전에는 반려가 첫 자리였고, 승인 · 반려 · 저장이 모두 같은 모양이었다. 되돌리기 어려운
|
|
426
|
+
* 것이 앞에 서고 무엇이 주된 흐름인지 화면이 말하지 않았다.
|
|
427
|
+
*
|
|
428
|
+
* 승인이 주 동작이다 — 채운 단추 하나. 반려는 대등한 선택이지만 예외 경로라 테두리
|
|
429
|
+
* 단추로 그 옆에 둔다.
|
|
430
|
+
*
|
|
431
|
+
* 「저장」은 이름이 뜻을 말하지 않았다. 이 단추가 저장하는 것은 **의견 하나**이고
|
|
432
|
+
* (saveActivityApproval 은 id 와 comment 만 보낸다), 판단은 미뤄 둔다. 그리고 그 결과는
|
|
433
|
+
* 목록에서 「메모 있음」 표식으로 나타난다(activity-cells 의 approvalMarks). 목록이
|
|
434
|
+
* 부르는 이름과 같은 낱말로 맞춘다.
|
|
435
|
+
*/
|
|
436
|
+
[
|
|
437
|
+
{ title: i18next.t('button.approve'),
|
|
438
|
+
action: this.approveActivityApproval.bind(this),
|
|
439
|
+
icon: 'approval',
|
|
440
|
+
emphasis: { raised: true,
|
|
441
|
+
outlined: false,
|
|
442
|
+
dense: false,
|
|
443
|
+
danger: false
|
|
444
|
+
}
|
|
445
|
+
},
|
|
446
|
+
{ title: i18next.t('button.reject'),
|
|
447
|
+
action: this.rejectActivityApproval.bind(this),
|
|
448
|
+
icon: 'assignment_return',
|
|
449
|
+
emphasis: { raised: false,
|
|
450
|
+
outlined: true,
|
|
451
|
+
dense: false,
|
|
452
|
+
danger: false
|
|
453
|
+
}
|
|
454
|
+
},
|
|
455
|
+
{ title: i18next.t('button.save-note'),
|
|
456
|
+
action: this.saveActivityApproval.bind(this),
|
|
457
|
+
icon: 'edit_note',
|
|
458
|
+
emphasis: { raised: false,
|
|
459
|
+
outlined: true,
|
|
460
|
+
dense: false,
|
|
461
|
+
danger: false
|
|
462
|
+
}
|
|
463
|
+
},
|
|
464
|
+
{ title: i18next.t('button.close'),
|
|
465
|
+
action: () => {
|
|
466
|
+
history.back();
|
|
467
|
+
},
|
|
468
|
+
...CommonButtonStyles.back,
|
|
469
|
+
icon: 'close'
|
|
470
|
+
}
|
|
471
|
+
]
|
|
288
472
|
// activityApproval: this.activityApproval
|
|
289
473
|
};
|
|
290
474
|
}
|
|
@@ -317,7 +501,9 @@ let ActivityApprovalPage = class ActivityApprovalPage extends localize(i18next)(
|
|
|
317
501
|
<section>
|
|
318
502
|
<h2>${i18next.t('field.wl-comment')}</h2>
|
|
319
503
|
<textarea
|
|
320
|
-
placeholder=${String(i18next.t(
|
|
504
|
+
placeholder=${String(i18next.t(this.isReference
|
|
505
|
+
? 'text.write-your-comment-as-reference'
|
|
506
|
+
: 'text.explain the reason for approval/rejection'))}
|
|
321
507
|
.value=${this.activityApproval?.comment}
|
|
322
508
|
@change=${(e) => {
|
|
323
509
|
this.activityApproval.comment = e.target.value;
|
|
@@ -326,8 +512,14 @@ let ActivityApprovalPage = class ActivityApprovalPage extends localize(i18next)(
|
|
|
326
512
|
<!--
|
|
327
513
|
반려는 의견이 필수다(rejectActivityApproval). 전에는 그 규칙을 **누른 뒤에** 토스트로
|
|
328
514
|
알렸다. 되돌릴 수 없는 것과 뜻이 다른 동작은 하기 전에 말한다.
|
|
515
|
+
|
|
516
|
+
A reference reads a different line: this one names the seat, because the approve
|
|
517
|
+
and reject buttons are absent for them and a reader whose buttons are missing
|
|
518
|
+
goes looking for them.
|
|
329
519
|
-->
|
|
330
|
-
<p class="hint"
|
|
520
|
+
<p class="hint">
|
|
521
|
+
${i18next.t(this.isReference ? 'text.reference-comment-hint' : 'text.approval-comment-hint')}
|
|
522
|
+
</p>
|
|
331
523
|
</section>
|
|
332
524
|
</div>
|
|
333
525
|
`
|
|
@@ -387,12 +579,163 @@ let ActivityApprovalPage = class ActivityApprovalPage extends localize(i18next)(
|
|
|
387
579
|
* approveActivityApproval / rejectActivityApproval 은 id 와 comment 만 보낸다 — 그 값은 어디에도
|
|
388
580
|
* 가지 않는다. 결재자가 적을 수 있는 것은 의견 하나이고, 그것은 화면 아래 칸이 받는다.
|
|
389
581
|
*/
|
|
582
|
+
/**
|
|
583
|
+
* The decision the activity declared, or nothing when it declared none.
|
|
584
|
+
*
|
|
585
|
+
* Returning nothing is how generatedContent knows to fall back to the model. An activity with no
|
|
586
|
+
* decisionKeys draws exactly what it drew before.
|
|
587
|
+
*
|
|
588
|
+
* A slot whose path led nowhere is skipped rather than drawn empty. Older instances of an activity
|
|
589
|
+
* predate a field the declaration names — plant hit that with its `policy` value — and an empty
|
|
590
|
+
* bar on the screen would read as "there is no reason" when the truth is that this record has no
|
|
591
|
+
* such value. What cannot be shown is left out; what is shown is only what the payload actually
|
|
592
|
+
* carries.
|
|
593
|
+
*
|
|
594
|
+
* `reason` is the exception. Missing and blank mean the same thing to whoever is reading — nobody
|
|
595
|
+
* wrote one — so both draw the grey line rather than disappearing. A reason that silently vanishes
|
|
596
|
+
* would let an approver assume it was never asked for.
|
|
597
|
+
*/
|
|
598
|
+
decisionContent() {
|
|
599
|
+
const { activityInstance } = this.activityThread || {};
|
|
600
|
+
const slots = decisionSlots(activityInstance?.activity?.decisionKeys, activityInstance?.input);
|
|
601
|
+
if (!slots.length) {
|
|
602
|
+
return nothing;
|
|
603
|
+
}
|
|
604
|
+
const headline = slotOfRole(slots, 'headline');
|
|
605
|
+
const subject = slotOfRole(slots, 'subject');
|
|
606
|
+
const reason = slotOfRole(slots, 'reason');
|
|
607
|
+
const consequences = slotsOfRole(slots, 'consequence').filter(slot => slot.found);
|
|
608
|
+
const policy = slotOfRole(slots, 'policy');
|
|
609
|
+
const evidence = slotsOfRole(slots, 'evidence').filter(slot => slot.found);
|
|
610
|
+
const currentState = slotOfRole(slots, 'currentState');
|
|
611
|
+
const reversibility = slotOfRole(slots, 'reversibility');
|
|
612
|
+
const drawable = [headline, subject, policy, currentState].some(slot => slot?.found) ||
|
|
613
|
+
!!reason ||
|
|
614
|
+
consequences.length ||
|
|
615
|
+
evidence.length ||
|
|
616
|
+
reversibilityOf(reversibility) !== undefined;
|
|
617
|
+
/*
|
|
618
|
+
* Every declared slot missed this payload. Saying so is not this screen's job — falling back to
|
|
619
|
+
* the model at least shows the values that are there, and the reader is no worse off than before
|
|
620
|
+
* the declaration existed.
|
|
621
|
+
*/
|
|
622
|
+
if (!drawable) {
|
|
623
|
+
return nothing;
|
|
624
|
+
}
|
|
625
|
+
return keyed(this.activityApproval.id, html `
|
|
626
|
+
<section decision>
|
|
627
|
+
${headline?.found ? html `<div class="headline">${this.slotText(headline)}</div>` : ''}
|
|
628
|
+
${subject?.found ? html `<div class="subject">${this.slotText(subject)}</div>` : ''}
|
|
629
|
+
${reason
|
|
630
|
+
? html `
|
|
631
|
+
<div class="block">
|
|
632
|
+
<div class="label">${i18next.t('field.reason')}</div>
|
|
633
|
+
<div class="said ${this.hasWords(reason) ? '' : 'none'}">
|
|
634
|
+
${this.hasWords(reason) ? this.slotText(reason) : i18next.t('text.no-reason-given')}
|
|
635
|
+
</div>
|
|
636
|
+
</div>
|
|
637
|
+
`
|
|
638
|
+
: ''}
|
|
639
|
+
${this.renderReversibility(reversibility)}
|
|
640
|
+
${evidence.length
|
|
641
|
+
? html `
|
|
642
|
+
<div class="block">
|
|
643
|
+
<div class="label">${i18next.t('label.what-it-was-judged-from')}</div>
|
|
644
|
+
${evidence.map(slot => html `
|
|
645
|
+
<div class="evidence">
|
|
646
|
+
${slot.tKey ? html `<div class="label">${i18next.t(slot.tKey)}</div>` : ''}
|
|
647
|
+
<div>${fieldValue(slot.value)}</div>
|
|
648
|
+
</div>
|
|
649
|
+
`)}
|
|
650
|
+
</div>
|
|
651
|
+
`
|
|
652
|
+
: ''}
|
|
653
|
+
${currentState?.found
|
|
654
|
+
? html `
|
|
655
|
+
<div class="current-state">
|
|
656
|
+
<div class="label">${i18next.t(currentState.tKey || 'label.current-state')}</div>
|
|
657
|
+
<div>${fieldValue(currentState.value)}</div>
|
|
658
|
+
</div>
|
|
659
|
+
`
|
|
660
|
+
: ''}
|
|
661
|
+
${consequences.length
|
|
662
|
+
? html `
|
|
663
|
+
<div class="block">
|
|
664
|
+
<div class="label">${i18next.t('label.what-changes')}</div>
|
|
665
|
+
${consequences.map(slot => html `
|
|
666
|
+
<div class="consequence">
|
|
667
|
+
${slot.tKey ? html `<div class="label">${i18next.t(slot.tKey)}</div>` : ''}
|
|
668
|
+
<div>${fieldValue(slot.value)}</div>
|
|
669
|
+
</div>
|
|
670
|
+
`)}
|
|
671
|
+
</div>
|
|
672
|
+
`
|
|
673
|
+
: ''}
|
|
674
|
+
${policy?.found
|
|
675
|
+
? html `
|
|
676
|
+
<div class="policy">
|
|
677
|
+
${i18next.t('label.why-approval')} — ${this.slotText(policy)}
|
|
678
|
+
</div>
|
|
679
|
+
`
|
|
680
|
+
: ''}
|
|
681
|
+
</section>
|
|
682
|
+
`);
|
|
683
|
+
}
|
|
684
|
+
/**
|
|
685
|
+
* Whether approving can be undone, drawn as the frame around the decision.
|
|
686
|
+
*
|
|
687
|
+
* Only an explicit true or false draws. Anything else — the path led nowhere, or the value is not
|
|
688
|
+
* a boolean — draws nothing, because saying "this can be undone" on a screen that does not know is
|
|
689
|
+
* the one mistake this line must never make.
|
|
690
|
+
*
|
|
691
|
+
* This is not rejectionIsFinal. That one says whether **rejecting** ends the case for good; this
|
|
692
|
+
* says whether **approving** can be taken back. The twin actuation carries both, which is exactly
|
|
693
|
+
* why they must not share a sentence.
|
|
694
|
+
*/
|
|
695
|
+
renderReversibility(slot) {
|
|
696
|
+
const reversible = reversibilityOf(slot);
|
|
697
|
+
if (reversible === undefined) {
|
|
698
|
+
return '';
|
|
699
|
+
}
|
|
700
|
+
return html `
|
|
701
|
+
<div class="reversibility" ?irreversible=${!reversible}>
|
|
702
|
+
<md-icon>${reversible ? 'undo' : 'lock'}</md-icon>
|
|
703
|
+
<span>${i18next.t(reversible ? 'text.approval-is-reversible' : 'text.approval-is-irreversible')}</span>
|
|
704
|
+
</div>
|
|
705
|
+
`;
|
|
706
|
+
}
|
|
707
|
+
/**
|
|
708
|
+
* One slot's value as something to read.
|
|
709
|
+
*
|
|
710
|
+
* A scalar prints with its unit when one was declared. Anything shaped — an object, a list — goes
|
|
711
|
+
* through fieldValue, the same laying-out the model sections use, so a payload reads the same way
|
|
712
|
+
* wherever it appears and a four-level object does not become one long line.
|
|
713
|
+
*/
|
|
714
|
+
slotText(slot) {
|
|
715
|
+
const scalar = slot.value !== null && slot.value !== undefined && typeof slot.value !== 'object';
|
|
716
|
+
if (scalar && slot.unit) {
|
|
717
|
+
return `${slot.value} ${slot.unit}`;
|
|
718
|
+
}
|
|
719
|
+
return scalar ? String(slot.value) : fieldValue(slot.value);
|
|
720
|
+
}
|
|
721
|
+
/** Did a person actually write something here. Whitespace is not words. */
|
|
722
|
+
hasWords(slot) {
|
|
723
|
+
return typeof slot.value === 'string' ? slot.value.trim().length > 0 : slot.found && slot.value != null;
|
|
724
|
+
}
|
|
390
725
|
generatedContent() {
|
|
391
726
|
if (!this.activityApproval) {
|
|
392
727
|
return html ``;
|
|
393
728
|
}
|
|
394
729
|
const { output, activityInstance } = this.activityThread || {};
|
|
395
730
|
const { input } = activityInstance || {};
|
|
731
|
+
/*
|
|
732
|
+
* The declaration goes first. It answers "what happens if I approve", which is the question this
|
|
733
|
+
* screen exists for; the model answers "what are the values", which is the fallback.
|
|
734
|
+
*/
|
|
735
|
+
const decision = this.decisionContent();
|
|
736
|
+
if (decision !== nothing) {
|
|
737
|
+
return decision;
|
|
738
|
+
}
|
|
396
739
|
const model = activityInstance?.activity?.model;
|
|
397
740
|
const inputSpec = inputSpecOf(model);
|
|
398
741
|
const outputSpec = outputSpecOf(model);
|
|
@@ -449,12 +792,37 @@ let ActivityApprovalPage = class ActivityApprovalPage extends localize(i18next)(
|
|
|
449
792
|
></ox-board-viewer>
|
|
450
793
|
`);
|
|
451
794
|
}
|
|
795
|
+
/**
|
|
796
|
+
* The element the activity names, or a plain statement that it could not be loaded.
|
|
797
|
+
*
|
|
798
|
+
* document.createElement answers something for any name, so an activity pointing at an element
|
|
799
|
+
* nobody registered used to produce an empty card. The approver got a screen with nothing on it
|
|
800
|
+
* and the approve button still worked — plant shipped two such forms in one day and found them by
|
|
801
|
+
* reading the file list, not by opening the screen.
|
|
802
|
+
*
|
|
803
|
+
* The reader is told what to judge by instead. Same shape as the empty generated screen: what is
|
|
804
|
+
* missing, and where to look — the submission reason and the history in the timeline below.
|
|
805
|
+
*
|
|
806
|
+
* ── Waiting for a late definition ─────────────────────────────────────────
|
|
807
|
+
* An element can be registered after this page renders, and answering "not loaded" forever in
|
|
808
|
+
* that case would be a screen inventing a defect. whenDefined resolves whenever it arrives and
|
|
809
|
+
* the page redraws; a name nobody ever registers simply never resolves, and the statement stands.
|
|
810
|
+
*/
|
|
452
811
|
customElementContent() {
|
|
453
812
|
if (!this.activityApproval) {
|
|
454
813
|
return html ``;
|
|
455
814
|
}
|
|
456
815
|
const { output, activityInstance } = this.activityThread;
|
|
457
816
|
const { viewSource: tagName, input } = activityInstance || {};
|
|
817
|
+
if (!tagName || !customElements.get(tagName)) {
|
|
818
|
+
if (tagName) {
|
|
819
|
+
customElements.whenDefined(tagName).then(() => this.requestUpdate());
|
|
820
|
+
}
|
|
821
|
+
return html `<section empty>
|
|
822
|
+
<span class="title">${i18next.t('text.approval-view-not-loaded')}</span>
|
|
823
|
+
<span class="why">${i18next.t('text.no-approval-content-why')}</span>
|
|
824
|
+
</section>`;
|
|
825
|
+
}
|
|
458
826
|
const element = document.createElement(tagName);
|
|
459
827
|
element.id = 'custom-content';
|
|
460
828
|
element.activityId = activityInstance.activity.id;
|
|
@@ -586,7 +954,21 @@ __decorate([
|
|
|
586
954
|
], ActivityApprovalPage.prototype, "board", void 0);
|
|
587
955
|
__decorate([
|
|
588
956
|
query('textarea'),
|
|
589
|
-
__metadata("design:type", HTMLTextAreaElement
|
|
957
|
+
__metadata("design:type", HTMLTextAreaElement
|
|
958
|
+
/**
|
|
959
|
+
* Is the reader seated here as a reference — someone who comments and does not decide?
|
|
960
|
+
*
|
|
961
|
+
* The rule comes from organization's client types, the same function its own approval-line editor
|
|
962
|
+
* and list use, so the two wire spellings of the enum are handled in one place. The approval line
|
|
963
|
+
* answers rather than ActivityApproval.participation, matching what the server refuses on
|
|
964
|
+
* (isReferenceOrder in approval-line.ts): the line decides who comes next, so letting the row
|
|
965
|
+
* decide who may judge would leave two authorities with nothing to settle a disagreement.
|
|
966
|
+
*
|
|
967
|
+
* The value comes back false while the query is still out. That is the same answer as for an
|
|
968
|
+
* approver, so the buttons show for a moment on a reference's screen — pressing one is refused by
|
|
969
|
+
* the server, which is why the server closed first.
|
|
970
|
+
*/
|
|
971
|
+
)
|
|
590
972
|
], ActivityApprovalPage.prototype, "commentInput", void 0);
|
|
591
973
|
__decorate([
|
|
592
974
|
query('ox-board-viewer'),
|