@things-factory/worklist 10.1.39 → 10.1.41

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.
Files changed (42) hide show
  1. package/dist-client/components/activity-starter-form.js +1 -1
  2. package/dist-client/components/activity-starter-form.js.map +1 -1
  3. package/dist-client/components/activity-thread-timeline.d.ts +2 -2
  4. package/dist-client/pages/activity-catalog/activity-detail-page.js +10 -0
  5. package/dist-client/pages/activity-catalog/activity-detail-page.js.map +1 -1
  6. package/dist-client/pages/activity-thread/activity-thread-view.d.ts +1 -1
  7. package/dist-client/pages/work-door/door-sentence.d.ts +63 -0
  8. package/dist-client/pages/work-door/door-sentence.js +109 -0
  9. package/dist-client/pages/work-door/door-sentence.js.map +1 -0
  10. package/dist-client/pages/work-door/door-words.d.ts +7 -0
  11. package/dist-client/pages/work-door/door-words.js +30 -0
  12. package/dist-client/pages/work-door/door-words.js.map +1 -1
  13. package/dist-client/pages/work-door/work-doors-page.d.ts +1 -1
  14. package/dist-client/pages/work-door/work-doors-page.js +49 -17
  15. package/dist-client/pages/work-door/work-doors-page.js.map +1 -1
  16. package/dist-client/route.d.ts +1 -1
  17. package/dist-client/tsconfig.tsbuildinfo +1 -1
  18. package/dist-server/service/index.d.ts +3 -3
  19. package/dist-server/service/work-door/work-door-declaration.d.ts +11 -5
  20. package/dist-server/service/work-door/work-door-declaration.js +5 -3
  21. package/dist-server/service/work-door/work-door-declaration.js.map +1 -1
  22. package/dist-server/service/work-door/work-door-resolver.js +1 -1
  23. package/dist-server/service/work-door/work-door-resolver.js.map +1 -1
  24. package/dist-server/service/work-door/work-door-service.js +3 -14
  25. package/dist-server/service/work-door/work-door-service.js.map +1 -1
  26. package/dist-server/service/work-door/work-door-type.d.ts +43 -6
  27. package/dist-server/service/work-door/work-door-type.js +102 -26
  28. package/dist-server/service/work-door/work-door-type.js.map +1 -1
  29. package/dist-server/service/work-door/work-door.d.ts +65 -16
  30. package/dist-server/service/work-door/work-door.js +53 -90
  31. package/dist-server/service/work-door/work-door.js.map +1 -1
  32. package/dist-server/tsconfig.tsbuildinfo +1 -1
  33. package/package.json +10 -10
  34. package/tests/work-door-door-words.test.ts +35 -1
  35. package/tests/work-door-not-used-refuse.test.ts +6 -6
  36. package/tests/work-door-sentence.test.ts +199 -0
  37. package/tests/work-door.test.ts +63 -56
  38. package/translations/en.json +26 -1
  39. package/translations/ja.json +26 -1
  40. package/translations/ko.json +26 -1
  41. package/translations/ms.json +26 -1
  42. package/translations/zh.json +26 -1
@@ -27,7 +27,7 @@ let ActivityStarterForm = class ActivityStarterForm extends localize(i18next)(Li
27
27
  display: flex;
28
28
  flex-direction: column;
29
29
 
30
- color: var(--md-sys-color-on-s);
30
+ color: var(--md-sys-color-on-surface);
31
31
  background-color: var(--md-sys-color-surface);
32
32
  }
33
33
 
@@ -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>${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"]}
1
+ {"version":3,"file":"activity-starter-form.js","sourceRoot":"","sources":["../../client/components/activity-starter-form.ts"],"names":[],"mappings":";AAAA,OAAO,4BAA4B,CAAA;AACnC,OAAO,gDAAgD,CAAA;AACvD,OAAO,8CAA8C,CAAA;AACrD,OAAO,wDAAwD,CAAA;AAC/D,OAAO,8BAA8B,CAAA;AAErC,OAAO,GAAG,MAAM,aAAa,CAAA;AAC7B,OAAO,EAAE,GAAG,EAAE,IAAI,EAAE,UAAU,EAAE,MAAM,KAAK,CAAA;AAC3C,OAAO,EAAE,aAAa,EAAE,QAAQ,EAAE,KAAK,EAAE,MAAM,mBAAmB,CAAA;AAElE,OAAO,EAAE,QAAQ,EAAE,MAAM,gBAAgB,CAAA;AACzC,OAAO,EAAE,MAAM,EAAE,MAAM,kBAAkB,CAAA;AACzC,OAAO,EAAE,OAAO,EAAE,QAAQ,EAAE,MAAM,eAAe,CAAA;AACjD,OAAO,EAAE,WAAW,EAAE,MAAM,kBAAkB,CAAA;AAC9C,OAAO,EAAE,MAAM,EAAE,MAAM,iBAAiB,CAAA;AACxC,OAAO,EAAE,kBAAkB,EAAE,eAAe,EAAE,MAAM,iBAAiB,CAAA;AAG9D,IAAM,mBAAmB,GAAzB,MAAM,mBAAoB,SAAQ,QAAQ,CAAC,OAAO,CAAC,CAAC,UAAU,CAAC;IAA/D;;QAmDI,aAAQ,GAAQ,EAAE,CAAA;QAClB,qBAAgB,GAAQ,EAAE,CAAA;IA8LrC,CAAC;aAjPQ,WAAM,GAAG;QACd,kBAAkB;QAClB,eAAe;QACf,GAAG,CAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;KA0CF;KACF,AA9CY,CA8CZ;IAOD,MAAM;QACJ,IAAI,EAAE,SAAS,EAAE,YAAY,EAAE,GAAG,IAAI,CAAC,QAAQ,IAAI,EAAE,CAAA;QACrD,IAAI,EAAE,IAAI,EAAE,WAAW,EAAE,GAAG,IAAI,CAAC,gBAAgB,CAAA;QAEjD,OAAO,IAAI,CAAA;;;kBAGG,OAAO,CAAC,CAAC,CAAC,yBAAyB,CAAC;;eAEvC,OAAO,CAAC,CAAC,CAAC,2BAA2B,EAAE;YACxC,MAAM,EAAE,OAAO,CAAC,CAAC,CAAC,YAAY,IAAI,OAAO,CAAC,CAAC,CAAC,cAAc,CAAC,CAAC,CAAC,aAAa,CAAC;SAC5E,CAAC;;;;;;;kBAOI,MAAM,CAAC,OAAO,CAAC,CAAC,CAAC,aAAa,CAAC,CAAC;mBAC/B,IAAI,IAAI,IAAI,CAAC,QAAQ,EAAE,IAAI,IAAI,EAAE;oBAChC,CAAC,CAAC,EAAE,CAAC,CAAC,IAAI,CAAC,gBAAgB,CAAC,IAAI,GAAG,CAAC,CAAC,aAAa,CAAC,KAAK,CAAC;;;;;;;kBAO3D,MAAM,CAAC,OAAO,CAAC,CAAC,CAAC,mBAAmB,CAAC,CAAC;;mBAErC,WAAW,IAAI,IAAI,CAAC,QAAQ,EAAE,WAAW,IAAI,EAAE;oBAC9C,CAAC,CAAC,EAAE;YACZ,IAAI,CAAC,gBAAgB,CAAC,WAAW,GAAG,CAAC,CAAC,aAAa,CAAC,KAAK,CAAA;QAC3D,CAAC;;;;;;;yBAOc,CAAC,CAAC,EAAE,CAAC,OAAO,CAAC,IAAI,EAAE,4BAA4B,OAAO,CAAC,CAAC,CAAC,cAAc,CAAC;yBACxE,IAAI,CAAC,qBAAqB,CAAC,IAAI,CAAC,IAAI,CAAC;mCAC3B,OAAO,CAAC,CAAC,CAAC,cAAc,CAAC;;;KAGvD,CAAA;IACH,CAAC;IAED,YAAY;QACV,IAAI,CAAC,aAAa,CAAC,IAAI,CAAC,UAAU,CAAC,CAAA;IACrC,CAAC;IAED,KAAK,CAAC,aAAa,CAAC,EAAE;QACpB,MAAM,QAAQ,GAAG,MAAM,MAAM,CAAC,KAAK,CAAC;YAClC,KAAK,EAAE,GAAG,CAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;OA6CT;YACD,SAAS,EAAE;gBACT,EAAE;aACH;SACF,CAAC,CAAA;QAEF,IAAI,CAAC,QAAQ,GAAG,QAAQ,CAAC,IAAI,CAAC,QAAQ,CAAA;IACxC,CAAC;IAED,KAAK,CAAC,qBAAqB;QACzB,IAAI,EAAE,EAAE,EAAE,UAAU,EAAE,GAAG,IAAI,CAAC,QAAQ,CAAA;QACtC,IAAI,EAAE,EAAE,EAAE,IAAI,EAAE,WAAW,EAAE,QAAQ,EAAE,UAAU,EAAE,UAAU,EAAE,KAAK,EAAE,KAAK,EAAE,SAAS,EAAE,YAAY,EAAE,GACpG,IAAI,CAAC,gBAAgB,CAAA;QAEvB,IAAI,KAAK,IAAI,CAAC,QAAQ,CAAC,IAAI,CAAA;QAC3B,WAAW,KAAK,IAAI,CAAC,QAAQ,CAAC,WAAW,CAAA;QACzC,SAAS,KAAK,IAAI,CAAC,QAAQ,CAAC,SAAS,CAAA;QACrC,YAAY,KAAK,IAAI,CAAC,QAAQ,CAAC,YAAY,CAAA;QAE3C,IAAI,gBAAgB,GAAG;YACrB,EAAE;YACF,UAAU;YACV,IAAI;YACJ,WAAW;YACX,QAAQ;YACR,UAAU;YACV,UAAU;YACV,KAAK;YACL,KAAK;YACL,SAAS;YACT,YAAY;SACb,CAAA;QAED,MAAM,OAAO,GAAG,MAAM,WAAW,CAAC,GAAG,EAAE,CAAC,MAAM,CAAC,MAAM,CAAC;YACpD,QAAQ,EAAE,GAAG,CAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;OAkCZ;YACD,SAAS,EAAE;gBACT,gBAAgB;aACjB;SACF,CAAC,CAAC,CAAA;QAEH,IAAI,CAAC,OAAO,CAAC,EAAE,EAAE,CAAC;YAAO,OAAM;QAClC,CAAC;QAEE,IAAI,CAAC,gBAAgB,GAAG,OAAO,CAAC,IAAI,CAAC,qBAAqB,CAAA;QACxD,MAAM,CAAC;YACL,OAAO,EAAE,OAAO,CAAC,CAAC,CAAC,0BAA0B,EAAE;gBAC7C,CAAC,EAAE,GAAG,OAAO,CAAC,CAAC,CAAC,yBAAyB,CAAC,IAAI,OAAO,CAAC,CAAC,CAAC,YAAY,CAAC,EAAE;aACxE,CAAC;SACH,CAAC,CAAA;QAEF,IAAI,CAAC,yBAAyB,CAAC,IAAI,CAAC,gBAAgB,CAAC,CAAA;IACzD,CAAC;IAED,yBAAyB,CAAC,gBAAgB;QACxC,QAAQ,CAAC,2BAA2B,gBAAgB,CAAC,EAAE,UAAU,gBAAgB,CAAC,IAAI,EAAE,CAAC,CAAA;IAC3F,CAAC;;AAhM2B;IAA3B,QAAQ,CAAC,EAAE,IAAI,EAAE,MAAM,EAAE,CAAC;;uDAAoB;AAEtC;IAAR,KAAK,EAAE;;qDAAmB;AAClB;IAAR,KAAK,EAAE;;6DAA2B;AApDxB,mBAAmB;IAD/B,aAAa,CAAC,uBAAuB,CAAC;GAC1B,mBAAmB,CAkP/B","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-surface);\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"]}
@@ -17,12 +17,12 @@ export declare class ActivityThreadTimeline extends LitElement {
17
17
  * 보일 항목 없음 화면이 「타임라인의 상신 사유를 보고 판단하세요」로 여기를 가리킨다
18
18
  */
19
19
  open?: boolean;
20
- render(): typeof nothing | import("lit-html").TemplateResult<1>;
20
+ render(): import("lit-html").TemplateResult<1> | typeof nothing;
21
21
  /** 접혔을 때 보이는 한 줄 — 마지막 기록의 「무엇을 · 누가 · 언제」. */
22
22
  lastLine(item: any): string;
23
23
  renderActivityThreadHistory(activityThreadHistory: ActivityThreadHistory): import("lit-html").TemplateResult<1>;
24
24
  renderActivityApproval(activityApproval: ActivityApproval): import("lit-html").TemplateResult<1>;
25
25
  /** 적힌 말이 없으면 상자를 그리지 않는다 — 빈 회색 상자는 내용이 있는 줄과 구별되지 않는다. */
26
- renderSaid(said?: string): typeof nothing | import("lit-html").TemplateResult<1>;
26
+ renderSaid(said?: string): import("lit-html").TemplateResult<1> | typeof nothing;
27
27
  renderOutput(output: any): string;
28
28
  }
