@things-factory/worklist 10.1.5 → 10.1.7

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 (130) hide show
  1. package/dist-client/components/activity-approval-ribon.js +17 -2
  2. package/dist-client/components/activity-approval-ribon.js.map +1 -1
  3. package/dist-client/components/activity-instance-preview.js +5 -4
  4. package/dist-client/components/activity-instance-preview.js.map +1 -1
  5. package/dist-client/components/activity-starter-form.js +14 -10
  6. package/dist-client/components/activity-starter-form.js.map +1 -1
  7. package/dist-client/components/activity-thread-timeline.d.ts +2 -2
  8. package/dist-client/components/decision-slots.d.ts +118 -0
  9. package/dist-client/components/decision-slots.js +125 -0
  10. package/dist-client/components/decision-slots.js.map +1 -0
  11. package/dist-client/components/mutation-outcome.d.ts +57 -0
  12. package/dist-client/components/mutation-outcome.js +78 -0
  13. package/dist-client/components/mutation-outcome.js.map +1 -0
  14. package/dist-client/components/say-outcome.d.ts +25 -0
  15. package/dist-client/components/say-outcome.js +51 -0
  16. package/dist-client/components/say-outcome.js.map +1 -0
  17. package/dist-client/pages/activity/activity-list-page.js +28 -12
  18. package/dist-client/pages/activity/activity-list-page.js.map +1 -1
  19. package/dist-client/pages/activity/activity-model-item-list.js +4 -3
  20. package/dist-client/pages/activity/activity-model-item-list.js.map +1 -1
  21. package/dist-client/pages/activity/activity-page.d.ts +2 -2
  22. package/dist-client/pages/activity/activity-page.js +25 -21
  23. package/dist-client/pages/activity/activity-page.js.map +1 -1
  24. package/dist-client/pages/activity-approval/activity-approval-importer.js +4 -3
  25. package/dist-client/pages/activity-approval/activity-approval-importer.js.map +1 -1
  26. package/dist-client/pages/activity-approval/activity-approval-list-page.js +8 -9
  27. package/dist-client/pages/activity-approval/activity-approval-list-page.js.map +1 -1
  28. package/dist-client/pages/activity-approval/activity-approval-page.d.ts +75 -1
  29. package/dist-client/pages/activity-approval/activity-approval-page.js +487 -57
  30. package/dist-client/pages/activity-approval/activity-approval-page.js.map +1 -1
  31. package/dist-client/pages/activity-catalog/activity-catalog-page.d.ts +11 -0
  32. package/dist-client/pages/activity-catalog/activity-catalog-page.js +48 -1
  33. package/dist-client/pages/activity-catalog/activity-catalog-page.js.map +1 -1
  34. package/dist-client/pages/activity-instance/activity-instance-start-page.js +24 -18
  35. package/dist-client/pages/activity-instance/activity-instance-start-page.js.map +1 -1
  36. package/dist-client/pages/activity-instance/activity-instance-view.js +1 -0
  37. package/dist-client/pages/activity-instance/activity-instance-view.js.map +1 -1
  38. package/dist-client/pages/activity-stats/activity-stats-importer.js +4 -3
  39. package/dist-client/pages/activity-stats/activity-stats-importer.js.map +1 -1
  40. package/dist-client/pages/activity-stats/activity-stats-list-page.js +8 -9
  41. package/dist-client/pages/activity-stats/activity-stats-list-page.js.map +1 -1
  42. package/dist-client/pages/activity-template/activity-template-importer.js +4 -3
  43. package/dist-client/pages/activity-template/activity-template-importer.js.map +1 -1
  44. package/dist-client/pages/activity-template/activity-template-list-page.js +8 -9
  45. package/dist-client/pages/activity-template/activity-template-list-page.js.map +1 -1
  46. package/dist-client/pages/activity-template/activity-template-model-item-list.js +4 -3
  47. package/dist-client/pages/activity-template/activity-template-model-item-list.js.map +1 -1
  48. package/dist-client/pages/activity-thread/activity-thread-importer.js +4 -3
  49. package/dist-client/pages/activity-thread/activity-thread-importer.js.map +1 -1
  50. package/dist-client/pages/activity-thread/activity-thread-list-page.js +8 -9
  51. package/dist-client/pages/activity-thread/activity-thread-list-page.js.map +1 -1
  52. package/dist-client/pages/activity-thread/activity-thread-page.d.ts +1 -1
  53. package/dist-client/pages/activity-thread/activity-thread-page.js +22 -20
  54. package/dist-client/pages/activity-thread/activity-thread-page.js.map +1 -1
  55. package/dist-client/pages/activity-thread/activity-thread-view-page.d.ts +1 -1
  56. package/dist-client/pages/activity-thread/activity-thread-view-page.js +1 -0
  57. package/dist-client/pages/activity-thread/activity-thread-view-page.js.map +1 -1
  58. package/dist-client/pages/activity-thread/activity-thread-view.d.ts +1 -1
  59. package/dist-client/pages/installable-activity/installable-activity-list-page.d.ts +27 -0
  60. package/dist-client/pages/installable-activity/installable-activity-list-page.js +70 -11
  61. package/dist-client/pages/installable-activity/installable-activity-list-page.js.map +1 -1
  62. package/dist-client/pages/todo/draft-list-page.js +1 -0
  63. package/dist-client/pages/todo/draft-list-page.js.map +1 -1
  64. package/dist-client/route.d.ts +1 -1
  65. package/dist-client/tsconfig.tsbuildinfo +1 -1
  66. package/dist-server/controllers/activity-approval/approval-line.d.ts +32 -0
  67. package/dist-server/controllers/activity-approval/approval-line.js +35 -0
  68. package/dist-server/controllers/activity-approval/approval-line.js.map +1 -1
  69. package/dist-server/controllers/activity-approval/approve.js +17 -0
  70. package/dist-server/controllers/activity-approval/approve.js.map +1 -1
  71. package/dist-server/controllers/activity-approval/reject.js +21 -1
  72. package/dist-server/controllers/activity-approval/reject.js.map +1 -1
  73. package/dist-server/controllers/activity-installation/activity-installation-controller.js +5 -9
  74. package/dist-server/controllers/activity-installation/activity-installation-controller.js.map +1 -1
  75. package/dist-server/controllers/activity-installation/installable-to-activity.d.ts +62 -0
  76. package/dist-server/controllers/activity-installation/installable-to-activity.js +53 -0
  77. package/dist-server/controllers/activity-installation/installable-to-activity.js.map +1 -0
  78. package/dist-server/controllers/activity-installation/registry-conflict.d.ts +32 -0
  79. package/dist-server/controllers/activity-installation/registry-conflict.js +21 -0
  80. package/dist-server/controllers/activity-installation/registry-conflict.js.map +1 -0
  81. package/dist-server/controllers/activity-instance/draft.js +3 -0
  82. package/dist-server/controllers/activity-instance/draft.js.map +1 -1
  83. package/dist-server/controllers/activity-instance/entitlement.d.ts +25 -0
  84. package/dist-server/controllers/activity-instance/entitlement.js +108 -0
  85. package/dist-server/controllers/activity-instance/entitlement.js.map +1 -0
  86. package/dist-server/controllers/activity-instance/issue.js +10 -0
  87. package/dist-server/controllers/activity-instance/issue.js.map +1 -1
  88. package/dist-server/controllers/activity-instance/pick.js +8 -0
  89. package/dist-server/controllers/activity-instance/pick.js.map +1 -1
  90. package/dist-server/service/activity/activity-decision-key-item-type.d.ts +160 -0
  91. package/dist-server/service/activity/activity-decision-key-item-type.js +176 -0
  92. package/dist-server/service/activity/activity-decision-key-item-type.js.map +1 -0
  93. package/dist-server/service/activity/activity-type.d.ts +3 -0
  94. package/dist-server/service/activity/activity-type.js +8 -0
  95. package/dist-server/service/activity/activity-type.js.map +1 -1
  96. package/dist-server/service/activity/activity.d.ts +30 -0
  97. package/dist-server/service/activity/activity.js +14 -0
  98. package/dist-server/service/activity/activity.js.map +1 -1
  99. package/dist-server/service/activity/decision-key-declaration.d.ts +33 -0
  100. package/dist-server/service/activity/decision-key-declaration.js +67 -0
  101. package/dist-server/service/activity/decision-key-declaration.js.map +1 -0
  102. package/dist-server/service/activity/{credential-guard-subscriber.d.ts → declaration-guard-subscriber.d.ts} +6 -1
  103. package/dist-server/service/activity/declaration-guard-subscriber.js +46 -0
  104. package/dist-server/service/activity/declaration-guard-subscriber.js.map +1 -0
  105. package/dist-server/service/activity/index.d.ts +2 -2
  106. package/dist-server/service/activity/index.js +2 -2
  107. package/dist-server/service/activity/index.js.map +1 -1
  108. package/dist-server/service/activity/search-key-declaration.d.ts +38 -0
  109. package/dist-server/service/activity/search-key-declaration.js +49 -0
  110. package/dist-server/service/activity/search-key-declaration.js.map +1 -0
  111. package/dist-server/service/activity-instance/activity-instance-mutation.js +20 -9
  112. package/dist-server/service/activity-instance/activity-instance-mutation.js.map +1 -1
  113. package/dist-server/service/activity-instance/activity-instance-query.js +25 -2
  114. package/dist-server/service/activity-instance/activity-instance-query.js.map +1 -1
  115. package/dist-server/service/activity-instance/activity-instance-type.js.map +1 -1
  116. package/dist-server/service/index.d.ts +2 -2
  117. package/dist-server/service/installable-activity/installable-activity-mutation.js +24 -0
  118. package/dist-server/service/installable-activity/installable-activity-mutation.js.map +1 -1
  119. package/dist-server/service/installable-activity/installable-activity.d.ts +9 -0
  120. package/dist-server/service/installable-activity/installable-activity.js +5 -0
  121. package/dist-server/service/installable-activity/installable-activity.js.map +1 -1
  122. package/dist-server/tsconfig.tsbuildinfo +1 -1
  123. package/package.json +11 -11
  124. package/translations/en.json +33 -6
  125. package/translations/ja.json +27 -0
  126. package/translations/ko.json +33 -6
  127. package/translations/ms.json +27 -0
  128. package/translations/zh.json +27 -0
  129. package/dist-server/service/activity/credential-guard-subscriber.js +0 -35
  130. package/dist-server/service/activity/credential-guard-subscriber.js.map +0 -1
