@things-factory/worklist 10.1.168 → 10.1.170

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 (66) hide show
  1. package/dist-client/components/decision-content.d.ts +35 -0
  2. package/dist-client/components/decision-content.js +322 -0
  3. package/dist-client/components/decision-content.js.map +1 -0
  4. package/dist-client/components/decision-slots.d.ts +8 -0
  5. package/dist-client/components/decision-slots.js +17 -0
  6. package/dist-client/components/decision-slots.js.map +1 -1
  7. package/dist-client/components/work-box-groups.d.ts +25 -0
  8. package/dist-client/components/work-box-groups.js +98 -0
  9. package/dist-client/components/work-box-groups.js.map +1 -0
  10. package/dist-client/my-work-menus.d.ts +1 -6
  11. package/dist-client/my-work-menus.js +0 -1
  12. package/dist-client/my-work-menus.js.map +1 -1
  13. package/dist-client/pages/activity-approval/activity-approval-page.d.ts +2 -52
  14. package/dist-client/pages/activity-approval/activity-approval-page.js +8 -298
  15. package/dist-client/pages/activity-approval/activity-approval-page.js.map +1 -1
  16. package/dist-client/pages/activity-instance/activity-instance-view.d.ts +19 -2
  17. package/dist-client/pages/activity-instance/activity-instance-view.js +47 -23
  18. package/dist-client/pages/activity-instance/activity-instance-view.js.map +1 -1
  19. package/dist-client/pages/activity-thread/activity-thread-page.d.ts +6 -2
  20. package/dist-client/pages/activity-thread/activity-thread-page.js +31 -16
  21. package/dist-client/pages/activity-thread/activity-thread-page.js.map +1 -1
  22. package/dist-client/pages/activity-thread/activity-thread-view-page.js +2 -2
  23. package/dist-client/pages/activity-thread/activity-thread-view-page.js.map +1 -1
  24. package/dist-client/pages/activity-thread/thread-sections.d.ts +34 -0
  25. package/dist-client/pages/activity-thread/thread-sections.js +36 -0
  26. package/dist-client/pages/activity-thread/thread-sections.js.map +1 -0
  27. package/dist-client/pages/todo/approval-pending-list-page.d.ts +1 -0
  28. package/dist-client/pages/todo/approval-pending-list-page.js +10 -77
  29. package/dist-client/pages/todo/approval-pending-list-page.js.map +1 -1
  30. package/dist-client/pages/todo/draft-list-page.d.ts +20 -0
  31. package/dist-client/pages/todo/draft-list-page.js +102 -5
  32. package/dist-client/pages/todo/draft-list-page.js.map +1 -1
  33. package/dist-client/pages/todo/todo-list-page.d.ts +19 -0
  34. package/dist-client/pages/todo/todo-list-page.js +147 -23
  35. package/dist-client/pages/todo/todo-list-page.js.map +1 -1
  36. package/dist-client/pages/todo/work-box.d.ts +36 -0
  37. package/dist-client/pages/todo/work-box.js +44 -0
  38. package/dist-client/pages/todo/work-box.js.map +1 -0
  39. package/dist-client/route.d.ts +1 -1
  40. package/dist-client/route.js +0 -3
  41. package/dist-client/route.js.map +1 -1
  42. package/dist-client/tsconfig.tsbuildinfo +1 -1
  43. package/dist-client/types/activity.d.ts +2 -0
  44. package/dist-client/types/activity.js.map +1 -1
  45. package/dist-server/service/activity-summary/open-work.d.ts +0 -1
  46. package/dist-server/service/activity-summary/open-work.js +3 -15
  47. package/dist-server/service/activity-summary/open-work.js.map +1 -1
  48. package/dist-server/service/activity-thread/activity-thread-query.d.ts +3 -0
  49. package/dist-server/service/activity-thread/activity-thread-query.js +24 -5
  50. package/dist-server/service/activity-thread/activity-thread-query.js.map +1 -1
  51. package/dist-server/service/activity-thread/my-open-threads.d.ts +23 -4
  52. package/dist-server/service/activity-thread/my-open-threads.js +38 -7
  53. package/dist-server/service/activity-thread/my-open-threads.js.map +1 -1
  54. package/dist-server/tsconfig.tsbuildinfo +1 -1
  55. package/package.json +5 -5
  56. package/tests/open-doors.test.ts +3 -2
  57. package/things-factory.config.js +0 -1
  58. package/translations/en.json +10 -2
  59. package/translations/es.json +10 -2
  60. package/translations/ja.json +10 -2
  61. package/translations/ko.json +10 -2
  62. package/translations/ms.json +10 -2
  63. package/translations/zh.json +10 -2
  64. package/dist-client/pages/todo/done-list-page.d.ts +0 -38
  65. package/dist-client/pages/todo/done-list-page.js +0 -382
  66. package/dist-client/pages/todo/done-list-page.js.map +0 -1
@@ -2,6 +2,7 @@ import { __decorate, __metadata } from "tslib";
2
2
  import '@operato/data-grist';
3
3
  import '@operato/data-grist/ox-filters-form.js';
4
4
  import '@operato/input/ox-input-select-buttons.js';
5
+ import '../../components/work-box-groups.js';
5
6
  import gql from 'graphql-tag';
6
7
  import { css, html } from 'lit';
7
8
  import { customElement, property, query, state } from 'lit/decorators.js';
@@ -11,11 +12,18 @@ import { dueSoonChip, dueSoonFilters, importantChip, importantFilters } from '..
11
12
  import { i18next, localize } from '@operato/i18n';
12
13
  import { navigate, PageView } from '@operato/shell';
13
14
  import { listWithThumbnail } from './list-thumbnail.js';
15
+ import { countsOnTab, groupAddress, groupAt, TODO_GROUPS } from './work-box.js';
14
16
  import { CommonGristStyles, CommonHeaderStyles, ScrollbarStyles, WorkSurfacePageStyles } from '@operato/styles';
15
17
  import { adjustFilters, isMobileDevice } from '@operato/utils';
16
18
  import { p13n } from '@operato/p13n';
17
19
  import { dueCell, priorityCell, subjectCell } from '../../activity-cells.js';
18
20
  import { ActivityThreadStatus } from '../../types/activity-thread.js';
21
+ /** 묶음마다 묻는 목록 — 서버의 세 질의가 같은 줄 모양을 준다. */
22
+ const QUERY_OF = {
23
+ todo: 'todoList',
24
+ submitted: 'submittedList',
25
+ completed: 'doneList'
26
+ };
19
27
  const MIN = 60;
20
28
  const HOUR = 60 * MIN;
21
29
  const DAY = 24 * HOUR;
@@ -23,6 +31,15 @@ let TodoListPage = class TodoListPage extends p13n(localize(i18next)(PageView))
23
31
  constructor() {
24
32
  super(...arguments);
25
33
  this.mode = isMobileDevice() ? 'CARD' : 'GRID';
34
+ /**
35
+ * 지금 어느 묶음을 보고 있나 — 할 것 · 제출한 것 · 완료 (pages/todo/work-box.ts).
36
+ *
37
+ * 내가 올린 건은 내 차례일 때만 여기 있다. 제출하고 결재를 기다리는 동안과 끝난 뒤에는 상신함이
38
+ * 따라간다 — 서버의 myThreadsOfOthersWhere 가 그 경계다.
39
+ */
40
+ this.group = 'todo';
41
+ /** 기다리는 두 묶음의 건수. 끝난 묶음은 이력이라 세지 않는다. */
42
+ this.counts = {};
26
43
  }
