@things-factory/worklist 10.0.18 → 10.1.0

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 (215) hide show
  1. package/dist-client/activity-cells.d.ts +21 -0
  2. package/dist-client/activity-cells.js +117 -0
  3. package/dist-client/activity-cells.js.map +1 -0
  4. package/dist-client/activity-summary-generator.js +57 -11
  5. package/dist-client/activity-summary-generator.js.map +1 -1
  6. package/dist-client/approval-progress.d.ts +18 -0
  7. package/dist-client/approval-progress.js +31 -0
  8. package/dist-client/approval-progress.js.map +1 -0
  9. package/dist-client/bootstrap.js +6 -11
  10. package/dist-client/bootstrap.js.map +1 -1
  11. package/dist-client/chip-filters.d.ts +53 -0
  12. package/dist-client/chip-filters.js +60 -0
  13. package/dist-client/chip-filters.js.map +1 -0
  14. package/dist-client/components/activity-approval-ribon.d.ts +19 -0
  15. package/dist-client/components/activity-approval-ribon.js +50 -126
  16. package/dist-client/components/activity-approval-ribon.js.map +1 -1
  17. package/dist-client/components/activity-fields.d.ts +50 -0
  18. package/dist-client/components/activity-fields.js +393 -0
  19. package/dist-client/components/activity-fields.js.map +1 -0
  20. package/dist-client/components/activity-instance-ribon.d.ts +19 -0
  21. package/dist-client/components/activity-instance-ribon.js +55 -122
  22. package/dist-client/components/activity-instance-ribon.js.map +1 -1
  23. package/dist-client/components/activity-thread-ribon.d.ts +25 -0
  24. package/dist-client/components/activity-thread-ribon.js +64 -121
  25. package/dist-client/components/activity-thread-ribon.js.map +1 -1
  26. package/dist-client/components/activity-thread-timeline.d.ts +14 -2
  27. package/dist-client/components/activity-thread-timeline.js +234 -104
  28. package/dist-client/components/activity-thread-timeline.js.map +1 -1
  29. package/dist-client/components/state-ribon.d.ts +40 -0
  30. package/dist-client/components/state-ribon.js +200 -0
  31. package/dist-client/components/state-ribon.js.map +1 -0
  32. package/dist-client/due.d.ts +16 -0
  33. package/dist-client/due.js +78 -0
  34. package/dist-client/due.js.map +1 -0
  35. package/dist-client/pages/activity/activity-list-page.js +4 -6
  36. package/dist-client/pages/activity/activity-list-page.js.map +1 -1
  37. package/dist-client/pages/activity-approval/activity-approval-list-page.js +2 -1
  38. package/dist-client/pages/activity-approval/activity-approval-list-page.js.map +1 -1
  39. package/dist-client/pages/activity-approval/activity-approval-page.d.ts +52 -5
  40. package/dist-client/pages/activity-approval/activity-approval-page.js +265 -118
  41. package/dist-client/pages/activity-approval/activity-approval-page.js.map +1 -1
  42. package/dist-client/pages/activity-instance/activity-instance-list-page.d.ts +0 -1
  43. package/dist-client/pages/activity-instance/activity-instance-list-page.js +8 -24
  44. package/dist-client/pages/activity-instance/activity-instance-list-page.js.map +1 -1
  45. package/dist-client/pages/activity-instance/activity-instance-start-page.d.ts +1 -0
  46. package/dist-client/pages/activity-instance/activity-instance-start-page.js +7 -0
  47. package/dist-client/pages/activity-instance/activity-instance-start-page.js.map +1 -1
  48. package/dist-client/pages/activity-instance/activity-instance-view.js +1 -1
  49. package/dist-client/pages/activity-instance/activity-instance-view.js.map +1 -1
  50. package/dist-client/pages/activity-stats/activity-stats-list-page.js +2 -1
  51. package/dist-client/pages/activity-stats/activity-stats-list-page.js.map +1 -1
  52. package/dist-client/pages/activity-thread/activity-thread-page.d.ts +30 -4
  53. package/dist-client/pages/activity-thread/activity-thread-page.js +142 -66
  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 +17 -6
  56. package/dist-client/pages/activity-thread/activity-thread-view-page.js +118 -65
  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 +24 -7
  59. package/dist-client/pages/activity-thread/activity-thread-view.js +84 -308
  60. package/dist-client/pages/activity-thread/activity-thread-view.js.map +1 -1
  61. package/dist-client/pages/installable-activity/installable-activity-list-page.d.ts +1 -1
  62. package/dist-client/pages/installable-activity/installable-activity-list-page.js +13 -9
  63. package/dist-client/pages/installable-activity/installable-activity-list-page.js.map +1 -1
  64. package/dist-client/pages/todo/approval-done-list-page.d.ts +1 -0
  65. package/dist-client/pages/todo/approval-done-list-page.js +111 -58
  66. package/dist-client/pages/todo/approval-done-list-page.js.map +1 -1
  67. package/dist-client/pages/todo/approval-pending-list-page.d.ts +32 -1
  68. package/dist-client/pages/todo/approval-pending-list-page.js +485 -130
  69. package/dist-client/pages/todo/approval-pending-list-page.js.map +1 -1
  70. package/dist-client/pages/todo/done-list-calendar-page.d.ts +2 -0
  71. package/dist-client/pages/todo/done-list-calendar-page.js +213 -29
  72. package/dist-client/pages/todo/done-list-calendar-page.js.map +1 -1
  73. package/dist-client/pages/todo/done-list-page.d.ts +1 -0
  74. package/dist-client/pages/todo/done-list-page.js +126 -62
  75. package/dist-client/pages/todo/done-list-page.js.map +1 -1
  76. package/dist-client/pages/todo/draft-list-page.d.ts +1 -0
  77. package/dist-client/pages/todo/draft-list-page.js +82 -34
  78. package/dist-client/pages/todo/draft-list-page.js.map +1 -1
  79. package/dist-client/pages/todo/pickable-list-page.js +6 -10
  80. package/dist-client/pages/todo/pickable-list-page.js.map +1 -1
  81. package/dist-client/pages/todo/todo-list-page.d.ts +1 -1
  82. package/dist-client/pages/todo/todo-list-page.js +102 -78
  83. package/dist-client/pages/todo/todo-list-page.js.map +1 -1
  84. package/dist-client/route.d.ts +1 -1
  85. package/dist-client/route.js +0 -6
  86. package/dist-client/route.js.map +1 -1
  87. package/dist-client/templates/activity-approval-context-template.js +60 -138
  88. package/dist-client/templates/activity-approval-context-template.js.map +1 -1
  89. package/dist-client/templates/activity-instance-context-template.js +13 -172
  90. package/dist-client/templates/activity-instance-context-template.js.map +1 -1
  91. package/dist-client/templates/activity-thread-context-template.js +39 -131
  92. package/dist-client/templates/activity-thread-context-template.js.map +1 -1
  93. package/dist-client/templates/context-panel.d.ts +26 -0
  94. package/dist-client/templates/context-panel.js +182 -0
  95. package/dist-client/templates/context-panel.js.map +1 -0
  96. package/dist-client/tsconfig.tsbuildinfo +1 -1
  97. package/dist-client/when.d.ts +4 -0
  98. package/dist-client/when.js +72 -0
  99. package/dist-client/when.js.map +1 -0
  100. package/dist-server/controllers/activity-approval/_abort.js +2 -1
  101. package/dist-server/controllers/activity-approval/_abort.js.map +1 -1
  102. package/dist-server/controllers/activity-approval/approval-line.d.ts +106 -0
  103. package/dist-server/controllers/activity-approval/approval-line.js +151 -0
  104. package/dist-server/controllers/activity-approval/approval-line.js.map +1 -0
  105. package/dist-server/controllers/activity-approval/approve.js +61 -51
  106. package/dist-server/controllers/activity-approval/approve.js.map +1 -1
  107. package/dist-server/controllers/activity-approval/claim.d.ts +42 -0
  108. package/dist-server/controllers/activity-approval/claim.js +77 -0
  109. package/dist-server/controllers/activity-approval/claim.js.map +1 -0
  110. package/dist-server/controllers/activity-approval/create-approval.d.ts +41 -0
  111. package/dist-server/controllers/activity-approval/create-approval.js +78 -0
  112. package/dist-server/controllers/activity-approval/create-approval.js.map +1 -0
  113. package/dist-server/controllers/activity-approval/delegate.d.ts +16 -0
  114. package/dist-server/controllers/activity-approval/delegate.js +43 -7
  115. package/dist-server/controllers/activity-approval/delegate.js.map +1 -1
  116. package/dist-server/controllers/activity-approval/opinion.d.ts +10 -0
  117. package/dist-server/controllers/activity-approval/opinion.js +43 -0
  118. package/dist-server/controllers/activity-approval/opinion.js.map +1 -0
  119. package/dist-server/controllers/activity-approval/reject.js +21 -1
  120. package/dist-server/controllers/activity-approval/reject.js.map +1 -1
  121. package/dist-server/controllers/activity-approval/save.js +26 -2
  122. package/dist-server/controllers/activity-approval/save.js.map +1 -1
  123. package/dist-server/controllers/activity-installation/activity-installation-controller.d.ts +26 -0
  124. package/dist-server/controllers/activity-installation/activity-installation-controller.js +45 -0
  125. package/dist-server/controllers/activity-installation/activity-installation-controller.js.map +1 -1
  126. package/dist-server/controllers/activity-instance/approval-expectation.d.ts +34 -0
  127. package/dist-server/controllers/activity-instance/approval-expectation.js +18 -0
  128. package/dist-server/controllers/activity-instance/approval-expectation.js.map +1 -0
  129. package/dist-server/controllers/activity-instance/issue.js +32 -0
  130. package/dist-server/controllers/activity-instance/issue.js.map +1 -1
  131. package/dist-server/controllers/activity-thread/restart.js +17 -1
  132. package/dist-server/controllers/activity-thread/restart.js.map +1 -1
  133. package/dist-server/controllers/activity-thread/submit.js +23 -43
  134. package/dist-server/controllers/activity-thread/submit.js.map +1 -1
  135. package/dist-server/controllers/common.js +46 -0
  136. package/dist-server/controllers/common.js.map +1 -1
  137. package/dist-server/controllers/index.d.ts +1 -0
  138. package/dist-server/controllers/index.js +8 -0
  139. package/dist-server/controllers/index.js.map +1 -1
  140. package/dist-server/service/activity/activity-mutation.js +25 -5
  141. package/dist-server/service/activity/activity-mutation.js.map +1 -1
  142. package/dist-server/service/activity/activity-type.d.ts +14 -0
  143. package/dist-server/service/activity/activity-type.js +8 -0
  144. package/dist-server/service/activity/activity-type.js.map +1 -1
  145. package/dist-server/service/activity/activity.d.ts +18 -0
  146. package/dist-server/service/activity/activity.js +5 -0
  147. package/dist-server/service/activity/activity.js.map +1 -1
  148. package/dist-server/service/activity-approval/activity-approval-mutation.js +3 -2
  149. package/dist-server/service/activity-approval/activity-approval-mutation.js.map +1 -1
  150. package/dist-server/service/activity-approval/activity-approval-query.d.ts +19 -1
  151. package/dist-server/service/activity-approval/activity-approval-query.js +186 -56
  152. package/dist-server/service/activity-approval/activity-approval-query.js.map +1 -1
  153. package/dist-server/service/activity-approval/activity-approval.d.ts +29 -1
  154. package/dist-server/service/activity-approval/activity-approval.js +19 -0
  155. package/dist-server/service/activity-approval/activity-approval.js.map +1 -1
  156. package/dist-server/service/activity-approval/my-pending-approvals.d.ts +21 -0
  157. package/dist-server/service/activity-approval/my-pending-approvals.js +40 -0
  158. package/dist-server/service/activity-approval/my-pending-approvals.js.map +1 -0
  159. package/dist-server/service/activity-instance/activity-instance-type.d.ts +20 -0
  160. package/dist-server/service/activity-instance/activity-instance-type.js +11 -0
  161. package/dist-server/service/activity-instance/activity-instance-type.js.map +1 -1
  162. package/dist-server/service/activity-instance/activity-instance.d.ts +6 -0
  163. package/dist-server/service/activity-instance/activity-instance.js +5 -0
  164. package/dist-server/service/activity-instance/activity-instance.js.map +1 -1
  165. package/dist-server/service/activity-stats/activity-stats-query.d.ts +5 -0
  166. package/dist-server/service/activity-stats/activity-stats-query.js +149 -11
  167. package/dist-server/service/activity-stats/activity-stats-query.js.map +1 -1
  168. package/dist-server/service/activity-stats/activity-stats-type.d.ts +19 -6
  169. package/dist-server/service/activity-stats/activity-stats-type.js +37 -10
  170. package/dist-server/service/activity-stats/activity-stats-type.js.map +1 -1
  171. package/dist-server/service/activity-stats/event-placement.d.ts +55 -0
  172. package/dist-server/service/activity-stats/event-placement.js +82 -0
  173. package/dist-server/service/activity-stats/event-placement.js.map +1 -0
  174. package/dist-server/service/activity-thread/activity-thread-query.js +48 -24
  175. package/dist-server/service/activity-thread/activity-thread-query.js.map +1 -1
  176. package/dist-server/service/activity-thread/my-open-threads.d.ts +15 -0
  177. package/dist-server/service/activity-thread/my-open-threads.js +40 -0
  178. package/dist-server/service/activity-thread/my-open-threads.js.map +1 -0
  179. package/dist-server/service/activity-thread/todo-order.d.ts +49 -0
  180. package/dist-server/service/activity-thread/todo-order.js +70 -0
  181. package/dist-server/service/activity-thread/todo-order.js.map +1 -0
  182. package/dist-server/service/installable-activity/installable-activity-mutation.d.ts +6 -0
  183. package/dist-server/service/installable-activity/installable-activity-mutation.js +7 -24
  184. package/dist-server/service/installable-activity/installable-activity-mutation.js.map +1 -1
  185. package/dist-server/service/nulls-last.d.ts +30 -0
  186. package/dist-server/service/nulls-last.js +37 -0
  187. package/dist-server/service/nulls-last.js.map +1 -0
  188. package/dist-server/tsconfig.tsbuildinfo +1 -1
  189. package/helps/dataset/activity-instance-search-page.ko.md +5 -0
  190. package/helps/dataset/activity-instance-search-page.md +13 -0
  191. package/helps/worklist/activity-approval.ko.md +5 -0
  192. package/helps/worklist/activity-approval.md +14 -0
  193. package/helps/worklist/activity-bank-page.ko.md +5 -0
  194. package/helps/worklist/activity-bank-page.md +13 -0
  195. package/helps/worklist/activity-reporter-list.ko.md +5 -0
  196. package/helps/worklist/activity-reporter-list.md +13 -0
  197. package/helps/worklist/activity-store.ko.md +5 -0
  198. package/helps/worklist/activity-store.md +13 -0
  199. package/helps/worklist/activity-template.ko.md +5 -0
  200. package/helps/worklist/activity-template.md +13 -0
  201. package/helps/worklist/installable-activity.ko.md +5 -0
  202. package/helps/worklist/installable-activity.md +13 -0
  203. package/package.json +13 -12
  204. package/things-factory.config.js +0 -5
  205. package/translations/en.json +129 -51
  206. package/translations/ja.json +130 -52
  207. package/translations/ko.json +82 -4
  208. package/translations/ms.json +129 -51
  209. package/translations/zh.json +132 -54
  210. package/dist-client/pages/dashboard/dashboard-home.d.ts +0 -1
  211. package/dist-client/pages/dashboard/dashboard-home.js +0 -22
  212. package/dist-client/pages/dashboard/dashboard-home.js.map +0 -1
  213. package/dist-client/pages/worklist-home.d.ts +0 -1
  214. package/dist-client/pages/worklist-home.js +0 -17
  215. package/dist-client/pages/worklist-home.js.map +0 -1