@@ -12,7 +12,22 @@ let ActivityApprovalRibon = class ActivityApprovalRibon extends localize(i18next
12
12
  render() {
13
13
  const { activityInstance, state } = this.activityApproval?.activityThread || {};
14
14
  const { description, assignee, approvalLine, activity } = activityInstance || {};
15
- const { startingType } = activity || {};
15
+ const { startingType, label } = activity || {};
16
+ /*
17
+ * What kind of decision this is — the activity's own name, not this instance's.
18
+ *
19
+ * Those are different facts and both belong here: 「부적합 처분 승인」 says what kind, and the
20
+ * headline the activity declares says what this one asks for. The activity's name reached only
21
+ * the catalog until it became a column on the row, so this screen showed the instance
22
+ * description alone.
23
+ *
24
+ * ── The fallback puts English on a Korean screen ──────────────────────
25
+ * Activity.description is what a developer wrote for other developers ("The disposition waiting
26
+ * for approval"), so an activity with no label shows that to the person approving. That is worse
27
+ * than the instance description and it is the reason to fill label in — it is not a fallback
28
+ * anybody should be content with.
29
+ */
30
+ const kind = label || description || '';
16
31
  return html `
17
32
  <span class="state">
18
33
  <i class="dot"></i>
@@ -34,7 +49,7 @@ let ActivityApprovalRibon = class ActivityApprovalRibon extends localize(i18next
34
49
  >info</md-icon
35
50
  >
36
51
 
37
- <span class="desc" title=${description || ''}>${description || ''}</span>
52
+ <span class="desc" title=${kind}>${kind}</span>
38
53
 
39
54
 
40
55
  ${startingType == 'issue' && assignee
@@ -1 +1 @@
1
- {"version":3,"file":"activity-approval-ribon.js","sourceRoot":"","sources":["../../client/components/activity-approval-ribon.ts"],"names":[],"mappings":";AAAA,OAAO,wDAAwD,CAAA;AAC/D,OAAO,2EAA2E,CAAA;AAClF,OAAO,oDAAoD,CAAA;AAE3D,OAAO,EAAE,IAAI,EAAE,UAAU,EAAE,MAAM,KAAK,CAAA;AACtC,OAAO,EAAE,aAAa,EAAE,QAAQ,EAAE,MAAM,mBAAmB,CAAA;AAE3D,OAAO,EAAE,OAAO,EAAE,QAAQ,EAAE,MAAM,eAAe,CAAA;AACjD,OAAO,EAAE,SAAS,EAAE,MAAM,iBAAiB,CAAA;AAE3C,OAAO,EAAE,gBAAgB,EAAE,MAAM,kBAAkB,CAAA;AAG5C,IAAM,qBAAqB,GAA3B,MAAM,qBAAsB,SAAQ,QAAQ,CAAC,OAAO,CAAC,CAAC,UAAU,CAAC;aAC/D,WAAM,GAAG,CAAC,gBAAgB,CAAC,AAArB,CAAqB;IAIlC,MAAM;QACJ,MAAM,EAAE,gBAAgB,EAAE,KAAK,EAAE,GAAG,IAAI,CAAC,gBAAgB,EAAE,cAAc,IAAI,EAAE,CAAA;QAC/E,MAAM,EAAE,WAAW,EAAE,QAAQ,EAAE,YAAY,EAAE,QAAQ,EAAE,GAAG,gBAAgB,IAAI,EAAE,CAAA;QAChF,MAAM,EAAE,YAAY,EAAE,GAAG,QAAQ,IAAI,EAAE,CAAA;QAEvC,OAAO,IAAI,CAAA;;;UAGL,OAAO,CAAC,CAAC,CAAC,uBAAuB,GAAG,KAAK,CAAC;;;;;;;gBAOpC,MAAM,CAAC,OAAO,CAAC,CAAC,CAAC,qBAAqB,CAAC,CAAC;iBACvC,GAAG,EAAE,CAAC,IAAI,CAAC,QAAQ,CAAC,KAAK,CAAC;mBACxB,CAAC,CAAgB,EAAE,EAAE;YAC9B,IAAI,CAAC,CAAC,GAAG,KAAK,OAAO,IAAI,CAAC,CAAC,GAAG,KAAK,GAAG,EAAE,CAAC;gBACvC,CAAC,CAAC,cAAc,EAAE,CAAA;gBAClB,IAAI,CAAC,QAAQ,CAAC,KAAK,CAAC,CAAA;YACtB,CAAC;QACH,CAAC;;;;iCAIwB,WAAW,IAAI,EAAE,IAAI,WAAW,IAAI,EAAE;;;QAG/D,YAAY,IAAI,OAAO,IAAI,QAAQ;YACnC,CAAC,CAAC,IAAI,CAAA,6CAA6C,OAAO,CAAC,CAAC,CAAC,gBAAgB,CAAC,UAAU,QAAQ,EAAE,IAAI,SAAS;YAC/G,CAAC,CAAC,EAAE;QACJ,YAAY;YACZ,CAAC,CAAC,IAAI,CAAA;qBACO,YAAY;uBACV,IAAI,CAAC,gBAAgB,CAAC,KAAK;kCAChB;YAC1B,CAAC,CAAC,EAAE;KACP,CAAA;IACH,CAAC;IAED;;;;;;;;;;;;;;;;;OAiBG;IACK,QAAQ,CAAC,KAAa;QAC5B,SAAS,CACP,IAAI,CAAA,yDAAyD,IAAI,CAAC,gBAAgB,UAAU,KAAK,wCAAwC,EACzI,EAAE,KAAK,EAAE,OAAO,CAAC,CAAC,CAAC,qBAAqB,CAAC,EAAE,CAC5C,CAAA;IACH,CAAC;IAED,OAAO,CAAC,OAAO;QACb,IAAI,OAAO,CAAC,GAAG,CAAC,kBAAkB,CAAC,IAAI,IAAI,CAAC,gBAAgB,EAAE,CAAC;YAC7D,MAAM,EAAE,KAAK,EAAE,GAAG,IAAI,CAAC,gBAAgB,CAAC,cAAc,CAAA;YAEtD,IAAI,CAAC,YAAY,CAAC,OAAO,EAAE,KAAK,CAAC,CAAA;QACnC,CAAC;IACH,CAAC;;AA1E2B;IAA3B,QAAQ,CAAC,EAAE,IAAI,EAAE,MAAM,EAAE,CAAC;;+DAAsB;AAHtC,qBAAqB;IADjC,aAAa,CAAC,yBAAyB,CAAC;GAC5B,qBAAqB,CA8EjC","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 } = activity || {}\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=${description || ''}>${description || ''}</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"]}
1
+ {"version":3,"file":"activity-approval-ribon.js","sourceRoot":"","sources":["../../client/components/activity-approval-ribon.ts"],"names":[],"mappings":";AAAA,OAAO,wDAAwD,CAAA;AAC/D,OAAO,2EAA2E,CAAA;AAClF,OAAO,oDAAoD,CAAA;AAE3D,OAAO,EAAE,IAAI,EAAE,UAAU,EAAE,MAAM,KAAK,CAAA;AACtC,OAAO,EAAE,aAAa,EAAE,QAAQ,EAAE,MAAM,mBAAmB,CAAA;AAE3D,OAAO,EAAE,OAAO,EAAE,QAAQ,EAAE,MAAM,eAAe,CAAA;AACjD,OAAO,EAAE,SAAS,EAAE,MAAM,iBAAiB,CAAA;AAE3C,OAAO,EAAE,gBAAgB,EAAE,MAAM,kBAAkB,CAAA;AAG5C,IAAM,qBAAqB,GAA3B,MAAM,qBAAsB,SAAQ,QAAQ,CAAC,OAAO,CAAC,CAAC,UAAU,CAAC;aAC/D,WAAM,GAAG,CAAC,gBAAgB,CAAC,AAArB,CAAqB;IAIlC,MAAM;QACJ,MAAM,EAAE,gBAAgB,EAAE,KAAK,EAAE,GAAG,IAAI,CAAC,gBAAgB,EAAE,cAAc,IAAI,EAAE,CAAA;QAC/E,MAAM,EAAE,WAAW,EAAE,QAAQ,EAAE,YAAY,EAAE,QAAQ,EAAE,GAAG,gBAAgB,IAAI,EAAE,CAAA;QAChF,MAAM,EAAE,YAAY,EAAE,KAAK,EAAE,GAAG,QAAQ,IAAI,EAAE,CAAA;QAE9C;;;;;;;;;;;;;WAaG;QACH,MAAM,IAAI,GAAG,KAAK,IAAI,WAAW,IAAI,EAAE,CAAA;QAEvC,OAAO,IAAI,CAAA;;;UAGL,OAAO,CAAC,CAAC,CAAC,uBAAuB,GAAG,KAAK,CAAC;;;;;;;gBAOpC,MAAM,CAAC,OAAO,CAAC,CAAC,CAAC,qBAAqB,CAAC,CAAC;iBACvC,GAAG,EAAE,CAAC,IAAI,CAAC,QAAQ,CAAC,KAAK,CAAC;mBACxB,CAAC,CAAgB,EAAE,EAAE;YAC9B,IAAI,CAAC,CAAC,GAAG,KAAK,OAAO,IAAI,CAAC,CAAC,GAAG,KAAK,GAAG,EAAE,CAAC;gBACvC,CAAC,CAAC,cAAc,EAAE,CAAA;gBAClB,IAAI,CAAC,QAAQ,CAAC,KAAK,CAAC,CAAA;YACtB,CAAC;QACH,CAAC;;;;iCAIwB,IAAI,IAAI,IAAI;;;QAGrC,YAAY,IAAI,OAAO,IAAI,QAAQ;YACnC,CAAC,CAAC,IAAI,CAAA,6CAA6C,OAAO,CAAC,CAAC,CAAC,gBAAgB,CAAC,UAAU,QAAQ,EAAE,IAAI,SAAS;YAC/G,CAAC,CAAC,EAAE;QACJ,YAAY;YACZ,CAAC,CAAC,IAAI,CAAA;qBACO,YAAY;uBACV,IAAI,CAAC,gBAAgB,CAAC,KAAK;kCAChB;YAC1B,CAAC,CAAC,EAAE;KACP,CAAA;IACH,CAAC;IAED;;;;;;;;;;;;;;;;;OAiBG;IACK,QAAQ,CAAC,KAAa;QAC5B,SAAS,CACP,IAAI,CAAA,yDAAyD,IAAI,CAAC,gBAAgB,UAAU,KAAK,wCAAwC,EACzI,EAAE,KAAK,EAAE,OAAO,CAAC,CAAC,CAAC,qBAAqB,CAAC,EAAE,CAC5C,CAAA;IACH,CAAC;IAED,OAAO,CAAC,OAAO;QACb,IAAI,OAAO,CAAC,GAAG,CAAC,kBAAkB,CAAC,IAAI,IAAI,CAAC,gBAAgB,EAAE,CAAC;YAC7D,MAAM,EAAE,KAAK,EAAE,GAAG,IAAI,CAAC,gBAAgB,CAAC,cAAc,CAAA;YAEtD,IAAI,CAAC,YAAY,CAAC,OAAO,EAAE,KAAK,CAAC,CAAA;QACnC,CAAC;IACH,CAAC;;AA1F2B;IAA3B,QAAQ,CAAC,EAAE,IAAI,EAAE,MAAM,EAAE,CAAC;;+DAAsB;AAHtC,qBAAqB;IADjC,aAAa,CAAC,yBAAyB,CAAC;GAC5B,qBAAqB,CA8FjC","sourcesContent":["import '@operato/property-editor/ox-properties-dynamic-view.js'\nimport '@things-factory/organization/dist-client/component/approval-line-brief.js'\nimport '../templates/activity-approval-context-template.js'\n\nimport { html, LitElement } from 'lit'\nimport { customElement, property } from 'lit/decorators.js'\n\nimport { i18next, localize } from '@operato/i18n'\nimport { openPopup } from '@operato/layout'\n\nimport { StateRibonStyles } from './state-ribon.js'\n\n@customElement('activity-approval-ribon')\nexport class ActivityApprovalRibon extends localize(i18next)(LitElement) {\n static styles = [StateRibonStyles]\n\n @property({ type: Object }) activityApproval: any\n\n render() {\n const { activityInstance, state } = this.activityApproval?.activityThread || {}\n const { description, assignee, approvalLine, activity } = activityInstance || {}\n const { startingType, label } = activity || {}\n\n /*\n * What kind of decision this is — the activity's own name, not this instance's.\n *\n * Those are different facts and both belong here: 「부적합 처분 승인」 says what kind, and the\n * headline the activity declares says what this one asks for. The activity's name reached only\n * the catalog until it became a column on the row, so this screen showed the instance\n * description alone.\n *\n * ── The fallback puts English on a Korean screen ──────────────────────\n * Activity.description is what a developer wrote for other developers (\"The disposition waiting\n * for approval\"), so an activity with no label shows that to the person approving. That is worse\n * than the instance description and it is the reason to fill label in — it is not a fallback\n * anybody should be content with.\n */\n const kind = label || description || ''\n\n return html`\n <span class=\"state\">\n <i class=\"dot\"></i>\n ${i18next.t('label.activity-state-' + state)}\n </span>\n\n <md-icon\n class=\"info\"\n role=\"button\"\n tabindex=\"0\"\n title=${String(i18next.t('label.approval-info'))}\n @click=${() => this.openInfo(state)}\n @keydown=${(e: KeyboardEvent) => {\n if (e.key === 'Enter' || e.key === ' ') {\n e.preventDefault()\n this.openInfo(state)\n }\n }}\n >info</md-icon\n >\n\n <span class=\"desc\" title=${kind}>${kind}</span>\n\n\n ${startingType == 'issue' && assignee\n ? html`<span class=\"who\"><span class=\"who-label\">${i18next.t('field.assignee')}</span>${assignee?.name}</span>`\n : ''}\n ${approvalLine\n ? html`<approval-line-brief\n .model=${approvalLine}\n .current=${this.activityApproval.order}\n ></approval-line-brief>`\n : ''}\n `\n }\n\n /**\n * 이 건의 기본 정보 — **팝업으로 연다.**\n *\n * ── 왜 aside 가 아닌가 (2026-09-06) ────────────────────────────────────\n * 전에는 화면 오른쪽에서 나오는 aside 판이었다. 두 가지가 걸린다.\n *\n * 자리를 다툰다 화면 오른쪽 세로 판은 operato-twin 의 twin-entity360 이 쓰는 자리다\n * (position: fixed · right: 0 · height: 100vh). 같은 자리에 둘이 선다.\n * 전역 슬롯이다 VIEWPART_POSITION.ASIDEBAR 은 앱이 하나만 갖는다. 열 개가 넘는 패키지가\n * 그 자리를 쓰고 있어(twin 의 AI 협의 도크 · board-ui · help · more-ui …),\n * 이 판을 열면 그중 열려 있던 것이 닫힌다.\n *\n * 그리고 자리의 뜻이 다르다. 오른쪽 드로어는 **보고 있는 대상을 따라다니는 상세**이고(360 이\n * 그것이다 — 포커스가 바뀌면 내용이 바뀌고 화면을 옮겨도 남는다), 이 판은 **이 화면의 이 건**에\n * 대한 것이라 화면을 벗어나면 뜻이 없다. 페이지에 매인 것을 앱 전역 자리에 두지 않는다.\n *\n * 내용도 팝업 크기다 — 값 여덟 줄과 접힌 타임라인이라 세로 100vh 를 쓸 일이 없었다.\n */\n private openInfo(state: string) {\n openPopup(\n html`<activity-approval-context-template .activityApproval=${this.activityApproval} state=${state}></activity-approval-context-template>`,\n { title: i18next.t('label.approval-info') }\n )\n }\n\n updated(changes) {\n if (changes.has('activityApproval') && this.activityApproval) {\n const { state } = this.activityApproval.activityThread\n\n this.setAttribute('state', state)\n }\n }\n}\n"]}
@@ -6,6 +6,7 @@ import { css, html, LitElement } from 'lit';
6
6
  import { customElement, property, state } from 'lit/decorators.js';