27
44
  static { this.styles = [
28
45
  /* The work surface frame for a list screen (ADR-0060 decision 8). */
@@ -108,6 +125,16 @@ let TodoListPage = class TodoListPage extends p13n(localize(i18next)(PageView))
108
125
  render() {
109
126
  const mode = this.mode || (isMobileDevice() ? 'CARD' : 'GRID');
110
127
  return html `
128
+ <work-box-groups
129
+ .groups=${[
130
+ ['todo', 'label.group-todo', 'text.group-todo-hint'],
131
+ ['submitted', 'label.group-submitted', 'text.group-submitted-hint'],
132
+ ['completed', 'label.group-completed', 'text.group-done-hint']
133
+ ].map(([key, label, hint]) => ({ key, label, hint, count: countsOnTab(key) ? this.counts[key] : undefined }))}
134
+ .selected=${this.group}
135
+ @select=${(e) => this.selectGroup(e.detail)}
136
+ ></work-box-groups>
137
+
111
138
  <ox-grist class="page-fill"
112
139
  .mode=${mode}
113
140
  .config=${this.gristConfig}
@@ -120,12 +147,7 @@ let TodoListPage = class TodoListPage extends p13n(localize(i18next)(PageView))
120
147
  <ox-filters-form class="filter" without-search></ox-filters-form>
121
148
  <ox-input-select-buttons
122
149
  .value=${this.filters}
123
- .options=${[
124
- importantChip(),
125
- dueSoonChip(),
126
- { display: i18next.t('label.filter-proceeding'), value: 'proceeding' },
127
- { display: i18next.t('label.filter-pending-approval'), value: 'pending-approval' }
128
- ]}
150
+ .options=${this.chips()}
129
151
  @change=${(e) => {
130
152
  this.filters = e.currentTarget?.value;
131
153
  this.grist.fetch();
@@ -140,7 +162,62 @@ let TodoListPage = class TodoListPage extends p13n(localize(i18next)(PageView))
140
162
  </ox-grist>
141
163
  `;
142
164
  }
165
+ /** 묶음마다 좁히는 칩이 다르다 — 끝난 일에 「만기」는 물음이 아니다. */
166
+ chips() {
167
+ switch (this.group) {
168
+ case 'todo':
169
+ return [importantChip(), dueSoonChip(), { display: i18next.t('label.filter-proceeding'), value: 'proceeding' }];
170
+ case 'submitted':
171
+ return [importantChip(), dueSoonChip()];
172
+ case 'completed':
173
+ return [
174
+ importantChip(),
175
+ { display: i18next.t('label.filter-recent'), value: 'recent' },
176
+ { display: i18next.t('label.filter-aborted'), value: 'aborted' }
177
+ ];
178
+ }
179
+ }
180
+ /** 주소만 바꾼다 — 목록도 설정도 pageUpdated 가 한 벌로 다시 세운다. */
181
+ selectGroup(group) {
182
+ if (this.group === group) {
183
+ return;
184
+ }
185
+ navigate(groupAddress(this.lifecycle?.page, group, TODO_GROUPS));
186
+ }
187
+ syncGroup(key) {
188
+ const group = groupAt(key, TODO_GROUPS);
189
+ if (this.group === group && this.gristConfig) {
190
+ return;
191
+ }
192
+ this.group = group;
193
+ this.filters = [];
194
+ this.applyConfig();
195
+ }
196
+ /** 안 보고 있는 기다리는 묶음의 건수 — 한 줄만 받아 total 을 읽는다. 못 읽은 수는 0 이 아니다. */
197
+ async countOther() {
198
+ const other = this.group === 'submitted' ? 'todo' : 'submitted';
199
+ const response = await client.query({
200
+ query: gql `
201
+ query ($pagination: Pagination) {
202
+ responses: ${QUERY_OF[other]}(pagination: $pagination) {
203
+ total
204
+ }
205
+ }
206
+ `,
207
+ variables: { pagination: { page: 1, limit: 1 } },
208
+ fetchPolicy: 'no-cache'
209
+ });
210
+ const total = response.errors?.length ? undefined : response.data?.responses?.total;
211
+ if (typeof total == 'number')
212
+ this.counts = { ...this.counts, [other]: total };
213
+ }
143
214
  async pageInitialized(lifecycle) {
215
+ /* pageUpdated 가 이 함수보다 먼저 지나가므로 주소로 바로 들어온 경우는 여기서 잡힌다. */
216
+ this.syncGroup(lifecycle?.resourceId);
217
+ await this.countOther();
218
+ }
219
+ applyConfig() {
220
+ const completed = this.group === 'completed';
144
221
  this.gristConfig = {
145
222
  list: { thumbnail: 'thumbnail', fields: ['name', 'description'], details: ['createdAt', 'due'] },
146
223
  columns: [
@@ -185,14 +262,20 @@ let TodoListPage = class TodoListPage extends p13n(localize(i18next)(PageView))
185
262
  sortable: true,
186
263
  width: 85
187
264
  },
265
+ /*
266
+ * 기한 — 끝난 일에서는 **다른 날짜 열과 같이** 시각만 적는다.
267
+ *
268
+ * dueCell 은 Date.now() 를 기준으로 「4일 13시간 지남」을 내고 1분마다 다시 센다. 아직 안 끝난
269
+ * 일에는 그게 물음이다 — 지금부터 얼마 남았나. 끝난 일에는 그 물음이 없고, 그대로 두면 **거짓을
270
+ * 말한다.** 기한 안에 끝낸 건도 오늘 날짜가 흐르면 빨간 「N일 지남」으로 바뀐다.
271
+ *
272
+ * 「기한을 지켰나」는 줄마다가 아니라 모아서 보는 물음이다 — activity-stats 의 자리다.
273
+ */
188
274
  {
189
275
  type: 'datetime',
190
276
  name: 'dueAt',
191
277
  header: i18next.t('field.wl-due'),
192
- record: {
193
- editable: false,
194
- renderer: dueCell(() => this.active)
195
- },
278
+ record: completed ? { editable: false } : { editable: false, renderer: dueCell(() => this.active) },
196
279
  sortable: true,
197
280
  width: 180
198
281
  },
@@ -229,6 +312,26 @@ let TodoListPage = class TodoListPage extends p13n(localize(i18next)(PageView))
229
312
  },
230
313
  width: 85
231
314
  },
315
+ ...(completed
316
+ ? [
317
+ {
318
+ type: 'datetime',
319
+ name: 'startedAt',
320
+ header: i18next.t('field.wl-started-at'),
321
+ record: { editable: false },
322
+ sortable: true,
323
+ width: 180
324
+ },
325
+ {
326
+ type: 'datetime',
327
+ name: 'terminatedAt',
328
+ header: i18next.t('field.wl-terminated-at'),
329
+ record: { editable: false },
330
+ sortable: true,
331
+ width: 180
332
+ }
333
+ ]
334
+ : []),
232
335
  {
233
336
  type: 'datetime',
234
337
  name: 'createdAt',
@@ -270,11 +373,15 @@ let TodoListPage = class TodoListPage extends p13n(localize(i18next)(PageView))
270
373
  }
271
374
  }
272
375
  },
273
- sorters: [{ name: 'dueAt', desc: false }],
376
+ sorters: completed ? [{ name: 'terminatedAt', desc: true }] : [{ name: 'dueAt', desc: false }],
274
377
  pagination: { limit: 50, pages: [20, 50, 100, 500] }
275
378
  };
276
379
  }
277
380
  async pageUpdated(changes, lifecycle, changedBefore) {
381
+ if (lifecycle?.resourceId !== changedBefore?.resourceId) {
382
+ this.syncGroup(lifecycle?.resourceId);
383
+ await this.countOther();
384
+ }
278
385
  if (this.active) {
279
386
  this.grist?.fetch();
280
387
  }
@@ -295,19 +402,18 @@ let TodoListPage = class TodoListPage extends p13n(localize(i18next)(PageView))
295
402
  if (this.filters?.includes('proceeding')) {
296
403
  filters = adjustFilters(filters, [{ name: 'state', operator: 'eq', value: ActivityThreadStatus.Started }]);
297
404
  }
298
- if (this.filters?.includes('pending-approval')) {
299
- filters = adjustFilters(filters, [
300
- {
301
- name: 'state',
302
- operator: 'in',
303
- value: [ActivityThreadStatus.Rejected, ActivityThreadStatus.Submitted, ActivityThreadStatus.Escalated]
304
- }
305
- ]);
405
+ if (this.filters?.includes('recent')) {
406
+ /* 최근 24시간 이내에 끝낸 일 */
407
+ const since = new Date(Date.now() - 24 * 3600 * 1000).toISOString().replace('T', ' ');
408
+ filters = adjustFilters(filters, [{ name: 'terminatedAt', operator: 'gte', value: since }]);
409
+ }
410
+ if (this.filters?.includes('aborted')) {
411
+ filters = adjustFilters(filters, [{ name: 'state', operator: 'eq', value: ActivityThreadStatus.Aborted }]);
306
412
  }
307
413
  const response = await client.query({
308
414
  query: gql `
309
415
  query ($filters: [Filter!], $pagination: Pagination, $sortings: [Sorting!]) {
310
- responses: todoList(filters: $filters, pagination: $pagination, sortings: $sortings) {
416
+ responses: ${QUERY_OF[this.group]}(filters: $filters, pagination: $pagination, sortings: $sortings) {
311
417
  items {
312
418
  id
313
419
  activityInstance {
@@ -332,6 +438,8 @@ let TodoListPage = class TodoListPage extends p13n(localize(i18next)(PageView))
332
438
  output
333
439
  dueAt
334
440
  assignedAt
441
+ startedAt
442
+ terminatedAt
335
443
  }
336
444
  total
337
445
  }
@@ -339,22 +447,30 @@ let TodoListPage = class TodoListPage extends p13n(localize(i18next)(PageView))
339
447
  `,
340
448
  variables: { filters, pagination: { page, limit }, sortings }
341
449
  });
450
+ const total = response.data.responses.total || 0;
451
+ /* 보고 있는 묶음의 수는 이 조회가 알려 준다. 나머지는 countOther 가 센다. */
452
+ if (countsOnTab(this.group))
453
+ this.counts = { ...this.counts, [this.group]: total };
342
454
  return {
343
- total: response.data.responses.total || 0,
455
+ total,
344
456
  records: (response.data.responses.items || []).map(item => {
345
457
  return {
458
+ ...item.activityInstance,
346
459
  id: item.id,
347
460
  state: item.state,
348
461
  output: item.output,
349
462
  dueAt: item.dueAt,
350
463
  assignedAt: item.assignedAt,
351
- ...item.activityInstance
464
+ startedAt: item.startedAt,
465
+ terminatedAt: item.terminatedAt
352
466
  };
353
467
  })
354
468
  };
355
469
  }
470
+ /** 끝난 일은 보기 화면으로 연다 — 고칠 것이 없는 화면에 저장 · 제출이 서면 안 된다. */
356
471
  openActivityThread(activityThread) {
357
- navigate(`activity-thread/${activityThread.id}?title=${activityThread.name}`);
472
+ const page = this.group === 'completed' ? 'activity-thread-view' : 'activity-thread';
473
+ navigate(`${page}/${activityThread.id}?title=${activityThread.name}`);
358
474
  }
359
475
  };