@@ -2,7 +2,7 @@ import '@operato/property-editor/ox-properties-dynamic-view.js';
2
2
  import '@operato/board/ox-board-viewer.js';
3
3
  import '../../components/activity-approval-ribon.js';
4
4
  import '../../components/activity-thread-timeline.js';
5
- import { TemplateResult } from 'lit';
5
+ import { nothing, TemplateResult } from 'lit';
6
6
  import { DirectiveResult } from 'lit-html/directive.js';
7
7
  import { PageView } from '@operato/shell';
8
8
  export declare const ActivityThreadStatus: {
@@ -17,12 +17,23 @@ declare const ActivityApprovalPage_base: (new (...args: any[]) => import("lit").
17
17
  export declare class ActivityApprovalPage extends ActivityApprovalPage_base {
18
18
  static styles: import("lit").CSSResult[];
19
19
  activityApproval: any;
20
+ /**
21
+ * 조회를 마쳤나 — **「아직 안 읽었다」와 「없다」는 다르다.**
22
+ *
23
+ * 전에는 값이 없으면 곧바로 「업무활동 정보가 없습니다」를 그렸다. 그런데 이 화면은 열리자마자
24
+ * 조회를 시작하므로, 응답이 오기 전까지 **없다고 단언하는 화면**이 보인다. 목록에서 줄을 눌러
25
+ * 들어온 사람은 방금 본 건이 없다는 말을 먼저 읽는다.
26
+ *
27
+ * 조회가 끝난 뒤에만 그 말을 한다. 그 전에는 아무 말도 하지 않는다.
28
+ */
29
+ loaded: boolean;
20
30
  activityThread: any;
21
31
  board: any;
22
32
  commentInput: HTMLTextAreaElement;
23
33
  get context(): {
24
34
  title: any;
25
35
  help: string;
36
+ menu: string;
26
37
  actions: {
27
38
  icon: string;
28
39
  emphasis: {
@@ -35,16 +46,52 @@ export declare class ActivityApprovalPage extends ActivityApprovalPage_base {
35
46
  action: () => void;
36
47
  }[];
37
48
  };
38
- render(): TemplateResult<1>;
39
- activityContent(): any;
49
+ render(): TemplateResult<1> | typeof nothing;
50
+ /** 화면에 낼 항목이 하나라도 있나. 타임라인을 펴 둘지 정하는 자리가 쓴다. */
51
+ hasFields(): boolean;
52
+ activityContent(): DirectiveResult<import("lit-html/directive.js").DirectiveClass>;
53
+ /**
54
+ * 화면 종류가 달라도 **같은 자리에 같은 모양으로 놓인다.**
55
+ *
56
+ * worklist 는 네 가지로 내용을 그린다(generated · custom-element · template · board). 그중
57
+ * generated 만 절 카드 안에 있었고 나머지 셋은 면 위에 맨몸으로 놓였다. 그래서 같은 결재 화면이
58
+ * 액티비티에 따라 카드였다가 아니었다가 했다 — 아래의 타임라인 · 의견은 늘 카드라 위계도 어긋났다.
59
+ *
60
+ * board 는 뺀다. 전체 폭 · 전체 높이를 쓰는 캔버스라 카드 안에 넣으면 여백이 두 겹이 되고 크기가
61
+ * 어긋난다.
62
+ *
63
+ * 카드는 여백을 두지 않는다(padding: 0). 안에 들어오는 것이 자기 조판을 갖고 있고, 두 겹으로
64
+ * 주면 안쪽 내용이 카드 가운데로 밀린다.
65
+ */
66
+ hostedContent(content: unknown): TemplateResult<1>;
40
67
  templateContent(): DirectiveResult<typeof import("lit-html/directives/unsafe-html.js").UnsafeHTMLDirective>;
41
- getInputSpec(): any;
42
- getOutputSpec(): any;
68
+ /**
69
+ * 결재자가 보는 내용 — **전부 읽기 전용이다.**
70
+ *
71
+ * 전에는 「Output」 절을 편집기로 그리고 변경을 activityApproval.output 에 적었다. 그런데
72
+ * approveActivityApproval / rejectActivityApproval 은 id 와 comment 만 보낸다 — 그 값은 어디에도
73
+ * 가지 않는다. 결재자가 적을 수 있는 것은 의견 하나이고, 그것은 화면 아래 칸이 받는다.
74
+ */
43
75
  generatedContent(): DirectiveResult;
44
76
  boardContent(): DirectiveResult;
45
77
  customElementContent(): any;
46
78
  oxBoardViewer: any;
47
79
  getOutputFromBoard(): any;
80
+ /**
81
+ * 화면이 열리면 **의견 칸에 캐럿을 둔다.**
82
+ *
83
+ * 결재자가 이 화면에서 적는 것은 의견 하나다. 나머지는 전부 읽는 것이고, 판단은 아래 버튼이
84
+ * 받는다. 그러면 열자마자 커서가 있어야 하는 자리는 하나뿐이다.
85
+ *
86
+ * 조건 둘을 지킨다.
87
+ *
88
+ * 활성 탭일 때만 MDI 라 뒤에 있는 탭이 응답을 받으면 앞 탭의 입력을 빼앗는다
89
+ * 한 건에 한 번 갱신마다 focus 를 부르면 사용자가 옮긴 커서를 계속 되돌린다
90
+ *
91
+ * preventScroll 을 준다 — 화면을 아래로 끌어내리면 정작 무엇을 승인하는지가 위로 사라진다.
92
+ */
93
+ private focusedFor?;
94
+ private focusComment;
48
95
  updated(changes: any): void;
49
96
  pageUpdated(changes: any, lifecycle: any, changedBefore: any): Promise<void>;
50
97
  fetchActivityApproval(id: any): Promise<void>;
@@ -13,6 +13,7 @@ import { i18next, localize } from '@operato/i18n';
13
13
  import { PageView } from '@operato/shell';
14
14
  import { CommonButtonStyles, ScrollbarStyles } from '@operato/styles';
15
15
  import { provider } from '@things-factory/board-ui/dist-client/board-provider.js';
16
+ import { ActivityFieldsStyles, inputSpecOf, outputSpecOf, renderGiven } from '../../components/activity-fields.js';
16
17
  const ActivityApprovalFetchResult = `\
17
18
  { id
18
19
  judgment
@@ -66,6 +67,7 @@ const ActivityApprovalFetchResult = `\
66
67
  options
67
68
  quantifier
68
69
  spec
70
+ hidden
69
71
  }
70
72
  }
71
73
  approvalLine { type
@@ -94,62 +96,137 @@ export const ActivityThreadStatus = { Unassigned: 'unassigned',
94
96
  Aborted: 'aborted'
95
97
  };
96
98
  let ActivityApprovalPage = class ActivityApprovalPage extends localize(i18next)(PageView) {
99
+ constructor() {
100
+ super(...arguments);
101
+ /**
102
+ * 조회를 마쳤나 — **「아직 안 읽었다」와 「없다」는 다르다.**
103
+ *
104
+ * 전에는 값이 없으면 곧바로 「업무활동 정보가 없습니다」를 그렸다. 그런데 이 화면은 열리자마자
105
+ * 조회를 시작하므로, 응답이 오기 전까지 **없다고 단언하는 화면**이 보인다. 목록에서 줄을 눌러
106
+ * 들어온 사람은 방금 본 건이 없다는 말을 먼저 읽는다.
107
+ *
108
+ * 조회가 끝난 뒤에만 그 말을 한다. 그 전에는 아무 말도 하지 않는다.
109
+ */
110
+ this.loaded = false;
111
+ }
97
112
  static { this.styles = [
98
113
  ScrollbarStyles,
114
+ ActivityFieldsStyles,
99
115
  css `
100
- :host { display: flex;
116
+ :host {
117
+ display: flex;
101
118
  flex-direction: column;
102
119
  position: relative;
103
120
 
104
121
  width: 100%;
105
122
  overflow: auto;
106
- background-color: var(--md-sys-color-background);
107
- }
123
+ background: var(--ui-bg, #f0f2f4);
124
+ color: var(--ui-ink, #17242c);
125
+ font-size: var(--ui-t-body, 13px);
126
+ }
108
127
 
109
- ox-board-viewer { width: 100%;
128
+ /* 카드가 담아 주므로 안에 들어오는 화면은 자기 면과 여백을 갖지 않는다. */
129
+ /*
130
+ * 줄어들지 않는다 — 줄어들면 본문이 잘린다.
131
+ *
132
+ * flex 항목인데 크기를 안 정해 두면 기본이 flex: 0 1 auto 다. **1 이 줄어든다는 뜻이다** —
133
+ * 세로가 모자라면 브라우저가 이 칸부터 줄이는데, 여기엔 카드 모서리를 따라 자르려고
134
+ * overflow: hidden 이 걸려 있어서 줄어든 만큼이 **스크롤도 없이 사라진다.**
135
+ *
136
+ * 완료 조회에서 실측했다(1400x620): 칸이 242px 로 줄고 내용은 362px 이라 「업무 내용」 절이
137
+ * 대부분 잘렸고, 잘린 자리 바로 아래에서 타임라인이 시작하니 타임라인이 본문을 덮은 것처럼
138
+ * 보였다. 세로가 넉넉하면 줄일 일이 없어 안 드러난다.
139
+ *
140
+ * 안에 오는 것은 문서다. 높이를 정해 주어야 하는 것은 board 뿐이고 board 는 이 칸을 거치지
141
+ * 않는다(activityContent 참조). 문서는 제 높이로 서고, 모자라면 페이지 전체가 스크롤한다 —
142
+ * :host 의 overflow: auto 가 그 자리다.
143
+ */
144
+ section[hosted] {
145
+ flex: none;
146
+ padding: 0;
147
+ overflow: hidden;
148
+ }
149
+
150
+ ox-board-viewer {
151
+ width: 100%;
110
152
  height: 100%;
111
- }
153
+ }
112
154
 
113
- activity-thread-timeline { margin: var(--spacing-medium);
114
- }
155
+ activity-thread-timeline {
156
+ margin: var(--spacing-large, 16px);
157
+ }
115
158
 
116
- div[comment] { display: flex;
159
+ /*
160
+ * 의견 칸 — 이 화면에서 **결재자가 유일하게 적는 자리**다.
161
+ *
162
+ * 화면 아래에 붙어 있어(sticky) 목록을 내려 읽는 동안에도 보인다. 그 자리를 지키되 모양은
163
+ * 다른 절과 같은 카드로 둔다. 전에는 회색 면(surface-variant)에 다른 테두리라 이 화면에서
164
+ * 혼자 다른 부품처럼 보였다.
165
+ */
166
+ /*
167
+ * 의견 — 이 화면에서 **결재자가 유일하게 적는 자리**다.
168
+ *
169
+ * 화면 아래에 붙어 있어(sticky) 내용을 내려 읽는 동안에도 보인다. 그 자리를 지키되 모양은
170
+ * 다른 절과 같은 카드로 둔다. 전에는 회색 면(surface-variant)에 다른 테두리라 이 화면에서
171
+ * 혼자 다른 부품처럼 보였다.
172
+ */
173
+ div[comment] {
117
174
  position: sticky;
118
175
  bottom: 0;
119
- margin: 0;
120
- padding: 0;
176
+ padding-bottom: var(--spacing-large, 16px);
177
+ background: var(--ui-bg, #f0f2f4);
178
+ }
179
+
180
+ /*
181
+ * 이 화면에서 **사용자가 유일하게 손대는 자리**라는 것을 모양으로 말한다.
182
+ *
183
+ * 나머지 절은 전부 읽는 것이고, 판단은 아래 툴바의 단추가 받는다. 그런데 의견 칸이 읽는
184
+ * 절들과 똑같은 카드라 「내 차례가 어디인지」가 화면에 없었다. 왼쪽에 강조색 띠를 둔다 —
185
+ * sticky 라 툴바 바로 위에 붙으므로 띠와 단추가 한 덩어리로 읽힌다.
186
+ */
187
+ div[comment] section {
188
+ border-left: 3px solid var(--ui-accent, #00727e);
189
+ }
190
+
191
+ div[comment] textarea {
192
+ display: block;
193
+ box-sizing: border-box;
121
194
  width: 100%;
122
- background-color: var(--md-sys-color-background);
195
+ height: 76px;
196
+ padding: 10px 12px;
197
+ background: var(--ui-panel, #ffffff);
198
+ border: 1px solid var(--ui-line, #d5dce0);
199
+ border-radius: var(--ui-r-small, 6px);
200
+ color: var(--ui-ink, #17242c);
201
+ font: inherit;
202
+ font-size: var(--ui-t-body, 13px);
203
+ resize: none;
204
+ outline: none;
205
+ }
123
206
 
124
- textarea { flex: 1;
125
- margin: var(--spacing-medium);
126
- padding: var(--spacing-medium);
127
- font: var(--input-font);
128
- outline: none;
129
- height: 80px;
130
- border-radius: var(--spacing-small);
131
- border: var(--input-field-border);
132
- resize: none;
133
- color: var(--md-sys-color-on-surface);
134
- background: var(--md-sys-color-surface-variant);
135
- }
136
- }
207
+ div[comment] textarea:focus {
208
+ border-color: var(--ui-accent, #00727e);
209
+ }
137
210
 
138
- [empty] { flex: 1;
139
- display: flex;
140
- align-items: center;
141
- justify-content: center;
142
- align-self: center;
143
- color: var(--md-sys-color-on-surface-variant);
144
- font: var(--md-sys-typescale-title-medium);
145
- opacity: 0.7;
146
- }
211
+ div[comment] .hint {
212
+ margin: 7px 0 0;
213
+ font-size: var(--ui-t-small, 11.5px);
214
+ color: var(--ui-faint, #8a959c);
215
+ word-break: keep-all;
216
+ }
147
217
  `
148
218
  ]; }
149
219
  get context() {
150
220
  const judgment = this.activityApproval?.judgment;
151
221
  return { title: this.lifecycle?.params?.['title'] || i18next.t('title.activity approval'),
152
222
  help: 'worklist/activity-approval',
223
+ /*
224
+ * 이 화면은 메뉴에 없다 — 「내 결재함」에서 줄을 눌러 들어온다. 그래서 왼쪽 메뉴가 가리킬
225
+ * 항목이 없고, 표시가 사라져 들어온 사람이 자기가 어디에 있는지 잃는다.
226
+ *
227
+ * 어느 목록에서 열리는지는 이 화면이 안다. 그것을 적어 둔다.
228
+ */
229
+ menu: 'approval-pending-list',
153
230
  actions: judgment
154
231
  ? [
155
232
  { title: i18next.t('button.close'),
@@ -159,67 +236,120 @@ let ActivityApprovalPage = class ActivityApprovalPage extends localize(i18next)(
159
236
  ...CommonButtonStyles.back
160
237
  }
161
238
  ]
162
- : [
163
- { title: i18next.t('button.reject'),
164
- action: this.rejectActivityApproval.bind(this),
165
- ...CommonButtonStyles.play,
166
- icon: 'assignment_return'
167
- },
168
- { title: i18next.t('button.approve'),
169
- action: this.approveActivityApproval.bind(this),
170
- ...CommonButtonStyles.save,
171
- icon: 'approval'
172
- },
173
- { title: i18next.t('button.save'),
174
- action: this.saveActivityApproval.bind(this),
175
- ...CommonButtonStyles.save
176
- },
177
- { title: i18next.t('button.close'),
178
- action: () => {
179
- history.back();
239
+ : /*
240
+ * ── 세 단추의 순서와 무게 (2026-09-06) ──────────────────────────
241
+ * 전에는 반려가 첫 자리였고, 승인 · 반려 · 저장이 모두 같은 모양이었다. 되돌리기 어려운
242
+ * 것이 앞에 서고 무엇이 주된 흐름인지 화면이 말하지 않았다.
243
+ *
244
+ * 승인이 주 동작이다 — 채운 단추 하나. 반려는 대등한 선택이지만 예외 경로라 테두리
245
+ * 단추로 그 옆에 둔다.
246
+ *
247
+ * 「저장」은 이름이 뜻을 말하지 않았다. 이 단추가 저장하는 것은 **의견 하나**이고
248
+ * (saveActivityApproval 은 id 와 comment 만 보낸다), 판단은 미뤄 둔다. 그리고 그 결과는
249
+ * 목록에서 「메모 있음」 표식으로 나타난다(activity-cells 의 approvalMarks). 목록이
250
+ * 부르는 이름과 같은 낱말로 맞춘다.
251
+ */
252
+ [
253
+ { title: i18next.t('button.approve'),
254
+ action: this.approveActivityApproval.bind(this),
255
+ icon: 'approval',
256
+ emphasis: { raised: true,
257
+ outlined: false,
258
+ dense: false,
259
+ danger: false
260
+ }
180
261
  },
181
- ...CommonButtonStyles.back,
182
- icon: 'close'
183
- }
184
- ]
262
+ { title: i18next.t('button.reject'),
263
+ action: this.rejectActivityApproval.bind(this),
264
+ icon: 'assignment_return',
265
+ emphasis: { raised: false,
266
+ outlined: true,
267
+ dense: false,
268
+ danger: false
269
+ }
270
+ },
271
+ { title: i18next.t('button.save-note'),
272
+ action: this.saveActivityApproval.bind(this),
273
+ icon: 'edit_note',
274
+ emphasis: { raised: false,
275
+ outlined: true,
276
+ dense: false,
277
+ danger: false
278
+ }
279
+ },
280
+ { title: i18next.t('button.close'),
281
+ action: () => {
282
+ history.back();
283
+ },
284
+ ...CommonButtonStyles.back,
285
+ icon: 'close'
286
+ }
287
+ ]
185
288
  // activityApproval: this.activityApproval
186
289
  };
187
290
  }
188
291
  render() {
189
292
  if (!this.activityThread) {
190
- return html `<div empty>${i18next.t('text.no activity thread info')}</div>`;
293
+ return this.loaded
294
+ ? html `<div empty>
295
+ <span class="title">${i18next.t('text.no activity thread info')}</span>
296
+ <span class="why">${i18next.t('text.no-activity-thread-why')}</span>
297
+ </div>`
298
+ : nothing;
191
299
  }
192
300
  const { terminatedAt } = this.activityApproval;
193
301
  const editable = !terminatedAt;
194
302
  return html `
195
303
  <activity-approval-ribon .activityApproval=${this.activityApproval}></activity-approval-ribon>
196
304
  ${this.activityContent()}
197
- <activity-thread-timeline .activityThread=${this.activityThread} short-form></activity-thread-timeline>
305
+ <!--
306
+ 보일 항목이 하나도 없으면 타임라인을 편다 — 그때는 화면이 「아래 타임라인의 상신 사유와
307
+ 이력을 보고 판단하세요」로 여기를 가리키므로, 접혀 있으면 그 안내가 거짓말이 된다.
308
+ -->
309
+ <activity-thread-timeline
310
+ .activityThread=${this.activityThread}
311
+ ?open=${!this.hasFields()}
312
+ short-form
313
+ ></activity-thread-timeline>
198
314
  ${editable
199
315
  ? html `
200
316
  <div comment>
201
- <textarea
202
- placeholder=${String(i18next.t('text.explain the reason for approval/rejection'))}
203
- .value=${this.activityApproval?.comment}
204
- @change=${(e) => {
317
+ <section>
318
+ <h2>${i18next.t('field.wl-comment')}</h2>
319
+ <textarea
320
+ placeholder=${String(i18next.t('text.explain the reason for approval/rejection'))}
321
+ .value=${this.activityApproval?.comment}
322
+ @change=${(e) => {
205
323
  this.activityApproval.comment = e.target.value;
206
324
  }}
207
- ></textarea>
325
+ ></textarea>
326
+ <!--
327
+ 반려는 의견이 필수다(rejectActivityApproval). 전에는 그 규칙을 **누른 뒤에** 토스트로
328
+ 알렸다. 되돌릴 수 없는 것과 뜻이 다른 동작은 하기 전에 말한다.
329
+ -->
330
+ <p class="hint">${i18next.t('text.approval-comment-hint')}</p>
331
+ </section>
208
332
  </div>
209
333
  `
210
334
  : nothing}
211
335
  `;
212
336
  }
337
+ /** 화면에 낼 항목이 하나라도 있나. 타임라인을 펴 둘지 정하는 자리가 쓴다. */
338
+ hasFields() {
339
+ const model = this.activityThread?.activityInstance?.activity?.model;
340
+ return inputSpecOf(model).length > 0 || outputSpecOf(model).length > 0;
341
+ }
213
342
  activityContent() {
214
343
  switch (this.activityThread?.activityInstance?.viewType) {
215
344
  case 'template':
216
- return this.templateContent();
345
+ return this.hostedContent(this.templateContent());
217
346
  case 'generated':
218
347
  return this.generatedContent();
348
+ /* board 는 전체 화면을 쓰는 캔버스라 카드에 담지 않는다(hostedContent 머리말). */
219
349
  case 'board':
220
350
  return this.boardContent();
221
351
  case 'custom-element':
222
- return this.customElementContent();
352
+ return this.hostedContent(this.customElementContent());
223
353
  case 'page':
224
354
  case 'external':
225
355
  return html ``;
@@ -227,6 +357,22 @@ let ActivityApprovalPage = class ActivityApprovalPage extends localize(i18next)(
227
357
  return this.generatedContent();
228
358
  }
229
359
  }
360
+ /**
361
+ * 화면 종류가 달라도 **같은 자리에 같은 모양으로 놓인다.**
362
+ *
363
+ * worklist 는 네 가지로 내용을 그린다(generated · custom-element · template · board). 그중
364
+ * generated 만 절 카드 안에 있었고 나머지 셋은 면 위에 맨몸으로 놓였다. 그래서 같은 결재 화면이
365
+ * 액티비티에 따라 카드였다가 아니었다가 했다 — 아래의 타임라인 · 의견은 늘 카드라 위계도 어긋났다.
366
+ *
367
+ * board 는 뺀다. 전체 폭 · 전체 높이를 쓰는 캔버스라 카드 안에 넣으면 여백이 두 겹이 되고 크기가
368
+ * 어긋난다.
369
+ *
370
+ * 카드는 여백을 두지 않는다(padding: 0). 안에 들어오는 것이 자기 조판을 갖고 있고, 두 겹으로
371
+ * 주면 안쪽 내용이 카드 가운데로 밀린다.
372
+ */
373
+ hostedContent(content) {
374
+ return html `<section hosted>${content}</section>`;
375
+ }
230
376
  templateContent() {
231
377
  if (!this.activityApproval) {
232
378
  return html ``;
@@ -234,65 +380,52 @@ let ActivityApprovalPage = class ActivityApprovalPage extends localize(i18next)(
234
380
  const { viewSource: template } = this.activityThread?.activityInstance;
235
381
  return unsafeHTML(template);
236
382
  }
237
- getInputSpec() {
238
- const model = this.activityThread?.activityInstance?.activity?.model;
239
- return (model || [])
240
- .filter(item => item.inout === 'in' || item.inout === 'inout')
241
- .map(item => {
242
- return { ...item,
243
- name: item.tag,
244
- label: item.tKey || item.name,
245
- property: item.options
246
- };
247
- });
248
- }
249
- getOutputSpec() {
250
- const model = this.activityThread?.activityInstance?.activity?.model;
251
- return (model || [])
252
- .filter(item => item.inout === 'inout' || item.inout === 'out')
253
- .map(item => {
254
- return { ...item,
255
- name: item.tag,
256
- label: item.tKey || item.name,
257
- property: item.options
258
- };
259
- });
260
- }
383
+ /**
384
+ * 결재자가 보는 내용 — **전부 읽기 전용이다.**
385
+ *
386
+ * 전에는 「Output」 절을 편집기로 그리고 변경을 activityApproval.output 적었다. 그런데
387
+ * approveActivityApproval / rejectActivityApproval 은 id 와 comment 만 보낸다 — 그 값은 어디에도
388
+ * 가지 않는다. 결재자가 적을 수 있는 것은 의견 하나이고, 그것은 화면 아래 칸이 받는다.
389
+ */
261
390
  generatedContent() {
262
391
  if (!this.activityApproval) {
263
392
  return html ``;
264
393
  }
265
- var { output, activityInstance } = this.activityThread || {};
266
- var { input } = activityInstance || {};
267
- const inputSpec = this.getInputSpec();
268
- const outputSpec = this.getOutputSpec();
269
- if (!output) {
270
- output = inputSpec
271
- .filter(item => item.inout === 'inout')
272
- .reduce((inout, item) => {
273
- inout[item.name] = input[item.name];
274
- return inout;
275
- }, {});
394
+ const { output, activityInstance } = this.activityThread || {};
395
+ const { input } = activityInstance || {};
396
+ const model = activityInstance?.activity?.model;
397
+ const inputSpec = inputSpecOf(model);
398
+ const outputSpec = outputSpecOf(model);
399
+ /*
400
+ * **결재 화면에서 내용이 비어 있는 것은 경고다.**
401
+ *
402
+ * 업무 상세라면 「적을 것이 없다」로 끝난다. 여기서는 다르다 — 무엇을 승인하는지 모르는 채로
403
+ * 승인 · 반려 버튼이 그대로 눌린다. 그 사실을 화면이 말하고, 대신 무엇을 보고 판단할지 알려
404
+ * 준다(타임라인의 상신 사유).
405
+ */
406
+ if (!inputSpec.length && !outputSpec.length) {
407
+ return keyed(this.activityApproval.id, html `<section empty>
408
+ <span class="title">${i18next.t('text.no-approval-content')}</span>
409
+ <span class="why">${i18next.t('text.no-approval-content-why')}</span>
410
+ </section>`);
276
411
  }
277
412
  return keyed(this.activityApproval.id, html `
278
- <fieldset>
279
- <legend>Input</legend>
280
- <ox-properties-dynamic-view
281
- data-name="input"
282
- .props=${inputSpec}
283
- .value=${input}
284
- ></ox-properties-dynamic-view>
285
- </fieldset>
286
-
287
- <fieldset>
288
- <legend>Output</legend>
289
- <ox-properties-dynamic-view
290
- data-name="output"
291
- .props=${outputSpec}
292
- .value=${output}
293
- @property-change=${e => (this.activityApproval.output = e.currentTarget.value)}
294
- ></ox-properties-dynamic-view>
295
- </fieldset>
413
+ ${inputSpec.length
414
+ ? html `
415
+ <section readonly>
416
+ <h2>${i18next.t('label.activity-input')}</h2>
417
+ ${renderGiven(inputSpec, input)}
418
+ </section>
419
+ `
420
+ : ''}
421
+ ${outputSpec.length
422
+ ? html `
423
+ <section readonly>
424
+ <h2>${i18next.t('field.artifact')}</h2>
425
+ ${renderGiven(outputSpec, output)}
426
+ </section>
427
+ `
428
+ : ''}
296
429
  `);
297
430
  }
298
431
  boardContent() {
@@ -331,16 +464,25 @@ let ActivityApprovalPage = class ActivityApprovalPage extends localize(i18next)(
331
464
  return element;
332
465
  }
333
466
  getOutputFromBoard() {
334
- const outputSpec = this.getOutputSpec();
467
+ const outputSpec = outputSpecOf(this.activityThread?.activityInstance?.activity?.model);
335
468
  const data = this.oxBoardViewer.getSceneValues();
336
469
  return outputSpec.reduce((output, spec) => {
337
470
  output[spec.name] = data[spec.name];
338
471
  return output;
339
472
  }, {});
340
473
  }
474
+ focusComment() {
475
+ const id = this.activityApproval?.id;
476
+ if (!id || !this.active || this.activityApproval?.terminatedAt || this.focusedFor === id) {
477
+ return;
478
+ }
479
+ this.commentInput?.focus({ preventScroll: true });
480
+ this.focusedFor = id;
481
+ }
341
482
  updated(changes) {
342
483
  if (changes.has('activityApproval')) {
343
484
  this.updateContext();
485
+ this.focusComment();
344
486
  }
345
487
  }
346
488
  async pageUpdated(changes, lifecycle, changedBefore) {
@@ -357,6 +499,7 @@ let ActivityApprovalPage = class ActivityApprovalPage extends localize(i18next)(
357
499
  }
358
500
  });
359
501
  this.activityApproval = response.data.activityApproval;
502
+ this.loaded = true;
360
503
  this.activityThread = this.activityApproval.activityThread;
361
504
  this.updateContext();
362
505
  }
@@ -429,6 +572,10 @@ __decorate([
429
572
  state(),
430
573
  __metadata("design:type", Object)
431
574
  ], ActivityApprovalPage.prototype, "activityApproval", void 0);
575
+ __decorate([
576
+ state(),
577
+ __metadata("design:type", Object)
578
+ ], ActivityApprovalPage.prototype, "loaded", void 0);
432
579
  __decorate([
433
580
  state(),
434
581
  __metadata("design:type", Object)