@@ -265,6 +265,15 @@ let ActivityDetailPage = class ActivityDetailPage extends localize(i18next)(Page
265
265
  async fetch() {
266
266
  this.loaded = false;
267
267
  this.loadError = null;
268
+ /*
269
+ * The tab and the document title come from `context`, and the shell reads it when the route
270
+ * changes - before this answer arrives. Nothing read it again, so the tab kept the previous
271
+ * activity's name while the page showed the next one [확인함 2026-09-24 :4000: 「교대 편성 변경
272
+ * 승인」 on the tab over 「계획 정비 연기 승인」]. Drop the old entry so the wait says the generic
273
+ * name, and hand the context over again once the answer is in.
274
+ */
275
+ this.entry = null;
276
+ this.updateContext();
268
277
  try {
269
278
  const response = await client.query({ query: DETAIL, variables: { name: this.name }, fetchPolicy: 'no-cache' });
270
279
  /*
@@ -281,6 +290,7 @@ let ActivityDetailPage = class ActivityDetailPage extends localize(i18next)(Page
281
290
  this.loadError = thrown;
282
291
  this.loaded = true;
283
292
  }
293
+ this.updateContext();
284
294
  }
285
295
  render() {
286
296
  return html `
@@ -1 +1 @@
1
- {"version":3,"file":"activity-detail-page.js","sourceRoot":"","sources":["../../../client/pages/activity-catalog/activity-detail-page.ts"],"names":[],"mappings":"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","sourcesContent":["import '@material/web/icon/icon.js'\nimport '@operato/list-state/ox-page-state.js'\nimport '@things-factory/organization'\n\nimport gql from 'graphql-tag'\nimport { css, html } from 'lit'\nimport { customElement, state } from 'lit/decorators.js'\nimport { client } from '@operato/graphql'\nimport { i18next, localize } from '@operato/i18n'\nimport { openPopup } from '@operato/layout'\nimport { navigate, PageView } from '@operato/shell'\nimport { DocumentPageStyles, ScrollbarStyles } from '@operato/styles'\n\nimport { ranMutation } from '../../components/say-outcome.js'\nimport { activityPanels, panelSection } from './activity-panels.js'\nimport { detailActions } from './activity-detail-actions.js'\nimport { canonicalStage } from './activity-stage.js'\nimport { guideLines } from './activity-guide.js'\n\n/**\n * 업무 하나 — **그 업무에 관한 일을 여기서 끝낸다.**\n *\n * ── 왜 이 화면이 생겼나 (2026-09-23) ───────────────────────────────────────\n * 결재선 하나를 세워서 문이 서는지 보려면 화면을 셋 열어야 했고, 역할에 사람이 없으면 넷에서\n * 다섯이었다 [확인함]. 카탈로그는 카드에 「결재선 없음」이라고 적어 놓고 **어디로 가야 하는지는\n * 말하지 않았다** — 그 파일 전체에 `navigate()` 도 `<a href>` 도 없었다. 사람은 메뉴로 돌아가\n * 이름으로 찾아야 했다.\n *\n * 그래서 카탈로그는 고르는 자리로 두고, 고른 뒤의 일은 이 화면 안에서 끝낸다.\n *\n * ── 돌아갈 길을 화면이 갖는다 ─────────────────────────────────────────────\n * 탭 줄에 카탈로그가 남아 있으니 됐다고 볼 수 없다. 탭 줄은 **없을 수 있다** — 페이지가\n * `mdibar: false` 를 적으면 셸이 걷고(`apptool-ui/client/layout/mdibar-visibility.ts`), 무엇보다\n * **주소를 받아서 바로 여는 사람에게는 이전 화면이 아예 없다.** 「이 업무 결재선 좀 봐 주세요」로\n * 링크를 받은 사람이 그 경우다. 그래서 머리에 돌아갈 자리를 직접 둔다.\n *\n * ── 못 하는 일은 까닭을 말한다 ────────────────────────────────────────────\n * 눌리지 않는 단추만 남기지 않는다. 무엇을 할 수 있는지와 못 하면 왜인지는\n * `activity-detail-actions.ts` 가 값으로 답하고, 이 화면은 그 값을 문장으로 바꾼다. 원인을 여기서\n * 지어내지 않는다.\n */\nconst DETAIL = gql`\n query ($name: String!) {\n responses: installableActivities {\n items {\n name\n label\n labelTKey\n description\n guide\n guideTKeys\n approvalSteps\n activity {\n id\n }\n readiness {\n stage\n }\n }\n }\n activityByName(name: $name) {\n id\n name\n description\n approvalLine {\n type\n value\n participation\n approver {\n id\n name\n description\n controlNo\n }\n }\n }\n }\n`\n\n/** 결재선에서 **서명하는 단계만** 센다. 참조는 알기만 하고 막지 않는다. */\nfunction approvalSteps(line?: any[]): number {\n return (line || []).filter(one => String(one?.participation || '') !== 'reference').length\n}\n\n@customElement('activity-detail-page')\nexport class ActivityDetailPage extends localize(i18next)(PageView) {\n static styles = [\n ScrollbarStyles,\n DocumentPageStyles,\n css`\n :host {\n display: flex;\n flex-direction: column;\n overflow: auto;\n }\n\n /* 돌아갈 자리. 제목 위에 둔다 — 읽기 전에 보인다. */\n a[back] {\n display: inline-flex;\n align-items: center;\n gap: 2px;\n align-self: flex-start;\n margin-bottom: var(--spacing-small);\n color: var(--md-sys-color-on-surface-variant);\n font-size: var(--ui-t-body, 13px);\n text-decoration: none;\n cursor: pointer;\n }\n\n a[back]:hover {\n color: var(--md-sys-color-on-surface);\n text-decoration: underline;\n }\n\n a[back] md-icon {\n --md-icon-size: 16px;\n }\n\n .head {\n display: flex;\n align-items: center;\n flex-wrap: wrap;\n gap: var(--spacing-small);\n }\n\n .head .name {\n font: var(--ui-t-title-font, bold 18px var(--theme-font));\n color: var(--md-sys-color-on-surface);\n }\n\n .stage,\n .use {\n padding: 1px 8px;\n border-radius: var(--md-sys-shape-corner-full);\n font-size: var(--ui-t-small, 12px);\n background-color: var(--md-sys-color-surface-container-high);\n color: var(--md-sys-color-on-surface-variant);\n }\n\n .use:not([idle]) {\n background-color: var(--md-sys-color-secondary-container);\n color: var(--md-sys-color-on-secondary-container);\n }\n\n section {\n margin-top: var(--spacing-large, 16px);\n }\n\n section > h3 {\n margin: 0 0 var(--spacing-small) 0;\n font-size: var(--ui-t-small, 12px);\n color: var(--md-sys-color-on-surface-variant);\n text-transform: uppercase;\n }\n\n .guide p {\n margin: 0 0 4px 0;\n line-height: 1.5;\n }\n\n /* 못 하는 까닭 · 비어 있다는 사실. 둘 다 **문장으로** 남는다. */\n .why {\n margin: 4px 0 0 0;\n color: var(--md-sys-color-on-surface-variant);\n font-size: var(--ui-t-body, 13px);\n }\n\n .steps {\n display: flex;\n flex-wrap: wrap;\n gap: 4px;\n margin-bottom: var(--spacing-small);\n }\n\n .steps span {\n padding: 2px 8px;\n border: 1px solid var(--md-sys-color-outline-variant);\n border-radius: var(--md-sys-shape-corner-full);\n font-size: var(--ui-t-small, 12px);\n }\n\n button {\n font: inherit;\n color: var(--md-sys-color-on-surface);\n background-color: var(--md-sys-color-surface-container);\n border: 1px solid var(--md-sys-color-outline-variant);\n border-radius: var(--md-sys-shape-corner-full);\n padding: 6px 14px;\n cursor: pointer;\n }\n\n button:hover:not(:disabled) {\n background-color: var(--md-sys-color-surface-container-high);\n }\n\n button:disabled {\n opacity: 0.4;\n cursor: default;\n }\n `\n ]\n\n @state() private name = ''\n @state() private entry: any = null\n @state() private activity: any = null\n @state() private loaded = false\n /** 구획이 「이 업무에는 보일 것 없음」을 알렸나. 이름으로 센다. */\n @state() private emptyPanels: Record<string, boolean> = {}\n /** 왜 못 읽었나 — ox-page-state 가 그것을 말하고 다시 시도를 준다. */\n @state() private loadError: unknown = null\n\n get context() {\n return {\n frame: 'document',\n title: this.entry ? this.shownName(this.entry) : i18next.t('title.activity-detail'),\n /*\n * 이름은 **이 화면이 그린다.** 제목 줄은 끈다.\n *\n * 이름 옆에 단계 띠와 「사용 중」이 함께 서야 한다 — 그 셋이 한 줄에 있어야 이 업무를 지금\n * 믿고 쓸 수 있는지가 한눈에 읽힌다. 제목 줄은 그것들을 못 받는다.\n *\n * 끄지 않으면 같은 이름이 화면에 두 번 뜬다(실측 2026-09-24: 제목 줄 「부적합 처분 승인」,\n * 바로 아래 또 「부적합 처분 승인」). `title` 은 그대로 두므로 **탭 이름은 살아 있다** —\n * `heading: false` 가 그리는 자리마다 켜고 끄라고 둔 문이다.\n */\n heading: false,\n help: 'worklist/activity-catalog-page'\n }\n }\n\n /**\n * 이름이 주소로 온다. 같은 라우트 안에서 이름만 바뀌어도 이 콜백이 다시 오므로, **이름이 실제로\n * 바뀌었을 때만** 다시 읽는다.\n */\n async pageUpdated(changes: any, lifecycle: any) {\n this.readName(lifecycle)\n }\n\n /**\n * 처음 그린 뒤에도 한 번 읽는다 — **첫 방문이 통째로 비는 것을 봤다.**\n *\n * [확인함 2026-09-24 :4000] 카드에서 처음 들어가면 주소는 맞고(`?name=…`) `lifecycle.params.name`\n * 도 들어 있는데 화면에 돌아갈 링크만 남았다. 같은 자리로 두 번째 들어가면 멀쩡했고, 그 상태에서\n * 콜백을 손으로 한 번 부르면 바로 채워졌다.\n *\n * 이 화면은 주소로 처음 닿을 때 **모듈이 그때 실려 온다**(route.ts 의 동적 import). 셸은 화면을\n * 처음 세울 때 이 콜백을 다음 animationFrame 으로 미루는데(page-view 가 「엘리먼트가 아직 안\n * 만들어졌을 수 있다」고 적어 둔 그 갈래), 그 사이에 요소가 아직 이 클래스로 올라오지 않았으면\n * **아무 일도 안 하는 기반 클래스의 콜백**이 불린다. 그 뒤로는 생애주기가 더 안 바뀌므로 이름을\n * 받을 기회가 다시 오지 않는다.\n *\n * 그래서 이름을 받는 자리를 둘로 둔다. 둘 다 같은 판단을 지나므로 두 번 읽지 않는다.\n */\n firstUpdated() {\n this.readName()\n }\n\n private readName(lifecycle?: any) {\n const name = String((lifecycle ?? this.lifecycle)?.params?.name || '')\n\n if (name && name !== this.name) {\n this.name = name\n /* 구획이 알린 것은 그 업무의 것이다. 다른 업무로 옮기면 다시 듣는다. */\n this.emptyPanels = {}\n this.fetch()\n }\n }\n\n private shownName(one: any): string {\n if (!one?.label) return String(one?.name ?? '')\n return one.labelTKey ? String(i18next.t(one.labelTKey, { defaultValue: one.label })) : String(one.label)\n }\n\n private async fetch() {\n this.loaded = false\n this.loadError = null\n\n try {\n const response = await client.query({ query: DETAIL, variables: { name: this.name }, fetchPolicy: 'no-cache' })\n\n /*\n * 목록에 필터가 없어서 전부 받아 하나를 고른다. 업무는 설치된 모듈이 선언하는 것이라 수가\n * 닫혀 있다 [확인함 2026-09-23: 마흔 안쪽]. 그 전제가 깨지면 서버에 이름으로 찾는 갈래를\n * 두는 것이 맞다 — 여기서 자르지 않는다.\n */\n const items = response?.data?.responses?.items || []\n\n this.entry = items.find((one: any) => one.name === this.name) || null\n this.activity = response?.data?.activityByName || null\n this.loaded = true\n } catch (thrown) {\n this.loadError = thrown\n this.loaded = true\n }\n }\n\n render() {\n return html`\n <a back @click=${() => navigate('activity-catalog')}>\n <md-icon>chevron_left</md-icon>${i18next.t('button.back-to-activity-catalog')}\n </a>\n\n <ox-page-state .loading=${!this.loaded} .error=${this.loadError} @retry=${() => this.fetch()}\n >${this.loaded && !this.loadError ? this.renderDetail() : ''}</ox-page-state\n >\n `\n }\n\n private renderDetail() {\n if (!this.entry) {\n /* 없는 이름으로 들어온 주소. 빈 화면으로 두지 않는다 — 무엇을 못 찾았는지 이름을 댄다. */\n return html`<div class=\"why\">${i18next.t('text.activity-not-found', { name: this.name })}</div>`\n }\n\n const actions = detailActions(this.entry)\n const stage = canonicalStage(this.entry.readiness?.stage)\n\n return html`\n <div class=\"head\">\n <span class=\"name\">${this.shownName(this.entry)}</span>\n ${stage ? html`<span class=\"stage\">${i18next.t('label.readiness-' + stage)}</span>` : ''}\n ${actions.registered\n ? html`<span class=\"use\" ?idle=${!actions.inUse}\n >${actions.inUse\n ? i18next.t('text.activity-in-use-here')\n : i18next.t('text.activity-not-in-use-here')}</span\n >`\n : ''}\n </div>\n\n ${this.renderGuide()} ${this.renderUse(actions)} ${this.renderApprovalLine(actions)} ${this.renderPanels()}\n `\n }\n\n /** 이 업무가 무엇인가. `guide` 가 그 자리이고, 없으면 설명이다. */\n private renderGuide() {\n const shown = guideLines(this.entry, (key, options) => i18next.t(key, options)).filter(Boolean)\n\n if (!shown.length && !this.entry.description) return html``\n\n return html`\n <section class=\"guide\">\n <h3>${i18next.t('label.activity-what-is-it')}</h3>\n ${shown.length\n ? shown.map(line => html`<p>${line}</p>`)\n : html`<p>${this.entry.description}</p>`}\n </section>\n `\n }\n\n private renderUse(actions: ReturnType<typeof detailActions>) {\n if (!actions.registered) return html``\n\n return html`\n <section>\n <h3>${i18next.t('label.activity-use-here')}</h3>\n ${actions.canInstall\n ? html`<button @click=${() => this.setUse(true)}>${i18next.t('button.activity-install')}</button>`\n : html`<button @click=${() => this.setUse(false)}>${i18next.t('button.activity-uninstall')}</button>`}\n </section>\n `\n }\n\n private renderApprovalLine(actions: ReturnType<typeof detailActions>) {\n const line = this.activity?.approvalLine || []\n const steps = approvalSteps(line)\n\n return html`\n <section>\n <h3>${i18next.t('label.activity-approval-line')}</h3>\n\n ${steps\n ? html`<div class=\"steps\">\n ${line.map((one: any) => html`<span>${one.approver?.name || one.value || ''}</span>`)}\n </div>`\n : ''}\n\n <button ?disabled=${!actions.canSetApprovalLine} @click=${() => this.openApprovalLine(line)}>\n ${i18next.t('button.activity-set-approval-line')}\n </button>\n\n <p class=\"why\">\n ${actions.approvalLineBlock\n ? i18next.t('text.activity-line-' + actions.approvalLineBlock)\n : steps\n ? i18next.t('text.activity-line-steps', { steps })\n : i18next.t('text.activity-line-none')}\n </p>\n </section>\n `\n }\n\n /**\n * 다른 꾸러미가 건 구획.\n *\n * **하나도 안 걸렸으면 그 사실을 말한다.** 빈자리로 두면 「이 앱에는 그 구획이 없다」와\n * 「정할 것이 없다」가 같은 화면이 된다.\n */\n private renderPanels() {\n const context = { activityName: this.entry.name, activityId: this.activity?.id }\n const panels = activityPanels(context)\n const shape = panelSection(\n panels.map(one => one.name),\n this.emptyPanels\n )\n\n if (shape.kind === 'none-registered') {\n return html`\n <section>\n <h3>${i18next.t('label.activity-panels')}</h3>\n <p class=\"why\">${i18next.t('text.activity-no-panels')}</p>\n </section>\n `\n }\n\n /*\n * 비었다고 알린 구획도 **그리기는 계속한다** — 숨길 뿐이다. 지우면 그 구획이 다시 읽고\n * 「있다」고 알릴 자리가 없어진다.\n */\n const hidden = shape.kind === 'all-empty' ? panels.map(one => one.name) : shape.hidden\n\n return html`\n <section ?hidden=${shape.kind === 'all-empty'}>\n <h3>${i18next.t('label.activity-panels')}</h3>\n ${panels.map(\n panel =>\n html`<div\n ?hidden=${hidden.includes(panel.name)}\n @activity-panel-content=${(event: CustomEvent) => this.panelReported(panel.name, event)}\n >\n ${panel.render(context)}\n </div>`\n )}\n </section>\n `\n }\n\n private panelReported(name: string, event: CustomEvent) {\n event.stopPropagation()\n this.emptyPanels = { ...this.emptyPanels, [name]: event.detail?.empty === true }\n }\n\n private async setUse(on: boolean) {\n const outcome = await ranMutation(() =>\n client.mutate({\n mutation: on\n ? gql`\n mutation ($name: String!) {\n activateInstallableActivity(name: $name) {\n name\n }\n }\n `\n : gql`\n mutation ($name: String!) {\n deactivateInstallableActivity(name: $name) {\n name\n }\n }\n `,\n variables: { name: this.entry.name }\n })\n )\n\n if (!outcome.ok) return\n\n this.fetch()\n }\n\n /**\n * 결재선 편집기는 **organization 것을 그대로 부른다.** 이 화면이 자기 편집기를 따로 지으면 같은\n * 결재선이 두 화면에서 다르게 편집된다.\n */\n private openApprovalLine(line: any[]) {\n const popup = openPopup(\n html`<approval-line-items-editor-popup\n .value=${line}\n .confirmCallback=${(after?: any[] | null) => this.saveApprovalLine(after || [])}\n ></approval-line-items-editor-popup>`,\n { backdrop: true, size: 'large', title: i18next.t('title.approval-line editor') }\n )\n\n return popup\n }\n\n private async saveApprovalLine(after: any[]) {\n const outcome = await ranMutation(() =>\n client.mutate({\n mutation: gql`\n mutation ($patches: [ActivityPatch!]!) {\n updateMultipleActivity(patches: $patches) {\n name\n }\n }\n `,\n variables: { patches: [{ id: this.activity.id, approvalLine: after, cuFlag: 'M' }] }\n })\n )\n\n if (!outcome.ok) return\n\n this.fetch()\n }\n}\n"]}
1
+ {"version":3,"file":"activity-detail-page.js","sourceRoot":"","sources":["../../../client/pages/activity-catalog/activity-detail-page.ts"],"names":[],"mappings":"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","sourcesContent":["import '@material/web/icon/icon.js'\nimport '@operato/list-state/ox-page-state.js'\nimport '@things-factory/organization'\n\nimport gql from 'graphql-tag'\nimport { css, html } from 'lit'\nimport { customElement, state } from 'lit/decorators.js'\nimport { client } from '@operato/graphql'\nimport { i18next, localize } from '@operato/i18n'\nimport { openPopup } from '@operato/layout'\nimport { navigate, PageView } from '@operato/shell'\nimport { DocumentPageStyles, ScrollbarStyles } from '@operato/styles'\n\nimport { ranMutation } from '../../components/say-outcome.js'\nimport { activityPanels, panelSection } from './activity-panels.js'\nimport { detailActions } from './activity-detail-actions.js'\nimport { canonicalStage } from './activity-stage.js'\nimport { guideLines } from './activity-guide.js'\n\n/**\n * 업무 하나 — **그 업무에 관한 일을 여기서 끝낸다.**\n *\n * ── 왜 이 화면이 생겼나 (2026-09-23) ───────────────────────────────────────\n * 결재선 하나를 세워서 문이 서는지 보려면 화면을 셋 열어야 했고, 역할에 사람이 없으면 넷에서\n * 다섯이었다 [확인함]. 카탈로그는 카드에 「결재선 없음」이라고 적어 놓고 **어디로 가야 하는지는\n * 말하지 않았다** — 그 파일 전체에 `navigate()` 도 `<a href>` 도 없었다. 사람은 메뉴로 돌아가\n * 이름으로 찾아야 했다.\n *\n * 그래서 카탈로그는 고르는 자리로 두고, 고른 뒤의 일은 이 화면 안에서 끝낸다.\n *\n * ── 돌아갈 길을 화면이 갖는다 ─────────────────────────────────────────────\n * 탭 줄에 카탈로그가 남아 있으니 됐다고 볼 수 없다. 탭 줄은 **없을 수 있다** — 페이지가\n * `mdibar: false` 를 적으면 셸이 걷고(`apptool-ui/client/layout/mdibar-visibility.ts`), 무엇보다\n * **주소를 받아서 바로 여는 사람에게는 이전 화면이 아예 없다.** 「이 업무 결재선 좀 봐 주세요」로\n * 링크를 받은 사람이 그 경우다. 그래서 머리에 돌아갈 자리를 직접 둔다.\n *\n * ── 못 하는 일은 까닭을 말한다 ────────────────────────────────────────────\n * 눌리지 않는 단추만 남기지 않는다. 무엇을 할 수 있는지와 못 하면 왜인지는\n * `activity-detail-actions.ts` 가 값으로 답하고, 이 화면은 그 값을 문장으로 바꾼다. 원인을 여기서\n * 지어내지 않는다.\n */\nconst DETAIL = gql`\n query ($name: String!) {\n responses: installableActivities {\n items {\n name\n label\n labelTKey\n description\n guide\n guideTKeys\n approvalSteps\n activity {\n id\n }\n readiness {\n stage\n }\n }\n }\n activityByName(name: $name) {\n id\n name\n description\n approvalLine {\n type\n value\n participation\n approver {\n id\n name\n description\n controlNo\n }\n }\n }\n }\n`\n\n/** 결재선에서 **서명하는 단계만** 센다. 참조는 알기만 하고 막지 않는다. */\nfunction approvalSteps(line?: any[]): number {\n return (line || []).filter(one => String(one?.participation || '') !== 'reference').length\n}\n\n@customElement('activity-detail-page')\nexport class ActivityDetailPage extends localize(i18next)(PageView) {\n static styles = [\n ScrollbarStyles,\n DocumentPageStyles,\n css`\n :host {\n display: flex;\n flex-direction: column;\n overflow: auto;\n }\n\n /* 돌아갈 자리. 제목 위에 둔다 — 읽기 전에 보인다. */\n a[back] {\n display: inline-flex;\n align-items: center;\n gap: 2px;\n align-self: flex-start;\n margin-bottom: var(--spacing-small);\n color: var(--md-sys-color-on-surface-variant);\n font-size: var(--ui-t-body, 13px);\n text-decoration: none;\n cursor: pointer;\n }\n\n a[back]:hover {\n color: var(--md-sys-color-on-surface);\n text-decoration: underline;\n }\n\n a[back] md-icon {\n --md-icon-size: 16px;\n }\n\n .head {\n display: flex;\n align-items: center;\n flex-wrap: wrap;\n gap: var(--spacing-small);\n }\n\n .head .name {\n font: var(--ui-t-title-font, bold 18px var(--theme-font));\n color: var(--md-sys-color-on-surface);\n }\n\n .stage,\n .use {\n padding: 1px 8px;\n border-radius: var(--md-sys-shape-corner-full);\n font-size: var(--ui-t-small, 12px);\n background-color: var(--md-sys-color-surface-container-high);\n color: var(--md-sys-color-on-surface-variant);\n }\n\n .use:not([idle]) {\n background-color: var(--md-sys-color-secondary-container);\n color: var(--md-sys-color-on-secondary-container);\n }\n\n section {\n margin-top: var(--spacing-large, 16px);\n }\n\n section > h3 {\n margin: 0 0 var(--spacing-small) 0;\n font-size: var(--ui-t-small, 12px);\n color: var(--md-sys-color-on-surface-variant);\n text-transform: uppercase;\n }\n\n .guide p {\n margin: 0 0 4px 0;\n line-height: 1.5;\n }\n\n /* 못 하는 까닭 · 비어 있다는 사실. 둘 다 **문장으로** 남는다. */\n .why {\n margin: 4px 0 0 0;\n color: var(--md-sys-color-on-surface-variant);\n font-size: var(--ui-t-body, 13px);\n }\n\n .steps {\n display: flex;\n flex-wrap: wrap;\n gap: 4px;\n margin-bottom: var(--spacing-small);\n }\n\n .steps span {\n padding: 2px 8px;\n border: 1px solid var(--md-sys-color-outline-variant);\n border-radius: var(--md-sys-shape-corner-full);\n font-size: var(--ui-t-small, 12px);\n }\n\n button {\n font: inherit;\n color: var(--md-sys-color-on-surface);\n background-color: var(--md-sys-color-surface-container);\n border: 1px solid var(--md-sys-color-outline-variant);\n border-radius: var(--md-sys-shape-corner-full);\n padding: 6px 14px;\n cursor: pointer;\n }\n\n button:hover:not(:disabled) {\n background-color: var(--md-sys-color-surface-container-high);\n }\n\n button:disabled {\n opacity: 0.4;\n cursor: default;\n }\n `\n ]\n\n @state() private name = ''\n @state() private entry: any = null\n @state() private activity: any = null\n @state() private loaded = false\n /** 구획이 「이 업무에는 보일 것 없음」을 알렸나. 이름으로 센다. */\n @state() private emptyPanels: Record<string, boolean> = {}\n /** 왜 못 읽었나 — ox-page-state 가 그것을 말하고 다시 시도를 준다. */\n @state() private loadError: unknown = null\n\n get context() {\n return {\n frame: 'document',\n title: this.entry ? this.shownName(this.entry) : i18next.t('title.activity-detail'),\n /*\n * 이름은 **이 화면이 그린다.** 제목 줄은 끈다.\n *\n * 이름 옆에 단계 띠와 「사용 중」이 함께 서야 한다 — 그 셋이 한 줄에 있어야 이 업무를 지금\n * 믿고 쓸 수 있는지가 한눈에 읽힌다. 제목 줄은 그것들을 못 받는다.\n *\n * 끄지 않으면 같은 이름이 화면에 두 번 뜬다(실측 2026-09-24: 제목 줄 「부적합 처분 승인」,\n * 바로 아래 또 「부적합 처분 승인」). `title` 은 그대로 두므로 **탭 이름은 살아 있다** —\n * `heading: false` 가 그리는 자리마다 켜고 끄라고 둔 문이다.\n */\n heading: false,\n help: 'worklist/activity-catalog-page'\n }\n }\n\n /**\n * 이름이 주소로 온다. 같은 라우트 안에서 이름만 바뀌어도 이 콜백이 다시 오므로, **이름이 실제로\n * 바뀌었을 때만** 다시 읽는다.\n */\n async pageUpdated(changes: any, lifecycle: any) {\n this.readName(lifecycle)\n }\n\n /**\n * 처음 그린 뒤에도 한 번 읽는다 — **첫 방문이 통째로 비는 것을 봤다.**\n *\n * [확인함 2026-09-24 :4000] 카드에서 처음 들어가면 주소는 맞고(`?name=…`) `lifecycle.params.name`\n * 도 들어 있는데 화면에 돌아갈 링크만 남았다. 같은 자리로 두 번째 들어가면 멀쩡했고, 그 상태에서\n * 콜백을 손으로 한 번 부르면 바로 채워졌다.\n *\n * 이 화면은 주소로 처음 닿을 때 **모듈이 그때 실려 온다**(route.ts 의 동적 import). 셸은 화면을\n * 처음 세울 때 이 콜백을 다음 animationFrame 으로 미루는데(page-view 가 「엘리먼트가 아직 안\n * 만들어졌을 수 있다」고 적어 둔 그 갈래), 그 사이에 요소가 아직 이 클래스로 올라오지 않았으면\n * **아무 일도 안 하는 기반 클래스의 콜백**이 불린다. 그 뒤로는 생애주기가 더 안 바뀌므로 이름을\n * 받을 기회가 다시 오지 않는다.\n *\n * 그래서 이름을 받는 자리를 둘로 둔다. 둘 다 같은 판단을 지나므로 두 번 읽지 않는다.\n */\n firstUpdated() {\n this.readName()\n }\n\n private readName(lifecycle?: any) {\n const name = String((lifecycle ?? this.lifecycle)?.params?.name || '')\n\n if (name && name !== this.name) {\n this.name = name\n /* 구획이 알린 것은 그 업무의 것이다. 다른 업무로 옮기면 다시 듣는다. */\n this.emptyPanels = {}\n this.fetch()\n }\n }\n\n private shownName(one: any): string {\n if (!one?.label) return String(one?.name ?? '')\n return one.labelTKey ? String(i18next.t(one.labelTKey, { defaultValue: one.label })) : String(one.label)\n }\n\n private async fetch() {\n this.loaded = false\n this.loadError = null\n /*\n * The tab and the document title come from `context`, and the shell reads it when the route\n * changes - before this answer arrives. Nothing read it again, so the tab kept the previous\n * activity's name while the page showed the next one [확인함 2026-09-24 :4000: 「교대 편성 변경\n * 승인」 on the tab over 「계획 정비 연기 승인」]. Drop the old entry so the wait says the generic\n * name, and hand the context over again once the answer is in.\n */\n this.entry = null\n this.updateContext()\n\n try {\n const response = await client.query({ query: DETAIL, variables: { name: this.name }, fetchPolicy: 'no-cache' })\n\n /*\n * 목록에 필터가 없어서 전부 받아 하나를 고른다. 업무는 설치된 모듈이 선언하는 것이라 수가\n * 닫혀 있다 [확인함 2026-09-23: 마흔 안쪽]. 그 전제가 깨지면 서버에 이름으로 찾는 갈래를\n * 두는 것이 맞다 — 여기서 자르지 않는다.\n */\n const items = response?.data?.responses?.items || []\n\n this.entry = items.find((one: any) => one.name === this.name) || null\n this.activity = response?.data?.activityByName || null\n this.loaded = true\n } catch (thrown) {\n this.loadError = thrown\n this.loaded = true\n }\n\n this.updateContext()\n }\n\n render() {\n return html`\n <a back @click=${() => navigate('activity-catalog')}>\n <md-icon>chevron_left</md-icon>${i18next.t('button.back-to-activity-catalog')}\n </a>\n\n <ox-page-state .loading=${!this.loaded} .error=${this.loadError} @retry=${() => this.fetch()}\n >${this.loaded && !this.loadError ? this.renderDetail() : ''}</ox-page-state\n >\n `\n }\n\n private renderDetail() {\n if (!this.entry) {\n /* 없는 이름으로 들어온 주소. 빈 화면으로 두지 않는다 — 무엇을 못 찾았는지 이름을 댄다. */\n return html`<div class=\"why\">${i18next.t('text.activity-not-found', { name: this.name })}</div>`\n }\n\n const actions = detailActions(this.entry)\n const stage = canonicalStage(this.entry.readiness?.stage)\n\n return html`\n <div class=\"head\">\n <span class=\"name\">${this.shownName(this.entry)}</span>\n ${stage ? html`<span class=\"stage\">${i18next.t('label.readiness-' + stage)}</span>` : ''}\n ${actions.registered\n ? html`<span class=\"use\" ?idle=${!actions.inUse}\n >${actions.inUse\n ? i18next.t('text.activity-in-use-here')\n : i18next.t('text.activity-not-in-use-here')}</span\n >`\n : ''}\n </div>\n\n ${this.renderGuide()} ${this.renderUse(actions)} ${this.renderApprovalLine(actions)} ${this.renderPanels()}\n `\n }\n\n /** 이 업무가 무엇인가. `guide` 가 그 자리이고, 없으면 설명이다. */\n private renderGuide() {\n const shown = guideLines(this.entry, (key, options) => i18next.t(key, options)).filter(Boolean)\n\n if (!shown.length && !this.entry.description) return html``\n\n return html`\n <section class=\"guide\">\n <h3>${i18next.t('label.activity-what-is-it')}</h3>\n ${shown.length\n ? shown.map(line => html`<p>${line}</p>`)\n : html`<p>${this.entry.description}</p>`}\n </section>\n `\n }\n\n private renderUse(actions: ReturnType<typeof detailActions>) {\n if (!actions.registered) return html``\n\n return html`\n <section>\n <h3>${i18next.t('label.activity-use-here')}</h3>\n ${actions.canInstall\n ? html`<button @click=${() => this.setUse(true)}>${i18next.t('button.activity-install')}</button>`\n : html`<button @click=${() => this.setUse(false)}>${i18next.t('button.activity-uninstall')}</button>`}\n </section>\n `\n }\n\n private renderApprovalLine(actions: ReturnType<typeof detailActions>) {\n const line = this.activity?.approvalLine || []\n const steps = approvalSteps(line)\n\n return html`\n <section>\n <h3>${i18next.t('label.activity-approval-line')}</h3>\n\n ${steps\n ? html`<div class=\"steps\">\n ${line.map((one: any) => html`<span>${one.approver?.name || one.value || ''}</span>`)}\n </div>`\n : ''}\n\n <button ?disabled=${!actions.canSetApprovalLine} @click=${() => this.openApprovalLine(line)}>\n ${i18next.t('button.activity-set-approval-line')}\n </button>\n\n <p class=\"why\">\n ${actions.approvalLineBlock\n ? i18next.t('text.activity-line-' + actions.approvalLineBlock)\n : steps\n ? i18next.t('text.activity-line-steps', { steps })\n : i18next.t('text.activity-line-none')}\n </p>\n </section>\n `\n }\n\n /**\n * 다른 꾸러미가 건 구획.\n *\n * **하나도 안 걸렸으면 그 사실을 말한다.** 빈자리로 두면 「이 앱에는 그 구획이 없다」와\n * 「정할 것이 없다」가 같은 화면이 된다.\n */\n private renderPanels() {\n const context = { activityName: this.entry.name, activityId: this.activity?.id }\n const panels = activityPanels(context)\n const shape = panelSection(\n panels.map(one => one.name),\n this.emptyPanels\n )\n\n if (shape.kind === 'none-registered') {\n return html`\n <section>\n <h3>${i18next.t('label.activity-panels')}</h3>\n <p class=\"why\">${i18next.t('text.activity-no-panels')}</p>\n </section>\n `\n }\n\n /*\n * 비었다고 알린 구획도 **그리기는 계속한다** — 숨길 뿐이다. 지우면 그 구획이 다시 읽고\n * 「있다」고 알릴 자리가 없어진다.\n */\n const hidden = shape.kind === 'all-empty' ? panels.map(one => one.name) : shape.hidden\n\n return html`\n <section ?hidden=${shape.kind === 'all-empty'}>\n <h3>${i18next.t('label.activity-panels')}</h3>\n ${panels.map(\n panel =>\n html`<div\n ?hidden=${hidden.includes(panel.name)}\n @activity-panel-content=${(event: CustomEvent) => this.panelReported(panel.name, event)}\n >\n ${panel.render(context)}\n </div>`\n )}\n </section>\n `\n }\n\n private panelReported(name: string, event: CustomEvent) {\n event.stopPropagation()\n this.emptyPanels = { ...this.emptyPanels, [name]: event.detail?.empty === true }\n }\n\n private async setUse(on: boolean) {\n const outcome = await ranMutation(() =>\n client.mutate({\n mutation: on\n ? gql`\n mutation ($name: String!) {\n activateInstallableActivity(name: $name) {\n name\n }\n }\n `\n : gql`\n mutation ($name: String!) {\n deactivateInstallableActivity(name: $name) {\n name\n }\n }\n `,\n variables: { name: this.entry.name }\n })\n )\n\n if (!outcome.ok) return\n\n this.fetch()\n }\n\n /**\n * 결재선 편집기는 **organization 것을 그대로 부른다.** 이 화면이 자기 편집기를 따로 지으면 같은\n * 결재선이 두 화면에서 다르게 편집된다.\n */\n private openApprovalLine(line: any[]) {\n const popup = openPopup(\n html`<approval-line-items-editor-popup\n .value=${line}\n .confirmCallback=${(after?: any[] | null) => this.saveApprovalLine(after || [])}\n ></approval-line-items-editor-popup>`,\n { backdrop: true, size: 'large', title: i18next.t('title.approval-line editor') }\n )\n\n return popup\n }\n\n private async saveApprovalLine(after: any[]) {\n const outcome = await ranMutation(() =>\n client.mutate({\n mutation: gql`\n mutation ($patches: [ActivityPatch!]!) {\n updateMultipleActivity(patches: $patches) {\n name\n }\n }\n `,\n variables: { patches: [{ id: this.activity.id, approvalLine: after, cuFlag: 'M' }] }\n })\n )\n\n if (!outcome.ok) return\n\n this.fetch()\n }\n}\n"]}
@@ -26,6 +26,6 @@ declare const ActivityThreadView_base: (new (...args: any[]) => LitElement) & ty
26
26
  export declare class ActivityThreadView extends ActivityThreadView_base {
27
27
  static styles: import("lit").CSSResult[];
28
28
  activityThread?: ActivityThread;
29
- render(): typeof nothing | import("lit-html").TemplateResult<1>;
29
+ render(): import("lit-html").TemplateResult<1> | typeof nothing;
30
30
  }
31
31
  export {};
@@ -0,0 +1,63 @@
1
+ /**
2
+ * The sentences of the work-doors screen, **composed here from facts and translations.**
3
+ *
4
+ * ═══════════════════════════════════════════════════════════════════════════
5
+ * ── Why the screen writes them ────────────────────────────────────────────
6
+ * The server used to send each row's sentence and the summary already written, in Korean. An English,
7
+ * Japanese, Chinese or Malay reader got Korean, and the screen had no way to draw a row differently
8
+ * without reading the sentence back apart. The server now sends facts (`WorkDoorType`) and every
9
+ * sentence is a translation key here.
10
+ *
11
+ * ── The empty line is the door's declaration, not one sentence ────────────
12
+ * What an empty approval line does is declared per door (ADR-0077 decision 1). `run` lets the raiser
13
+ * approve their own; `refuse` refuses the raise; `as-established` turns on how the row stood. The
14
+ * old sentence said "the raiser approves their own" for every door, and four refusing doors on :4000
15
+ * carried it (2026-09-24). A door with no declaration says nothing about the consequence rather than
16
+ * guessing one.
17
+ *
18
+ * Pure: `t` is passed in, so a test can load the real translation files and read the sentences.
19
+ * ═══════════════════════════════════════════════════════════════════════════
20
+ */
21
+ /** The row as this screen holds it, after `door-words` has moved the wire spellings. */
22
+ export type DoorFacts = {
23
+ name: string;
24
+ labelKey: string;
25
+ kind: string;
26
+ standing: string;
27
+ reason: string;
28
+ approvers: number;
29
+ whenNoLine?: string;
30
+ whenNoLineBecause?: string;
31
+ followsLabelKey?: string;
32
+ assigneeRole?: string;
33
+ notUsedBecause?: string;
34
+ };
35
+ export type DoorCounts = {
36
+ on: number;
37
+ off: number;
38
+ missing: number;
39
+ notUsed: number;
40
+ todo: number;
41
+ };
42
+ type T = (key: string, options?: Record<string, unknown>) => string;
43
+ /**
44
+ * A door's name. A label key without a translation falls back to the form name - a name a person can
45
+ * search for - rather than printing the key.
46
+ */
47
+ export declare function doorLabel(t: T, door: {
48
+ labelKey: string;
49
+ name: string;
50
+ }): string;
51
+ /** Why an approval door will not run on an empty line, as a short phrase. Empty when not declared. */
52
+ export declare function whyItRefuses(t: T, door: Pick<DoorFacts, 'whenNoLineBecause'>): string;
53
+ /** What this row says about its standing. */
54
+ export declare function doorSentence(t: T, door: DoorFacts): string;
55
+ /**
56
+ * What the door does when its line is empty, as a short tag - shown on rows whose sentence does not
57
+ * already say it (ADR-0077 decision 3). An empty-line row already says it; a not-used or missing row
58
+ * does not go through the line at all.
59
+ */
60
+ export declare function whenNoLineTag(t: T, door: DoorFacts): string;
61
+ /** The whole plant in one sentence - a list alone makes the reader count rows. */
62
+ export declare function doorsSummary(t: T, counts: DoorCounts): string;
63
+ export {};
@@ -0,0 +1,109 @@
1
+ /**
2
+ * The sentences of the work-doors screen, **composed here from facts and translations.**
3
+ *
4
+ * ═══════════════════════════════════════════════════════════════════════════
5
+ * ── Why the screen writes them ────────────────────────────────────────────
6
+ * The server used to send each row's sentence and the summary already written, in Korean. An English,
7
+ * Japanese, Chinese or Malay reader got Korean, and the screen had no way to draw a row differently
8
+ * without reading the sentence back apart. The server now sends facts (`WorkDoorType`) and every
9
+ * sentence is a translation key here.
10
+ *
11
+ * ── The empty line is the door's declaration, not one sentence ────────────
12
+ * What an empty approval line does is declared per door (ADR-0077 decision 1). `run` lets the raiser
13
+ * approve their own; `refuse` refuses the raise; `as-established` turns on how the row stood. The
14
+ * old sentence said "the raiser approves their own" for every door, and four refusing doors on :4000
15
+ * carried it (2026-09-24). A door with no declaration says nothing about the consequence rather than
16
+ * guessing one.
17
+ *
18
+ * Pure: `t` is passed in, so a test can load the real translation files and read the sentences.
19
+ * ═══════════════════════════════════════════════════════════════════════════
20
+ */
21
+ /*
22
+ * Values reach the sentence through lit, which escapes them. i18next escaping on top would print
23
+ * `&amp;` for a plant's own "we do not use this" note.
24
+ */
25
+ const RAW = { interpolation: { escapeValue: false } };
26
+ /**
27
+ * A door's name. A label key without a translation falls back to the form name - a name a person can
28
+ * search for - rather than printing the key.
29
+ */
30
+ export function doorLabel(t, door) {
31
+ return String(t(door.labelKey, { defaultValue: door.name }));
32
+ }
33
+ /** Why an approval door will not run on an empty line, as a short phrase. Empty when not declared. */
34
+ export function whyItRefuses(t, door) {
35
+ return door.whenNoLineBecause ? String(t(`text.door-refuses-because-${door.whenNoLineBecause}`)) : '';
36
+ }
37
+ /** What this row says about its standing. */
38
+ export function doorSentence(t, door) {
39
+ const label = doorLabel(t, door);
40
+ const said = [String(t(sentenceKey(door), { ...RAW, label, ...sentenceParams(t, door) }))];
41
+ if (door.followsLabelKey && door.standing !== 'not-used' && door.standing !== 'missing') {
42
+ said.push(String(t('text.door-because-follows', { ...RAW, label: doorLabel(t, { labelKey: door.followsLabelKey, name: '' }) })));
43
+ }
44
+ return said.join(' ');
45
+ }
46
+ function sentenceKey(door) {
47
+ if (door.reason === 'line-empty') {
48
+ return door.whenNoLine ? `text.door-because-line-empty-${door.whenNoLine}` : 'text.door-because-line-empty';
49
+ }
50
+ return `text.door-because-${door.reason}`;
51
+ }
52
+ function sentenceParams(t, door) {
53
+ switch (door.reason) {
54
+ case 'not-used':
55
+ return { reason: door.notUsedBecause ?? '' };
56
+ case 'line-filled':
57
+ return { count: door.approvers };
58
+ case 'assignee-bound':
59
+ return { role: door.assigneeRole ?? '' };
60
+ case 'line-empty':
61
+ return { why: whyItRefuses(t, door) };
62
+ default:
63
+ return {};
64
+ }
65
+ }
66
+ /**
67
+ * What the door does when its line is empty, as a short tag - shown on rows whose sentence does not
68
+ * already say it (ADR-0077 decision 3). An empty-line row already says it; a not-used or missing row
69
+ * does not go through the line at all.
70
+ */
71
+ export function whenNoLineTag(t, door) {
72
+ if (door.kind !== 'approval' || !door.whenNoLine || door.reason === 'line-empty') {
73
+ return '';
74
+ }
75
+ if (door.standing !== 'on' && door.standing !== 'off') {
76
+ return '';
77
+ }
78
+ const why = whyItRefuses(t, door);
79
+ const tag = String(t(`text.door-when-no-line-${door.whenNoLine}`));
80
+ return door.whenNoLine === 'refuse' && why ? `${tag} (${why})` : tag;
81
+ }
82
+ /** The whole plant in one sentence - a list alone makes the reader count rows. */
83
+ export function doorsSummary(t, counts) {
84
+ const total = counts.on + counts.off + counts.missing + counts.notUsed;
85
+ if (!total) {
86
+ return String(t('text.work-doors-summary-none'));
87
+ }
88
+ /*
89
+ * Only `off + missing` is counted, so that zero means done. Counting the doors a plant opted out of
90
+ * would leave the number standing in a plant that filled everything, and the screen would nag.
91
+ */
92
+ if (!counts.todo) {
93
+ return counts.notUsed
94
+ ? String(t('text.work-doors-summary-done-not-used', { on: counts.on, notUsed: counts.notUsed }))
95
+ : String(t('text.work-doors-summary-all-on', { count: total }));
96
+ }
97
+ const said = [String(t('text.work-doors-summary-todo', { count: counts.todo }))];
98
+ if (counts.off) {
99
+ said.push(String(t('text.work-doors-summary-off', { count: counts.off })));
100
+ }
101
+ if (counts.missing) {
102
+ said.push(String(t('text.work-doors-summary-missing', { count: counts.missing })));
103
+ }
104
+ if (counts.notUsed) {
105
+ said.push(String(t('text.work-doors-summary-not-used', { count: counts.notUsed })));
106
+ }
107
+ return said.join(' ');
108
+ }
109
+ //# sourceMappingURL=door-sentence.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"door-sentence.js","sourceRoot":"","sources":["../../../client/pages/work-door/door-sentence.ts"],"names":[],"mappings":"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","sourcesContent":["/**\n * The sentences of the work-doors screen, **composed here from facts and translations.**\n *\n * ═══════════════════════════════════════════════════════════════════════════\n * ── Why the screen writes them ────────────────────────────────────────────\n * The server used to send each row's sentence and the summary already written, in Korean. An English,\n * Japanese, Chinese or Malay reader got Korean, and the screen had no way to draw a row differently\n * without reading the sentence back apart. The server now sends facts (`WorkDoorType`) and every\n * sentence is a translation key here.\n *\n * ── The empty line is the door's declaration, not one sentence ────────────\n * What an empty approval line does is declared per door (ADR-0077 decision 1). `run` lets the raiser\n * approve their own; `refuse` refuses the raise; `as-established` turns on how the row stood. The\n * old sentence said \"the raiser approves their own\" for every door, and four refusing doors on :4000\n * carried it (2026-09-24). A door with no declaration says nothing about the consequence rather than\n * guessing one.\n *\n * Pure: `t` is passed in, so a test can load the real translation files and read the sentences.\n * ═══════════════════════════════════════════════════════════════════════════\n */\n\n/** The row as this screen holds it, after `door-words` has moved the wire spellings. */\nexport type DoorFacts = {\n name: string\n labelKey: string\n kind: string\n standing: string\n reason: string\n approvers: number\n whenNoLine?: string\n whenNoLineBecause?: string\n followsLabelKey?: string\n assigneeRole?: string\n notUsedBecause?: string\n}\n\nexport type DoorCounts = { on: number; off: number; missing: number; notUsed: number; todo: number }\n\ntype T = (key: string, options?: Record<string, unknown>) => string\n\n/*\n * Values reach the sentence through lit, which escapes them. i18next escaping on top would print\n * `&amp;` for a plant's own \"we do not use this\" note.\n */\nconst RAW = { interpolation: { escapeValue: false } }\n\n/**\n * A door's name. A label key without a translation falls back to the form name - a name a person can\n * search for - rather than printing the key.\n */\nexport function doorLabel(t: T, door: { labelKey: string; name: string }): string {\n return String(t(door.labelKey, { defaultValue: door.name }))\n}\n\n/** Why an approval door will not run on an empty line, as a short phrase. Empty when not declared. */\nexport function whyItRefuses(t: T, door: Pick<DoorFacts, 'whenNoLineBecause'>): string {\n return door.whenNoLineBecause ? String(t(`text.door-refuses-because-${door.whenNoLineBecause}`)) : ''\n}\n\n/** What this row says about its standing. */\nexport function doorSentence(t: T, door: DoorFacts): string {\n const label = doorLabel(t, door)\n const said = [String(t(sentenceKey(door), { ...RAW, label, ...sentenceParams(t, door) }))]\n\n if (door.followsLabelKey && door.standing !== 'not-used' && door.standing !== 'missing') {\n said.push(String(t('text.door-because-follows', { ...RAW, label: doorLabel(t, { labelKey: door.followsLabelKey, name: '' }) })))\n }\n\n return said.join(' ')\n}\n\nfunction sentenceKey(door: DoorFacts): string {\n if (door.reason === 'line-empty') {\n return door.whenNoLine ? `text.door-because-line-empty-${door.whenNoLine}` : 'text.door-because-line-empty'\n }\n\n return `text.door-because-${door.reason}`\n}\n\nfunction sentenceParams(t: T, door: DoorFacts): Record<string, unknown> {\n switch (door.reason) {\n case 'not-used':\n return { reason: door.notUsedBecause ?? '' }\n case 'line-filled':\n return { count: door.approvers }\n case 'assignee-bound':\n return { role: door.assigneeRole ?? '' }\n case 'line-empty':\n return { why: whyItRefuses(t, door) }\n default:\n return {}\n }\n}\n\n/**\n * What the door does when its line is empty, as a short tag - shown on rows whose sentence does not\n * already say it (ADR-0077 decision 3). An empty-line row already says it; a not-used or missing row\n * does not go through the line at all.\n */\nexport function whenNoLineTag(t: T, door: DoorFacts): string {\n if (door.kind !== 'approval' || !door.whenNoLine || door.reason === 'line-empty') {\n return ''\n }\n\n if (door.standing !== 'on' && door.standing !== 'off') {\n return ''\n }\n\n const why = whyItRefuses(t, door)\n const tag = String(t(`text.door-when-no-line-${door.whenNoLine}`))\n\n return door.whenNoLine === 'refuse' && why ? `${tag} (${why})` : tag\n}\n\n/** The whole plant in one sentence - a list alone makes the reader count rows. */\nexport function doorsSummary(t: T, counts: DoorCounts): string {\n const total = counts.on + counts.off + counts.missing + counts.notUsed\n\n if (!total) {\n return String(t('text.work-doors-summary-none'))\n }\n\n /*\n * Only `off + missing` is counted, so that zero means done. Counting the doors a plant opted out of\n * would leave the number standing in a plant that filled everything, and the screen would nag.\n */\n if (!counts.todo) {\n return counts.notUsed\n ? String(t('text.work-doors-summary-done-not-used', { on: counts.on, notUsed: counts.notUsed }))\n : String(t('text.work-doors-summary-all-on', { count: total }))\n }\n\n const said = [String(t('text.work-doors-summary-todo', { count: counts.todo }))]\n\n if (counts.off) {\n said.push(String(t('text.work-doors-summary-off', { count: counts.off })))\n }\n\n if (counts.missing) {\n said.push(String(t('text.work-doors-summary-missing', { count: counts.missing })))\n }\n\n if (counts.notUsed) {\n said.push(String(t('text.work-doors-summary-not-used', { count: counts.notUsed })))\n }\n\n return said.join(' ')\n}\n"]}
@@ -36,6 +36,13 @@
36
36
  /** 전선의 철자 → 판단부의 낱말. 키가 전선의 것이라 대문자다 — 일부러다. */
37
37
  export declare const DOOR_STANDING_WORD: Record<string, string>;
38
38
  export declare const DOOR_KIND_WORD: Record<string, string>;
39
+ export declare const DOOR_REASON_WORD: Record<string, string>;
40
+ export declare const WHEN_NO_LINE_WORD: Record<string, string>;
41
+ export declare const WHEN_NO_LINE_BECAUSE_WORD: Record<string, string>;
39
42
  /** 모르는 철자면 `undefined` — 부르는 쪽이 「모른다」를 그리게 한다. */
40
43
  export declare function standingWord(wire: string): string | undefined;
41
44
  export declare function kindWord(wire: string): string | undefined;
45
+ export declare function reasonWord(wire: string): string | undefined;
46
+ /** 비어 있으면(배정 문) 비어 있는 채로 — 선언이 없는 것을 `run` 으로 기울이지 않는다. */
47
+ export declare function whenNoLineWord(wire?: string | null): string | undefined;
48
+ export declare function whenNoLineBecauseWord(wire?: string | null): string | undefined;
@@ -44,6 +44,26 @@ export const DOOR_KIND_WORD = {
44
44
  Approval: 'approval',
45
45
  Assignment: 'assignment'
46
46
  };
47
+ export const DOOR_REASON_WORD = {
48
+ NotUsed: 'not-used',
49
+ Missing: 'missing',
50
+ LineEmpty: 'line-empty',
51
+ RoleEmpty: 'role-empty',
52
+ PersonAbsent: 'person-absent',
53
+ NoAssignee: 'no-assignee',
54
+ LineFilled: 'line-filled',
55
+ AssigneeBound: 'assignee-bound'
56
+ };
57
+ export const WHEN_NO_LINE_WORD = {
58
+ Run: 'run',
59
+ Refuse: 'refuse',
60
+ AsEstablished: 'as-established'
61
+ };
62
+ export const WHEN_NO_LINE_BECAUSE_WORD = {
63
+ Irreversible: 'irreversible',
64
+ ApprovalIsTheAct: 'approval-is-the-act',
65
+ LowersAControl: 'lowers-a-control'
66
+ };
47
67
  /** 모르는 철자면 `undefined` — 부르는 쪽이 「모른다」를 그리게 한다. */
48
68
  export function standingWord(wire) {
49
69
  return DOOR_STANDING_WORD[wire];
@@ -51,4 +71,14 @@ export function standingWord(wire) {
51
71
  export function kindWord(wire) {
52
72
  return DOOR_KIND_WORD[wire];
53
73
  }
74
+ export function reasonWord(wire) {
75
+ return DOOR_REASON_WORD[wire];
76
+ }
77
+ /** 비어 있으면(배정 문) 비어 있는 채로 — 선언이 없는 것을 `run` 으로 기울이지 않는다. */
78
+ export function whenNoLineWord(wire) {
79
+ return wire ? WHEN_NO_LINE_WORD[wire] : undefined;
80
+ }
81
+ export function whenNoLineBecauseWord(wire) {
82
+ return wire ? WHEN_NO_LINE_BECAUSE_WORD[wire] : undefined;
83
+ }
54
84
  //# sourceMappingURL=door-words.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"door-words.js","sourceRoot":"","sources":["../../../client/pages/work-door/door-words.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAkCG;AAEH,gDAAgD;AAChD,MAAM,CAAC,MAAM,kBAAkB,GAA2B;IACxD,EAAE,EAAE,IAAI;IACR,GAAG,EAAE,KAAK;IACV,OAAO,EAAE,SAAS;IAClB,OAAO,EAAE,UAAU;CACpB,CAAA;AAED,MAAM,CAAC,MAAM,cAAc,GAA2B;IACpD,QAAQ,EAAE,UAAU;IACpB,UAAU,EAAE,YAAY;CACzB,CAAA;AAED,kDAAkD;AAClD,MAAM,UAAU,YAAY,CAAC,IAAY;IACvC,OAAO,kBAAkB,CAAC,IAAI,CAAC,CAAA;AACjC,CAAC;AAED,MAAM,UAAU,QAAQ,CAAC,IAAY;IACnC,OAAO,cAAc,CAAC,IAAI,CAAC,CAAA;AAC7B,CAAC","sourcesContent":["/**\n * 전선으로 오는 문 상태를 **이 화면의 낱말로** 옮긴다 — 경계 한 곳에서.\n *\n * ═══════════════════════════════════════════════════════════════════════════\n * ── 왜 옮겨야 하나 ────────────────────────────────────────────────────────\n * `type-graphql` 의 `registerEnumType` 은 **멤버 이름**을 전선에 싣는다. 값이 아니다.\n *\n * ```ts\n * export enum DoorStandingValue {\n * Off = 'off' // ← 전선으로 가는 것은 'Off' 다\n * }\n * ```\n *\n * 판단부(`work-door.ts`)의 낱말은 `off` 이고, i18n 키도 CSS 클래스도 그 낱말로 적혀 있다. 그래서\n * 옮기지 않으면 **둘 다 조용히 어긋난다.**\n *\n * ```\n * [확인함] 2026-09-12 실행 중인 화면 (MIRATEK)\n * 전선 \"Off\" · \"Approval\"\n * i18n text.door-standing-Off — 없는 키라 화면에 키 글자가 그대로\n * CSS .mark.Off 안 맞음 → 상태 색이 안 걸리고 물려받은 글자색으로 그려짐\n * ```\n *\n * 상태 색이 한 번도 안 나왔고, 열두 줄에 한국어 대신 키가 적혀 있었다. 서버도 시험도 전부 초록이다 —\n * **클라이언트만 조용히 틀리는** 부류다.\n *\n * ── 왜 서버 쪽 철자를 안 고치나 ───────────────────────────────────────────\n * `not-used` 는 enum 멤버 이름이 될 수 없다(붙임표). 그래서 어떤 철자를 골라도 한쪽은 옮겨야 하고,\n * 옮기는 자리를 **하나**로 두는 것이 답이다. 화면이 받는 자리가 그 하나다.\n *\n * ── 모르는 값을 지어내지 않는다 ───────────────────────────────────────────\n * 새 상태가 생겼는데 여기 안 적히면 `undefined` 다. 화면은 그때 받은 글자를 그대로 보이고 색을 안\n * 칠한다 — 「모른다」가 보여야 이 표를 고칠 수 있다. `off` 로 기울이면 새 상태가 조용히 묻힌다.\n * ═══════════════════════════════════════════════════════════════════════════\n */\n\n/** 전선의 철자 → 판단부의 낱말. 키가 전선의 것이라 대문자다 — 일부러다. */\nexport const DOOR_STANDING_WORD: Record<string, string> = {\n On: 'on',\n Off: 'off',\n Missing: 'missing',\n NotUsed: 'not-used'\n}\n\nexport const DOOR_KIND_WORD: Record<string, string> = {\n Approval: 'approval',\n Assignment: 'assignment'\n}\n\n/** 모르는 철자면 `undefined` — 부르는 쪽이 「모른다」를 그리게 한다. */\nexport function standingWord(wire: string): string | undefined {\n return DOOR_STANDING_WORD[wire]\n}\n\nexport function kindWord(wire: string): string | undefined {\n return DOOR_KIND_WORD[wire]\n}\n"]}
1
+ {"version":3,"file":"door-words.js","sourceRoot":"","sources":["../../../client/pages/work-door/door-words.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAkCG;AAEH,gDAAgD;AAChD,MAAM,CAAC,MAAM,kBAAkB,GAA2B;IACxD,EAAE,EAAE,IAAI;IACR,GAAG,EAAE,KAAK;IACV,OAAO,EAAE,SAAS;IAClB,OAAO,EAAE,UAAU;CACpB,CAAA;AAED,MAAM,CAAC,MAAM,cAAc,GAA2B;IACpD,QAAQ,EAAE,UAAU;IACpB,UAAU,EAAE,YAAY;CACzB,CAAA;AAED,MAAM,CAAC,MAAM,gBAAgB,GAA2B;IACtD,OAAO,EAAE,UAAU;IACnB,OAAO,EAAE,SAAS;IAClB,SAAS,EAAE,YAAY;IACvB,SAAS,EAAE,YAAY;IACvB,YAAY,EAAE,eAAe;IAC7B,UAAU,EAAE,aAAa;IACzB,UAAU,EAAE,aAAa;IACzB,aAAa,EAAE,gBAAgB;CAChC,CAAA;AAED,MAAM,CAAC,MAAM,iBAAiB,GAA2B;IACvD,GAAG,EAAE,KAAK;IACV,MAAM,EAAE,QAAQ;IAChB,aAAa,EAAE,gBAAgB;CAChC,CAAA;AAED,MAAM,CAAC,MAAM,yBAAyB,GAA2B;IAC/D,YAAY,EAAE,cAAc;IAC5B,gBAAgB,EAAE,qBAAqB;IACvC,cAAc,EAAE,kBAAkB;CACnC,CAAA;AAED,kDAAkD;AAClD,MAAM,UAAU,YAAY,CAAC,IAAY;IACvC,OAAO,kBAAkB,CAAC,IAAI,CAAC,CAAA;AACjC,CAAC;AAED,MAAM,UAAU,QAAQ,CAAC,IAAY;IACnC,OAAO,cAAc,CAAC,IAAI,CAAC,CAAA;AAC7B,CAAC;AAED,MAAM,UAAU,UAAU,CAAC,IAAY;IACrC,OAAO,gBAAgB,CAAC,IAAI,CAAC,CAAA;AAC/B,CAAC;AAED,2DAA2D;AAC3D,MAAM,UAAU,cAAc,CAAC,IAAoB;IACjD,OAAO,IAAI,CAAC,CAAC,CAAC,iBAAiB,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,SAAS,CAAA;AACnD,CAAC;AAED,MAAM,UAAU,qBAAqB,CAAC,IAAoB;IACxD,OAAO,IAAI,CAAC,CAAC,CAAC,yBAAyB,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,SAAS,CAAA;AAC3D,CAAC","sourcesContent":["/**\n * 전선으로 오는 문 상태를 **이 화면의 낱말로** 옮긴다 — 경계 한 곳에서.\n *\n * ═══════════════════════════════════════════════════════════════════════════\n * ── 왜 옮겨야 하나 ────────────────────────────────────────────────────────\n * `type-graphql` 의 `registerEnumType` 은 **멤버 이름**을 전선에 싣는다. 값이 아니다.\n *\n * ```ts\n * export enum DoorStandingValue {\n * Off = 'off' // ← 전선으로 가는 것은 'Off' 다\n * }\n * ```\n *\n * 판단부(`work-door.ts`)의 낱말은 `off` 이고, i18n 키도 CSS 클래스도 그 낱말로 적혀 있다. 그래서\n * 옮기지 않으면 **둘 다 조용히 어긋난다.**\n *\n * ```\n * [확인함] 2026-09-12 실행 중인 화면 (MIRATEK)\n * 전선 \"Off\" · \"Approval\"\n * i18n text.door-standing-Off — 없는 키라 화면에 키 글자가 그대로\n * CSS .mark.Off 안 맞음 → 상태 색이 안 걸리고 물려받은 글자색으로 그려짐\n * ```\n *\n * 상태 색이 한 번도 안 나왔고, 열두 줄에 한국어 대신 키가 적혀 있었다. 서버도 시험도 전부 초록이다 —\n * **클라이언트만 조용히 틀리는** 부류다.\n *\n * ── 왜 서버 쪽 철자를 안 고치나 ───────────────────────────────────────────\n * `not-used` 는 enum 멤버 이름이 될 수 없다(붙임표). 그래서 어떤 철자를 골라도 한쪽은 옮겨야 하고,\n * 옮기는 자리를 **하나**로 두는 것이 답이다. 화면이 받는 자리가 그 하나다.\n *\n * ── 모르는 값을 지어내지 않는다 ───────────────────────────────────────────\n * 새 상태가 생겼는데 여기 안 적히면 `undefined` 다. 화면은 그때 받은 글자를 그대로 보이고 색을 안\n * 칠한다 — 「모른다」가 보여야 이 표를 고칠 수 있다. `off` 로 기울이면 새 상태가 조용히 묻힌다.\n * ═══════════════════════════════════════════════════════════════════════════\n */\n\n/** 전선의 철자 → 판단부의 낱말. 키가 전선의 것이라 대문자다 — 일부러다. */\nexport const DOOR_STANDING_WORD: Record<string, string> = {\n On: 'on',\n Off: 'off',\n Missing: 'missing',\n NotUsed: 'not-used'\n}\n\nexport const DOOR_KIND_WORD: Record<string, string> = {\n Approval: 'approval',\n Assignment: 'assignment'\n}\n\nexport const DOOR_REASON_WORD: Record<string, string> = {\n NotUsed: 'not-used',\n Missing: 'missing',\n LineEmpty: 'line-empty',\n RoleEmpty: 'role-empty',\n PersonAbsent: 'person-absent',\n NoAssignee: 'no-assignee',\n LineFilled: 'line-filled',\n AssigneeBound: 'assignee-bound'\n}\n\nexport const WHEN_NO_LINE_WORD: Record<string, string> = {\n Run: 'run',\n Refuse: 'refuse',\n AsEstablished: 'as-established'\n}\n\nexport const WHEN_NO_LINE_BECAUSE_WORD: Record<string, string> = {\n Irreversible: 'irreversible',\n ApprovalIsTheAct: 'approval-is-the-act',\n LowersAControl: 'lowers-a-control'\n}\n\n/** 모르는 철자면 `undefined` — 부르는 쪽이 「모른다」를 그리게 한다. */\nexport function standingWord(wire: string): string | undefined {\n return DOOR_STANDING_WORD[wire]\n}\n\nexport function kindWord(wire: string): string | undefined {\n return DOOR_KIND_WORD[wire]\n}\n\nexport function reasonWord(wire: string): string | undefined {\n return DOOR_REASON_WORD[wire]\n}\n\n/** 비어 있으면(배정 문) 비어 있는 채로 — 선언이 없는 것을 `run` 으로 기울이지 않는다. */\nexport function whenNoLineWord(wire?: string | null): string | undefined {\n return wire ? WHEN_NO_LINE_WORD[wire] : undefined\n}\n\nexport function whenNoLineBecauseWord(wire?: string | null): string | undefined {\n return wire ? WHEN_NO_LINE_BECAUSE_WORD[wire] : undefined\n}\n"]}
@@ -4,7 +4,7 @@ declare const WorkDoorsPage_base: (new (...args: any[]) => import("lit").LitElem
4
4
  export declare class WorkDoorsPage extends WorkDoorsPage_base {
5
5
  static styles: import("lit").CSSResult[];
6
6
  private doors?;
7
- private summary;
7
+ private counts;
8
8
  private todo;
9
9
  private seatsStanding;
10
10
  private seatsOffered;