360
476
  __decorate([
@@ -373,6 +489,14 @@ __decorate([
373
489
  state(),
374
490
  __metadata("design:type", Array)
375
491
  ], TodoListPage.prototype, "filters", void 0);
492
+ __decorate([
493
+ state(),
494
+ __metadata("design:type", String)
495
+ ], TodoListPage.prototype, "group", void 0);
496
+ __decorate([
497
+ state(),
498
+ __metadata("design:type", Object)
499
+ ], TodoListPage.prototype, "counts", void 0);
376
500
  TodoListPage = __decorate([
377
501
  customElement('todo-list-page')
378
502
  ], TodoListPage);
@@ -1 +1 @@
1
- {"version":3,"file":"todo-list-page.js","sourceRoot":"","sources":["../../../client/pages/todo/todo-list-page.ts"],"names":[],"mappings":"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","sourcesContent":["import '@operato/data-grist'\nimport '@operato/data-grist/ox-filters-form.js'\nimport '@operato/input/ox-input-select-buttons.js'\n\nimport gql from 'graphql-tag'\nimport { css, html } from 'lit'\nimport { customElement, property, query, state } from 'lit/decorators.js'\nimport { asyncReplace } from 'lit/directives/async-replace.js'\nimport { DataGrist, FetchOption, getRenderer } from '@operato/data-grist'\nimport { client } from '@operato/graphql'\nimport { dueSoonChip, dueSoonFilters, importantChip, importantFilters } from '../../chip-filters.js'\nimport { i18next, localize } from '@operato/i18n'\nimport { navigate, PageView } from '@operato/shell'\nimport { listWithThumbnail } from './list-thumbnail.js'\nimport { CommonGristStyles, CommonHeaderStyles, ScrollbarStyles, WorkSurfacePageStyles } from '@operato/styles'\nimport { adjustFilters, isMobileDevice, sleep } from '@operato/utils'\n\nimport { p13n } from '@operato/p13n'\n\nimport { dueCell, priorityCell, subjectCell } from '../../activity-cells.js'\n\nimport { ActivityThreadStatus } from '../../types/activity-thread.js'\n\nconst MIN = 60\nconst HOUR = 60 * MIN\nconst DAY = 24 * HOUR\n\n@customElement('todo-list-page')\nexport class TodoListPage extends p13n(localize(i18next)(PageView)) {\n static styles = [\n /* The work surface frame for a list screen (ADR-0060 decision 8). */\n WorkSurfacePageStyles,\n ScrollbarStyles,\n CommonGristStyles,\n CommonHeaderStyles,\n css`\n :host {\n --grid-record-emphasized-background-color: #8b0000;\n --grid-record-emphasized-color: #ff6b6b;\n }\n\n /*\n * 제목은 헤드룸에 두지 않는다.\n *\n * MDI 를 켜면 제목이 이미 두 곳에 있다 — 헤더 바와 탭. 여기에 또 두면 한 화면에 같은 글자가\n * 셋이 된다. 그래서 표준 배치의 title 줄을 쓰지 않고 한 줄로 둔다.\n */\n .header {\n grid-template-areas: 'filters actions';\n }\n\n /*\n * ── 헤드룸의 왼쪽 기준선은 표와 같다 ─────────────────────────────────\n * CommonHeaderStyles 의 .filters 는 배경과 모서리와 여백을 가진 영역이다. 그 배경이\n * --md-sys-color-surface 인데 이 제품에서는 바탕색과 같은 값이라, **보이지 않는 영역이\n * 자리만 차지하고** 검색창을 여백만큼(12px) 안쪽으로 밀었다.\n *\n * 실측: 표 왼쪽 끝 212 · 필터 영역 212 · 검색창 224. 화면의 왼쪽 기준선이 둘이 됐다.\n *\n * 그 규칙들은 .header 안에 중첩되어 있어(.header .filters) 밑줄 없는 .filters 로는 이길 수\n * 없다 — 특정도가 0,1,0 대 0,2,0 이다.\n */\n .header .filters {\n padding: 0;\n background: none;\n border-radius: 0;\n gap: 12px;\n }\n\n `\n ]\n\n @property({ type: String }) mode: 'GRID' | 'LIST' | 'CARD' = isMobileDevice() ? 'CARD' : 'GRID'\n\n @query('ox-grist') grist!: DataGrist\n\n @state() gristConfig?: any\n @state() filters?: string[]\n\n get context() {\n return {\n title: i18next.t('title.todo list'),\n /*\n * 검색의 자리는 **기기가 정한다.**\n *\n * PC 에서는 화면 안으로 내린다. 상단 바에 두면 거른 조건과 걸러진 결과가 화면의 위아래 끝으로\n * 갈라지고, 지금 무엇으로 걸렀는지가 목록 옆에서 보이지 않는다.\n *\n * 좁은 화면에서는 상단 바에 그대로 둔다. 헤드룸에 두면 검색창과 필터가 목록을 그만큼 밀어\n * 내리고, 카드 두 장이 화면 밖으로 나간다. 상단 바는 그 자리를 아끼려고 있는 것이다.\n *\n * 이 저장소에는 두 방식이 다 있다 — 헤드룸 50곳, 상단 바 51곳. 정형인 것은 구조\n * (.header / .filters / .filter)이고 검색의 자리는 화면이 정한다.\n */\n /*\n * 검색은 **페이지 제목 줄의 오른쪽 끝**에 둔다 — 다른 화면들과 같은 자리다.\n *\n * 전에는 좁은 화면에서만 여기에 넣고, 넓은 화면에서는 헤드룸의 ox-filters-form 이 검색을\n * 그렸다. 그래서 같은 앱 안에서 검색 상자의 자리가 화면마다 달랐다.\n *\n * 헤드룸에는 좁히는 칩만 남는다. 폼은 without-search 로 남겨 두어, 나중에 어느 칸에\n * filter 를 달면 그 UI 가 저절로 생긴다(비면 아무것도 그리지 않는다).\n */\n search: {\n handler: (search: string) => {\n this.grist.searchText = search\n },\n value: this.grist?.searchText || ''\n },\n filter: {\n handler: () => {\n this.grist.toggleHeadroom()\n }\n },\n help: 'worklist/todo-list-page',\n actions: []\n }\n }\n\n render() {\n const mode = this.mode || (isMobileDevice() ? 'CARD' : 'GRID')\n\n return html`\n <ox-grist class=\"page-fill\"\n .mode=${mode}\n .config=${this.gristConfig}\n .fetchHandler=${this.fetchHandler.bind(this)}\n .personalConfigProvider=${this.getPagePreferenceProvider('ox-grist')!}\n >\n <div slot=\"headroom\" class=\"header\">\n <div class=\"filters\">\n <!-- 좁은 화면에서는 상단 바가 검색을 갖는다(위 context 주석 참조). -->\n <ox-filters-form class=\"filter\" without-search></ox-filters-form>\n <ox-input-select-buttons\n .value=${this.filters}\n .options=${[\n importantChip(),\n dueSoonChip(),\n { display: i18next.t('label.filter-proceeding'), value: 'proceeding' },\n { display: i18next.t('label.filter-pending-approval'), value: 'pending-approval' }\n ]}\n @change=${(e: CustomEvent) => {\n this.filters = (e.currentTarget as any)?.value\n this.grist.fetch()\n }}\n ></ox-input-select-buttons>\n <!-- <ox-filters-form class=\"filter\" autofocus without-search></ox-filters-form> -->\n </div>\n\n </div>\n\n <ox-grist-personalizer slot=\"setting\"></ox-grist-personalizer>\n </ox-grist>\n `\n }\n\n async pageInitialized(lifecycle) {\n this.gristConfig = {\n list: { thumbnail: 'thumbnail', fields: ['name', 'description'], details: ['createdAt', 'due'] },\n columns: [\n { type: 'gutter', gutterName: 'sequence', fixed: true },\n {\n type: 'string',\n name: 'name',\n header: i18next.t('field.wl-subject'),\n fixed: true,\n record: {\n editable: false,\n renderer: subjectCell()\n },\n filter: 'search',\n sortable: true,\n width: 250\n },\n {\n /*\n * 설명은 제목 칸 안에서 두 줄로 보인다(activity-cells 의 subjectCell). 그래서 따로 보일 칸이\n * 필요하지 않다.\n *\n * 그런데 **칸을 없애면 설명으로 검색하는 기능이 함께 사라진다.** searchText 는\n * filter: 'search' 를 선언한 컬럼마다 필터를 만들고 hidden 은 보지 않는다\n * (data-grist.ts 의 set searchText). 실측으로 확인했다 — 컬럼을 없앤 뒤 설명에만 있는\n * 낱말로 검색하면 0건이었다.\n *\n * 그래서 감춘 칸으로 남겨 검색만 남긴다.\n */\n type: 'string',\n name: 'description',\n header: i18next.t('field.description'),\n record: { editable: false },\n filter: 'search',\n hidden: true\n },\n {\n type: 'resource-object',\n name: 'creator',\n header: i18next.t('field.wl-drafter'),\n record: { editable: false },\n sortable: true,\n width: 85\n },\n {\n type: 'datetime',\n name: 'dueAt',\n header: i18next.t('field.wl-due'),\n record: {\n editable: false,\n renderer: dueCell(() => this.active)\n },\n sortable: true,\n width: 180\n },\n {\n type: 'number',\n name: 'priority',\n header: i18next.t('field.wl-priority'),\n record: {\n editable: false,\n align: 'center',\n renderer: priorityCell()\n },\n sortable: true,\n width: 70\n },\n {\n type: 'select',\n name: 'state',\n header: i18next.t('field.wl-state'),\n record: {\n editable: false,\n align: 'center',\n options: [\n { display: i18next.t('label.activity-state-unassigned'), value: 'unassigned' },\n { display: i18next.t('label.activity-state-assigned'), value: 'assigned' },\n { display: i18next.t('label.activity-state-started'), value: 'started' },\n { display: i18next.t('label.activity-state-delegated'), value: 'delegated' },\n { display: i18next.t('label.activity-state-submitted'), value: 'submitted' },\n { display: i18next.t('label.activity-state-escalated'), value: 'escalated' },\n { display: i18next.t('label.activity-state-rejected'), value: 'rejected' },\n { display: i18next.t('label.activity-state-ended'), value: 'ended' },\n { display: i18next.t('label.activity-state-aborted'), value: 'aborted' }\n ]\n },\n width: 85\n },\n {\n type: 'datetime',\n name: 'createdAt',\n header: i18next.t('field.wl-submitted-at'),\n record: { editable: false },\n sortable: true,\n filter: false,\n width: 180\n },\n {\n type: 'string',\n name: 'uiSource',\n header: i18next.t('field.wl-view-source'),\n record: {\n editable: false,\n renderer: function (value, column, record, rowIndex, field) {\n const { uiType, uiSource } = record.activity || {}\n var type = uiType !== 'board' ? 'string' : 'board'\n return getRenderer(type)(uiSource, column, record, rowIndex, field)\n }\n },\n width: 140,\n hidden: true\n },\n {\n type: 'image',\n name: 'thumbnail',\n header: i18next.t('field.thumbnail'),\n record: { editable: false },\n hidden: true\n }\n ],\n rows: {\n appendable: false,\n editable: false,\n handlers: {\n click: (columns, data, column, record, rowIndex) => {\n this.openActivityThread(record)\n }\n }\n },\n sorters: [{ name: 'dueAt', desc: false }],\n pagination: { limit: 50, pages: [20, 50, 100, 500] }\n }\n }\n\n async pageUpdated(changes, lifecycle, changedBefore) {\n if (this.active) {\n this.grist?.fetch()\n }\n }\n\n /* 읽은 것에 그림이 하나도 없으면 카드마다 빈 그림 칸을 세우지 않는다(§ list-thumbnail.ts). */\n async fetchHandler(options: FetchOption) {\n const fetched = await this.fetchRows(options)\n\n this.gristConfig = listWithThumbnail(this.gristConfig, fetched?.records || [])\n\n return fetched\n }\n\n async fetchRows({ page, limit, sortings = [], filters = [] }: FetchOption) {\n if (this.filters?.includes('important')) {\n filters = adjustFilters(filters, importantFilters())\n }\n\n if (this.filters?.includes('due')) {\n filters = adjustFilters(filters, dueSoonFilters())\n }\n\n if (this.filters?.includes('proceeding')) {\n filters = adjustFilters(filters, [{ name: 'state', operator: 'eq', value: ActivityThreadStatus.Started }])\n }\n\n if (this.filters?.includes('pending-approval')) {\n filters = adjustFilters(filters, [\n {\n name: 'state',\n operator: 'in',\n value: [ActivityThreadStatus.Rejected, ActivityThreadStatus.Submitted, ActivityThreadStatus.Escalated]\n }\n ])\n }\n\n const response = await client.query({\n query: gql`\n query ($filters: [Filter!], $pagination: Pagination, $sortings: [Sorting!]) {\n responses: todoList(filters: $filters, pagination: $pagination, sortings: $sortings) {\n items {\n id\n activityInstance {\n activityId: id\n name\n description\n priority\n input\n refBy\n activityType\n uiType\n uiSource\n thumbnail\n updatedAt\n createdAt\n creator {\n id\n name\n }\n }\n state\n output\n dueAt\n assignedAt\n }\n total\n }\n }\n `,\n variables: { filters, pagination: { page, limit }, sortings }\n })\n\n return {\n total: response.data.responses.total || 0,\n records: (response.data.responses.items || []).map(item => {\n return {\n id: item.id,\n state: item.state,\n output: item.output,\n dueAt: item.dueAt,\n assignedAt: item.assignedAt,\n ...item.activityInstance\n }\n })\n }\n }\n\n openActivityThread(activityThread) {\n navigate(`activity-thread/${activityThread.id}?title=${activityThread.name}`)\n }\n\n}\n"]}
1
+ {"version":3,"file":"todo-list-page.js","sourceRoot":"","sources":["../../../client/pages/todo/todo-list-page.ts"],"names":[],"mappings":"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","sourcesContent":["import '@operato/data-grist'\nimport '@operato/data-grist/ox-filters-form.js'\nimport '@operato/input/ox-input-select-buttons.js'\nimport '../../components/work-box-groups.js'\n\nimport gql from 'graphql-tag'\nimport { css, html } from 'lit'\nimport { customElement, property, query, state } from 'lit/decorators.js'\nimport { asyncReplace } from 'lit/directives/async-replace.js'\nimport { DataGrist, FetchOption, getRenderer } from '@operato/data-grist'\nimport { client } from '@operato/graphql'\nimport { dueSoonChip, dueSoonFilters, importantChip, importantFilters } from '../../chip-filters.js'\nimport { i18next, localize } from '@operato/i18n'\nimport { navigate, PageView } from '@operato/shell'\nimport { listWithThumbnail } from './list-thumbnail.js'\nimport { countsOnTab, groupAddress, groupAt, TODO_GROUPS, TodoGroup } from './work-box.js'\nimport { CommonGristStyles, CommonHeaderStyles, ScrollbarStyles, WorkSurfacePageStyles } from '@operato/styles'\nimport { adjustFilters, isMobileDevice, sleep } from '@operato/utils'\n\nimport { p13n } from '@operato/p13n'\n\nimport { dueCell, priorityCell, subjectCell } from '../../activity-cells.js'\n\nimport { ActivityThreadStatus } from '../../types/activity-thread.js'\n\n/** 묶음마다 묻는 목록 — 서버의 세 질의가 같은 줄 모양을 준다. */\nconst QUERY_OF: Record<TodoGroup, string> = {\n todo: 'todoList',\n submitted: 'submittedList',\n completed: 'doneList'\n}\n\nconst MIN = 60\nconst HOUR = 60 * MIN\nconst DAY = 24 * HOUR\n\n@customElement('todo-list-page')\nexport class TodoListPage extends p13n(localize(i18next)(PageView)) {\n static styles = [\n /* The work surface frame for a list screen (ADR-0060 decision 8). */\n WorkSurfacePageStyles,\n ScrollbarStyles,\n CommonGristStyles,\n CommonHeaderStyles,\n css`\n :host {\n --grid-record-emphasized-background-color: #8b0000;\n --grid-record-emphasized-color: #ff6b6b;\n }\n\n /*\n * 제목은 헤드룸에 두지 않는다.\n *\n * MDI 를 켜면 제목이 이미 두 곳에 있다 — 헤더 바와 탭. 여기에 또 두면 한 화면에 같은 글자가\n * 셋이 된다. 그래서 표준 배치의 title 줄을 쓰지 않고 한 줄로 둔다.\n */\n .header {\n grid-template-areas: 'filters actions';\n }\n\n /*\n * ── 헤드룸의 왼쪽 기준선은 표와 같다 ─────────────────────────────────\n * CommonHeaderStyles 의 .filters 는 배경과 모서리와 여백을 가진 영역이다. 그 배경이\n * --md-sys-color-surface 인데 이 제품에서는 바탕색과 같은 값이라, **보이지 않는 영역이\n * 자리만 차지하고** 검색창을 여백만큼(12px) 안쪽으로 밀었다.\n *\n * 실측: 표 왼쪽 끝 212 · 필터 영역 212 · 검색창 224. 화면의 왼쪽 기준선이 둘이 됐다.\n *\n * 그 규칙들은 .header 안에 중첩되어 있어(.header .filters) 밑줄 없는 .filters 로는 이길 수\n * 없다 — 특정도가 0,1,0 대 0,2,0 이다.\n */\n .header .filters {\n padding: 0;\n background: none;\n border-radius: 0;\n gap: 12px;\n }\n\n `\n ]\n\n @property({ type: String }) mode: 'GRID' | 'LIST' | 'CARD' = isMobileDevice() ? 'CARD' : 'GRID'\n\n @query('ox-grist') grist!: DataGrist\n\n @state() gristConfig?: any\n @state() filters?: string[]\n\n /**\n * 지금 어느 묶음을 보고 있나 — 할 것 · 제출한 것 · 완료 (pages/todo/work-box.ts).\n *\n * 내가 올린 건은 내 차례일 때만 여기 있다. 제출하고 결재를 기다리는 동안과 끝난 뒤에는 상신함이\n * 따라간다 — 서버의 myThreadsOfOthersWhere 가 그 경계다.\n */\n @state() private group: TodoGroup = 'todo'\n\n /** 기다리는 두 묶음의 건수. 끝난 묶음은 이력이라 세지 않는다. */\n @state() private counts: Partial<Record<TodoGroup, number>> = {}\n\n get context() {\n return {\n title: i18next.t('title.todo list'),\n /*\n * 검색의 자리는 **기기가 정한다.**\n *\n * PC 에서는 화면 안으로 내린다. 상단 바에 두면 거른 조건과 걸러진 결과가 화면의 위아래 끝으로\n * 갈라지고, 지금 무엇으로 걸렀는지가 목록 옆에서 보이지 않는다.\n *\n * 좁은 화면에서는 상단 바에 그대로 둔다. 헤드룸에 두면 검색창과 필터가 목록을 그만큼 밀어\n * 내리고, 카드 두 장이 화면 밖으로 나간다. 상단 바는 그 자리를 아끼려고 있는 것이다.\n *\n * 이 저장소에는 두 방식이 다 있다 — 헤드룸 50곳, 상단 바 51곳. 정형인 것은 구조\n * (.header / .filters / .filter)이고 검색의 자리는 화면이 정한다.\n */\n /*\n * 검색은 **페이지 제목 줄의 오른쪽 끝**에 둔다 — 다른 화면들과 같은 자리다.\n *\n * 전에는 좁은 화면에서만 여기에 넣고, 넓은 화면에서는 헤드룸의 ox-filters-form 이 검색을\n * 그렸다. 그래서 같은 앱 안에서 검색 상자의 자리가 화면마다 달랐다.\n *\n * 헤드룸에는 좁히는 칩만 남는다. 폼은 without-search 로 남겨 두어, 나중에 어느 칸에\n * filter 를 달면 그 UI 가 저절로 생긴다(비면 아무것도 그리지 않는다).\n */\n search: {\n handler: (search: string) => {\n this.grist.searchText = search\n },\n value: this.grist?.searchText || ''\n },\n filter: {\n handler: () => {\n this.grist.toggleHeadroom()\n }\n },\n help: 'worklist/todo-list-page',\n actions: []\n }\n }\n\n render() {\n const mode = this.mode || (isMobileDevice() ? 'CARD' : 'GRID')\n\n return html`\n <work-box-groups\n .groups=${(\n [\n ['todo', 'label.group-todo', 'text.group-todo-hint'],\n ['submitted', 'label.group-submitted', 'text.group-submitted-hint'],\n ['completed', 'label.group-completed', 'text.group-done-hint']\n ] as const\n ).map(([key, label, hint]) => ({ key, label, hint, count: countsOnTab(key) ? this.counts[key] : undefined }))}\n .selected=${this.group}\n @select=${(e: CustomEvent) => this.selectGroup(e.detail)}\n ></work-box-groups>\n\n <ox-grist class=\"page-fill\"\n .mode=${mode}\n .config=${this.gristConfig}\n .fetchHandler=${this.fetchHandler.bind(this)}\n .personalConfigProvider=${this.getPagePreferenceProvider('ox-grist')!}\n >\n <div slot=\"headroom\" class=\"header\">\n <div class=\"filters\">\n <!-- 좁은 화면에서는 상단 바가 검색을 갖는다(위 context 주석 참조). -->\n <ox-filters-form class=\"filter\" without-search></ox-filters-form>\n <ox-input-select-buttons\n .value=${this.filters}\n .options=${this.chips()}\n @change=${(e: CustomEvent) => {\n this.filters = (e.currentTarget as any)?.value\n this.grist.fetch()\n }}\n ></ox-input-select-buttons>\n <!-- <ox-filters-form class=\"filter\" autofocus without-search></ox-filters-form> -->\n </div>\n\n </div>\n\n <ox-grist-personalizer slot=\"setting\"></ox-grist-personalizer>\n </ox-grist>\n `\n }\n\n /** 묶음마다 좁히는 칩이 다르다 — 끝난 일에 「만기」는 물음이 아니다. */\n private chips() {\n switch (this.group) {\n case 'todo':\n return [importantChip(), dueSoonChip(), { display: i18next.t('label.filter-proceeding'), value: 'proceeding' }]\n case 'submitted':\n return [importantChip(), dueSoonChip()]\n case 'completed':\n return [\n importantChip(),\n { display: i18next.t('label.filter-recent'), value: 'recent' },\n { display: i18next.t('label.filter-aborted'), value: 'aborted' }\n ]\n }\n }\n\n /** 주소만 바꾼다 — 목록도 설정도 pageUpdated 가 한 벌로 다시 세운다. */\n private selectGroup(group: TodoGroup) {\n if (this.group === group) {\n return\n }\n\n navigate(groupAddress((this as any).lifecycle?.page, group, TODO_GROUPS))\n }\n\n private syncGroup(key?: string) {\n const group = groupAt(key, TODO_GROUPS)\n\n if (this.group === group && this.gristConfig) {\n return\n }\n\n this.group = group\n this.filters = []\n this.applyConfig()\n }\n\n /** 안 보고 있는 기다리는 묶음의 건수 — 한 줄만 받아 total 을 읽는다. 못 읽은 수는 0 이 아니다. */\n private async countOther() {\n const other = this.group === 'submitted' ? 'todo' : 'submitted'\n const response = await client.query({\n query: gql`\n query ($pagination: Pagination) {\n responses: ${QUERY_OF[other]}(pagination: $pagination) {\n total\n }\n }\n `,\n variables: { pagination: { page: 1, limit: 1 } },\n fetchPolicy: 'no-cache'\n })\n\n const total = response.errors?.length ? undefined : response.data?.responses?.total\n if (typeof total == 'number') this.counts = { ...this.counts, [other]: total }\n }\n\n async pageInitialized(lifecycle) {\n /* pageUpdated 가 이 함수보다 먼저 지나가므로 주소로 바로 들어온 경우는 여기서 잡힌다. */\n this.syncGroup(lifecycle?.resourceId)\n await this.countOther()\n }\n\n private applyConfig() {\n const completed = this.group === 'completed'\n\n this.gristConfig = {\n list: { thumbnail: 'thumbnail', fields: ['name', 'description'], details: ['createdAt', 'due'] },\n columns: [\n { type: 'gutter', gutterName: 'sequence', fixed: true },\n {\n type: 'string',\n name: 'name',\n header: i18next.t('field.wl-subject'),\n fixed: true,\n record: {\n editable: false,\n renderer: subjectCell()\n },\n filter: 'search',\n sortable: true,\n width: 250\n },\n {\n /*\n * 설명은 제목 칸 안에서 두 줄로 보인다(activity-cells 의 subjectCell). 그래서 따로 보일 칸이\n * 필요하지 않다.\n *\n * 그런데 **칸을 없애면 설명으로 검색하는 기능이 함께 사라진다.** searchText 는\n * filter: 'search' 를 선언한 컬럼마다 필터를 만들고 hidden 은 보지 않는다\n * (data-grist.ts 의 set searchText). 실측으로 확인했다 — 컬럼을 없앤 뒤 설명에만 있는\n * 낱말로 검색하면 0건이었다.\n *\n * 그래서 감춘 칸으로 남겨 검색만 남긴다.\n */\n type: 'string',\n name: 'description',\n header: i18next.t('field.description'),\n record: { editable: false },\n filter: 'search',\n hidden: true\n },\n {\n type: 'resource-object',\n name: 'creator',\n header: i18next.t('field.wl-drafter'),\n record: { editable: false },\n sortable: true,\n width: 85\n },\n /*\n * 기한 — 끝난 일에서는 **다른 날짜 열과 같이** 시각만 적는다.\n *\n * dueCell 은 Date.now() 를 기준으로 「4일 13시간 지남」을 내고 1분마다 다시 센다. 아직 안 끝난\n * 일에는 그게 물음이다 — 지금부터 얼마 남았나. 끝난 일에는 그 물음이 없고, 그대로 두면 **거짓을\n * 말한다.** 기한 안에 끝낸 건도 오늘 날짜가 흐르면 빨간 「N일 지남」으로 바뀐다.\n *\n * 「기한을 지켰나」는 줄마다가 아니라 모아서 보는 물음이다 — activity-stats 의 자리다.\n */\n {\n type: 'datetime',\n name: 'dueAt',\n header: i18next.t('field.wl-due'),\n record: completed ? { editable: false } : { editable: false, renderer: dueCell(() => this.active) },\n sortable: true,\n width: 180\n },\n {\n type: 'number',\n name: 'priority',\n header: i18next.t('field.wl-priority'),\n record: {\n editable: false,\n align: 'center',\n renderer: priorityCell()\n },\n sortable: true,\n width: 70\n },\n {\n type: 'select',\n name: 'state',\n header: i18next.t('field.wl-state'),\n record: {\n editable: false,\n align: 'center',\n options: [\n { display: i18next.t('label.activity-state-unassigned'), value: 'unassigned' },\n { display: i18next.t('label.activity-state-assigned'), value: 'assigned' },\n { display: i18next.t('label.activity-state-started'), value: 'started' },\n { display: i18next.t('label.activity-state-delegated'), value: 'delegated' },\n { display: i18next.t('label.activity-state-submitted'), value: 'submitted' },\n { display: i18next.t('label.activity-state-escalated'), value: 'escalated' },\n { display: i18next.t('label.activity-state-rejected'), value: 'rejected' },\n { display: i18next.t('label.activity-state-ended'), value: 'ended' },\n { display: i18next.t('label.activity-state-aborted'), value: 'aborted' }\n ]\n },\n width: 85\n },\n ...(completed\n ? [\n {\n type: 'datetime',\n name: 'startedAt',\n header: i18next.t('field.wl-started-at'),\n record: { editable: false },\n sortable: true,\n width: 180\n },\n {\n type: 'datetime',\n name: 'terminatedAt',\n header: i18next.t('field.wl-terminated-at'),\n record: { editable: false },\n sortable: true,\n width: 180\n }\n ]\n : []),\n {\n type: 'datetime',\n name: 'createdAt',\n header: i18next.t('field.wl-submitted-at'),\n record: { editable: false },\n sortable: true,\n filter: false,\n width: 180\n },\n {\n type: 'string',\n name: 'uiSource',\n header: i18next.t('field.wl-view-source'),\n record: {\n editable: false,\n renderer: function (value, column, record, rowIndex, field) {\n const { uiType, uiSource } = record.activity || {}\n var type = uiType !== 'board' ? 'string' : 'board'\n return getRenderer(type)(uiSource, column, record, rowIndex, field)\n }\n },\n width: 140,\n hidden: true\n },\n {\n type: 'image',\n name: 'thumbnail',\n header: i18next.t('field.thumbnail'),\n record: { editable: false },\n hidden: true\n }\n ],\n rows: {\n appendable: false,\n editable: false,\n handlers: {\n click: (columns, data, column, record, rowIndex) => {\n this.openActivityThread(record)\n }\n }\n },\n sorters: completed ? [{ name: 'terminatedAt', desc: true }] : [{ name: 'dueAt', desc: false }],\n pagination: { limit: 50, pages: [20, 50, 100, 500] }\n }\n }\n\n async pageUpdated(changes, lifecycle, changedBefore) {\n if (lifecycle?.resourceId !== changedBefore?.resourceId) {\n this.syncGroup(lifecycle?.resourceId)\n await this.countOther()\n }\n\n if (this.active) {\n this.grist?.fetch()\n }\n }\n\n /* 읽은 것에 그림이 하나도 없으면 카드마다 빈 그림 칸을 세우지 않는다(§ list-thumbnail.ts). */\n async fetchHandler(options: FetchOption) {\n const fetched = await this.fetchRows(options)\n\n this.gristConfig = listWithThumbnail(this.gristConfig, fetched?.records || [])\n\n return fetched\n }\n\n async fetchRows({ page, limit, sortings = [], filters = [] }: FetchOption) {\n if (this.filters?.includes('important')) {\n filters = adjustFilters(filters, importantFilters())\n }\n\n if (this.filters?.includes('due')) {\n filters = adjustFilters(filters, dueSoonFilters())\n }\n\n if (this.filters?.includes('proceeding')) {\n filters = adjustFilters(filters, [{ name: 'state', operator: 'eq', value: ActivityThreadStatus.Started }])\n }\n\n if (this.filters?.includes('recent')) {\n /* 최근 24시간 이내에 끝낸 일 */\n const since = new Date(Date.now() - 24 * 3600 * 1000).toISOString().replace('T', ' ')\n filters = adjustFilters(filters, [{ name: 'terminatedAt', operator: 'gte', value: since }])\n }\n\n if (this.filters?.includes('aborted')) {\n filters = adjustFilters(filters, [{ name: 'state', operator: 'eq', value: ActivityThreadStatus.Aborted }])\n }\n\n const response = await client.query({\n query: gql`\n query ($filters: [Filter!], $pagination: Pagination, $sortings: [Sorting!]) {\n responses: ${QUERY_OF[this.group]}(filters: $filters, pagination: $pagination, sortings: $sortings) {\n items {\n id\n activityInstance {\n activityId: id\n name\n description\n priority\n input\n refBy\n activityType\n uiType\n uiSource\n thumbnail\n updatedAt\n createdAt\n creator {\n id\n name\n }\n }\n state\n output\n dueAt\n assignedAt\n startedAt\n terminatedAt\n }\n total\n }\n }\n `,\n variables: { filters, pagination: { page, limit }, sortings }\n })\n\n const total = response.data.responses.total || 0\n /* 보고 있는 묶음의 수는 이 조회가 알려 준다. 나머지는 countOther 가 센다. */\n if (countsOnTab(this.group)) this.counts = { ...this.counts, [this.group]: total }\n\n return {\n total,\n records: (response.data.responses.items || []).map(item => {\n return {\n ...item.activityInstance,\n id: item.id,\n state: item.state,\n output: item.output,\n dueAt: item.dueAt,\n assignedAt: item.assignedAt,\n startedAt: item.startedAt,\n terminatedAt: item.terminatedAt\n }\n })\n }\n }\n\n /** 끝난 일은 보기 화면으로 연다 — 고칠 것이 없는 화면에 저장 · 제출이 서면 안 된다. */\n openActivityThread(activityThread) {\n const page = this.group === 'completed' ? 'activity-thread-view' : 'activity-thread'\n navigate(`${page}/${activityThread.id}?title=${activityThread.name}`)\n }\n\n}\n"]}
@@ -0,0 +1,36 @@
1
+ /**
2
+ * The three boxes of my work, and the groups each one is split into.
3
+ *
4
+ * 할 일 what I have to do 할 것 · 제출한 것 · 완료
5
+ * 내 결재함 what I have to decide 결재할 것 · 참조로 받은 것 · 완료
6
+ * 상신함 what I gave others to do 작성 중 · 진행 중 · 완료
7
+ *
8
+ * Each box ends in its own history, so a separate 「완료」 screen is not needed: it listed my
9
+ * threads that ended, which mixed work I finished for someone with my own requests that someone
10
+ * else decided. The first group of each box is what waits on me, and it is what the badge counts.
11
+ *
12
+ * Kept free of imports so the test runner can hold it.
13
+ */
14
+ export declare const TODO_GROUPS: readonly ["todo", "submitted", "completed"];
15
+ export declare const APPROVAL_GROUPS: readonly ["approval", "reference", "completed"];
16
+ export declare const DRAFT_GROUPS: readonly ["draft", "progress", "completed"];
17
+ export type TodoGroup = (typeof TODO_GROUPS)[number];
18
+ export type ApprovalGroup = (typeof APPROVAL_GROUPS)[number];
19
+ export type DraftGroup = (typeof DRAFT_GROUPS)[number];
20
+ /**
21
+ * The address names the group: `todo-list/submitted`. What is listed changes, so it is part of the
22
+ * address and can be sent to someone, unlike a filter. No name, or one the box does not have, is
23
+ * the first group.
24
+ */
25
+ export declare function groupAt<G extends string>(resourceId: string | undefined | null, groups: readonly G[]): G;
26
+ /** The address of a group - the first group is the page itself. */
27
+ export declare function groupAddress<G extends string>(page: string, group: G, groups: readonly G[]): string;
28
+ /** A finished group is history, so it has no count on its tab. */
29
+ export declare function countsOnTab(group: string): boolean;
30
+ /**
31
+ * 상신함 groups by the state of what I put up (ActivityInstanceStatus, written out).
32
+ *
33
+ * Every state is in exactly one group - test/work-box.test.ts holds this to the server's enum, so a
34
+ * new state cannot fall out of the box unseen.
35
+ */
36
+ export declare const DRAFT_GROUP_STATES: Record<DraftGroup, readonly string[]>;
@@ -0,0 +1,44 @@
1
+ /**
2
+ * The three boxes of my work, and the groups each one is split into.
3
+ *
4
+ * 할 일 what I have to do 할 것 · 제출한 것 · 완료
5
+ * 내 결재함 what I have to decide 결재할 것 · 참조로 받은 것 · 완료
6
+ * 상신함 what I gave others to do 작성 중 · 진행 중 · 완료
7
+ *
8
+ * Each box ends in its own history, so a separate 「완료」 screen is not needed: it listed my
9
+ * threads that ended, which mixed work I finished for someone with my own requests that someone
10
+ * else decided. The first group of each box is what waits on me, and it is what the badge counts.
11
+ *
12
+ * Kept free of imports so the test runner can hold it.
13
+ */
14
+ export const TODO_GROUPS = ['todo', 'submitted', 'completed'];
15
+ export const APPROVAL_GROUPS = ['approval', 'reference', 'completed'];
16
+ export const DRAFT_GROUPS = ['draft', 'progress', 'completed'];
17
+ /**
18
+ * The address names the group: `todo-list/submitted`. What is listed changes, so it is part of the
19
+ * address and can be sent to someone, unlike a filter. No name, or one the box does not have, is
20
+ * the first group.
21
+ */
22
+ export function groupAt(resourceId, groups) {
23
+ return groups.includes(String(resourceId)) ? resourceId : groups[0];
24
+ }
25
+ /** The address of a group - the first group is the page itself. */
26
+ export function groupAddress(page, group, groups) {
27
+ return group === groups[0] ? page : `${page}/${group}`;
28
+ }
29
+ /** A finished group is history, so it has no count on its tab. */
30
+ export function countsOnTab(group) {
31
+ return group !== 'completed';
32
+ }
33
+ /**
34
+ * 상신함 groups by the state of what I put up (ActivityInstanceStatus, written out).
35
+ *
36
+ * Every state is in exactly one group - test/work-box.test.ts holds this to the server's enum, so a
37
+ * new state cannot fall out of the box unseen.
38
+ */
39
+ export const DRAFT_GROUP_STATES = {
40
+ draft: ['draft'],
41
+ progress: ['issued', 'unassigned', 'assigned', 'started', 'pending'],
42
+ completed: ['ended', 'aborted']
43
+ };
44
+ //# sourceMappingURL=work-box.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"work-box.js","sourceRoot":"","sources":["../../../client/pages/todo/work-box.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;GAYG;AAEH,MAAM,CAAC,MAAM,WAAW,GAAG,CAAC,MAAM,EAAE,WAAW,EAAE,WAAW,CAAU,CAAA;AACtE,MAAM,CAAC,MAAM,eAAe,GAAG,CAAC,UAAU,EAAE,WAAW,EAAE,WAAW,CAAU,CAAA;AAC9E,MAAM,CAAC,MAAM,YAAY,GAAG,CAAC,OAAO,EAAE,UAAU,EAAE,WAAW,CAAU,CAAA;AAMvE;;;;GAIG;AACH,MAAM,UAAU,OAAO,CAAmB,UAAqC,EAAE,MAAoB;IACnG,OAAQ,MAA4B,CAAC,QAAQ,CAAC,MAAM,CAAC,UAAU,CAAC,CAAC,CAAC,CAAC,CAAE,UAAgB,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,CAAA;AACnG,CAAC;AAED,mEAAmE;AACnE,MAAM,UAAU,YAAY,CAAmB,IAAY,EAAE,KAAQ,EAAE,MAAoB;IACzF,OAAO,KAAK,KAAK,MAAM,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,GAAG,IAAI,IAAI,KAAK,EAAE,CAAA;AACxD,CAAC;AAED,kEAAkE;AAClE,MAAM,UAAU,WAAW,CAAC,KAAa;IACvC,OAAO,KAAK,KAAK,WAAW,CAAA;AAC9B,CAAC;AAED;;;;;GAKG;AACH,MAAM,CAAC,MAAM,kBAAkB,GAA0C;IACvE,KAAK,EAAE,CAAC,OAAO,CAAC;IAChB,QAAQ,EAAE,CAAC,QAAQ,EAAE,YAAY,EAAE,UAAU,EAAE,SAAS,EAAE,SAAS,CAAC;IACpE,SAAS,EAAE,CAAC,OAAO,EAAE,SAAS,CAAC;CAChC,CAAA","sourcesContent":["/**\n * The three boxes of my work, and the groups each one is split into.\n *\n * 할 일 what I have to do 할 것 · 제출한 것 · 완료\n * 내 결재함 what I have to decide 결재할 것 · 참조로 받은 것 · 완료\n * 상신함 what I gave others to do 작성 중 · 진행 중 · 완료\n *\n * Each box ends in its own history, so a separate 「완료」 screen is not needed: it listed my\n * threads that ended, which mixed work I finished for someone with my own requests that someone\n * else decided. The first group of each box is what waits on me, and it is what the badge counts.\n *\n * Kept free of imports so the test runner can hold it.\n */\n\nexport const TODO_GROUPS = ['todo', 'submitted', 'completed'] as const\nexport const APPROVAL_GROUPS = ['approval', 'reference', 'completed'] as const\nexport const DRAFT_GROUPS = ['draft', 'progress', 'completed'] as const\n\nexport type TodoGroup = (typeof TODO_GROUPS)[number]\nexport type ApprovalGroup = (typeof APPROVAL_GROUPS)[number]\nexport type DraftGroup = (typeof DRAFT_GROUPS)[number]\n\n/**\n * The address names the group: `todo-list/submitted`. What is listed changes, so it is part of the\n * address and can be sent to someone, unlike a filter. No name, or one the box does not have, is\n * the first group.\n */\nexport function groupAt<G extends string>(resourceId: string | undefined | null, groups: readonly G[]): G {\n return (groups as readonly string[]).includes(String(resourceId)) ? (resourceId as G) : groups[0]\n}\n\n/** The address of a group - the first group is the page itself. */\nexport function groupAddress<G extends string>(page: string, group: G, groups: readonly G[]): string {\n return group === groups[0] ? page : `${page}/${group}`\n}\n\n/** A finished group is history, so it has no count on its tab. */\nexport function countsOnTab(group: string): boolean {\n return group !== 'completed'\n}\n\n/**\n * 상신함 groups by the state of what I put up (ActivityInstanceStatus, written out).\n *\n * Every state is in exactly one group - test/work-box.test.ts holds this to the server's enum, so a\n * new state cannot fall out of the box unseen.\n */\nexport const DRAFT_GROUP_STATES: Record<DraftGroup, readonly string[]> = {\n draft: ['draft'],\n progress: ['issued', 'unassigned', 'assigned', 'started', 'pending'],\n completed: ['ended', 'aborted']\n}\n"]}
@@ -1 +1 @@
1
- export default function route(page: string): "activity" | "todo-list" | "approval-pending-list" | "draft-list" | "done-list" | "approval-done-list" | "done-list-calendar" | "pickable-list" | "starter-list" | "reporter-list" | "activity-instance-list" | "activity-catalog" | "work-doors-page" | "activity-thread" | "activity-thread-view" | "activity-approval" | "activity-detail" | "activity-list" | "activity-instance-start" | "activity-instance-search" | "activity-template-list" | "activity-store" | "activity-thread-list" | "activity-approval-list" | "installable-activity-list" | "activity-stats-list" | undefined;
1
+ export default function route(page: string): "approval-pending-list" | "todo-list" | "activity" | "done-list-calendar" | "activity-catalog" | "activity-detail" | "work-doors-page" | "approval-done-list" | "draft-list" | "pickable-list" | "starter-list" | "reporter-list" | "activity-list" | "activity-instance-start" | "activity-thread" | "activity-thread-view" | "activity-approval" | "activity-instance-list" | "activity-instance-search" | "activity-template-list" | "activity-store" | "activity-thread-list" | "activity-approval-list" | "installable-activity-list" | "activity-stats-list" | undefined;
@@ -15,9 +15,6 @@ export default function route(page) {
15
15
  case 'todo-list':
16
16
  import('./pages/todo/todo-list-page.js');
17
17
  return page;
18
- case 'done-list':
19
- import('./pages/todo/done-list-page.js');
20
- return page;
21
18
  case 'approval-pending-list':
22
19
  import('./pages/todo/approval-pending-list-page.js');
23
20
  return page;
@@ -1 +1 @@
1
- {"version":3,"file":"route.js","sourceRoot":"","sources":["../client/route.ts"],"names":[],"mappings":"AAAA,MAAM,CAAC,OAAO,UAAU,KAAK,CAAC,IAAY;IACxC,QAAQ,IAAI,EAAE,CAAC;QACb,KAAK,oBAAoB;YACvB,MAAM,CAAC,yCAAyC,CAAC,CAAA;YACjD,OAAO,IAAI,CAAA;QAEb,KAAK,kBAAkB;YACrB,MAAM,CAAC,mDAAmD,CAAC,CAAA;YAC3D,OAAO,IAAI,CAAA;QAEb,KAAK,iBAAiB;YACpB,MAAM,CAAC,kDAAkD,CAAC,CAAA;YAC1D,OAAO,IAAI,CAAA;QAEb,KAAK,iBAAiB;YACpB,MAAM,CAAC,sCAAsC,CAAC,CAAA;YAC9C,OAAO,IAAI,CAAA;QAEb,KAAK,WAAW;YACd,MAAM,CAAC,gCAAgC,CAAC,CAAA;YACxC,OAAO,IAAI,CAAA;QAEb,KAAK,WAAW;YACd,MAAM,CAAC,gCAAgC,CAAC,CAAA;YACxC,OAAO,IAAI,CAAA;QAEb,KAAK,uBAAuB;YAC1B,MAAM,CAAC,4CAA4C,CAAC,CAAA;YACpD,OAAO,IAAI,CAAA;QAEb,KAAK,oBAAoB;YACvB,MAAM,CAAC,yCAAyC,CAAC,CAAA;YACjD,OAAO,IAAI,CAAA;QAEb,KAAK,YAAY;YACf,MAAM,CAAC,iCAAiC,CAAC,CAAA;YACzC,OAAO,IAAI,CAAA;QAEb,KAAK,eAAe;YAClB,MAAM,CAAC,oCAAoC,CAAC,CAAA;YAC5C,OAAO,IAAI,CAAA;QAEb,KAAK,cAAc;YACjB,MAAM,CAAC,uCAAuC,CAAC,CAAA;YAC/C,OAAO,IAAI,CAAA;QAEb,KAAK,eAAe;YAClB,MAAM,CAAC,mDAAmD,CAAC,CAAA;YAC3D,OAAO,IAAI,CAAA;QAEb,KAAK,eAAe;YAClB,MAAM,CAAC,wCAAwC,CAAC,CAAA;YAChD,OAAO,IAAI,CAAA;QAEb,KAAK,UAAU;YACb,MAAM,CAAC,mCAAmC,CAAC,CAAA;YAC3C,OAAO,IAAI,CAAA;QAEb,KAAK,yBAAyB;YAC5B,MAAM,CAAC,2DAA2D,CAAC,CAAA;YACnE,OAAO,IAAI,CAAA;QAEb,KAAK,iBAAiB;YACpB,MAAM,CAAC,iDAAiD,CAAC,CAAA;YACzD,OAAO,IAAI,CAAA;QAEb,KAAK,sBAAsB;YACzB,MAAM,CAAC,sDAAsD,CAAC,CAAA;YAC9D,OAAO,IAAI,CAAA;QAEb,KAAK,mBAAmB;YACtB,MAAM,CAAC,qDAAqD,CAAC,CAAA;YAC7D,OAAO,IAAI,CAAA;QAEb,KAAK,wBAAwB;YAC3B,MAAM,CAAC,0DAA0D,CAAC,CAAA;YAClE,OAAO,IAAI,CAAA;QAEb,KAAK,0BAA0B;YAC7B,MAAM,CAAC,4DAA4D,CAAC,CAAA;YACpE,OAAO,IAAI,CAAA;QAEb,KAAK,wBAAwB;YAC3B,MAAM,CAAC,0DAA0D,CAAC,CAAA;YAClE,OAAO,IAAI,CAAA;QAEb,KAAK,gBAAgB;YACnB,MAAM,CAAC,+CAA+C,CAAC,CAAA;YACvD,OAAO,IAAI,CAAA;QAEb,KAAK,sBAAsB;YACzB,MAAM,CAAC,sDAAsD,CAAC,CAAA;YAC9D,OAAO,IAAI,CAAA;QAEb,KAAK,wBAAwB;YAC3B,MAAM,CAAC,uDAAuD,CAAC,CAAA;YAC/D,OAAO,IAAI,CAAA;QAEb,KAAK,2BAA2B;YAC9B,MAAM,CAAC,6DAA6D,CAAC,CAAA;YACrE,OAAO,IAAI,CAAA;QAEb,KAAK,qBAAqB;YACxB,MAAM,CAAC,iDAAiD,CAAC,CAAA;YACzD,OAAO,IAAI,CAAA;IACf,CAAC;AACH,CAAC","sourcesContent":["export default function route(page: string) {\n switch (page) {\n case 'done-list-calendar':\n import('./pages/todo/done-list-calendar-page.js')\n return page\n\n case 'activity-catalog':\n import('./pages/activity-catalog/activity-catalog-page.js')\n return page\n\n case 'activity-detail':\n import('./pages/activity-catalog/activity-detail-page.js')\n return page\n\n case 'work-doors-page':\n import('./pages/work-door/work-doors-page.js')\n return page\n\n case 'todo-list':\n import('./pages/todo/todo-list-page.js')\n return page\n\n case 'done-list':\n import('./pages/todo/done-list-page.js')\n return page\n\n case 'approval-pending-list':\n import('./pages/todo/approval-pending-list-page.js')\n return page\n\n case 'approval-done-list':\n import('./pages/todo/approval-done-list-page.js')\n return page\n\n case 'draft-list':\n import('./pages/todo/draft-list-page.js')\n return page\n\n case 'pickable-list':\n import('./pages/todo/pickable-list-page.js')\n return page\n\n case 'starter-list':\n import('./pages/activity/starter-list-page.js')\n return page\n\n case 'reporter-list':\n import('./pages/activity-supervisor/reporter-list-page.js')\n return page\n\n case 'activity-list':\n import('./pages/activity/activity-list-page.js')\n return page\n\n case 'activity':\n import('./pages/activity/activity-page.js')\n return page\n\n case 'activity-instance-start':\n import('./pages/activity-instance/activity-instance-start-page.js')\n return page\n\n case 'activity-thread':\n import('./pages/activity-thread/activity-thread-page.js')\n return page\n\n case 'activity-thread-view':\n import('./pages/activity-thread/activity-thread-view-page.js')\n return page\n\n case 'activity-approval':\n import('./pages/activity-approval/activity-approval-page.js')\n return page\n\n case 'activity-instance-list':\n import('./pages/activity-instance/activity-instance-list-page.js')\n return page\n\n case 'activity-instance-search':\n import('./pages/activity-instance/activity-instance-search-page.js')\n return page\n\n case 'activity-template-list':\n import('./pages/activity-template/activity-template-list-page.js')\n return page\n\n case 'activity-store':\n import('./pages/activity-store/activity-store-page.js')\n return page\n\n case 'activity-thread-list':\n import('./pages/activity-thread/activity-thread-list-page.js')\n return page\n\n case 'activity-approval-list':\n import('./pages/activity-approval/activity-approval-list-page')\n return page\n\n case 'installable-activity-list':\n import('./pages/installable-activity/installable-activity-list-page')\n return page\n\n case 'activity-stats-list':\n import('./pages/activity-stats/activity-stats-list-page')\n return page\n }\n}\n"]}
1
+ {"version":3,"file":"route.js","sourceRoot":"","sources":["../client/route.ts"],"names":[],"mappings":"AAAA,MAAM,CAAC,OAAO,UAAU,KAAK,CAAC,IAAY;IACxC,QAAQ,IAAI,EAAE,CAAC;QACb,KAAK,oBAAoB;YACvB,MAAM,CAAC,yCAAyC,CAAC,CAAA;YACjD,OAAO,IAAI,CAAA;QAEb,KAAK,kBAAkB;YACrB,MAAM,CAAC,mDAAmD,CAAC,CAAA;YAC3D,OAAO,IAAI,CAAA;QAEb,KAAK,iBAAiB;YACpB,MAAM,CAAC,kDAAkD,CAAC,CAAA;YAC1D,OAAO,IAAI,CAAA;QAEb,KAAK,iBAAiB;YACpB,MAAM,CAAC,sCAAsC,CAAC,CAAA;YAC9C,OAAO,IAAI,CAAA;QAEb,KAAK,WAAW;YACd,MAAM,CAAC,gCAAgC,CAAC,CAAA;YACxC,OAAO,IAAI,CAAA;QAEb,KAAK,uBAAuB;YAC1B,MAAM,CAAC,4CAA4C,CAAC,CAAA;YACpD,OAAO,IAAI,CAAA;QAEb,KAAK,oBAAoB;YACvB,MAAM,CAAC,yCAAyC,CAAC,CAAA;YACjD,OAAO,IAAI,CAAA;QAEb,KAAK,YAAY;YACf,MAAM,CAAC,iCAAiC,CAAC,CAAA;YACzC,OAAO,IAAI,CAAA;QAEb,KAAK,eAAe;YAClB,MAAM,CAAC,oCAAoC,CAAC,CAAA;YAC5C,OAAO,IAAI,CAAA;QAEb,KAAK,cAAc;YACjB,MAAM,CAAC,uCAAuC,CAAC,CAAA;YAC/C,OAAO,IAAI,CAAA;QAEb,KAAK,eAAe;YAClB,MAAM,CAAC,mDAAmD,CAAC,CAAA;YAC3D,OAAO,IAAI,CAAA;QAEb,KAAK,eAAe;YAClB,MAAM,CAAC,wCAAwC,CAAC,CAAA;YAChD,OAAO,IAAI,CAAA;QAEb,KAAK,UAAU;YACb,MAAM,CAAC,mCAAmC,CAAC,CAAA;YAC3C,OAAO,IAAI,CAAA;QAEb,KAAK,yBAAyB;YAC5B,MAAM,CAAC,2DAA2D,CAAC,CAAA;YACnE,OAAO,IAAI,CAAA;QAEb,KAAK,iBAAiB;YACpB,MAAM,CAAC,iDAAiD,CAAC,CAAA;YACzD,OAAO,IAAI,CAAA;QAEb,KAAK,sBAAsB;YACzB,MAAM,CAAC,sDAAsD,CAAC,CAAA;YAC9D,OAAO,IAAI,CAAA;QAEb,KAAK,mBAAmB;YACtB,MAAM,CAAC,qDAAqD,CAAC,CAAA;YAC7D,OAAO,IAAI,CAAA;QAEb,KAAK,wBAAwB;YAC3B,MAAM,CAAC,0DAA0D,CAAC,CAAA;YAClE,OAAO,IAAI,CAAA;QAEb,KAAK,0BAA0B;YAC7B,MAAM,CAAC,4DAA4D,CAAC,CAAA;YACpE,OAAO,IAAI,CAAA;QAEb,KAAK,wBAAwB;YAC3B,MAAM,CAAC,0DAA0D,CAAC,CAAA;YAClE,OAAO,IAAI,CAAA;QAEb,KAAK,gBAAgB;YACnB,MAAM,CAAC,+CAA+C,CAAC,CAAA;YACvD,OAAO,IAAI,CAAA;QAEb,KAAK,sBAAsB;YACzB,MAAM,CAAC,sDAAsD,CAAC,CAAA;YAC9D,OAAO,IAAI,CAAA;QAEb,KAAK,wBAAwB;YAC3B,MAAM,CAAC,uDAAuD,CAAC,CAAA;YAC/D,OAAO,IAAI,CAAA;QAEb,KAAK,2BAA2B;YAC9B,MAAM,CAAC,6DAA6D,CAAC,CAAA;YACrE,OAAO,IAAI,CAAA;QAEb,KAAK,qBAAqB;YACxB,MAAM,CAAC,iDAAiD,CAAC,CAAA;YACzD,OAAO,IAAI,CAAA;IACf,CAAC;AACH,CAAC","sourcesContent":["export default function route(page: string) {\n switch (page) {\n case 'done-list-calendar':\n import('./pages/todo/done-list-calendar-page.js')\n return page\n\n case 'activity-catalog':\n import('./pages/activity-catalog/activity-catalog-page.js')\n return page\n\n case 'activity-detail':\n import('./pages/activity-catalog/activity-detail-page.js')\n return page\n\n case 'work-doors-page':\n import('./pages/work-door/work-doors-page.js')\n return page\n\n case 'todo-list':\n import('./pages/todo/todo-list-page.js')\n return page\n\n case 'approval-pending-list':\n import('./pages/todo/approval-pending-list-page.js')\n return page\n\n case 'approval-done-list':\n import('./pages/todo/approval-done-list-page.js')\n return page\n\n case 'draft-list':\n import('./pages/todo/draft-list-page.js')\n return page\n\n case 'pickable-list':\n import('./pages/todo/pickable-list-page.js')\n return page\n\n case 'starter-list':\n import('./pages/activity/starter-list-page.js')\n return page\n\n case 'reporter-list':\n import('./pages/activity-supervisor/reporter-list-page.js')\n return page\n\n case 'activity-list':\n import('./pages/activity/activity-list-page.js')\n return page\n\n case 'activity':\n import('./pages/activity/activity-page.js')\n return page\n\n case 'activity-instance-start':\n import('./pages/activity-instance/activity-instance-start-page.js')\n return page\n\n case 'activity-thread':\n import('./pages/activity-thread/activity-thread-page.js')\n return page\n\n case 'activity-thread-view':\n import('./pages/activity-thread/activity-thread-view-page.js')\n return page\n\n case 'activity-approval':\n import('./pages/activity-approval/activity-approval-page.js')\n return page\n\n case 'activity-instance-list':\n import('./pages/activity-instance/activity-instance-list-page.js')\n return page\n\n case 'activity-instance-search':\n import('./pages/activity-instance/activity-instance-search-page.js')\n return page\n\n case 'activity-template-list':\n import('./pages/activity-template/activity-template-list-page.js')\n return page\n\n case 'activity-store':\n import('./pages/activity-store/activity-store-page.js')\n return page\n\n case 'activity-thread-list':\n import('./pages/activity-thread/activity-thread-list-page.js')\n return page\n\n case 'activity-approval-list':\n import('./pages/activity-approval/activity-approval-list-page')\n return page\n\n case 'installable-activity-list':\n import('./pages/installable-activity/installable-activity-list-page')\n return page\n\n case 'activity-stats-list':\n import('./pages/activity-stats/activity-stats-list-page')\n return page\n }\n}\n"]}