@things-factory/worklist 10.1.4 → 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 +24 -0
- package/dist-client/pages/activity-catalog/activity-catalog-page.js +101 -6
- 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
|
@@ -12,7 +12,22 @@ let ActivityApprovalRibon = class ActivityApprovalRibon extends localize(i18next
|
|
|
12
12
|
render() {
|
|
13
13
|
const { activityInstance, state } = this.activityApproval?.activityThread || {};
|
|
14
14
|
const { description, assignee, approvalLine, activity } = activityInstance || {};
|
|
15
|
-
const { startingType } = activity || {};
|
|
15
|
+
const { startingType, label } = activity || {};
|
|
16
|
+
/*
|
|
17
|
+
* What kind of decision this is — the activity's own name, not this instance's.
|
|
18
|
+
*
|
|
19
|
+
* Those are different facts and both belong here: 「부적합 처분 승인」 says what kind, and the
|
|
20
|
+
* headline the activity declares says what this one asks for. The activity's name reached only
|
|
21
|
+
* the catalog until it became a column on the row, so this screen showed the instance
|
|
22
|
+
* description alone.
|
|
23
|
+
*
|
|
24
|
+
* ── The fallback puts English on a Korean screen ──────────────────────
|
|
25
|
+
* Activity.description is what a developer wrote for other developers ("The disposition waiting
|
|
26
|
+
* for approval"), so an activity with no label shows that to the person approving. That is worse
|
|
27
|
+
* than the instance description and it is the reason to fill label in — it is not a fallback
|
|
28
|
+
* anybody should be content with.
|
|
29
|
+
*/
|
|
30
|
+
const kind = label || description || '';
|
|
16
31
|
return html `
|
|
17
32
|
<span class="state">
|
|
18
33
|
<i class="dot"></i>
|
|
@@ -34,7 +49,7 @@ let ActivityApprovalRibon = class ActivityApprovalRibon extends localize(i18next
|
|
|
34
49
|
>info</md-icon
|
|
35
50
|
>
|
|
36
51
|
|
|
37
|
-
<span class="desc" title=${
|
|
52
|
+
<span class="desc" title=${kind}>${kind}</span>
|
|
38
53
|
|
|
39
54
|
|
|
40
55
|
${startingType == 'issue' && assignee
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"activity-approval-ribon.js","sourceRoot":"","sources":["../../client/components/activity-approval-ribon.ts"],"names":[],"mappings":";AAAA,OAAO,wDAAwD,CAAA;AAC/D,OAAO,2EAA2E,CAAA;AAClF,OAAO,oDAAoD,CAAA;AAE3D,OAAO,EAAE,IAAI,EAAE,UAAU,EAAE,MAAM,KAAK,CAAA;AACtC,OAAO,EAAE,aAAa,EAAE,QAAQ,EAAE,MAAM,mBAAmB,CAAA;AAE3D,OAAO,EAAE,OAAO,EAAE,QAAQ,EAAE,MAAM,eAAe,CAAA;AACjD,OAAO,EAAE,SAAS,EAAE,MAAM,iBAAiB,CAAA;AAE3C,OAAO,EAAE,gBAAgB,EAAE,MAAM,kBAAkB,CAAA;AAG5C,IAAM,qBAAqB,GAA3B,MAAM,qBAAsB,SAAQ,QAAQ,CAAC,OAAO,CAAC,CAAC,UAAU,CAAC;aAC/D,WAAM,GAAG,CAAC,gBAAgB,CAAC,AAArB,CAAqB;IAIlC,MAAM;QACJ,MAAM,EAAE,gBAAgB,EAAE,KAAK,EAAE,GAAG,IAAI,CAAC,gBAAgB,EAAE,cAAc,IAAI,EAAE,CAAA;QAC/E,MAAM,EAAE,WAAW,EAAE,QAAQ,EAAE,YAAY,EAAE,QAAQ,EAAE,GAAG,gBAAgB,IAAI,EAAE,CAAA;QAChF,MAAM,EAAE,YAAY,EAAE,GAAG,QAAQ,IAAI,EAAE,CAAA;QAEvC,OAAO,IAAI,CAAA;;;UAGL,OAAO,CAAC,CAAC,CAAC,uBAAuB,GAAG,KAAK,CAAC;;;;;;;gBAOpC,MAAM,CAAC,OAAO,CAAC,CAAC,CAAC,qBAAqB,CAAC,CAAC;iBACvC,GAAG,EAAE,CAAC,IAAI,CAAC,QAAQ,CAAC,KAAK,CAAC;mBACxB,CAAC,CAAgB,EAAE,EAAE;YAC9B,IAAI,CAAC,CAAC,GAAG,KAAK,OAAO,IAAI,CAAC,CAAC,GAAG,KAAK,GAAG,EAAE,CAAC;gBACvC,CAAC,CAAC,cAAc,EAAE,CAAA;gBAClB,IAAI,CAAC,QAAQ,CAAC,KAAK,CAAC,CAAA;YACtB,CAAC;QACH,CAAC;;;;iCAIwB,
|
|
1
|
+
{"version":3,"file":"activity-approval-ribon.js","sourceRoot":"","sources":["../../client/components/activity-approval-ribon.ts"],"names":[],"mappings":";AAAA,OAAO,wDAAwD,CAAA;AAC/D,OAAO,2EAA2E,CAAA;AAClF,OAAO,oDAAoD,CAAA;AAE3D,OAAO,EAAE,IAAI,EAAE,UAAU,EAAE,MAAM,KAAK,CAAA;AACtC,OAAO,EAAE,aAAa,EAAE,QAAQ,EAAE,MAAM,mBAAmB,CAAA;AAE3D,OAAO,EAAE,OAAO,EAAE,QAAQ,EAAE,MAAM,eAAe,CAAA;AACjD,OAAO,EAAE,SAAS,EAAE,MAAM,iBAAiB,CAAA;AAE3C,OAAO,EAAE,gBAAgB,EAAE,MAAM,kBAAkB,CAAA;AAG5C,IAAM,qBAAqB,GAA3B,MAAM,qBAAsB,SAAQ,QAAQ,CAAC,OAAO,CAAC,CAAC,UAAU,CAAC;aAC/D,WAAM,GAAG,CAAC,gBAAgB,CAAC,AAArB,CAAqB;IAIlC,MAAM;QACJ,MAAM,EAAE,gBAAgB,EAAE,KAAK,EAAE,GAAG,IAAI,CAAC,gBAAgB,EAAE,cAAc,IAAI,EAAE,CAAA;QAC/E,MAAM,EAAE,WAAW,EAAE,QAAQ,EAAE,YAAY,EAAE,QAAQ,EAAE,GAAG,gBAAgB,IAAI,EAAE,CAAA;QAChF,MAAM,EAAE,YAAY,EAAE,KAAK,EAAE,GAAG,QAAQ,IAAI,EAAE,CAAA;QAE9C;;;;;;;;;;;;;WAaG;QACH,MAAM,IAAI,GAAG,KAAK,IAAI,WAAW,IAAI,EAAE,CAAA;QAEvC,OAAO,IAAI,CAAA;;;UAGL,OAAO,CAAC,CAAC,CAAC,uBAAuB,GAAG,KAAK,CAAC;;;;;;;gBAOpC,MAAM,CAAC,OAAO,CAAC,CAAC,CAAC,qBAAqB,CAAC,CAAC;iBACvC,GAAG,EAAE,CAAC,IAAI,CAAC,QAAQ,CAAC,KAAK,CAAC;mBACxB,CAAC,CAAgB,EAAE,EAAE;YAC9B,IAAI,CAAC,CAAC,GAAG,KAAK,OAAO,IAAI,CAAC,CAAC,GAAG,KAAK,GAAG,EAAE,CAAC;gBACvC,CAAC,CAAC,cAAc,EAAE,CAAA;gBAClB,IAAI,CAAC,QAAQ,CAAC,KAAK,CAAC,CAAA;YACtB,CAAC;QACH,CAAC;;;;iCAIwB,IAAI,IAAI,IAAI;;;QAGrC,YAAY,IAAI,OAAO,IAAI,QAAQ;YACnC,CAAC,CAAC,IAAI,CAAA,6CAA6C,OAAO,CAAC,CAAC,CAAC,gBAAgB,CAAC,UAAU,QAAQ,EAAE,IAAI,SAAS;YAC/G,CAAC,CAAC,EAAE;QACJ,YAAY;YACZ,CAAC,CAAC,IAAI,CAAA;qBACO,YAAY;uBACV,IAAI,CAAC,gBAAgB,CAAC,KAAK;kCAChB;YAC1B,CAAC,CAAC,EAAE;KACP,CAAA;IACH,CAAC;IAED;;;;;;;;;;;;;;;;;OAiBG;IACK,QAAQ,CAAC,KAAa;QAC5B,SAAS,CACP,IAAI,CAAA,yDAAyD,IAAI,CAAC,gBAAgB,UAAU,KAAK,wCAAwC,EACzI,EAAE,KAAK,EAAE,OAAO,CAAC,CAAC,CAAC,qBAAqB,CAAC,EAAE,CAC5C,CAAA;IACH,CAAC;IAED,OAAO,CAAC,OAAO;QACb,IAAI,OAAO,CAAC,GAAG,CAAC,kBAAkB,CAAC,IAAI,IAAI,CAAC,gBAAgB,EAAE,CAAC;YAC7D,MAAM,EAAE,KAAK,EAAE,GAAG,IAAI,CAAC,gBAAgB,CAAC,cAAc,CAAA;YAEtD,IAAI,CAAC,YAAY,CAAC,OAAO,EAAE,KAAK,CAAC,CAAA;QACnC,CAAC;IACH,CAAC;;AA1F2B;IAA3B,QAAQ,CAAC,EAAE,IAAI,EAAE,MAAM,EAAE,CAAC;;+DAAsB;AAHtC,qBAAqB;IADjC,aAAa,CAAC,yBAAyB,CAAC;GAC5B,qBAAqB,CA8FjC","sourcesContent":["import '@operato/property-editor/ox-properties-dynamic-view.js'\nimport '@things-factory/organization/dist-client/component/approval-line-brief.js'\nimport '../templates/activity-approval-context-template.js'\n\nimport { html, LitElement } from 'lit'\nimport { customElement, property } from 'lit/decorators.js'\n\nimport { i18next, localize } from '@operato/i18n'\nimport { openPopup } from '@operato/layout'\n\nimport { StateRibonStyles } from './state-ribon.js'\n\n@customElement('activity-approval-ribon')\nexport class ActivityApprovalRibon extends localize(i18next)(LitElement) {\n static styles = [StateRibonStyles]\n\n @property({ type: Object }) activityApproval: any\n\n render() {\n const { activityInstance, state } = this.activityApproval?.activityThread || {}\n const { description, assignee, approvalLine, activity } = activityInstance || {}\n const { startingType, label } = activity || {}\n\n /*\n * What kind of decision this is — the activity's own name, not this instance's.\n *\n * Those are different facts and both belong here: 「부적합 처분 승인」 says what kind, and the\n * headline the activity declares says what this one asks for. The activity's name reached only\n * the catalog until it became a column on the row, so this screen showed the instance\n * description alone.\n *\n * ── The fallback puts English on a Korean screen ──────────────────────\n * Activity.description is what a developer wrote for other developers (\"The disposition waiting\n * for approval\"), so an activity with no label shows that to the person approving. That is worse\n * than the instance description and it is the reason to fill label in — it is not a fallback\n * anybody should be content with.\n */\n const kind = label || description || ''\n\n return html`\n <span class=\"state\">\n <i class=\"dot\"></i>\n ${i18next.t('label.activity-state-' + state)}\n </span>\n\n <md-icon\n class=\"info\"\n role=\"button\"\n tabindex=\"0\"\n title=${String(i18next.t('label.approval-info'))}\n @click=${() => this.openInfo(state)}\n @keydown=${(e: KeyboardEvent) => {\n if (e.key === 'Enter' || e.key === ' ') {\n e.preventDefault()\n this.openInfo(state)\n }\n }}\n >info</md-icon\n >\n\n <span class=\"desc\" title=${kind}>${kind}</span>\n\n\n ${startingType == 'issue' && assignee\n ? html`<span class=\"who\"><span class=\"who-label\">${i18next.t('field.assignee')}</span>${assignee?.name}</span>`\n : ''}\n ${approvalLine\n ? html`<approval-line-brief\n .model=${approvalLine}\n .current=${this.activityApproval.order}\n ></approval-line-brief>`\n : ''}\n `\n }\n\n /**\n * 이 건의 기본 정보 — **팝업으로 연다.**\n *\n * ── 왜 aside 가 아닌가 (2026-09-06) ────────────────────────────────────\n * 전에는 화면 오른쪽에서 나오는 aside 판이었다. 두 가지가 걸린다.\n *\n * 자리를 다툰다 화면 오른쪽 세로 판은 operato-twin 의 twin-entity360 이 쓰는 자리다\n * (position: fixed · right: 0 · height: 100vh). 같은 자리에 둘이 선다.\n * 전역 슬롯이다 VIEWPART_POSITION.ASIDEBAR 은 앱이 하나만 갖는다. 열 개가 넘는 패키지가\n * 그 자리를 쓰고 있어(twin 의 AI 협의 도크 · board-ui · help · more-ui …),\n * 이 판을 열면 그중 열려 있던 것이 닫힌다.\n *\n * 그리고 자리의 뜻이 다르다. 오른쪽 드로어는 **보고 있는 대상을 따라다니는 상세**이고(360 이\n * 그것이다 — 포커스가 바뀌면 내용이 바뀌고 화면을 옮겨도 남는다), 이 판은 **이 화면의 이 건**에\n * 대한 것이라 화면을 벗어나면 뜻이 없다. 페이지에 매인 것을 앱 전역 자리에 두지 않는다.\n *\n * 내용도 팝업 크기다 — 값 여덟 줄과 접힌 타임라인이라 세로 100vh 를 쓸 일이 없었다.\n */\n private openInfo(state: string) {\n openPopup(\n html`<activity-approval-context-template .activityApproval=${this.activityApproval} state=${state}></activity-approval-context-template>`,\n { title: i18next.t('label.approval-info') }\n )\n }\n\n updated(changes) {\n if (changes.has('activityApproval') && this.activityApproval) {\n const { state } = this.activityApproval.activityThread\n\n this.setAttribute('state', state)\n }\n }\n}\n"]}
|
|
@@ -0,0 +1,89 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Turns an activity's decisionKeys declaration plus an instance's input into the slots a decision
|
|
3
|
+
* screen draws.
|
|
4
|
+
*
|
|
5
|
+
* ── Nothing is imported ───────────────────────────────────────────────────
|
|
6
|
+
* No lit, no i18next. The rule is a mapping from a declaration and a payload to an ordered list,
|
|
7
|
+
* and keeping it free of imports is what lets the test runner hold it: that runner parses
|
|
8
|
+
* TypeScript by stripping types and reads neither decorators nor enums, so one heavy import takes
|
|
9
|
+
* a whole test file down with it. Labels and markup are the caller's half.
|
|
10
|
+
*/
|
|
11
|
+
/** The roles that may appear more than once. Every other role names one value. */
|
|
12
|
+
export declare const REPEATABLE_ROLES: readonly ["consequence", "evidence"];
|
|
13
|
+
/** Listed in the order the screen reads them: what is asked, then past, present, future. */
|
|
14
|
+
export declare const DECISION_ROLES: readonly ["headline", "subject", "reversibility", "reason", "evidence", "currentState", "consequence", "policy"];
|
|
15
|
+
export type DecisionKeyDeclaration = {
|
|
16
|
+
role?: string;
|
|
17
|
+
inputPath?: string;
|
|
18
|
+
name?: string;
|
|
19
|
+
tKey?: string;
|
|
20
|
+
unit?: string;
|
|
21
|
+
};
|
|
22
|
+
export type DecisionSlot = {
|
|
23
|
+
role: string;
|
|
24
|
+
inputPath: string;
|
|
25
|
+
tKey?: string;
|
|
26
|
+
unit?: string;
|
|
27
|
+
/** What the path led to. Undefined both when the path leads nowhere and when the value is unset. */
|
|
28
|
+
value: unknown;
|
|
29
|
+
/**
|
|
30
|
+
* Whether the path led anywhere at all.
|
|
31
|
+
*
|
|
32
|
+
* A reason nobody wrote and a reason whose path is wrong look identical in `value`, and the screen
|
|
33
|
+
* owes different answers: the first is 「사유 없음」 in grey, the second is a declaration that does
|
|
34
|
+
* not match the payload and must not be drawn as if the person left it blank. Folding them into
|
|
35
|
+
* one value is the fallback that shifts meaning.
|
|
36
|
+
*/
|
|
37
|
+
found: boolean;
|
|
38
|
+
};
|
|
39
|
+
/**
|
|
40
|
+
* Reads a dotted path out of the input.
|
|
41
|
+
*
|
|
42
|
+
* Dots only. An array index or a wildcard is not part of the path language — drawing a list is the
|
|
43
|
+
* slot's job — so 'shift.passes[0]' looks for a key spelled "passes[0]", finds nothing, and reports
|
|
44
|
+
* found: false. The declaration guard refuses such a path when it arrives, so this is the second
|
|
45
|
+
* line rather than the first.
|
|
46
|
+
*
|
|
47
|
+
* A path that runs into a non-object partway reports found: false rather than throwing. The screen
|
|
48
|
+
* has to draw something either way, and a thrown error here would take the whole approval down over
|
|
49
|
+
* one slot.
|
|
50
|
+
*/
|
|
51
|
+
export declare function valueAtPath(input: any, path: string): {
|
|
52
|
+
value: unknown;
|
|
53
|
+
found: boolean;
|
|
54
|
+
};
|
|
55
|
+
/**
|
|
56
|
+
* The slots to draw, in the order they were declared.
|
|
57
|
+
*
|
|
58
|
+
* Declaration order is the screen's hierarchy: plant wrote four of these screens by hand and all
|
|
59
|
+
* four put the headline first, then the subject, the reason, what changes, and why it came up. That
|
|
60
|
+
* agreement is what makes the order part of the contract rather than a preference, so this function
|
|
61
|
+
* neither sorts nor groups.
|
|
62
|
+
*
|
|
63
|
+
* Every declared key produces a slot, including one whose path leads nowhere. Dropping those would
|
|
64
|
+
* leave the screen unable to say that a declaration and a payload disagree, and a reader would see
|
|
65
|
+
* a screen that looks complete.
|
|
66
|
+
*/
|
|
67
|
+
export declare function decisionSlots(decisionKeys: DecisionKeyDeclaration[] | null | undefined, input: any): DecisionSlot[];
|
|
68
|
+
/** The slots for one role, in declared order. Empty when the activity declared none. */
|
|
69
|
+
export declare function slotsOfRole(slots: DecisionSlot[], role: string): DecisionSlot[];
|
|
70
|
+
/**
|
|
71
|
+
* The single slot for a role that names one value, or undefined.
|
|
72
|
+
*
|
|
73
|
+
* Reaching for a second one would be reading a declaration the guard refuses, so this answers the
|
|
74
|
+
* first and does not quietly merge.
|
|
75
|
+
*/
|
|
76
|
+
export declare function slotOfRole(slots: DecisionSlot[], role: string): DecisionSlot | undefined;
|
|
77
|
+
/**
|
|
78
|
+
* Whether approving can be undone: true, false, or undefined for "the screen does not know".
|
|
79
|
+
*
|
|
80
|
+
* Three answers, not two. A path that led nowhere and a value that is not a boolean both mean the
|
|
81
|
+
* payload did not say, and the screen must draw nothing then — telling an approver that an action
|
|
82
|
+
* can be taken back when nobody said so is the one mistake this line cannot make. Reading a
|
|
83
|
+
* truthy value as reversible would do exactly that, since a non-empty string is truthy.
|
|
84
|
+
*
|
|
85
|
+
* This is not rejectionIsFinal. That says whether **rejecting** ends the case for good; this says
|
|
86
|
+
* whether **approving** can be taken back. The twin actuation carries both, which is why they must
|
|
87
|
+
* never share a sentence.
|
|
88
|
+
*/
|
|
89
|
+
export declare function reversibilityOf(slot?: DecisionSlot): boolean | undefined;
|
|
@@ -0,0 +1,111 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Turns an activity's decisionKeys declaration plus an instance's input into the slots a decision
|
|
3
|
+
* screen draws.
|
|
4
|
+
*
|
|
5
|
+
* ── Nothing is imported ───────────────────────────────────────────────────
|
|
6
|
+
* No lit, no i18next. The rule is a mapping from a declaration and a payload to an ordered list,
|
|
7
|
+
* and keeping it free of imports is what lets the test runner hold it: that runner parses
|
|
8
|
+
* TypeScript by stripping types and reads neither decorators nor enums, so one heavy import takes
|
|
9
|
+
* a whole test file down with it. Labels and markup are the caller's half.
|
|
10
|
+
*/
|
|
11
|
+
/** The roles that may appear more than once. Every other role names one value. */
|
|
12
|
+
export const REPEATABLE_ROLES = ['consequence', 'evidence'];
|
|
13
|
+
/** Listed in the order the screen reads them: what is asked, then past, present, future. */
|
|
14
|
+
export const DECISION_ROLES = [
|
|
15
|
+
'headline',
|
|
16
|
+
'subject',
|
|
17
|
+
'reversibility',
|
|
18
|
+
'reason',
|
|
19
|
+
'evidence',
|
|
20
|
+
'currentState',
|
|
21
|
+
'consequence',
|
|
22
|
+
'policy'
|
|
23
|
+
];
|
|
24
|
+
/**
|
|
25
|
+
* Reads a dotted path out of the input.
|
|
26
|
+
*
|
|
27
|
+
* Dots only. An array index or a wildcard is not part of the path language — drawing a list is the
|
|
28
|
+
* slot's job — so 'shift.passes[0]' looks for a key spelled "passes[0]", finds nothing, and reports
|
|
29
|
+
* found: false. The declaration guard refuses such a path when it arrives, so this is the second
|
|
30
|
+
* line rather than the first.
|
|
31
|
+
*
|
|
32
|
+
* A path that runs into a non-object partway reports found: false rather than throwing. The screen
|
|
33
|
+
* has to draw something either way, and a thrown error here would take the whole approval down over
|
|
34
|
+
* one slot.
|
|
35
|
+
*/
|
|
36
|
+
export function valueAtPath(input, path) {
|
|
37
|
+
const steps = String(path ?? '')
|
|
38
|
+
.split('.')
|
|
39
|
+
.filter(step => step.length > 0);
|
|
40
|
+
if (!steps.length) {
|
|
41
|
+
return { value: undefined, found: false };
|
|
42
|
+
}
|
|
43
|
+
let at = input;
|
|
44
|
+
for (const step of steps) {
|
|
45
|
+
if (at === null || at === undefined || typeof at !== 'object') {
|
|
46
|
+
return { value: undefined, found: false };
|
|
47
|
+
}
|
|
48
|
+
if (!Object.prototype.hasOwnProperty.call(at, step)) {
|
|
49
|
+
return { value: undefined, found: false };
|
|
50
|
+
}
|
|
51
|
+
at = at[step];
|
|
52
|
+
}
|
|
53
|
+
return { value: at, found: true };
|
|
54
|
+
}
|
|
55
|
+
/**
|
|
56
|
+
* The slots to draw, in the order they were declared.
|
|
57
|
+
*
|
|
58
|
+
* Declaration order is the screen's hierarchy: plant wrote four of these screens by hand and all
|
|
59
|
+
* four put the headline first, then the subject, the reason, what changes, and why it came up. That
|
|
60
|
+
* agreement is what makes the order part of the contract rather than a preference, so this function
|
|
61
|
+
* neither sorts nor groups.
|
|
62
|
+
*
|
|
63
|
+
* Every declared key produces a slot, including one whose path leads nowhere. Dropping those would
|
|
64
|
+
* leave the screen unable to say that a declaration and a payload disagree, and a reader would see
|
|
65
|
+
* a screen that looks complete.
|
|
66
|
+
*/
|
|
67
|
+
export function decisionSlots(decisionKeys, input) {
|
|
68
|
+
if (!decisionKeys?.length) {
|
|
69
|
+
return [];
|
|
70
|
+
}
|
|
71
|
+
return decisionKeys.map(key => {
|
|
72
|
+
const { value, found } = valueAtPath(input, String(key?.inputPath ?? ''));
|
|
73
|
+
return {
|
|
74
|
+
role: String(key?.role ?? ''),
|
|
75
|
+
inputPath: String(key?.inputPath ?? ''),
|
|
76
|
+
tKey: key?.tKey,
|
|
77
|
+
unit: key?.unit,
|
|
78
|
+
value,
|
|
79
|
+
found
|
|
80
|
+
};
|
|
81
|
+
});
|
|
82
|
+
}
|
|
83
|
+
/** The slots for one role, in declared order. Empty when the activity declared none. */
|
|
84
|
+
export function slotsOfRole(slots, role) {
|
|
85
|
+
return slots.filter(slot => slot.role === role);
|
|
86
|
+
}
|
|
87
|
+
/**
|
|
88
|
+
* The single slot for a role that names one value, or undefined.
|
|
89
|
+
*
|
|
90
|
+
* Reaching for a second one would be reading a declaration the guard refuses, so this answers the
|
|
91
|
+
* first and does not quietly merge.
|
|
92
|
+
*/
|
|
93
|
+
export function slotOfRole(slots, role) {
|
|
94
|
+
return slots.find(slot => slot.role === role);
|
|
95
|
+
}
|
|
96
|
+
/**
|
|
97
|
+
* Whether approving can be undone: true, false, or undefined for "the screen does not know".
|
|
98
|
+
*
|
|
99
|
+
* Three answers, not two. A path that led nowhere and a value that is not a boolean both mean the
|
|
100
|
+
* payload did not say, and the screen must draw nothing then — telling an approver that an action
|
|
101
|
+
* can be taken back when nobody said so is the one mistake this line cannot make. Reading a
|
|
102
|
+
* truthy value as reversible would do exactly that, since a non-empty string is truthy.
|
|
103
|
+
*
|
|
104
|
+
* This is not rejectionIsFinal. That says whether **rejecting** ends the case for good; this says
|
|
105
|
+
* whether **approving** can be taken back. The twin actuation carries both, which is why they must
|
|
106
|
+
* never share a sentence.
|
|
107
|
+
*/
|
|
108
|
+
export function reversibilityOf(slot) {
|
|
109
|
+
return typeof slot?.value === 'boolean' ? slot.value : undefined;
|
|
110
|
+
}
|
|
111
|
+
//# sourceMappingURL=decision-slots.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"decision-slots.js","sourceRoot":"","sources":["../../client/components/decision-slots.ts"],"names":[],"mappings":"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","sourcesContent":["/**\n * Turns an activity's decisionKeys declaration plus an instance's input into the slots a decision\n * screen draws.\n *\n * ── Nothing is imported ───────────────────────────────────────────────────\n * No lit, no i18next. The rule is a mapping from a declaration and a payload to an ordered list,\n * and keeping it free of imports is what lets the test runner hold it: that runner parses\n * TypeScript by stripping types and reads neither decorators nor enums, so one heavy import takes\n * a whole test file down with it. Labels and markup are the caller's half.\n */\n\n/** The roles that may appear more than once. Every other role names one value. */\nexport const REPEATABLE_ROLES = ['consequence', 'evidence'] as const\n\n/** Listed in the order the screen reads them: what is asked, then past, present, future. */\nexport const DECISION_ROLES = [\n 'headline',\n 'subject',\n 'reversibility',\n 'reason',\n 'evidence',\n 'currentState',\n 'consequence',\n 'policy'\n] as const\n\nexport type DecisionKeyDeclaration = {\n role?: string\n inputPath?: string\n name?: string\n tKey?: string\n unit?: string\n}\n\nexport type DecisionSlot = {\n role: string\n inputPath: string\n tKey?: string\n unit?: string\n /** What the path led to. Undefined both when the path leads nowhere and when the value is unset. */\n value: unknown\n /**\n * Whether the path led anywhere at all.\n *\n * A reason nobody wrote and a reason whose path is wrong look identical in `value`, and the screen\n * owes different answers: the first is 「사유 없음」 in grey, the second is a declaration that does\n * not match the payload and must not be drawn as if the person left it blank. Folding them into\n * one value is the fallback that shifts meaning.\n */\n found: boolean\n}\n\n/**\n * Reads a dotted path out of the input.\n *\n * Dots only. An array index or a wildcard is not part of the path language — drawing a list is the\n * slot's job — so 'shift.passes[0]' looks for a key spelled \"passes[0]\", finds nothing, and reports\n * found: false. The declaration guard refuses such a path when it arrives, so this is the second\n * line rather than the first.\n *\n * A path that runs into a non-object partway reports found: false rather than throwing. The screen\n * has to draw something either way, and a thrown error here would take the whole approval down over\n * one slot.\n */\nexport function valueAtPath(input: any, path: string): { value: unknown; found: boolean } {\n const steps = String(path ?? '')\n .split('.')\n .filter(step => step.length > 0)\n\n if (!steps.length) {\n return { value: undefined, found: false }\n }\n\n let at: any = input\n\n for (const step of steps) {\n if (at === null || at === undefined || typeof at !== 'object') {\n return { value: undefined, found: false }\n }\n\n if (!Object.prototype.hasOwnProperty.call(at, step)) {\n return { value: undefined, found: false }\n }\n\n at = at[step]\n }\n\n return { value: at, found: true }\n}\n\n/**\n * The slots to draw, in the order they were declared.\n *\n * Declaration order is the screen's hierarchy: plant wrote four of these screens by hand and all\n * four put the headline first, then the subject, the reason, what changes, and why it came up. That\n * agreement is what makes the order part of the contract rather than a preference, so this function\n * neither sorts nor groups.\n *\n * Every declared key produces a slot, including one whose path leads nowhere. Dropping those would\n * leave the screen unable to say that a declaration and a payload disagree, and a reader would see\n * a screen that looks complete.\n */\nexport function decisionSlots(\n decisionKeys: DecisionKeyDeclaration[] | null | undefined,\n input: any\n): DecisionSlot[] {\n if (!decisionKeys?.length) {\n return []\n }\n\n return decisionKeys.map(key => {\n const { value, found } = valueAtPath(input, String(key?.inputPath ?? ''))\n\n return {\n role: String(key?.role ?? ''),\n inputPath: String(key?.inputPath ?? ''),\n tKey: key?.tKey,\n unit: key?.unit,\n value,\n found\n }\n })\n}\n\n/** The slots for one role, in declared order. Empty when the activity declared none. */\nexport function slotsOfRole(slots: DecisionSlot[], role: string): DecisionSlot[] {\n return slots.filter(slot => slot.role === role)\n}\n\n/**\n * The single slot for a role that names one value, or undefined.\n *\n * Reaching for a second one would be reading a declaration the guard refuses, so this answers the\n * first and does not quietly merge.\n */\nexport function slotOfRole(slots: DecisionSlot[], role: string): DecisionSlot | undefined {\n return slots.find(slot => slot.role === role)\n}\n\n/**\n * Whether approving can be undone: true, false, or undefined for \"the screen does not know\".\n *\n * Three answers, not two. A path that led nowhere and a value that is not a boolean both mean the\n * payload did not say, and the screen must draw nothing then — telling an approver that an action\n * can be taken back when nobody said so is the one mistake this line cannot make. Reading a\n * truthy value as reversible would do exactly that, since a non-empty string is truthy.\n *\n * This is not rejectionIsFinal. That says whether **rejecting** ends the case for good; this says\n * whether **approving** can be taken back. The twin actuation carries both, which is why they must\n * never share a sentence.\n */\nexport function reversibilityOf(slot?: DecisionSlot): boolean | undefined {\n return typeof slot?.value === 'boolean' ? slot.value : undefined\n}\n"]}
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import '@material/web/icon/icon.js';
|
|
1
2
|
import '@operato/property-editor/ox-properties-dynamic-view.js';
|
|
2
3
|
import '@operato/board/ox-board-viewer.js';
|
|
3
4
|
import '../../components/activity-approval-ribon.js';
|
|
@@ -30,6 +31,20 @@ export declare class ActivityApprovalPage extends ActivityApprovalPage_base {
|
|
|
30
31
|
activityThread: any;
|
|
31
32
|
board: any;
|
|
32
33
|
commentInput: HTMLTextAreaElement;
|
|
34
|
+
/**
|
|
35
|
+
* Is the reader seated here as a reference — someone who comments and does not decide?
|
|
36
|
+
*
|
|
37
|
+
* The rule comes from organization's client types, the same function its own approval-line editor
|
|
38
|
+
* and list use, so the two wire spellings of the enum are handled in one place. The approval line
|
|
39
|
+
* answers rather than ActivityApproval.participation, matching what the server refuses on
|
|
40
|
+
* (isReferenceOrder in approval-line.ts): the line decides who comes next, so letting the row
|
|
41
|
+
* decide who may judge would leave two authorities with nothing to settle a disagreement.
|
|
42
|
+
*
|
|
43
|
+
* The value comes back false while the query is still out. That is the same answer as for an
|
|
44
|
+
* approver, so the buttons show for a moment on a reference's screen — pressing one is refused by
|
|
45
|
+
* the server, which is why the server closed first.
|
|
46
|
+
*/
|
|
47
|
+
get isReference(): boolean;
|
|
33
48
|
get context(): {
|
|
34
49
|
title: any;
|
|
35
50
|
help: string;
|
|
@@ -72,8 +87,65 @@ export declare class ActivityApprovalPage extends ActivityApprovalPage_base {
|
|
|
72
87
|
* approveActivityApproval / rejectActivityApproval 은 id 와 comment 만 보낸다 — 그 값은 어디에도
|
|
73
88
|
* 가지 않는다. 결재자가 적을 수 있는 것은 의견 하나이고, 그것은 화면 아래 칸이 받는다.
|
|
74
89
|
*/
|
|
90
|
+
/**
|
|
91
|
+
* The decision the activity declared, or nothing when it declared none.
|
|
92
|
+
*
|
|
93
|
+
* Returning nothing is how generatedContent knows to fall back to the model. An activity with no
|
|
94
|
+
* decisionKeys draws exactly what it drew before.
|
|
95
|
+
*
|
|
96
|
+
* A slot whose path led nowhere is skipped rather than drawn empty. Older instances of an activity
|
|
97
|
+
* predate a field the declaration names — plant hit that with its `policy` value — and an empty
|
|
98
|
+
* bar on the screen would read as "there is no reason" when the truth is that this record has no
|
|
99
|
+
* such value. What cannot be shown is left out; what is shown is only what the payload actually
|
|
100
|
+
* carries.
|
|
101
|
+
*
|
|
102
|
+
* `reason` is the exception. Missing and blank mean the same thing to whoever is reading — nobody
|
|
103
|
+
* wrote one — so both draw the grey line rather than disappearing. A reason that silently vanishes
|
|
104
|
+
* would let an approver assume it was never asked for.
|
|
105
|
+
*/
|
|
106
|
+
decisionContent(): DirectiveResult<{
|
|
107
|
+
new (_partInfo: import("lit-html/directive.js").PartInfo): import("lit-html/directives/keyed.js").Keyed<TemplateResult<1>>;
|
|
108
|
+
}>;
|
|
109
|
+
/**
|
|
110
|
+
* Whether approving can be undone, drawn as the frame around the decision.
|
|
111
|
+
*
|
|
112
|
+
* Only an explicit true or false draws. Anything else — the path led nowhere, or the value is not
|
|
113
|
+
* a boolean — draws nothing, because saying "this can be undone" on a screen that does not know is
|
|
114
|
+
* the one mistake this line must never make.
|
|
115
|
+
*
|
|
116
|
+
* This is not rejectionIsFinal. That one says whether **rejecting** ends the case for good; this
|
|
117
|
+
* says whether **approving** can be taken back. The twin actuation carries both, which is exactly
|
|
118
|
+
* why they must not share a sentence.
|
|
119
|
+
*/
|
|
120
|
+
private renderReversibility;
|
|
121
|
+
/**
|
|
122
|
+
* One slot's value as something to read.
|
|
123
|
+
*
|
|
124
|
+
* A scalar prints with its unit when one was declared. Anything shaped — an object, a list — goes
|
|
125
|
+
* through fieldValue, the same laying-out the model sections use, so a payload reads the same way
|
|
126
|
+
* wherever it appears and a four-level object does not become one long line.
|
|
127
|
+
*/
|
|
128
|
+
private slotText;
|
|
129
|
+
/** Did a person actually write something here. Whitespace is not words. */
|
|
130
|
+
private hasWords;
|
|
75
131
|
generatedContent(): DirectiveResult;
|
|
76
132
|
boardContent(): DirectiveResult;
|
|
133
|
+
/**
|
|
134
|
+
* The element the activity names, or a plain statement that it could not be loaded.
|
|
135
|
+
*
|
|
136
|
+
* document.createElement answers something for any name, so an activity pointing at an element
|
|
137
|
+
* nobody registered used to produce an empty card. The approver got a screen with nothing on it
|
|
138
|
+
* and the approve button still worked — plant shipped two such forms in one day and found them by
|
|
139
|
+
* reading the file list, not by opening the screen.
|
|
140
|
+
*
|
|
141
|
+
* The reader is told what to judge by instead. Same shape as the empty generated screen: what is
|
|
142
|
+
* missing, and where to look — the submission reason and the history in the timeline below.
|
|
143
|
+
*
|
|
144
|
+
* ── Waiting for a late definition ─────────────────────────────────────────
|
|
145
|
+
* An element can be registered after this page renders, and answering "not loaded" forever in
|
|
146
|
+
* that case would be a screen inventing a defect. whenDefined resolves whenever it arrives and
|
|
147
|
+
* the page redraws; a name nobody ever registers simply never resolves, and the statement stands.
|
|
148
|
+
*/
|
|
77
149
|
customElementContent(): any;
|
|
78
150
|
oxBoardViewer: any;
|
|
79
151
|
getOutputFromBoard(): any;
|