@things-factory/worklist 10.1.24 → 10.1.26
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 +3 -2
- package/dist-client/components/activity-approval-ribon.js.map +1 -1
- package/dist-client/components/activity-starter-form.js +4 -7
- package/dist-client/components/activity-starter-form.js.map +1 -1
- package/dist-client/components/decision-slots.d.ts +1 -1
- package/dist-client/components/decision-slots.js +1 -2
- package/dist-client/components/decision-slots.js.map +1 -1
- package/dist-client/components/state-ribon.js +2 -1
- package/dist-client/components/state-ribon.js.map +1 -1
- package/dist-client/pages/activity/activity-page.js +1 -1
- package/dist-client/pages/activity/activity-page.js.map +1 -1
- package/dist-client/pages/activity-approval/activity-approval-page.d.ts +2 -1
- package/dist-client/pages/activity-approval/activity-approval-page.js +29 -18
- package/dist-client/pages/activity-approval/activity-approval-page.js.map +1 -1
- package/dist-client/pages/activity-approval/approval-gate.d.ts +21 -0
- package/dist-client/pages/activity-approval/approval-gate.js +9 -0
- package/dist-client/pages/activity-approval/approval-gate.js.map +1 -0
- package/dist-client/pages/activity-catalog/activity-catalog-page.d.ts +2 -1
- package/dist-client/pages/activity-catalog/activity-catalog-page.js +19 -4
- package/dist-client/pages/activity-catalog/activity-catalog-page.js.map +1 -1
- package/dist-client/pages/activity-instance/activity-instance-start-page.js +1 -1
- package/dist-client/pages/activity-instance/activity-instance-start-page.js.map +1 -1
- package/dist-client/pages/activity-thread/activity-thread-page.js +1 -1
- package/dist-client/pages/activity-thread/activity-thread-page.js.map +1 -1
- package/dist-client/pages/activity-thread/activity-thread-view-page.js +1 -1
- package/dist-client/pages/activity-thread/activity-thread-view-page.js.map +1 -1
- package/dist-client/pages/installable-activity/installable-activity-list-page.js +5 -1
- package/dist-client/pages/installable-activity/installable-activity-list-page.js.map +1 -1
- package/dist-client/tsconfig.tsbuildinfo +1 -1
- package/dist-server/service/activity/activity-decision-key-item-type.d.ts +3 -6
- package/dist-server/service/activity/activity-decision-key-item-type.js +3 -6
- package/dist-server/service/activity/activity-decision-key-item-type.js.map +1 -1
- package/dist-server/service/activity/activity-query.d.ts +2 -0
- package/dist-server/service/activity/activity-query.js +12 -0
- package/dist-server/service/activity/activity-query.js.map +1 -1
- package/dist-server/service/activity/decision-key-declaration.d.ts +34 -2
- package/dist-server/service/activity/decision-key-declaration.js +14 -2
- package/dist-server/service/activity/decision-key-declaration.js.map +1 -1
- package/dist-server/service/installable-activity/installable-activity-query.d.ts +4 -0
- package/dist-server/service/installable-activity/installable-activity-query.js +23 -0
- package/dist-server/service/installable-activity/installable-activity-query.js.map +1 -1
- package/dist-server/service/installable-activity/installable-activity.d.ts +3 -2
- package/dist-server/service/installable-activity/installable-activity.js +1 -1
- package/dist-server/service/installable-activity/installable-activity.js.map +1 -1
- package/dist-server/tsconfig.tsbuildinfo +1 -1
- package/package.json +13 -11
- package/translations/en.json +21 -20
- package/translations/ja.json +22 -21
- package/translations/ko.json +22 -21
- package/translations/ms.json +22 -21
- package/translations/zh.json +22 -21
|
@@ -12,7 +12,7 @@ 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, label } = activity || {};
|
|
15
|
+
const { startingType, label, labelTKey } = activity || {};
|
|
16
16
|
/*
|
|
17
17
|
* What kind of decision this is — the activity's own name, not this instance's.
|
|
18
18
|
*
|
|
@@ -27,7 +27,8 @@ let ActivityApprovalRibon = class ActivityApprovalRibon extends localize(i18next
|
|
|
27
27
|
* than the instance description and it is the reason to fill label in — it is not a fallback
|
|
28
28
|
* anybody should be content with.
|
|
29
29
|
*/
|
|
30
|
-
const
|
|
30
|
+
const named = label && labelTKey ? String(i18next.t(labelTKey, { defaultValue: label })) : label;
|
|
31
|
+
const kind = named || description || '';
|
|
31
32
|
return html `
|
|
32
33
|
<span class="state">
|
|
33
34
|
<i class="dot"></i>
|
|
@@ -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,KAAK,EAAE,GAAG,QAAQ,IAAI,EAAE,CAAA;
|
|
1
|
+
{"version":3,"file":"activity-approval-ribon.js","sourceRoot":"","sources":["../../client/components/activity-approval-ribon.ts"],"names":[],"mappings":"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","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, labelTKey } = 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 named = label && labelTKey ? String(i18next.t(labelTKey, { defaultValue: label })) : label\n const kind = named || 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"]}
|
|
@@ -72,14 +72,11 @@ let ActivityStarterForm = class ActivityStarterForm extends localize(i18next)(Li
|
|
|
72
72
|
return html `
|
|
73
73
|
<content>
|
|
74
74
|
<div desc>
|
|
75
|
+
<span>${i18next.t('text.activity-draft-how')}</span>
|
|
75
76
|
<span
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
<span
|
|
81
|
-
>이렇게 생성된 업무 초안은 '작성중인 업무' 리스트에서 찾아볼 수 있으며,
|
|
82
|
-
'${startingType == 'issue' ? '이슈' : '게시'}' 전까지 언제든지 수정할 수 있습니다.</span
|
|
77
|
+
>${i18next.t('text.activity-draft-where', {
|
|
78
|
+
action: i18next.t(startingType == 'issue' ? 'button.issue' : 'button.post')
|
|
79
|
+
})}</span
|
|
83
80
|
>
|
|
84
81
|
</div>
|
|
85
82
|
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"activity-starter-form.js","sourceRoot":"","sources":["../../client/components/activity-starter-form.ts"],"names":[],"mappings":"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","sourcesContent":["import '@material/web/icon/icon.js'\nimport '@material/web/textfield/outlined-text-field.js'\nimport '@material/web/textfield/filled-text-field.js'\nimport '@operato/property-editor/ox-properties-dynamic-view.js'\nimport '@things-factory/organization'\n\nimport gql from 'graphql-tag'\nimport { css, html, LitElement } from 'lit'\nimport { customElement, property, state } from 'lit/decorators.js'\n\nimport { navigate } from '@operato/shell'\nimport { client } from '@operato/graphql'\nimport { i18next, localize } from '@operato/i18n'\nimport { ranMutation } from './say-outcome.js'\nimport { notify } from '@operato/layout'\nimport { CommonHeaderStyles, ScrollbarStyles } from '@operato/styles'\n\n@customElement('activity-starter-form')\nexport class ActivityStarterForm extends localize(i18next)(LitElement) {\n static styles = [\n CommonHeaderStyles,\n ScrollbarStyles,\n css`\n :host {\n display: flex;\n flex-direction: column;\n\n color: var(--md-sys-color-on-s);\n background-color: var(--md-sys-color-surface);\n }\n\n content {\n flex: 1;\n display: flex;\n flex-direction: column;\n padding: var(--spacing-medium);\n gap: var(--spacing-medium);\n overflow: auto;\n }\n\n content > div {\n display: flex;\n flex-direction: column;\n }\n\n content label {\n font: var(--label-font);\n }\n content input,\n content textarea {\n border-radius: var(--border-radius);\n border: var(--border-dim-color);\n padding: var(--input-padding);\n margin: var(--input-margin);\n font: var(--input-font);\n }\n\n content [desc] {\n font-size: 0.9em;\n }\n\n #description {\n flex: 1;\n }\n `\n ]\n\n @property({ type: String }) activityId?: string\n\n @state() activity: any = {}\n @state() activityInstance: any = {}\n\n render() {\n var { thumbnail, startingType } = this.activity || {}\n var { name, description } = this.activityInstance\n\n return html`\n <content>\n <div desc>\n <span\n >업무의 타이틀과 설명을 작성해서 초안저장을 클릭하시면, 업무 초안이 생성되고 편집할 수 있는 페이지로\n 이동합니다.</span\n >\n\n <span\n >이렇게 생성된 업무 초안은 '작성중인 업무' 리스트에서 찾아볼 수 있으며,\n '${startingType == 'issue' ? '이슈' : '게시'}' 전까지 언제든지 수정할 수 있습니다.</span\n >\n </div>\n\n <md-outlined-text-field\n id=\"name\"\n type=\"text\"\n label=${String(i18next.t('label.title'))}\n .value=${name || this.activity?.name || ''}\n @change=${e => (this.activityInstance.name = e.currentTarget.value)}\n >\n </md-outlined-text-field>\n\n <md-filled-text-field\n id=\"description\"\n type=\"textarea\"\n label=${String(i18next.t('label.description'))}\n resize=\"none\"\n .value=${description || this.activity?.description || ''}\n @change=${e => {\n this.activityInstance.description = e.currentTarget.value\n }}\n >\n </md-filled-text-field>\n </content>\n\n <div class=\"footer\">\n <div filler></div>\n <button @click=${e => history.back()}><md-icon>close</md-icon>${i18next.t('button.close')}</button>\n <button @click=${this.draftActivityInstance.bind(this)} done>\n <md-icon>save</md-icon>${i18next.t('button.draft')}\n </button>\n </div>\n `\n }\n\n firstUpdated() {\n this.fetchActivity(this.activityId)\n }\n\n async fetchActivity(id) {\n const response = await client.query({\n query: gql`\n query activity($id: String!) {\n activity(id: $id) {\n id\n name\n description\n state\n multiple\n startingType\n assignees {\n type\n value\n assignee {\n id\n name\n description\n controlNo\n }\n }\n approvalLine {\n type\n participation\n value\n approver {\n id\n name\n description\n controlNo\n }\n }\n thumbnail\n model {\n name\n description\n active\n tag\n inout\n type\n unit\n options\n quantifier\n spec\n }\n }\n }\n `,\n variables: {\n id\n }\n })\n\n this.activity = response.data.activity\n }\n\n async draftActivityInstance() {\n var { id: activityId } = this.activity\n var { id, name, description, priority, threadsMin, threadsMax, dueAt, input, assignees, approvalLine } =\n this.activityInstance\n\n name ||= this.activity.name\n description ||= this.activity.description\n assignees ||= this.activity.assignees\n approvalLine ||= this.activity.approvalLine\n\n var activityInstance = {\n id,\n activityId,\n name,\n description,\n priority,\n threadsMax,\n threadsMin,\n dueAt,\n input,\n assignees,\n approvalLine\n }\n\n const outcome = await ranMutation(() => client.mutate({\n mutation: gql`\n mutation ($activityInstance: ActivityInstanceDraft!) {\n draftActivityInstance(activityInstance: $activityInstance) {\n id\n name\n description\n input\n output\n state\n assignees {\n type\n value\n assignee {\n id\n name\n description\n controlNo\n }\n }\n approvalLine {\n type\n participation\n value\n approver {\n id\n name\n description\n controlNo\n }\n }\n threadsMin\n threadsMax\n }\n }\n `,\n variables: {\n activityInstance\n }\n }))\n\n if (!outcome.ok) { return\n }\n\n this.activityInstance = outcome.data.draftActivityInstance\n notify({\n message: i18next.t('text.info_x_successfully', {\n x: `${i18next.t('label.activity-instance')} ${i18next.t('text.draft')}`\n })\n })\n\n this.openActivityInstanceStart(this.activityInstance)\n }\n\n openActivityInstanceStart(activityInstance) {\n navigate(`activity-instance-start/${activityInstance.id}?title=${activityInstance.name}`)\n }\n}\n"]}
|
|
1
|
+
{"version":3,"file":"activity-starter-form.js","sourceRoot":"","sources":["../../client/components/activity-starter-form.ts"],"names":[],"mappings":"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","sourcesContent":["import '@material/web/icon/icon.js'\nimport '@material/web/textfield/outlined-text-field.js'\nimport '@material/web/textfield/filled-text-field.js'\nimport '@operato/property-editor/ox-properties-dynamic-view.js'\nimport '@things-factory/organization'\n\nimport gql from 'graphql-tag'\nimport { css, html, LitElement } from 'lit'\nimport { customElement, property, state } from 'lit/decorators.js'\n\nimport { navigate } from '@operato/shell'\nimport { client } from '@operato/graphql'\nimport { i18next, localize } from '@operato/i18n'\nimport { ranMutation } from './say-outcome.js'\nimport { notify } from '@operato/layout'\nimport { CommonHeaderStyles, ScrollbarStyles } from '@operato/styles'\n\n@customElement('activity-starter-form')\nexport class ActivityStarterForm extends localize(i18next)(LitElement) {\n static styles = [\n CommonHeaderStyles,\n ScrollbarStyles,\n css`\n :host {\n display: flex;\n flex-direction: column;\n\n color: var(--md-sys-color-on-s);\n background-color: var(--md-sys-color-surface);\n }\n\n content {\n flex: 1;\n display: flex;\n flex-direction: column;\n padding: var(--spacing-medium);\n gap: var(--spacing-medium);\n overflow: auto;\n }\n\n content > div {\n display: flex;\n flex-direction: column;\n }\n\n content label {\n font: var(--label-font);\n }\n content input,\n content textarea {\n border-radius: var(--border-radius);\n border: var(--border-dim-color);\n padding: var(--input-padding);\n margin: var(--input-margin);\n font: var(--input-font);\n }\n\n content [desc] {\n font-size: 0.9em;\n }\n\n #description {\n flex: 1;\n }\n `\n ]\n\n @property({ type: String }) activityId?: string\n\n @state() activity: any = {}\n @state() activityInstance: any = {}\n\n render() {\n var { thumbnail, startingType } = this.activity || {}\n var { name, description } = this.activityInstance\n\n return html`\n <content>\n <div desc>\n <span>${i18next.t('text.activity-draft-how')}</span>\n <span\n >${i18next.t('text.activity-draft-where', {\n action: i18next.t(startingType == 'issue' ? 'button.issue' : 'button.post')\n })}</span\n >\n </div>\n\n <md-outlined-text-field\n id=\"name\"\n type=\"text\"\n label=${String(i18next.t('label.title'))}\n .value=${name || this.activity?.name || ''}\n @change=${e => (this.activityInstance.name = e.currentTarget.value)}\n >\n </md-outlined-text-field>\n\n <md-filled-text-field\n id=\"description\"\n type=\"textarea\"\n label=${String(i18next.t('label.description'))}\n resize=\"none\"\n .value=${description || this.activity?.description || ''}\n @change=${e => {\n this.activityInstance.description = e.currentTarget.value\n }}\n >\n </md-filled-text-field>\n </content>\n\n <div class=\"footer\">\n <div filler></div>\n <button @click=${e => history.back()}><md-icon>close</md-icon>${i18next.t('button.close')}</button>\n <button @click=${this.draftActivityInstance.bind(this)} done>\n <md-icon>save</md-icon>${i18next.t('button.draft')}\n </button>\n </div>\n `\n }\n\n firstUpdated() {\n this.fetchActivity(this.activityId)\n }\n\n async fetchActivity(id) {\n const response = await client.query({\n query: gql`\n query activity($id: String!) {\n activity(id: $id) {\n id\n name\n description\n state\n multiple\n startingType\n assignees {\n type\n value\n assignee {\n id\n name\n description\n controlNo\n }\n }\n approvalLine {\n type\n participation\n value\n approver {\n id\n name\n description\n controlNo\n }\n }\n thumbnail\n model {\n name\n description\n active\n tag\n inout\n type\n unit\n options\n quantifier\n spec\n }\n }\n }\n `,\n variables: {\n id\n }\n })\n\n this.activity = response.data.activity\n }\n\n async draftActivityInstance() {\n var { id: activityId } = this.activity\n var { id, name, description, priority, threadsMin, threadsMax, dueAt, input, assignees, approvalLine } =\n this.activityInstance\n\n name ||= this.activity.name\n description ||= this.activity.description\n assignees ||= this.activity.assignees\n approvalLine ||= this.activity.approvalLine\n\n var activityInstance = {\n id,\n activityId,\n name,\n description,\n priority,\n threadsMax,\n threadsMin,\n dueAt,\n input,\n assignees,\n approvalLine\n }\n\n const outcome = await ranMutation(() => client.mutate({\n mutation: gql`\n mutation ($activityInstance: ActivityInstanceDraft!) {\n draftActivityInstance(activityInstance: $activityInstance) {\n id\n name\n description\n input\n output\n state\n assignees {\n type\n value\n assignee {\n id\n name\n description\n controlNo\n }\n }\n approvalLine {\n type\n participation\n value\n approver {\n id\n name\n description\n controlNo\n }\n }\n threadsMin\n threadsMax\n }\n }\n `,\n variables: {\n activityInstance\n }\n }))\n\n if (!outcome.ok) { return\n }\n\n this.activityInstance = outcome.data.draftActivityInstance\n notify({\n message: i18next.t('text.info_x_successfully', {\n x: `${i18next.t('label.activity-instance')} ${i18next.t('text.draft')}`\n })\n })\n\n this.openActivityInstanceStart(this.activityInstance)\n }\n\n openActivityInstanceStart(activityInstance) {\n navigate(`activity-instance-start/${activityInstance.id}?title=${activityInstance.name}`)\n }\n}\n"]}
|
|
@@ -11,7 +11,7 @@
|
|
|
11
11
|
/** The roles that may appear more than once. Every other role names one value. */
|
|
12
12
|
export declare const REPEATABLE_ROLES: readonly ["consequence", "evidence"];
|
|
13
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"
|
|
14
|
+
export declare const DECISION_ROLES: readonly ["headline", "subject", "reversibility", "reason", "evidence", "currentState", "consequence"];
|
|
15
15
|
export type DecisionKeyDeclaration = {
|
|
16
16
|
role?: string;
|
|
17
17
|
inputPath?: string;
|
|
@@ -1 +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 /** i18n key for the value **sentence** — `approval.<door>.<inputPath>`, computed by the server. */\n valueTKey?: string\n /** What the sentence puts in its blanks: name in the sentence → inputPath to read it from. */\n params?: { [name: string]: string }\n}\n\nexport type DecisionSlot = {\n role: string\n inputPath: string\n /**\n * 번역이 없을 때 화면이 보일 수 있는 단 하나의 글.\n *\n * 선언은 늘 이것을 주는데 슬롯이 버리고 있었다. 그래서 `tKey` 가 다섯 언어 어디에도 없으면 화면에\n * 남는 것이 점 섞인 키뿐이었다 — 보일 것이 없는 게 아니라 **가진 것을 안 나른 것**이다.\n */\n name?: string\n tKey?: string\n unit?: string\n /** i18n key for the value sentence. Absent means the frozen `value` is what this slot has. */\n valueTKey?: string\n /**\n * The sentence's blanks, **already read out of the input.**\n *\n * The declaration says where each value lives; this says what was there. Resolving here rather\n * than on the screen keeps the path language in one place — the same `valueAtPath` the slot's own\n * value goes through, so a params path that leads nowhere behaves the way an inputPath does\n * instead of inventing a second rule.\n */\n params?: { [name: string]: unknown }\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 name: key?.name,\n tKey: key?.tKey,\n unit: key?.unit,\n valueTKey: key?.valueTKey,\n params: paramsFrom(key?.params, input),\n value,\n found\n }\n })\n}\n\n/**\n * Read the sentence's blanks out of the input.\n *\n * A path that leads nowhere lands as `undefined`, the same as a slot's own value — i18next prints\n * an empty blank rather than the word `undefined`, and the sentence still says the rest. Folding it\n * into an empty string here would hide which of the two it was from anyone looking later.\n *\n * Returns undefined when nothing was declared, so a slot without a sentence carries no empty object\n * for a reader to puzzle over.\n */\nfunction paramsFrom(\n declared: { [name: string]: string } | undefined,\n input: { [key: string]: any } | undefined | null\n): { [name: string]: unknown } | undefined {\n const names = Object.keys(declared || {})\n\n if (!names.length) {\n return undefined\n }\n\n const read: { [name: string]: unknown } = {}\n\n for (const name of names) {\n read[name] = valueAtPath(input, String(declared![name] ?? '')).value\n }\n\n return read\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 * What the declaration says about undoing this approval.\n *\n * The value is an object: `reversible` is required and `caveat` is the module's own sentence about\n * it. The asymmetry is the point — the boolean decides how heavily the screen draws the band, and\n * a sentence alone cannot decide that.\n *\n * { reversible: false, caveat: '버린 자재는 돌아오지 않습니다' }\n *\n * ── A condition is written as false ───────────────────────────────────────\n * 「되돌릴 수 있습니다 — 단, 실적이 마감되기 전까지」 is written `false` with the condition in the\n * caveat. Written `true` the screen draws it lightly and the reader walks past the condition. There\n * is no third value: a middle one always draws ambiguously, and the reader has to guess which side\n * it is on. (2026-09-11, architect's ruling)\n *\n * ── Not `note` ───────────────────────────────────────────────────────────\n * ops-contract already has CommandApproval.note, and that one is **the approver's own comment** —\n * a person's words, in the same neighbourhood as this screen. Same word for a module's sentence\n * would be read as the person's. `caveat` is used nowhere in the three repositories.\n */\nexport type Reversibility = { reversible: boolean; caveat?: string }\n\n/**\n * What the slot says, or undefined when it does not say.\n *\n * Undefined covers both \"the path led nowhere\" and \"nobody declared the role\". Drawing nothing is\n * right for both: telling an approver an action can be taken back when the payload never said so\n * is the one mistake this line cannot make, and a truthy read would make it — the string\n * '되돌릴 수 없습니다…' is truthy.\n */\nexport function reversibilityOf(slot?: DecisionSlot): Reversibility | undefined {\n const value: any = slot?.value\n\n if (!value || typeof value !== 'object' || typeof value.reversible !== 'boolean') {\n return undefined\n }\n\n return {\n reversible: value.reversible,\n ...(typeof value.caveat === 'string' && value.caveat.trim() ? { caveat: value.caveat } : {})\n }\n}\n\n/**\n * The value is there but not the shape this role takes.\n *\n * plant declared the role and put a sentence at that path, so the band drew nothing at all and the\n * heaviest line on the screen was silently missing. Reporting nothing to the reader is right — the\n * screen cannot tell which way it goes — but a developer should not have to find it by hand. The\n * caller logs this; the rule stays free of side effects so a test can hold it.\n */\nexport function reversibilityIsMalformed(slot?: DecisionSlot): boolean {\n return !!slot && slot.found && slot.value != null && reversibilityOf(slot) === undefined\n}\n"]}
|
|
1
|
+
{"version":3,"file":"decision-slots.js","sourceRoot":"","sources":["../../client/components/decision-slots.ts"],"names":[],"mappings":"AAAA;;;;;;;;;GASG;AAEH,kFAAkF;AAClF,MAAM,CAAC,MAAM,gBAAgB,GAAG,CAAC,aAAa,EAAE,UAAU,CAAU,CAAA;AAEpE,4FAA4F;AAC5F,MAAM,CAAC,MAAM,cAAc,GAAG;IAC5B,UAAU;IACV,SAAS;IACT,eAAe;IACf,QAAQ;IACR,UAAU;IACV,cAAc;IACd,aAAa;CACL,CAAA;AAkDV;;;;;;;;;;;GAWG;AACH,MAAM,UAAU,WAAW,CAAC,KAAU,EAAE,IAAY;IAClD,MAAM,KAAK,GAAG,MAAM,CAAC,IAAI,IAAI,EAAE,CAAC;SAC7B,KAAK,CAAC,GAAG,CAAC;SACV,MAAM,CAAC,IAAI,CAAC,EAAE,CAAC,IAAI,CAAC,MAAM,GAAG,CAAC,CAAC,CAAA;IAElC,IAAI,CAAC,KAAK,CAAC,MAAM,EAAE,CAAC;QAClB,OAAO,EAAE,KAAK,EAAE,SAAS,EAAE,KAAK,EAAE,KAAK,EAAE,CAAA;IAC3C,CAAC;IAED,IAAI,EAAE,GAAQ,KAAK,CAAA;IAEnB,KAAK,MAAM,IAAI,IAAI,KAAK,EAAE,CAAC;QACzB,IAAI,EAAE,KAAK,IAAI,IAAI,EAAE,KAAK,SAAS,IAAI,OAAO,EAAE,KAAK,QAAQ,EAAE,CAAC;YAC9D,OAAO,EAAE,KAAK,EAAE,SAAS,EAAE,KAAK,EAAE,KAAK,EAAE,CAAA;QAC3C,CAAC;QAED,IAAI,CAAC,MAAM,CAAC,SAAS,CAAC,cAAc,CAAC,IAAI,CAAC,EAAE,EAAE,IAAI,CAAC,EAAE,CAAC;YACpD,OAAO,EAAE,KAAK,EAAE,SAAS,EAAE,KAAK,EAAE,KAAK,EAAE,CAAA;QAC3C,CAAC;QAED,EAAE,GAAG,EAAE,CAAC,IAAI,CAAC,CAAA;IACf,CAAC;IAED,OAAO,EAAE,KAAK,EAAE,EAAE,EAAE,KAAK,EAAE,IAAI,EAAE,CAAA;AACnC,CAAC;AAED;;;;;;;;;;;GAWG;AACH,MAAM,UAAU,aAAa,CAC3B,YAAyD,EACzD,KAAU;IAEV,IAAI,CAAC,YAAY,EAAE,MAAM,EAAE,CAAC;QAC1B,OAAO,EAAE,CAAA;IACX,CAAC;IAED,OAAO,YAAY,CAAC,GAAG,CAAC,GAAG,CAAC,EAAE;QAC5B,MAAM,EAAE,KAAK,EAAE,KAAK,EAAE,GAAG,WAAW,CAAC,KAAK,EAAE,MAAM,CAAC,GAAG,EAAE,SAAS,IAAI,EAAE,CAAC,CAAC,CAAA;QAEzE,OAAO;YACL,IAAI,EAAE,MAAM,CAAC,GAAG,EAAE,IAAI,IAAI,EAAE,CAAC;YAC7B,SAAS,EAAE,MAAM,CAAC,GAAG,EAAE,SAAS,IAAI,EAAE,CAAC;YACvC,IAAI,EAAE,GAAG,EAAE,IAAI;YACf,IAAI,EAAE,GAAG,EAAE,IAAI;YACf,IAAI,EAAE,GAAG,EAAE,IAAI;YACf,SAAS,EAAE,GAAG,EAAE,SAAS;YACzB,MAAM,EAAE,UAAU,CAAC,GAAG,EAAE,MAAM,EAAE,KAAK,CAAC;YACtC,KAAK;YACL,KAAK;SACN,CAAA;IACH,CAAC,CAAC,CAAA;AACJ,CAAC;AAED;;;;;;;;;GASG;AACH,SAAS,UAAU,CACjB,QAAgD,EAChD,KAAgD;IAEhD,MAAM,KAAK,GAAG,MAAM,CAAC,IAAI,CAAC,QAAQ,IAAI,EAAE,CAAC,CAAA;IAEzC,IAAI,CAAC,KAAK,CAAC,MAAM,EAAE,CAAC;QAClB,OAAO,SAAS,CAAA;IAClB,CAAC;IAED,MAAM,IAAI,GAAgC,EAAE,CAAA;IAE5C,KAAK,MAAM,IAAI,IAAI,KAAK,EAAE,CAAC;QACzB,IAAI,CAAC,IAAI,CAAC,GAAG,WAAW,CAAC,KAAK,EAAE,MAAM,CAAC,QAAS,CAAC,IAAI,CAAC,IAAI,EAAE,CAAC,CAAC,CAAC,KAAK,CAAA;IACtE,CAAC;IAED,OAAO,IAAI,CAAA;AACb,CAAC;AAED,wFAAwF;AACxF,MAAM,UAAU,WAAW,CAAC,KAAqB,EAAE,IAAY;IAC7D,OAAO,KAAK,CAAC,MAAM,CAAC,IAAI,CAAC,EAAE,CAAC,IAAI,CAAC,IAAI,KAAK,IAAI,CAAC,CAAA;AACjD,CAAC;AAED;;;;;GAKG;AACH,MAAM,UAAU,UAAU,CAAC,KAAqB,EAAE,IAAY;IAC5D,OAAO,KAAK,CAAC,IAAI,CAAC,IAAI,CAAC,EAAE,CAAC,IAAI,CAAC,IAAI,KAAK,IAAI,CAAC,CAAA;AAC/C,CAAC;AAwBD;;;;;;;GAOG;AACH,MAAM,UAAU,eAAe,CAAC,IAAmB;IACjD,MAAM,KAAK,GAAQ,IAAI,EAAE,KAAK,CAAA;IAE9B,IAAI,CAAC,KAAK,IAAI,OAAO,KAAK,KAAK,QAAQ,IAAI,OAAO,KAAK,CAAC,UAAU,KAAK,SAAS,EAAE,CAAC;QACjF,OAAO,SAAS,CAAA;IAClB,CAAC;IAED,OAAO;QACL,UAAU,EAAE,KAAK,CAAC,UAAU;QAC5B,GAAG,CAAC,OAAO,KAAK,CAAC,MAAM,KAAK,QAAQ,IAAI,KAAK,CAAC,MAAM,CAAC,IAAI,EAAE,CAAC,CAAC,CAAC,EAAE,MAAM,EAAE,KAAK,CAAC,MAAM,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;KAC7F,CAAA;AACH,CAAC;AAED;;;;;;;GAOG;AACH,MAAM,UAAU,wBAAwB,CAAC,IAAmB;IAC1D,OAAO,CAAC,CAAC,IAAI,IAAI,IAAI,CAAC,KAAK,IAAI,IAAI,CAAC,KAAK,IAAI,IAAI,IAAI,eAAe,CAAC,IAAI,CAAC,KAAK,SAAS,CAAA;AAC1F,CAAC","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] as const\n\nexport type DecisionKeyDeclaration = {\n role?: string\n inputPath?: string\n name?: string\n tKey?: string\n unit?: string\n /** i18n key for the value **sentence** — `approval.<door>.<inputPath>`, computed by the server. */\n valueTKey?: string\n /** What the sentence puts in its blanks: name in the sentence → inputPath to read it from. */\n params?: { [name: string]: string }\n}\n\nexport type DecisionSlot = {\n role: string\n inputPath: string\n /**\n * 번역이 없을 때 화면이 보일 수 있는 단 하나의 글.\n *\n * 선언은 늘 이것을 주는데 슬롯이 버리고 있었다. 그래서 `tKey` 가 다섯 언어 어디에도 없으면 화면에\n * 남는 것이 점 섞인 키뿐이었다 — 보일 것이 없는 게 아니라 **가진 것을 안 나른 것**이다.\n */\n name?: string\n tKey?: string\n unit?: string\n /** i18n key for the value sentence. Absent means the frozen `value` is what this slot has. */\n valueTKey?: string\n /**\n * The sentence's blanks, **already read out of the input.**\n *\n * The declaration says where each value lives; this says what was there. Resolving here rather\n * than on the screen keeps the path language in one place — the same `valueAtPath` the slot's own\n * value goes through, so a params path that leads nowhere behaves the way an inputPath does\n * instead of inventing a second rule.\n */\n params?: { [name: string]: unknown }\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 name: key?.name,\n tKey: key?.tKey,\n unit: key?.unit,\n valueTKey: key?.valueTKey,\n params: paramsFrom(key?.params, input),\n value,\n found\n }\n })\n}\n\n/**\n * Read the sentence's blanks out of the input.\n *\n * A path that leads nowhere lands as `undefined`, the same as a slot's own value — i18next prints\n * an empty blank rather than the word `undefined`, and the sentence still says the rest. Folding it\n * into an empty string here would hide which of the two it was from anyone looking later.\n *\n * Returns undefined when nothing was declared, so a slot without a sentence carries no empty object\n * for a reader to puzzle over.\n */\nfunction paramsFrom(\n declared: { [name: string]: string } | undefined,\n input: { [key: string]: any } | undefined | null\n): { [name: string]: unknown } | undefined {\n const names = Object.keys(declared || {})\n\n if (!names.length) {\n return undefined\n }\n\n const read: { [name: string]: unknown } = {}\n\n for (const name of names) {\n read[name] = valueAtPath(input, String(declared![name] ?? '')).value\n }\n\n return read\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 * What the declaration says about undoing this approval.\n *\n * The value is an object: `reversible` is required and `caveat` is the module's own sentence about\n * it. The asymmetry is the point — the boolean decides how heavily the screen draws the band, and\n * a sentence alone cannot decide that.\n *\n * { reversible: false, caveat: '버린 자재는 돌아오지 않습니다' }\n *\n * ── A condition is written as false ───────────────────────────────────────\n * 「되돌릴 수 있습니다 — 단, 실적이 마감되기 전까지」 is written `false` with the condition in the\n * caveat. Written `true` the screen draws it lightly and the reader walks past the condition. There\n * is no third value: a middle one always draws ambiguously, and the reader has to guess which side\n * it is on. (2026-09-11, architect's ruling)\n *\n * ── Not `note` ───────────────────────────────────────────────────────────\n * ops-contract already has CommandApproval.note, and that one is **the approver's own comment** —\n * a person's words, in the same neighbourhood as this screen. Same word for a module's sentence\n * would be read as the person's. `caveat` is used nowhere in the three repositories.\n */\nexport type Reversibility = { reversible: boolean; caveat?: string }\n\n/**\n * What the slot says, or undefined when it does not say.\n *\n * Undefined covers both \"the path led nowhere\" and \"nobody declared the role\". Drawing nothing is\n * right for both: telling an approver an action can be taken back when the payload never said so\n * is the one mistake this line cannot make, and a truthy read would make it — the string\n * '되돌릴 수 없습니다…' is truthy.\n */\nexport function reversibilityOf(slot?: DecisionSlot): Reversibility | undefined {\n const value: any = slot?.value\n\n if (!value || typeof value !== 'object' || typeof value.reversible !== 'boolean') {\n return undefined\n }\n\n return {\n reversible: value.reversible,\n ...(typeof value.caveat === 'string' && value.caveat.trim() ? { caveat: value.caveat } : {})\n }\n}\n\n/**\n * The value is there but not the shape this role takes.\n *\n * plant declared the role and put a sentence at that path, so the band drew nothing at all and the\n * heaviest line on the screen was silently missing. Reporting nothing to the reader is right — the\n * screen cannot tell which way it goes — but a developer should not have to find it by hand. The\n * caller logs this; the rule stays free of side effects so a test can hold it.\n */\nexport function reversibilityIsMalformed(slot?: DecisionSlot): boolean {\n return !!slot && slot.found && slot.value != null && reversibilityOf(slot) === undefined\n}\n"]}
|
|
@@ -56,7 +56,8 @@ export const StateRibonStyles = css `
|
|
|
56
56
|
align-items: center;
|
|
57
57
|
gap: var(--spacing-medium, 8px);
|
|
58
58
|
|
|
59
|
-
|
|
59
|
+
/* office control height, the same for mouse and finger (WCAG AA target, user decision 2026-09-17) */
|
|
60
|
+
min-height: 36px;
|
|
60
61
|
padding: 0 var(--spacing-large, 16px);
|
|
61
62
|
box-sizing: border-box;
|
|
62
63
|
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"state-ribon.js","sourceRoot":"","sources":["../../client/components/state-ribon.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,GAAG,EAAE,MAAM,KAAK,CAAA;AAEzB;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAsCG;AACH,MAAM,CAAC,MAAM,gBAAgB,GAAG,GAAG,CAAA
|
|
1
|
+
{"version":3,"file":"state-ribon.js","sourceRoot":"","sources":["../../client/components/state-ribon.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,GAAG,EAAE,MAAM,KAAK,CAAA;AAEzB;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAsCG;AACH,MAAM,CAAC,MAAM,gBAAgB,GAAG,GAAG,CAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;CA+JlC,CAAA","sourcesContent":["import { css } from 'lit'\n\n/**\n * 업무 · 결재 화면의 머리 띠 — **세 화면이 한 모양을 쓴다.**\n *\n * activity-thread-ribon · activity-approval-ribon · activity-instance-ribon 이 같은 자리에 같은\n * 것을 보인다(상태 · 설명 · 결재선 또는 담당자). 그런데 셋이 각자 100여 줄의 CSS 를 갖고 있었고,\n * 상태색 여덟 개가 세 벌로 복사되어 있었다.\n *\n * ── 채운 띠를 걷은 이유 — 글자가 안 읽혔다 ─────────────────────────────────\n * 전에는 상태마다 다른 색으로 띠 전체를 채우고 그 위에 흰 글자를 얹었다. 색은 하드코딩된 hex 여덟\n * 개였고, --md-sys-color-on-primary(대개 흰색)를 글자색으로 썼다. contrast 를 계산하면 12px 글자\n * 기준 AA(4.5:1)에 네 개가 못 미친다.\n *\n * started #56af45 2.76 ← 작업자가 가장 오래 보는 상태\n * ended #02acae 2.79\n * rejected #f27429 2.87\n * submitted #428df3 3.31\n * unassigned #5f7184 5.02 (통과)\n * escalated #595de5 5.09 (통과)\n * aborted #cb3a33 5.01 (통과)\n * delegated #8654b0 5.37 (통과)\n *\n * 색을 여덟 개 다시 고르는 대신 **띠를 채우지 않는다.** SurfaceStyles 가 정한 규칙과 같다 —\n * 흰 면에 1px 선을 두르고, 색은 상태 앞의 점 하나가 말한다. 글자는 --ui-ink 라 어느 상태에서든\n * 읽히고, 점은 UI 요소라 3:1 기준으로 판단한다.\n *\n * ── 색 여덟 개를 뜻 여섯 개로 ──────────────────────────────────────────────\n * 하드코딩된 hex 는 앱 팔레트를 따르지 않는다. worklist 는 framework 패키지라 operato-plant ·\n * operato-gangsters · operato-dataset 이 모두 이 화면을 쓰는데, 어느 앱에서도 그 앱 색이 아니었다.\n * 토큰으로 바꾸면 앱마다 자기 라이트 · 다크 테마를 따라온다.\n *\n * unassigned · assigned --ui-muted 아직 시작하지 않았다\n * started --ui-accent 내 손에서 진행 중이다\n * submitted · escalated · delegated --ui-info 남의 판단을 기다린다\n * rejected --ui-warn 되돌아왔다. 다시 해야 한다\n * ended · approved --ui-good 끝났다\n * aborted --ui-crit 중단됐다\n *\n * 색만으로 뜻을 전하지 않는다 — 상태 이름을 항상 함께 적는다.\n */\nexport const StateRibonStyles = css`\n /*\n * ── 면을 갖지 않는다 (2026-09-06) ─────────────────────────────────────\n * 채운 색 띠를 걷어내면서 흰 면(--ui-panel)으로 바꿨는데, 그것이 카드와 **같은 색**이었다.\n * 그래서 한 화면에 흰 블록이 넷이 되고(머리 띠 · 내용 · 타임라인 · 의견) 위계가 사라졌다.\n * 실측: 결재 화면의 네 블록이 전부 rgb(255,255,255) 에 1px 테두리였다.\n *\n * 이 띠가 말하는 것(상태 · 설명 · 결재선)은 전부 보조다. 사용자가 먼저 묻는 것은 「무엇을\n * 승인하나」이지 「지금 몇 단계인가」가 아니다.\n *\n * 그래서 페이지 바탕이 비치게 두고 아래 구분선도 없앤다. 흰 면은 「읽을 내용」에만 남는다 —\n * 그 규칙이 서면 카드가 곧 본문이라는 것이 모양만으로 읽힌다.\n */\n :host {\n display: flex;\n align-items: center;\n gap: var(--spacing-medium, 8px);\n\n /* office control height, the same for mouse and finger (WCAG AA target, user decision 2026-09-17) */\n min-height: 36px;\n padding: 0 var(--spacing-large, 16px);\n box-sizing: border-box;\n\n color: var(--ui-ink, #17242c);\n font-size: var(--ui-t-body, 13px);\n }\n\n /* ── 상태 ────────────────────────────────────────────────────────────── */\n .state {\n display: inline-flex;\n align-items: center;\n gap: 6px;\n flex: none;\n font-weight: 600;\n white-space: nowrap;\n }\n\n /*\n * 상태색을 쓰는 자리는 이 점 하나다. 기본값은 --ui-muted — 서버가 아직 모르는 상태 이름이\n * 오더라도 점이 사라지지 않고 회색으로 남는다(색이 없으면 상태가 없는 것처럼 보인다).\n */\n .dot {\n width: 8px;\n height: 8px;\n border-radius: 50%;\n background: var(--worklist-state-color, var(--ui-muted, #57676f));\n }\n\n :host([state='unassigned']),\n :host([state='assigned']),\n :host([state='draft']) {\n --worklist-state-color: var(--ui-muted, #57676f);\n }\n\n :host([state='started']),\n :host([state='issued']),\n :host([state='posted']) {\n --worklist-state-color: var(--ui-accent, #00727e);\n }\n\n :host([state='submitted']),\n :host([state='escalated']),\n :host([state='delegated']),\n :host([state='pending']) {\n --worklist-state-color: var(--ui-info, #2b72ad);\n }\n\n :host([state='rejected']) {\n --worklist-state-color: var(--ui-warn, #9f5e02);\n }\n\n :host([state='ended']),\n :host([state='approved']) {\n --worklist-state-color: var(--ui-good, #297d39);\n }\n\n :host([state='aborted']),\n :host([state='deprecated']) {\n --worklist-state-color: var(--ui-crit, #d14946);\n }\n\n /* ── 설명 ────────────────────────────────────────────────────────────── */\n /*\n * 한 줄로 자른다. 이 자리는 머리 띠라 높이가 고정이고, 설명이 길면 아래 내용을 밀어낸다.\n * 전체 글은 정보 아이콘이 여는 overlay 가 갖는다.\n */\n .desc {\n flex: 1;\n min-width: 0;\n overflow: hidden;\n text-overflow: ellipsis;\n white-space: nowrap;\n color: var(--ui-muted, #57676f);\n }\n\n /* ── 정보 아이콘 ─────────────────────────────────────────────────────── */\n /*\n * 상태 바로 뒤에 둔다. 전에는 띠의 오른쪽 끝, 결재선 바로 왼쪽에 있었다 — 그 자리에서는\n * **결재선의 일부처럼** 읽힌다(결재선을 펴 보는 단추인가 하고 누르게 된다).\n *\n * 이 아이콘이 여는 것은 이 건의 기본 정보이고, 그 판의 첫 줄이 상태다. 상태 옆에 붙여\n * 두 개가 한 덩어리로 읽히게 한다 — 앞의 gap 만 좁혀서 붙이고 뒤는 띠의 기본 간격을 쓴다.\n */\n .info {\n flex: none;\n margin-left: calc(var(--spacing-medium, 8px) * -1 + 4px);\n cursor: pointer;\n color: var(--ui-muted, #57676f);\n font-size: 18px;\n }\n\n .info:hover {\n color: var(--ui-ink, #17242c);\n }\n\n /* 키보드로 온 것이 보여야 한다 — 이 아이콘은 role=button 이라 탭 순서에 든다. */\n .info:focus-visible {\n outline: 2px solid var(--ui-accent, #00727e);\n outline-offset: 2px;\n border-radius: 50%;\n color: var(--ui-ink, #17242c);\n }\n\n /* ── 담당자 ──────────────────────────────────────────────────────────── */\n .who {\n display: inline-flex;\n align-items: baseline;\n gap: 5px;\n flex: none;\n white-space: nowrap;\n }\n\n .who-label {\n font-size: var(--ui-t-small, 11.5px);\n color: var(--ui-muted, #57676f);\n }\n\n /* ── 결재선 ──────────────────────────────────────────────────────────── */\n approval-line-brief {\n flex: none;\n font-size: var(--ui-t-small, 11.5px);\n }\n\n /*\n * 좁은 화면 — 결재선과 담당자를 감춘다. 상태와 설명이 먼저다.\n *\n * 결재선은 단계마다 44px 이상을 쓴다. 세 단계면 이음선까지 200px 을 넘고, 460px 화면에서는\n * 설명이 들어갈 자리가 남지 않는다.\n */\n @media only screen and (max-width: 460px) {\n :host {\n padding: 0 var(--spacing-medium, 8px);\n }\n\n .who,\n approval-line-brief {\n display: none;\n }\n }\n`\n"]}
|
|
@@ -10,7 +10,7 @@ import { i18next, localize } from '@operato/i18n';
|
|
|
10
10
|
import { ranMutation } from '../../components/say-outcome.js';
|
|
11
11
|
import { PageView } from '@operato/shell';
|
|
12
12
|
import { CommonButtonStyles, ScrollbarStyles } from '@operato/styles';
|
|
13
|
-
import { provider } from '@
|
|
13
|
+
import { provider } from '@operato/board/board-provider.js';
|
|
14
14
|
function getSafeFormatter(locale, options) {
|
|
15
15
|
try {
|
|
16
16
|
const safeLocale = locale || 'en-US';
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"activity-page.js","sourceRoot":"","sources":["../../../client/pages/activity/activity-page.ts"],"names":[],"mappings":"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","sourcesContent":["import '@operato/property-editor/ox-properties-dynamic-view.js'\nimport '@operato/board/ox-board-viewer.js'\n\nimport gql from 'graphql-tag'\nimport { css, html } from 'lit'\nimport { unsafeHTML } from 'lit-html/directives/unsafe-html.js'\nimport { customElement, property, query } from 'lit/decorators.js'\nimport { client } from '@operato/graphql'\nimport { i18next, localize } from '@operato/i18n'\nimport { ranMutation } from '../../components/say-outcome.js'\nimport { PageView } from '@operato/shell'\nimport { CommonButtonStyles, ScrollbarStyles } from '@operato/styles'\nimport { provider } from '@things-factory/board-ui/dist-client/board-provider.js'\n\nfunction getSafeFormatter(locale: string, options: Intl.DateTimeFormatOptions): Intl.DateTimeFormat { try { const safeLocale = locale || 'en-US'\n return new Intl.DateTimeFormat(safeLocale, options)\n } catch (e) { console.warn(`Invalid locale or options provided: ${locale}, falling back to default en-US.`, e)\n return new Intl.DateTimeFormat('en-US', options)\n }\n}\n\nconst formatter = getSafeFormatter(navigator.language, { dateStyle: 'full', timeStyle: 'short' })\n\nexport const ActivityInstanceStatus = { Draft: 'draft',\n Issued: 'issued',\n Unassigned: 'unassigned',\n Assigned: 'assigned',\n Started: 'started',\n Pending: 'pending',\n Ended: 'ended',\n Aborted: 'aborted'\n}\n\n@customElement('activity-page')\nexport class ActivityPage extends localize(i18next)(PageView) { static styles = [\n ScrollbarStyles,\n css`\n :host { display: flex;\n flex-direction: column;\n\n width: 100%;\n padding: 5px;\n overflow: auto;\n }\n\n [header] { display: block;\n padding: 5px;\n }\n\n [content] { flex: 1;\n display: block;\n padding: 5px;\n }\n\n ox-board-viewer { width: 100%;\n height: 100%;\n }\n `\n ]\n\n @property({ type: Object }) activityInstance: any\n @property({ type: Object }) board: any\n\n get context() { const startable = [ActivityInstanceStatus.Assigned, ActivityInstanceStatus.Issued].includes(\n this.activityInstance?.state\n )\n\n const finishable = [ActivityInstanceStatus.Started].includes(this.activityInstance?.state)\n const savable = finishable\n\n return { title: this.lifecycle?.params?.['title'] || i18next.t('title.activity'),\n help: 'worklist/activity',\n actions: [\n startable && { title: i18next.t('button.play'),\n action: this._startActivityInstance.bind(this),\n ...CommonButtonStyles.play\n },\n\n savable && { title: i18next.t('button.save'),\n action: this._saveActivityInstance.bind(this),\n ...CommonButtonStyles.save\n },\n\n finishable && { title: i18next.t('button.finish'),\n action: this._endActivityInstance.bind(this),\n ...CommonButtonStyles.save\n }\n ].filter(Boolean /* truthy only */)\n }\n }\n\n render() { const { name, description, state, thumbnail, dueAt, createdAt } = this.activityInstance || {}\n return html`\n <div header>\n <div>name: ${name}</div>\n <div>description: ${description}</div>\n <div>state: ${state}</div>\n <div>posted at: ${createdAt && formatter.format(new Date(createdAt))}</div>\n <div>due at: ${dueAt && formatter.format(new Date(dueAt))}</div>\n <img src=${thumbnail} />\n </div>\n\n <div content>${this.activityContent()}</div>\n `\n }\n\n activityContent() { switch (this.activityInstance?.uiType) { case 'template':\n return this.templateContent()\n case 'generated':\n return this.generatedContent()\n case 'board':\n return this.boardContent()\n case 'page':\n case 'external':\n default:\n return html``\n }\n }\n\n templateContent() { const { uiSource: template } = this.activityInstance\n return unsafeHTML(template)\n }\n\n getInputSpec() { const model = this.activityInstance?.activity?.model\n\n return (model || [])\n .filter(item => item.inout === 'in' || item.inout === 'inout')\n .map(item => { return { ...item,\n name: item.tag,\n label: item.tKey || item.name,\n property: item.options\n }\n })\n }\n\n getOutputSpec() { const model = this.activityInstance?.activity?.model\n\n return (model || [])\n .filter(item => item.inout === 'inout' || item.inout === 'out')\n .map(item => { return { ...item,\n name: item.tag,\n label: item.tKey || item.name,\n property: item.options\n }\n })\n }\n\n generatedContent() { var { input, output } = this.activityInstance || {}\n\n const inputSpec = this.getInputSpec()\n const outputSpec = this.getOutputSpec()\n\n if (!output) { output = inputSpec\n .filter(item => item.inout === 'inout')\n .reduce((inout, item) => { inout[item.name] = input[item.name]\n return inout\n }, {})\n }\n\n return html`\n <fieldset>\n <legend>Input</legend>\n <ox-properties-dynamic-view data-name=\"input\" .props=${inputSpec} .value=${input}></ox-properties-dynamic-view>\n </fieldset>\n\n <fieldset>\n <legend>Output</legend>\n <ox-properties-dynamic-view\n data-name=\"output\"\n .props=${outputSpec}\n .value=${output}\n @property-change=${e => (this.activityInstance.output = e.currentTarget.value)}\n ></ox-properties-dynamic-view>\n </fieldset>\n `\n }\n\n boardContent() { const { uiSource: boardId, input, output } = this.activityInstance\n\n if (!this.board || this.board.id !== boardId) { this.board = { id: boardId\n }\n }\n\n return html`\n <ox-board-viewer\n style=\"background-color: white;\"\n .board=${this.board}\n .provider=${provider}\n .values=${{ ...input, ...output }}\n hide-fullscreen\n hide-navigation\n ></ox-board-viewer>\n `\n }\n\n @query('ox-board-viewer') boardViewer: any\n\n getOutputFromBoard() { const outputSpec = this.getOutputSpec()\n const data = this.boardViewer.getSceneValues()\n\n return outputSpec.reduce((output, spec) => { output[spec.name] = data[spec.name]\n return output\n }, {})\n }\n\n updated(changes) { if (changes.has('activityInstance')) { this.updateContext()\n }\n }\n\n async pageUpdated(changes, lifecycle, changedBefore) { if (this.active) { this.fetchActivityInstance(lifecycle.resourceId)\n }\n }\n\n async fetchActivityInstance(id) { const response = await client.query({ query: gql`\n query activityInstance($id: String!) { activityInstance(id: $id) { id\n name\n description\n state\n activity { model { name\n description\n active\n tag\n inout\n type\n unit\n options\n quantifier\n spec\n }\n }\n thumbnail\n input\n output\n uiType\n uiSource\n dueAt\n createdAt\n }\n }\n `,\n variables: { id\n }\n })\n\n this.activityInstance = response.data.activityInstance\n }\n\n async _startActivityInstance() { var { id, output, reason, uiType } = this.activityInstance\n if (uiType === 'board') { output = this.getOutputFromBoard()\n }\n\n const outcome = await ranMutation(() => client.mutate({ mutation: gql`\n mutation ($id: String!, $output: Object) { startActivityInstance(id: $id, output: $output) { name\n }\n }\n `,\n variables: { id,\n output\n }\n }))\n\n if (!outcome.ok) { return\n }\n\n await this.fetchActivityInstance(this.activityInstance.id)\n\n document.dispatchEvent(\n new CustomEvent('notify', { detail: { message: i18next.t('text.task_is_started_successfully')\n }\n })\n )\n }\n\n async _saveActivityInstance() { var { id, output, reason, uiType } = this.activityInstance\n if (uiType === 'board') { output = this.getOutputFromBoard()\n }\n\n const outcome = await ranMutation(() => client.mutate({ mutation: gql`\n mutation ($id: String!, $save: ActivityInstanceSave!) { draftActivityInstance(id: $id, save: $save) { id\n name\n description\n state\n activity { model { name\n description\n active\n tag\n inout\n type\n unit\n options\n quantifier\n spec\n }\n }\n thumbnail\n input\n output\n uiType\n uiSource\n dueAt\n createdAt\n }\n }\n `,\n variables: { id,\n save: { output\n }\n }\n }))\n\n if (!outcome.ok) { return\n }\n\n this.activityInstance = outcome.data.saveActivityInstance\n\n document.dispatchEvent(\n new CustomEvent('notify', { detail: { message: i18next.t('text.task_is_saved_successfully')\n }\n })\n )\n }\n\n async _endActivityInstance() { var { id, output, reason, uiType } = this.activityInstance\n if (uiType === 'board') { output = this.getOutputFromBoard()\n }\n\n const outcome = await ranMutation(() => client.mutate({ mutation: gql`\n mutation ($id: String!, $output: Object, $reason: String) { endActivityInstance(id: $id, output: $output, reason: $reason) { id\n name\n description\n state\n activity { model { name\n description\n active\n tag\n inout\n type\n unit\n options\n quantifier\n spec\n }\n }\n thumbnail\n input\n output\n uiType\n uiSource\n dueAt\n createdAt\n }\n }\n `,\n variables: { id,\n output,\n reason\n }\n }))\n\n if (!outcome.ok) { return\n }\n\n this.activityInstance = outcome.data.endActivityInstance\n\n document.dispatchEvent(\n new CustomEvent('notify', { detail: { message: i18next.t('text.task_is_finished_successfully')\n }\n })\n )\n }\n}\n"]}
|
|
1
|
+
{"version":3,"file":"activity-page.js","sourceRoot":"","sources":["../../../client/pages/activity/activity-page.ts"],"names":[],"mappings":"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","sourcesContent":["import '@operato/property-editor/ox-properties-dynamic-view.js'\nimport '@operato/board/ox-board-viewer.js'\n\nimport gql from 'graphql-tag'\nimport { css, html } from 'lit'\nimport { unsafeHTML } from 'lit-html/directives/unsafe-html.js'\nimport { customElement, property, query } from 'lit/decorators.js'\nimport { client } from '@operato/graphql'\nimport { i18next, localize } from '@operato/i18n'\nimport { ranMutation } from '../../components/say-outcome.js'\nimport { PageView } from '@operato/shell'\nimport { CommonButtonStyles, ScrollbarStyles } from '@operato/styles'\nimport { provider } from '@operato/board/board-provider.js'\n\nfunction getSafeFormatter(locale: string, options: Intl.DateTimeFormatOptions): Intl.DateTimeFormat { try { const safeLocale = locale || 'en-US'\n return new Intl.DateTimeFormat(safeLocale, options)\n } catch (e) { console.warn(`Invalid locale or options provided: ${locale}, falling back to default en-US.`, e)\n return new Intl.DateTimeFormat('en-US', options)\n }\n}\n\nconst formatter = getSafeFormatter(navigator.language, { dateStyle: 'full', timeStyle: 'short' })\n\nexport const ActivityInstanceStatus = { Draft: 'draft',\n Issued: 'issued',\n Unassigned: 'unassigned',\n Assigned: 'assigned',\n Started: 'started',\n Pending: 'pending',\n Ended: 'ended',\n Aborted: 'aborted'\n}\n\n@customElement('activity-page')\nexport class ActivityPage extends localize(i18next)(PageView) { static styles = [\n ScrollbarStyles,\n css`\n :host { display: flex;\n flex-direction: column;\n\n width: 100%;\n padding: 5px;\n overflow: auto;\n }\n\n [header] { display: block;\n padding: 5px;\n }\n\n [content] { flex: 1;\n display: block;\n padding: 5px;\n }\n\n ox-board-viewer { width: 100%;\n height: 100%;\n }\n `\n ]\n\n @property({ type: Object }) activityInstance: any\n @property({ type: Object }) board: any\n\n get context() { const startable = [ActivityInstanceStatus.Assigned, ActivityInstanceStatus.Issued].includes(\n this.activityInstance?.state\n )\n\n const finishable = [ActivityInstanceStatus.Started].includes(this.activityInstance?.state)\n const savable = finishable\n\n return { title: this.lifecycle?.params?.['title'] || i18next.t('title.activity'),\n help: 'worklist/activity',\n actions: [\n startable && { title: i18next.t('button.play'),\n action: this._startActivityInstance.bind(this),\n ...CommonButtonStyles.play\n },\n\n savable && { title: i18next.t('button.save'),\n action: this._saveActivityInstance.bind(this),\n ...CommonButtonStyles.save\n },\n\n finishable && { title: i18next.t('button.finish'),\n action: this._endActivityInstance.bind(this),\n ...CommonButtonStyles.save\n }\n ].filter(Boolean /* truthy only */)\n }\n }\n\n render() { const { name, description, state, thumbnail, dueAt, createdAt } = this.activityInstance || {}\n return html`\n <div header>\n <div>name: ${name}</div>\n <div>description: ${description}</div>\n <div>state: ${state}</div>\n <div>posted at: ${createdAt && formatter.format(new Date(createdAt))}</div>\n <div>due at: ${dueAt && formatter.format(new Date(dueAt))}</div>\n <img src=${thumbnail} />\n </div>\n\n <div content>${this.activityContent()}</div>\n `\n }\n\n activityContent() { switch (this.activityInstance?.uiType) { case 'template':\n return this.templateContent()\n case 'generated':\n return this.generatedContent()\n case 'board':\n return this.boardContent()\n case 'page':\n case 'external':\n default:\n return html``\n }\n }\n\n templateContent() { const { uiSource: template } = this.activityInstance\n return unsafeHTML(template)\n }\n\n getInputSpec() { const model = this.activityInstance?.activity?.model\n\n return (model || [])\n .filter(item => item.inout === 'in' || item.inout === 'inout')\n .map(item => { return { ...item,\n name: item.tag,\n label: item.tKey || item.name,\n property: item.options\n }\n })\n }\n\n getOutputSpec() { const model = this.activityInstance?.activity?.model\n\n return (model || [])\n .filter(item => item.inout === 'inout' || item.inout === 'out')\n .map(item => { return { ...item,\n name: item.tag,\n label: item.tKey || item.name,\n property: item.options\n }\n })\n }\n\n generatedContent() { var { input, output } = this.activityInstance || {}\n\n const inputSpec = this.getInputSpec()\n const outputSpec = this.getOutputSpec()\n\n if (!output) { output = inputSpec\n .filter(item => item.inout === 'inout')\n .reduce((inout, item) => { inout[item.name] = input[item.name]\n return inout\n }, {})\n }\n\n return html`\n <fieldset>\n <legend>Input</legend>\n <ox-properties-dynamic-view data-name=\"input\" .props=${inputSpec} .value=${input}></ox-properties-dynamic-view>\n </fieldset>\n\n <fieldset>\n <legend>Output</legend>\n <ox-properties-dynamic-view\n data-name=\"output\"\n .props=${outputSpec}\n .value=${output}\n @property-change=${e => (this.activityInstance.output = e.currentTarget.value)}\n ></ox-properties-dynamic-view>\n </fieldset>\n `\n }\n\n boardContent() { const { uiSource: boardId, input, output } = this.activityInstance\n\n if (!this.board || this.board.id !== boardId) { this.board = { id: boardId\n }\n }\n\n return html`\n <ox-board-viewer\n style=\"background-color: white;\"\n .board=${this.board}\n .provider=${provider}\n .values=${{ ...input, ...output }}\n hide-fullscreen\n hide-navigation\n ></ox-board-viewer>\n `\n }\n\n @query('ox-board-viewer') boardViewer: any\n\n getOutputFromBoard() { const outputSpec = this.getOutputSpec()\n const data = this.boardViewer.getSceneValues()\n\n return outputSpec.reduce((output, spec) => { output[spec.name] = data[spec.name]\n return output\n }, {})\n }\n\n updated(changes) { if (changes.has('activityInstance')) { this.updateContext()\n }\n }\n\n async pageUpdated(changes, lifecycle, changedBefore) { if (this.active) { this.fetchActivityInstance(lifecycle.resourceId)\n }\n }\n\n async fetchActivityInstance(id) { const response = await client.query({ query: gql`\n query activityInstance($id: String!) { activityInstance(id: $id) { id\n name\n description\n state\n activity { model { name\n description\n active\n tag\n inout\n type\n unit\n options\n quantifier\n spec\n }\n }\n thumbnail\n input\n output\n uiType\n uiSource\n dueAt\n createdAt\n }\n }\n `,\n variables: { id\n }\n })\n\n this.activityInstance = response.data.activityInstance\n }\n\n async _startActivityInstance() { var { id, output, reason, uiType } = this.activityInstance\n if (uiType === 'board') { output = this.getOutputFromBoard()\n }\n\n const outcome = await ranMutation(() => client.mutate({ mutation: gql`\n mutation ($id: String!, $output: Object) { startActivityInstance(id: $id, output: $output) { name\n }\n }\n `,\n variables: { id,\n output\n }\n }))\n\n if (!outcome.ok) { return\n }\n\n await this.fetchActivityInstance(this.activityInstance.id)\n\n document.dispatchEvent(\n new CustomEvent('notify', { detail: { message: i18next.t('text.task_is_started_successfully')\n }\n })\n )\n }\n\n async _saveActivityInstance() { var { id, output, reason, uiType } = this.activityInstance\n if (uiType === 'board') { output = this.getOutputFromBoard()\n }\n\n const outcome = await ranMutation(() => client.mutate({ mutation: gql`\n mutation ($id: String!, $save: ActivityInstanceSave!) { draftActivityInstance(id: $id, save: $save) { id\n name\n description\n state\n activity { model { name\n description\n active\n tag\n inout\n type\n unit\n options\n quantifier\n spec\n }\n }\n thumbnail\n input\n output\n uiType\n uiSource\n dueAt\n createdAt\n }\n }\n `,\n variables: { id,\n save: { output\n }\n }\n }))\n\n if (!outcome.ok) { return\n }\n\n this.activityInstance = outcome.data.saveActivityInstance\n\n document.dispatchEvent(\n new CustomEvent('notify', { detail: { message: i18next.t('text.task_is_saved_successfully')\n }\n })\n )\n }\n\n async _endActivityInstance() { var { id, output, reason, uiType } = this.activityInstance\n if (uiType === 'board') { output = this.getOutputFromBoard()\n }\n\n const outcome = await ranMutation(() => client.mutate({ mutation: gql`\n mutation ($id: String!, $output: Object, $reason: String) { endActivityInstance(id: $id, output: $output, reason: $reason) { id\n name\n description\n state\n activity { model { name\n description\n active\n tag\n inout\n type\n unit\n options\n quantifier\n spec\n }\n }\n thumbnail\n input\n output\n uiType\n uiSource\n dueAt\n createdAt\n }\n }\n `,\n variables: { id,\n output,\n reason\n }\n }))\n\n if (!outcome.ok) { return\n }\n\n this.activityInstance = outcome.data.endActivityInstance\n\n document.dispatchEvent(\n new CustomEvent('notify', { detail: { message: i18next.t('text.task_is_finished_successfully')\n }\n })\n )\n }\n}\n"]}
|
|
@@ -94,7 +94,7 @@ export declare class ActivityApprovalPage extends ActivityApprovalPage_base {
|
|
|
94
94
|
* decisionKeys draws exactly what it drew before.
|
|
95
95
|
*
|
|
96
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
|
|
97
|
+
* predate a field the declaration names and an empty
|
|
98
98
|
* bar on the screen would read as "there is no reason" when the truth is that this record has no
|
|
99
99
|
* such value. What cannot be shown is left out; what is shown is only what the payload actually
|
|
100
100
|
* carries.
|
|
@@ -182,6 +182,7 @@ export declare class ActivityApprovalPage extends ActivityApprovalPage_base {
|
|
|
182
182
|
updated(changes: any): void;
|
|
183
183
|
pageUpdated(changes: any, lifecycle: any, changedBefore: any): Promise<void>;
|
|
184
184
|
fetchActivityApproval(id: any): Promise<void>;
|
|
185
|
+
confirmIfIrreversible(): Promise<boolean>;
|
|
185
186
|
rejectActivityApproval(): Promise<void>;
|
|
186
187
|
approveActivityApproval(): Promise<void>;
|
|
187
188
|
saveActivityApproval(): Promise<void>;
|
|
@@ -10,11 +10,13 @@ import { unsafeHTML } from 'lit-html/directives/unsafe-html.js';
|
|
|
10
10
|
import { customElement, query, state } from 'lit/decorators.js';
|
|
11
11
|
import { keyed } from 'lit/directives/keyed.js';
|
|
12
12
|
import { client } from '@operato/graphql';
|
|
13
|
+
import { OxPrompt } from '@operato/popup';
|
|
13
14
|
import { i18next, localize } from '@operato/i18n';
|
|
14
15
|
import { ranMutation } from '../../components/say-outcome.js';
|
|
16
|
+
import { approvalGate } from './approval-gate.js';
|
|
15
17
|
import { PageView } from '@operato/shell';
|
|
16
18
|
import { CommonButtonStyles, ScrollbarStyles } from '@operato/styles';
|
|
17
|
-
import { provider } from '@
|
|
19
|
+
import { provider } from '@operato/board/board-provider.js';
|
|
18
20
|
import { isReferenceStep } from '@things-factory/organization/dist-client';
|
|
19
21
|
import { ActivityFieldsStyles, declaredLabel, fieldValue, inputSpecOf, outputSpecOf, renderGiven } from '../../components/activity-fields.js';
|
|
20
22
|
import { decisionSlots, reversibilityIsMalformed, reversibilityOf, slotOfRole, slotsOfRole } from '../../components/decision-slots.js';
|
|
@@ -62,6 +64,7 @@ const ActivityApprovalFetchResult = `\
|
|
|
62
64
|
state
|
|
63
65
|
activity { id
|
|
64
66
|
label
|
|
67
|
+
labelTKey
|
|
65
68
|
decisionKeys { role
|
|
66
69
|
inputPath
|
|
67
70
|
tKey
|
|
@@ -346,13 +349,6 @@ let ActivityApprovalPage = class ActivityApprovalPage extends localize(i18next)(
|
|
|
346
349
|
color: var(--ui-muted, #57676f);
|
|
347
350
|
}
|
|
348
351
|
|
|
349
|
-
section[decision] .policy {
|
|
350
|
-
margin-top: 14px;
|
|
351
|
-
padding-top: 11px;
|
|
352
|
-
border-top: 1px solid var(--ui-line, #d5dce0);
|
|
353
|
-
font-size: var(--ui-t-small, 11.5px);
|
|
354
|
-
color: var(--ui-muted, #57676f);
|
|
355
|
-
}
|
|
356
352
|
`
|
|
357
353
|
]; }
|
|
358
354
|
/**
|
|
@@ -615,7 +611,7 @@ let ActivityApprovalPage = class ActivityApprovalPage extends localize(i18next)(
|
|
|
615
611
|
* decisionKeys draws exactly what it drew before.
|
|
616
612
|
*
|
|
617
613
|
* A slot whose path led nowhere is skipped rather than drawn empty. Older instances of an activity
|
|
618
|
-
* predate a field the declaration names
|
|
614
|
+
* predate a field the declaration names and an empty
|
|
619
615
|
* bar on the screen would read as "there is no reason" when the truth is that this record has no
|
|
620
616
|
* such value. What cannot be shown is left out; what is shown is only what the payload actually
|
|
621
617
|
* carries.
|
|
@@ -634,11 +630,10 @@ let ActivityApprovalPage = class ActivityApprovalPage extends localize(i18next)(
|
|
|
634
630
|
const subject = slotOfRole(slots, 'subject');
|
|
635
631
|
const reason = slotOfRole(slots, 'reason');
|
|
636
632
|
const consequences = slotsOfRole(slots, 'consequence').filter(slot => slot.found);
|
|
637
|
-
const policy = slotOfRole(slots, 'policy');
|
|
638
633
|
const evidence = slotsOfRole(slots, 'evidence').filter(slot => slot.found);
|
|
639
634
|
const currentState = slotOfRole(slots, 'currentState');
|
|
640
635
|
const reversibility = slotOfRole(slots, 'reversibility');
|
|
641
|
-
const drawable = [headline, subject,
|
|
636
|
+
const drawable = [headline, subject, currentState].some(slot => slot?.found) ||
|
|
642
637
|
!!reason ||
|
|
643
638
|
consequences.length ||
|
|
644
639
|
evidence.length ||
|
|
@@ -700,13 +695,6 @@ let ActivityApprovalPage = class ActivityApprovalPage extends localize(i18next)(
|
|
|
700
695
|
</div>
|
|
701
696
|
`
|
|
702
697
|
: ''}
|
|
703
|
-
${policy?.found
|
|
704
|
-
? html `
|
|
705
|
-
<div class="policy">
|
|
706
|
-
${i18next.t('label.why-approval')} — ${this.slotText(policy)}
|
|
707
|
-
</div>
|
|
708
|
-
`
|
|
709
|
-
: ''}
|
|
710
698
|
</section>
|
|
711
699
|
`);
|
|
712
700
|
}
|
|
@@ -941,6 +929,26 @@ let ActivityApprovalPage = class ActivityApprovalPage extends localize(i18next)(
|
|
|
941
929
|
this.activityThread = this.activityApproval.activityThread;
|
|
942
930
|
this.updateContext();
|
|
943
931
|
}
|
|
932
|
+
/*
|
|
933
|
+
* The approval declared that it cannot be undone: ask once, as a destructive confirmation, before
|
|
934
|
+
* sending it. Reversible and undeclared approvals go straight through, as before.
|
|
935
|
+
*/
|
|
936
|
+
async confirmIfIrreversible() {
|
|
937
|
+
const { activityInstance } = this.activityThread || {};
|
|
938
|
+
const slots = decisionSlots(activityInstance?.activity?.decisionKeys, activityInstance?.input);
|
|
939
|
+
const gate = approvalGate(slotOfRole(slots, 'reversibility'));
|
|
940
|
+
if (!gate.ask) {
|
|
941
|
+
return true;
|
|
942
|
+
}
|
|
943
|
+
return await OxPrompt.open({
|
|
944
|
+
type: 'warning',
|
|
945
|
+
title: i18next.t('text.approval-is-irreversible'),
|
|
946
|
+
text: gate.caveat,
|
|
947
|
+
/* From the declaration, not a literal: this screen does not decide what is irreversible. */
|
|
948
|
+
confirmButton: { text: i18next.t('button.approve'), destructive: gate.ask },
|
|
949
|
+
cancelButton: { text: i18next.t('button.cancel') }
|
|
950
|
+
});
|
|
951
|
+
}
|
|
944
952
|
async rejectActivityApproval() {
|
|
945
953
|
var { id, comment } = this.activityApproval;
|
|
946
954
|
if (!comment) {
|
|
@@ -969,6 +977,9 @@ let ActivityApprovalPage = class ActivityApprovalPage extends localize(i18next)(
|
|
|
969
977
|
}
|
|
970
978
|
async approveActivityApproval() {
|
|
971
979
|
var { id, comment } = this.activityApproval;
|
|
980
|
+
if (!(await this.confirmIfIrreversible())) {
|
|
981
|
+
return;
|
|
982
|
+
}
|
|
972
983
|
const outcome = await ranMutation(() => client.mutate({ mutation: gql `
|
|
973
984
|
mutation ($id: String!, $comment: String) { approveActivityApproval(id: $id, comment: $comment) ${ActivityApprovalFetchResult}
|
|
974
985
|
}
|