7
7
  import { client } from '@operato/graphql';
8
8
  import { i18next, localize } from '@operato/i18n';
9
+ import { ranMutation } from './say-outcome.js';
9
10
  import { notify } from '@operato/layout';
10
11
  import { CommonHeaderStyles, ScrollbarStyles } from '@operato/styles';
11
12
  let ActivityInstancePreview = class ActivityInstancePreview extends localize(i18next)(LitElement) {
@@ -142,7 +143,7 @@ let ActivityInstancePreview = class ActivityInstancePreview extends localize(i18
142
143
  this.activityThreads = response.data.activityThreads.items;
143
144
  }
144
145
  async pickActivityInstance() {
145
- const response = await client.mutate({
146
+ const outcome = await ranMutation(() => client.mutate({
146
147
  mutation: gql `
147
148
  mutation ($id: String!) {
148
149
  pickActivityInstance(id: $id) {
@@ -153,10 +154,10 @@ let ActivityInstancePreview = class ActivityInstancePreview extends localize(i18
153
154
  variables: {
154
155
  id: this.activityInstanceId
155
156
  }
156
- });
157
- if (!response.errors) {
157
+ }));
158
+ if (outcome.ok) {
158
159
  this.picked = true;
159
- this.activityThreads = [response.data.pickActivityInstance];
160
+ this.activityThreads = [outcome.data.pickActivityInstance];
160
161
  notify({
161
162
  message: i18next.t('text.info_x_successfully', {
162
163
  x: `${i18next.t('label.activity-instance')} ${i18next.t('text.pick')}`
@@ -1 +1 @@
1
- {"version":3,"file":"activity-instance-preview.js","sourceRoot":"","sources":["../../client/components/activity-instance-preview.ts"],"names":[],"mappings":"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","sourcesContent":["import '@material/web/button/elevated-button.js'\nimport '@operato/property-editor/ox-properties-dynamic-view.js'\n\nimport gql from 'graphql-tag'\nimport { css, html, LitElement } from 'lit'\nimport { customElement, property, state } from 'lit/decorators.js'\n\nimport { client } from '@operato/graphql'\nimport { i18next, localize } from '@operato/i18n'\nimport { notify } from '@operato/layout'\nimport { CommonHeaderStyles, ScrollbarStyles } from '@operato/styles'\n\n@customElement('activity-instance-preview')\nclass ActivityInstancePreview extends localize(i18next)(LitElement) {\n static styles = [\n CommonHeaderStyles,\n ScrollbarStyles,\n css`\n :host {\n display: flex;\n flex-direction: column;\n\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 overflow: auto;\n }\n\n section {\n display: flex;\n flex-direction: column;\n }\n\n #description {\n height: 60px;\n }\n `\n ]\n\n @property({ type: String }) activityInstanceId?: string\n @property({ type: Object }) activityInstance: any = {}\n @property({ type: Array }) activityThreads: any\n\n @state() picked: boolean = false\n\n render() {\n const {\n id,\n name,\n description,\n input,\n state,\n threadsMin = 0,\n threadsMax = 0,\n activity\n } = this.activityInstance || {}\n const { model, thumbnail } = activity || {}\n\n const inputSpec = (model || [])\n .filter(item => item.inout === 'in' || item.inout === 'inout')\n .map(item => {\n return {\n ...item,\n label: item.name\n }\n })\n\n const pickable = !this.picked && this.activityThreads?.length < threadsMax\n\n return html`\n <content>\n <section>\n <h2>mission statement</h2>\n <div>title: ${name}</div>\n <div>${description}</div>\n <div>min-max: ${threadsMin} - ${threadsMax}</div>\n <img src=${thumbnail} />\n </section>\n\n <label>Input</label>\n ${!model\n ? html``\n : html`\n <ox-properties-dynamic-view\n .props=${inputSpec}\n .value=${input}\n @property-change=${e => {\n this.activityInstance.input = e.currentTarget.value\n console.log('activity-instance', this.activityInstance.input)\n }}\n ></ox-properties-dynamic-view>\n `}\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 ${pickable\n ? html`<button @click=${this.pickActivityInstance.bind(this)} done>\n <md-icon>done</md-icon>${i18next.t('button.pick')}\n </button>`\n : html``}\n </div>\n `\n }\n\n updated(changes) {\n if (changes.has('activityInstanceId')) {\n this.fetchAll(this.activityInstanceId)\n }\n }\n\n async fetchAll(id) {\n const response = await client.query({\n query: gql`\n {\n activityInstance(id: \"${id}\") {\n id\n name\n description\n input\n state\n threadsMin\n threadsMax\n activity {\n id\n name\n description\n state\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 activityThreads(filters: [{ name: \"activityInstanceId\", operator: \"eq\", value: \"${id}\"}]) {\n items {\n id\n }\n total\n }\n }\n `\n })\n\n this.activityInstance = response.data.activityInstance\n this.activityThreads = response.data.activityThreads.items\n }\n\n async pickActivityInstance() {\n const response = await client.mutate({\n mutation: gql`\n mutation ($id: String!) {\n pickActivityInstance(id: $id) {\n id\n }\n }\n `,\n variables: {\n id: this.activityInstanceId\n }\n })\n\n if (!response.errors) {\n this.picked = true\n this.activityThreads = [response.data.pickActivityInstance]\n notify({\n message: i18next.t('text.info_x_successfully', {\n x: `${i18next.t('label.activity-instance')} ${i18next.t('text.pick')}`\n })\n })\n }\n }\n}\n"]}
1
+ {"version":3,"file":"activity-instance-preview.js","sourceRoot":"","sources":["../../client/components/activity-instance-preview.ts"],"names":[],"mappings":"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","sourcesContent":["import '@material/web/button/elevated-button.js'\nimport '@operato/property-editor/ox-properties-dynamic-view.js'\n\nimport gql from 'graphql-tag'\nimport { css, html, LitElement } from 'lit'\nimport { customElement, property, state } from 'lit/decorators.js'\n\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-instance-preview')\nclass ActivityInstancePreview extends localize(i18next)(LitElement) {\n static styles = [\n CommonHeaderStyles,\n ScrollbarStyles,\n css`\n :host {\n display: flex;\n flex-direction: column;\n\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 overflow: auto;\n }\n\n section {\n display: flex;\n flex-direction: column;\n }\n\n #description {\n height: 60px;\n }\n `\n ]\n\n @property({ type: String }) activityInstanceId?: string\n @property({ type: Object }) activityInstance: any = {}\n @property({ type: Array }) activityThreads: any\n\n @state() picked: boolean = false\n\n render() {\n const {\n id,\n name,\n description,\n input,\n state,\n threadsMin = 0,\n threadsMax = 0,\n activity\n } = this.activityInstance || {}\n const { model, thumbnail } = activity || {}\n\n const inputSpec = (model || [])\n .filter(item => item.inout === 'in' || item.inout === 'inout')\n .map(item => {\n return {\n ...item,\n label: item.name\n }\n })\n\n const pickable = !this.picked && this.activityThreads?.length < threadsMax\n\n return html`\n <content>\n <section>\n <h2>mission statement</h2>\n <div>title: ${name}</div>\n <div>${description}</div>\n <div>min-max: ${threadsMin} - ${threadsMax}</div>\n <img src=${thumbnail} />\n </section>\n\n <label>Input</label>\n ${!model\n ? html``\n : html`\n <ox-properties-dynamic-view\n .props=${inputSpec}\n .value=${input}\n @property-change=${e => {\n this.activityInstance.input = e.currentTarget.value\n console.log('activity-instance', this.activityInstance.input)\n }}\n ></ox-properties-dynamic-view>\n `}\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 ${pickable\n ? html`<button @click=${this.pickActivityInstance.bind(this)} done>\n <md-icon>done</md-icon>${i18next.t('button.pick')}\n </button>`\n : html``}\n </div>\n `\n }\n\n updated(changes) {\n if (changes.has('activityInstanceId')) {\n this.fetchAll(this.activityInstanceId)\n }\n }\n\n async fetchAll(id) {\n const response = await client.query({\n query: gql`\n {\n activityInstance(id: \"${id}\") {\n id\n name\n description\n input\n state\n threadsMin\n threadsMax\n activity {\n id\n name\n description\n state\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 activityThreads(filters: [{ name: \"activityInstanceId\", operator: \"eq\", value: \"${id}\"}]) {\n items {\n id\n }\n total\n }\n }\n `\n })\n\n this.activityInstance = response.data.activityInstance\n this.activityThreads = response.data.activityThreads.items\n }\n\n async pickActivityInstance() {\n const outcome = await ranMutation(() => client.mutate({\n mutation: gql`\n mutation ($id: String!) {\n pickActivityInstance(id: $id) {\n id\n }\n }\n `,\n variables: {\n id: this.activityInstanceId\n }\n }))\n\n if (outcome.ok) {\n this.picked = true\n this.activityThreads = [outcome.data.pickActivityInstance]\n notify({\n message: i18next.t('text.info_x_successfully', {\n x: `${i18next.t('label.activity-instance')} ${i18next.t('text.pick')}`\n })\n })\n }\n }\n}\n"]}
@@ -10,6 +10,7 @@ import { customElement, property, state } from 'lit/decorators.js';
10
10
  import { navigate } from '@operato/shell';
11
11
  import { client } from '@operato/graphql';
12
12
  import { i18next, localize } from '@operato/i18n';
13
+ import { ranMutation } from './say-outcome.js';
13
14
  import { notify } from '@operato/layout';
14
15
  import { CommonHeaderStyles, ScrollbarStyles } from '@operato/styles';
15
16
  let ActivityStarterForm = class ActivityStarterForm extends localize(i18next)(LitElement) {
@@ -139,6 +140,7 @@ let ActivityStarterForm = class ActivityStarterForm extends localize(i18next)(Li
139
140
  }
140
141
  approvalLine {
141
142
  type
143
+ participation
142
144
  value
143
145
  approver {
144
146
  id
@@ -189,7 +191,7 @@ let ActivityStarterForm = class ActivityStarterForm extends localize(i18next)(Li
189
191
  assignees,
190
192
  approvalLine
191
193
  };
192
- const response = await client.mutate({
194
+ const outcome = await ranMutation(() => client.mutate({
193
195
  mutation: gql `
194
196
  mutation ($activityInstance: ActivityInstanceDraft!) {
195
197
  draftActivityInstance(activityInstance: $activityInstance) {
@@ -211,6 +213,7 @@ let ActivityStarterForm = class ActivityStarterForm extends localize(i18next)(Li
211
213
  }
212
214
  approvalLine {
213
215
  type
216
+ participation
214
217
  value
215
218
  approver {
216
219
  id
@@ -227,16 +230,17 @@ let ActivityStarterForm = class ActivityStarterForm extends localize(i18next)(Li
227
230
  variables: {
228
231
  activityInstance
229
232
  }
230
- });
231
- if (!response.errors) {
232
- this.activityInstance = response.data.draftActivityInstance;
233
- notify({
234
- message: i18next.t('text.info_x_successfully', {
235
- x: `${i18next.t('label.activity-instance')} ${i18next.t('text.draft')}`
236
- })
237
- });
238
- this.openActivityInstanceStart(this.activityInstance);
233
+ }));
234
+ if (!outcome.ok) {
235
+ return;
239
236
  }
237
+ this.activityInstance = outcome.data.draftActivityInstance;
238
+ notify({
239
+ message: i18next.t('text.info_x_successfully', {
240
+ x: `${i18next.t('label.activity-instance')} ${i18next.t('text.draft')}`
241
+ })
242
+ });
243
+ this.openActivityInstanceStart(this.activityInstance);
240
244
  }
241
245
  openActivityInstanceStart(activityInstance) {
242
246
  navigate(`activity-instance-start/${activityInstance.id}?title=${activityInstance.name}`);
@@ -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 { 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 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 response = await 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 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 (!response.errors) {\n this.activityInstance = response.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\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\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"]}
@@ -17,12 +17,12 @@ export declare class ActivityThreadTimeline extends LitElement {
17
17
  * 보일 항목 없음 화면이 「타임라인의 상신 사유를 보고 판단하세요」로 여기를 가리킨다
18
18
  */
19
19
  open?: boolean;
20
- render(): import("lit-html").TemplateResult<1> | typeof nothing;
20
+ render(): typeof nothing | import("lit-html").TemplateResult<1>;
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): import("lit-html").TemplateResult<1> | typeof nothing;
26
+ renderSaid(said?: string): typeof nothing | import("lit-html").TemplateResult<1>;
27
27
  renderOutput(output: any): string;
28
28
  }
@@ -0,0 +1,118 @@
1
+ /**
2
+ * Turns an activity's decisionKeys declaration plus an instance's input into the slots a decision
3
+ * screen draws.
4
+ *
5
+ * ── Nothing is imported ───────────────────────────────────────────────────
6
+ * No lit, no i18next. The rule is a mapping from a declaration and a payload to an ordered list,
7
+ * and keeping it free of imports is what lets the test runner hold it: that runner parses
8
+ * TypeScript by stripping types and reads neither decorators nor enums, so one heavy import takes
9
+ * a whole test file down with it. Labels and markup are the caller's half.
10
+ */
11
+ /** The roles that may appear more than once. Every other role names one value. */
12
+ export declare const REPEATABLE_ROLES: readonly ["consequence", "evidence"];
13
+ /** Listed in the order the screen reads them: what is asked, then past, present, future. */
14
+ export declare const DECISION_ROLES: readonly ["headline", "subject", "reversibility", "reason", "evidence", "currentState", "consequence", "policy"];
15
+ export type DecisionKeyDeclaration = {
16
+ role?: string;
17
+ inputPath?: string;
18
+ name?: string;
19
+ tKey?: string;
20
+ unit?: string;
21
+ };
22
+ export type DecisionSlot = {
23
+ role: string;
24
+ inputPath: string;
25
+ tKey?: string;
26
+ unit?: string;
27
+ /** What the path led to. Undefined both when the path leads nowhere and when the value is unset. */
28
+ value: unknown;
29
+ /**
30
+ * Whether the path led anywhere at all.
31
+ *
32
+ * A reason nobody wrote and a reason whose path is wrong look identical in `value`, and the screen
33
+ * owes different answers: the first is 「사유 없음」 in grey, the second is a declaration that does
34
+ * not match the payload and must not be drawn as if the person left it blank. Folding them into
35
+ * one value is the fallback that shifts meaning.
36
+ */
37
+ found: boolean;
38
+ };
39
+ /**
40
+ * Reads a dotted path out of the input.
41
+ *
42
+ * Dots only. An array index or a wildcard is not part of the path language — drawing a list is the
43
+ * slot's job — so 'shift.passes[0]' looks for a key spelled "passes[0]", finds nothing, and reports
44
+ * found: false. The declaration guard refuses such a path when it arrives, so this is the second
45
+ * line rather than the first.
46
+ *
47
+ * A path that runs into a non-object partway reports found: false rather than throwing. The screen
48
+ * has to draw something either way, and a thrown error here would take the whole approval down over
49
+ * one slot.
50
+ */
51
+ export declare function valueAtPath(input: any, path: string): {
52
+ value: unknown;
53
+ found: boolean;
54
+ };
55
+ /**
56
+ * The slots to draw, in the order they were declared.
57
+ *
58
+ * Declaration order is the screen's hierarchy: plant wrote four of these screens by hand and all
59
+ * four put the headline first, then the subject, the reason, what changes, and why it came up. That
60
+ * agreement is what makes the order part of the contract rather than a preference, so this function
61
+ * neither sorts nor groups.
62
+ *
63
+ * Every declared key produces a slot, including one whose path leads nowhere. Dropping those would
64
+ * leave the screen unable to say that a declaration and a payload disagree, and a reader would see
65
+ * a screen that looks complete.
66
+ */
67
+ export declare function decisionSlots(decisionKeys: DecisionKeyDeclaration[] | null | undefined, input: any): DecisionSlot[];
68
+ /** The slots for one role, in declared order. Empty when the activity declared none. */
69
+ export declare function slotsOfRole(slots: DecisionSlot[], role: string): DecisionSlot[];
70
+ /**
71
+ * The single slot for a role that names one value, or undefined.
72
+ *
73
+ * Reaching for a second one would be reading a declaration the guard refuses, so this answers the
74
+ * first and does not quietly merge.
75
+ */
76
+ export declare function slotOfRole(slots: DecisionSlot[], role: string): DecisionSlot | undefined;
77
+ /**
78
+ * What the declaration says about undoing this approval.
79
+ *
80
+ * The value is an object: `reversible` is required and `caveat` is the module's own sentence about
81
+ * it. The asymmetry is the point — the boolean decides how heavily the screen draws the band, and
82
+ * a sentence alone cannot decide that.
83
+ *
84
+ * { reversible: false, caveat: '버린 자재는 돌아오지 않습니다' }
85
+ *
86
+ * ── A condition is written as false ───────────────────────────────────────
87
+ * 「되돌릴 수 있습니다 — 단, 실적이 마감되기 전까지」 is written `false` with the condition in the
88
+ * caveat. Written `true` the screen draws it lightly and the reader walks past the condition. There
89
+ * is no third value: a middle one always draws ambiguously, and the reader has to guess which side
90
+ * it is on. (2026-09-11, architect's ruling)
91
+ *
92
+ * ── Not `note` ───────────────────────────────────────────────────────────
93
+ * ops-contract already has CommandApproval.note, and that one is **the approver's own comment** —
94
+ * a person's words, in the same neighbourhood as this screen. Same word for a module's sentence
95
+ * would be read as the person's. `caveat` is used nowhere in the three repositories.
96
+ */
97
+ export type Reversibility = {
98
+ reversible: boolean;
99
+ caveat?: string;
100
+ };
101
+ /**
102
+ * What the slot says, or undefined when it does not say.
103
+ *
104
+ * Undefined covers both "the path led nowhere" and "nobody declared the role". Drawing nothing is
105
+ * right for both: telling an approver an action can be taken back when the payload never said so
106
+ * is the one mistake this line cannot make, and a truthy read would make it — the string
107
+ * '되돌릴 수 없습니다…' is truthy.
108
+ */
109
+ export declare function reversibilityOf(slot?: DecisionSlot): Reversibility | undefined;
110
+ /**
111
+ * The value is there but not the shape this role takes.
112
+ *
113
+ * plant declared the role and put a sentence at that path, so the band drew nothing at all and the
114
+ * heaviest line on the screen was silently missing. Reporting nothing to the reader is right — the
115
+ * screen cannot tell which way it goes — but a developer should not have to find it by hand. The
116
+ * caller logs this; the rule stays free of side effects so a test can hold it.
117
+ */
118
+ export declare function reversibilityIsMalformed(slot?: DecisionSlot): boolean;
@@ -0,0 +1,125 @@
1
+ /**
2
+ * Turns an activity's decisionKeys declaration plus an instance's input into the slots a decision
3
+ * screen draws.
4
+ *
5
+ * ── Nothing is imported ───────────────────────────────────────────────────
6
+ * No lit, no i18next. The rule is a mapping from a declaration and a payload to an ordered list,
7
+ * and keeping it free of imports is what lets the test runner hold it: that runner parses
8
+ * TypeScript by stripping types and reads neither decorators nor enums, so one heavy import takes
9
+ * a whole test file down with it. Labels and markup are the caller's half.
10
+ */
11
+ /** The roles that may appear more than once. Every other role names one value. */
12
+ export const REPEATABLE_ROLES = ['consequence', 'evidence'];
13
+ /** Listed in the order the screen reads them: what is asked, then past, present, future. */
14
+ export const DECISION_ROLES = [
15
+ 'headline',
16
+ 'subject',
17
+ 'reversibility',
18
+ 'reason',
19
+ 'evidence',
20
+ 'currentState',
21
+ 'consequence',
22
+ 'policy'
23
+ ];
24
+ /**
25
+ * Reads a dotted path out of the input.
26
+ *
27
+ * Dots only. An array index or a wildcard is not part of the path language — drawing a list is the
28
+ * slot's job — so 'shift.passes[0]' looks for a key spelled "passes[0]", finds nothing, and reports
29
+ * found: false. The declaration guard refuses such a path when it arrives, so this is the second
30
+ * line rather than the first.
31
+ *
32
+ * A path that runs into a non-object partway reports found: false rather than throwing. The screen
33
+ * has to draw something either way, and a thrown error here would take the whole approval down over
34
+ * one slot.
35
+ */
36
+ export function valueAtPath(input, path) {
37
+ const steps = String(path ?? '')
38
+ .split('.')
39
+ .filter(step => step.length > 0);
40
+ if (!steps.length) {
41
+ return { value: undefined, found: false };
42
+ }
43
+ let at = input;
44
+ for (const step of steps) {
45
+ if (at === null || at === undefined || typeof at !== 'object') {
46
+ return { value: undefined, found: false };
47
+ }
48
+ if (!Object.prototype.hasOwnProperty.call(at, step)) {
49
+ return { value: undefined, found: false };
50
+ }
51
+ at = at[step];
52
+ }
53
+ return { value: at, found: true };
54
+ }
55
+ /**
56
+ * The slots to draw, in the order they were declared.
57
+ *
58
+ * Declaration order is the screen's hierarchy: plant wrote four of these screens by hand and all
59
+ * four put the headline first, then the subject, the reason, what changes, and why it came up. That
60
+ * agreement is what makes the order part of the contract rather than a preference, so this function
61
+ * neither sorts nor groups.
62
+ *
63
+ * Every declared key produces a slot, including one whose path leads nowhere. Dropping those would
64
+ * leave the screen unable to say that a declaration and a payload disagree, and a reader would see
65
+ * a screen that looks complete.
66
+ */
67
+ export function decisionSlots(decisionKeys, input) {
68
+ if (!decisionKeys?.length) {
69
+ return [];
70
+ }
71
+ return decisionKeys.map(key => {
72
+ const { value, found } = valueAtPath(input, String(key?.inputPath ?? ''));
73
+ return {
74
+ role: String(key?.role ?? ''),
75
+ inputPath: String(key?.inputPath ?? ''),
76
+ tKey: key?.tKey,
77
+ unit: key?.unit,
78
+ value,
79
+ found
80
+ };
81
+ });
82
+ }
83
+ /** The slots for one role, in declared order. Empty when the activity declared none. */
84
+ export function slotsOfRole(slots, role) {
85
+ return slots.filter(slot => slot.role === role);
86
+ }
87
+ /**
88
+ * The single slot for a role that names one value, or undefined.
89
+ *
90
+ * Reaching for a second one would be reading a declaration the guard refuses, so this answers the
91
+ * first and does not quietly merge.
92
+ */
93
+ export function slotOfRole(slots, role) {
94
+ return slots.find(slot => slot.role === role);
95
+ }
96
+ /**
97
+ * What the slot says, or undefined when it does not say.
98
+ *
99
+ * Undefined covers both "the path led nowhere" and "nobody declared the role". Drawing nothing is
100
+ * right for both: telling an approver an action can be taken back when the payload never said so
101
+ * is the one mistake this line cannot make, and a truthy read would make it — the string
102
+ * '되돌릴 수 없습니다…' is truthy.
103
+ */
104
+ export function reversibilityOf(slot) {
105
+ const value = slot?.value;
106
+ if (!value || typeof value !== 'object' || typeof value.reversible !== 'boolean') {
107
+ return undefined;
108
+ }
109
+ return {
110
+ reversible: value.reversible,
111
+ ...(typeof value.caveat === 'string' && value.caveat.trim() ? { caveat: value.caveat } : {})
112
+ };
113
+ }
114
+ /**
115
+ * The value is there but not the shape this role takes.
116
+ *
117
+ * plant declared the role and put a sentence at that path, so the band drew nothing at all and the
118
+ * heaviest line on the screen was silently missing. Reporting nothing to the reader is right — the
119
+ * screen cannot tell which way it goes — but a developer should not have to find it by hand. The
120
+ * caller logs this; the rule stays free of side effects so a test can hold it.
121
+ */
122
+ export function reversibilityIsMalformed(slot) {
123
+ return !!slot && slot.found && slot.value != null && reversibilityOf(slot) === undefined;
124
+ }
125
+ //# sourceMappingURL=decision-slots.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"decision-slots.js","sourceRoot":"","sources":["../../client/components/decision-slots.ts"],"names":[],"mappings":"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","sourcesContent":["/**\n * Turns an activity's decisionKeys declaration plus an instance's input into the slots a decision\n * screen draws.\n *\n * ── Nothing is imported ───────────────────────────────────────────────────\n * No lit, no i18next. The rule is a mapping from a declaration and a payload to an ordered list,\n * and keeping it free of imports is what lets the test runner hold it: that runner parses\n * TypeScript by stripping types and reads neither decorators nor enums, so one heavy import takes\n * a whole test file down with it. Labels and markup are the caller's half.\n */\n\n/** The roles that may appear more than once. Every other role names one value. */\nexport const REPEATABLE_ROLES = ['consequence', 'evidence'] as const\n\n/** Listed in the order the screen reads them: what is asked, then past, present, future. */\nexport const DECISION_ROLES = [\n 'headline',\n 'subject',\n 'reversibility',\n 'reason',\n 'evidence',\n 'currentState',\n 'consequence',\n 'policy'\n] as const\n\nexport type DecisionKeyDeclaration = {\n role?: string\n inputPath?: string\n name?: string\n tKey?: string\n unit?: string\n}\n\nexport type DecisionSlot = {\n role: string\n inputPath: string\n tKey?: string\n unit?: string\n /** What the path led to. Undefined both when the path leads nowhere and when the value is unset. */\n value: unknown\n /**\n * Whether the path led anywhere at all.\n *\n * A reason nobody wrote and a reason whose path is wrong look identical in `value`, and the screen\n * owes different answers: the first is 「사유 없음」 in grey, the second is a declaration that does\n * not match the payload and must not be drawn as if the person left it blank. Folding them into\n * one value is the fallback that shifts meaning.\n */\n found: boolean\n}\n\n/**\n * Reads a dotted path out of the input.\n *\n * Dots only. An array index or a wildcard is not part of the path language — drawing a list is the\n * slot's job — so 'shift.passes[0]' looks for a key spelled \"passes[0]\", finds nothing, and reports\n * found: false. The declaration guard refuses such a path when it arrives, so this is the second\n * line rather than the first.\n *\n * A path that runs into a non-object partway reports found: false rather than throwing. The screen\n * has to draw something either way, and a thrown error here would take the whole approval down over\n * one slot.\n */\nexport function valueAtPath(input: any, path: string): { value: unknown; found: boolean } {\n const steps = String(path ?? '')\n .split('.')\n .filter(step => step.length > 0)\n\n if (!steps.length) {\n return { value: undefined, found: false }\n }\n\n let at: any = input\n\n for (const step of steps) {\n if (at === null || at === undefined || typeof at !== 'object') {\n return { value: undefined, found: false }\n }\n\n if (!Object.prototype.hasOwnProperty.call(at, step)) {\n return { value: undefined, found: false }\n }\n\n at = at[step]\n }\n\n return { value: at, found: true }\n}\n\n/**\n * The slots to draw, in the order they were declared.\n *\n * Declaration order is the screen's hierarchy: plant wrote four of these screens by hand and all\n * four put the headline first, then the subject, the reason, what changes, and why it came up. That\n * agreement is what makes the order part of the contract rather than a preference, so this function\n * neither sorts nor groups.\n *\n * Every declared key produces a slot, including one whose path leads nowhere. Dropping those would\n * leave the screen unable to say that a declaration and a payload disagree, and a reader would see\n * a screen that looks complete.\n */\nexport function decisionSlots(\n decisionKeys: DecisionKeyDeclaration[] | null | undefined,\n input: any\n): DecisionSlot[] {\n if (!decisionKeys?.length) {\n return []\n }\n\n return decisionKeys.map(key => {\n const { value, found } = valueAtPath(input, String(key?.inputPath ?? ''))\n\n return {\n role: String(key?.role ?? ''),\n inputPath: String(key?.inputPath ?? ''),\n tKey: key?.tKey,\n unit: key?.unit,\n value,\n found\n }\n })\n}\n\n/** The slots for one role, in declared order. Empty when the activity declared none. */\nexport function slotsOfRole(slots: DecisionSlot[], role: string): DecisionSlot[] {\n return slots.filter(slot => slot.role === role)\n}\n\n/**\n * The single slot for a role that names one value, or undefined.\n *\n * Reaching for a second one would be reading a declaration the guard refuses, so this answers the\n * first and does not quietly merge.\n */\nexport function slotOfRole(slots: DecisionSlot[], role: string): DecisionSlot | undefined {\n return slots.find(slot => slot.role === role)\n}\n\n/**\n * 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"]}
@@ -0,0 +1,57 @@
1
+ /**
2
+ * What came back from a mutation, in the terms a screen has to speak.
3
+ *
4
+ * ── Two failures that arrive by different roads ───────────────────────────
5
+ * A privilege refusal is a GraphQL error. The server marks it itself
6
+ * ([읽었음] auth-base/server/service/privilege/privilege-rejection.ts:61) with
7
+ * `extensions: { code: 'FORBIDDEN', requires }`, and `mutate` is configured with
8
+ * `errorPolicy: 'all'` ([읽었음] operato/webcomponents/graphql/src/graphql-client.ts:18), so it
9
+ * **resolves** with `errors` rather than throwing.
10
+ *
11
+ * A missing or expired session never reaches GraphQL at all:
12
+ *
13
+ * [확인함] curl -X POST http://localhost:4000/graphql -d '{"query":"{ __typename }"}'
14
+ * HTTP 401 · body: No auth token
15
+ *
16
+ * That is an HTTP failure with a plain-text body, so it arrives as a thrown error, not as `errors`.
17
+ * A handler that only looks at `errors` misses it, and the throw takes the rest of the handler with
18
+ * it. Both roads are handled here so a caller does not have to remember there are two.
19
+ *
20
+ * ── Why they must not share a sentence ────────────────────────────────────
21
+ * Telling someone whose session expired to ask an administrator for a privilege sends them to the
22
+ * wrong place, and they will wait for something nobody is going to do. (2026-09-11, architect)
23
+ *
24
+ * Nothing is imported: the test runner strips types without reading decorators, and one heavy
25
+ * import takes a whole test file down — that happened three times in one day.
26
+ */
27
+ export type MutationOutcome =
28
+ /** It went through. `data` is what the mutation answered, so the caller need not keep the response. */
29
+ {
30
+ ok: true;
31
+ data: any;
32
+ }
33
+ /** The server said this user may not. `requires` is what it said is needed, when it said. */
34
+ | {
35
+ ok: false;
36
+ kind: 'forbidden';
37
+ said: string;
38
+ requires?: unknown;
39
+ }
40
+ /** No session reached the server. Signing in again is the answer, not a privilege. */
41
+ | {
42
+ ok: false;
43
+ kind: 'signed-out';
44
+ said: string;
45
+ }
46
+ /** Something else. `said` is the server's own sentence — this side does not know the cause. */
47
+ | {
48
+ ok: false;
49
+ kind: 'failed';
50
+ said: string;
51
+ };
52
+ /** Reading a resolved response. */
53
+ export declare function outcomeOf(response: any): MutationOutcome;
54
+ /** Reading a thrown error — the road a 401 takes. */
55
+ export declare function outcomeOfThrow(thrown: any): MutationOutcome;
56
+ /** The i18n key for a failure, so every screen says the same thing about the same thing. */
57
+ export declare function outcomeKey(outcome: MutationOutcome): string;