@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
@@ -1,382 +0,0 @@
1
- import { __decorate, __metadata } from "tslib";
2
- import '@operato/data-grist';
3
- import '@operato/data-grist/ox-filters-form.js';
4
- import '@operato/input/ox-input-select-buttons.js';
5
- import gql from 'graphql-tag';
6
- import { css, html } from 'lit';
7
- import { customElement, property, query, state } from 'lit/decorators.js';
8
- import { DataGrist, getRenderer } from '@operato/data-grist';
9
- import { client } from '@operato/graphql';
10
- import { importantChip, importantFilters } from '../../chip-filters.js';
11
- import { i18next, localize } from '@operato/i18n';
12
- import { navigate, PageView } from '@operato/shell';
13
- import { listWithThumbnail } from './list-thumbnail.js';
14
- import { CommonHeaderStyles, ScrollbarStyles, WorkSurfacePageStyles } from '@operato/styles';
15
- import { adjustFilters, isMobileDevice } from '@operato/utils';
16
- import { ActivityThreadStatus } from '../../types/activity-thread.js';
17
- import { priorityCell, subjectCell } from '../../activity-cells.js';
18
- let DoneListPage = class DoneListPage extends localize(i18next)(PageView) {
19
- constructor() {
20
- super(...arguments);
21
- this.mode = isMobileDevice() ? 'CARD' : 'GRID';
22
- }
23
- static { this.styles = [
24
- /* The work surface frame for a list screen (ADR-0060 decision 8). */
25
- WorkSurfacePageStyles,
26
- ScrollbarStyles,
27
- CommonHeaderStyles,
28
- css `
29
- :host {
30
- --grid-record-emphasized-background-color: #8b0000;
31
- --grid-record-emphasized-color: #ff6b6b;
32
- }
33
-
34
- .header { grid-template-areas: 'filters actions';
35
- }
36
-
37
- /*
38
- * ── 헤드룸의 왼쪽 기준선은 표와 같다 ─────────────────────────────────
39
- * CommonHeaderStyles 의 .filters 는 배경과 모서리와 여백을 가진 영역이다. 그 배경이
40
- * --md-sys-color-surface 인데 이 제품에서는 바탕색과 같은 값이라, **보이지 않는 영역이
41
- * 자리만 차지하고** 검색창을 여백만큼(12px) 안쪽으로 밀었다.
42
- *
43
- * 실측: 표 왼쪽 끝 212 · 필터 영역 212 · 검색창 224. 화면의 왼쪽 기준선이 둘이 됐다.
44
- *
45
- * 그 규칙들은 .header 안에 중첩되어 있어(.header .filters) 밑줄 없는 .filters 로는 이길 수
46
- * 없다 — 특정도가 0,1,0 대 0,2,0 이다.
47
- */
48
- .header .filters {
49
- padding: 0;
50
- background: none;
51
- border-radius: 0;
52
- gap: 12px;
53
- }
54
-
55
- `
56
- ]; }
57
- get context() {
58
- return { title: i18next.t('title.done list'),
59
- /*
60
- * 검색의 자리는 **기기가 정한다.**
61
- *
62
- * PC 에서는 화면 안으로 내린다. 상단 바에 두면 거른 조건과 걸러진 결과가 화면의 위아래 끝으로
63
- * 갈라지고, 지금 무엇으로 걸렀는지가 목록 옆에서 보이지 않는다.
64
- *
65
- * 좁은 화면에서는 상단 바에 그대로 둔다. 헤드룸에 두면 검색창과 필터가 목록을 그만큼 밀어
66
- * 내리고, 카드 두 장이 화면 밖으로 나간다. 상단 바는 그 자리를 아끼려고 있는 것이다.
67
- *
68
- * 이 저장소에는 두 방식이 다 있다 — 헤드룸 50곳, 상단 바 51곳. 정형인 것은 구조
69
- * (.header / .filters / .filter)이고 검색의 자리는 화면이 정한다.
70
- */
71
- /*
72
- * 검색은 **페이지 제목 줄의 오른쪽 끝**에 둔다 — 다른 화면들과 같은 자리다.
73
- *
74
- * 전에는 좁은 화면에서만 여기에 넣고, 넓은 화면에서는 헤드룸의 ox-filters-form 이 검색을
75
- * 그렸다. 그래서 같은 앱 안에서 검색 상자의 자리가 화면마다 달랐다.
76
- *
77
- * 헤드룸에는 좁히는 칩만 남는다. 폼은 without-search 로 남겨 두어, 나중에 어느 칸에
78
- * filter 를 달면 그 UI 가 저절로 생긴다(비면 아무것도 그리지 않는다).
79
- */
80
- search: {
81
- handler: (search) => {
82
- this.grist.searchText = search;
83
- },
84
- value: this.grist?.searchText || ''
85
- },
86
- filter: { handler: () => {
87
- this.grist.toggleHeadroom();
88
- }
89
- },
90
- help: 'worklist/done-list-page',
91
- actions: [] };
92
- }
93
- render() {
94
- const mode = this.mode || (isMobileDevice() ? 'CARD' : 'GRID');
95
- return html `
96
- <ox-grist class="page-fill" .mode=${mode} .config=${this.gristConfig} .fetchHandler=${this.fetchHandler.bind(this)}>
97
- <div slot="headroom" class="header">
98
- <div class="filters">
99
- <!-- 좁은 화면에서는 상단 바가 검색을 갖는다(위 context 주석 참조). -->
100
- <ox-filters-form class="filter" without-search></ox-filters-form>
101
- <ox-input-select-buttons
102
- .value=${this.filters}
103
- .options=${[
104
- importantChip(),
105
- { display: i18next.t('label.filter-recent'),
106
- value: 'recent'
107
- },
108
- { display: i18next.t('label.filter-aborted'),
109
- value: 'aborted'
110
- }
111
- ]}
112
- @change=${(e) => {
113
- this.filters = e.currentTarget?.value;
114
- this.grist.fetch();
115
- }}
116
- ></ox-input-select-buttons>
117
- <!-- <ox-filters-form class="filter" autofocus without-search></ox-filters-form> -->
118
- </div>
119
-
120
- </div>
121
- </ox-grist>
122
- `;
123
- }
124
- async pageInitialized(lifecycle) {
125
- this.gristConfig = { list: { thumbnail: 'thumbnail',
126
- fields: ['name', 'description'],
127
- details: ['createdAt', 'due']
128
- },
129
- columns: [
130
- { type: 'gutter', gutterName: 'sequence', fixed: true },
131
- { type: 'string',
132
- name: 'name',
133
- fixed: true,
134
- header: i18next.t('field.wl-subject'),
135
- record: {
136
- editable: false,
137
- renderer: subjectCell()
138
- },
139
- filter: 'search',
140
- sortable: true,
141
- width: 225
142
- },
143
- {
144
- /*
145
- * 설명은 제목 칸 안에서 두 줄로 보인다(activity-cells 의 subjectCell). 그래서 따로 보일 칸이
146
- * 필요하지 않다.
147
- *
148
- * 그런데 **칸을 없애면 설명으로 검색하는 기능이 함께 사라진다.** searchText 는
149
- * filter: 'search' 를 선언한 컬럼마다 필터를 만들고 hidden 은 보지 않는다
150
- * (data-grist.ts 의 set searchText). 실측으로 확인했다 — 컬럼을 없앤 뒤 설명에만 있는
151
- * 낱말로 검색하면 0건이었다.
152
- *
153
- * 그래서 감춘 칸으로 남겨 검색만 남긴다.
154
- */
155
- type: 'string',
156
- name: 'description',
157
- header: i18next.t('field.description'),
158
- record: { editable: false },
159
- filter: 'search',
160
- hidden: true
161
- },
162
- { type: 'resource-object',
163
- name: 'creator',
164
- header: i18next.t('field.wl-drafter'),
165
- record: { editable: false
166
- },
167
- sortable: true,
168
- width: 85
169
- },
170
- /*
171
- * 기한 — 여기서는 **다른 날짜 열과 같이** 시각만 적는다.
172
- *
173
- * 할 일 · 내 결재함은 dueCell 을 쓴다. 그 셀은 Date.now() 를 기준으로 「4일 13시간 지남」을
174
- * 내고 1분마다 다시 센다. 아직 안 끝난 일에는 그게 물음이다 — 지금부터 얼마 남았나.
175
- *
176
- * 끝난 일에는 그 물음이 없고, 그대로 두면 **거짓을 말한다.** 기한 안에 끝낸 건도 오늘 날짜가
177
- * 흐르면 빨간 「N일 지남」으로 바뀐다. 끝난 일 목록에서 타이머가 도는 것도 셈만 하는 일이다.
178
- *
179
- * 이 줄에는 날짜가 넷이다(기한 · 시작 · 완료 · 상신일). 그중 하나만 빨갛게 소리치고 스스로
180
- * 갱신하던 것이 어긋남이었고, 값 자체는 남을 자리가 있다.
181
- *
182
- * 「기한을 지켰나」는 줄마다가 아니라 모아서 보는 물음이다 — activity-stats 의 자리다.
183
- *
184
- * No renderer either. A custom one (recordedDueCell) stood here first, and its
185
- * toLocaleString call carried no hour12 option, so grist's datetime columns (hour12: false)
186
- * and this one printed the same row two ways — 기한 as 「오후 3:04」 beside 시작 · 완료 ·
187
- * 상신일 as 「15:04」. Written as "like the other date columns" and drawn unlike them. With
188
- * no reason to draw this column specially, the shared renderer is the one that decides.
189
- */
190
- { type: 'datetime',
191
- name: 'dueAt',
192
- header: i18next.t('field.wl-due'),
193
- record: { editable: false
194
- },
195
- sortable: true,
196
- width: 180
197
- },
198
- { type: 'number',
199
- name: 'priority',
200
- header: i18next.t('field.wl-priority'),
201
- record: {
202
- editable: false,
203
- align: 'center',
204
- renderer: priorityCell()
205
- },
206
- width: 75
207
- },
208
- { type: 'select',
209
- name: 'state',
210
- header: i18next.t('field.wl-state'),
211
- record: { editable: false,
212
- options: [
213
- { display: i18next.t('label.activity-state-draft'), value: 'draft' },
214
- { display: i18next.t('label.activity-state-posted'), value: 'posted' },
215
- { display: i18next.t('label.activity-state-unassigned'), value: 'unassigned' },
216
- { display: i18next.t('label.activity-state-assigned'), value: 'assigned' },
217
- { display: i18next.t('label.activity-state-started'), value: 'started' },
218
- { display: i18next.t('label.activity-state-pending'), value: 'pending' },
219
- { display: i18next.t('label.activity-state-escalated'), value: 'escalated' },
220
- { display: i18next.t('label.activity-state-ended'), value: 'ended' },
221
- { display: i18next.t('label.activity-state-aborted'), value: 'aborted' }
222
- ]
223
- },
224
- width: 80
225
- },
226
- { type: 'datetime',
227
- name: 'startedAt',
228
- header: i18next.t('field.wl-started-at'),
229
- record: { editable: false
230
- },
231
- sortable: true,
232
- width: 180
233
- },
234
- { type: 'datetime',
235
- name: 'terminatedAt',
236
- header: i18next.t('field.wl-terminated-at'),
237
- record: { editable: false
238
- },
239
- sortable: true,
240
- width: 180
241
- },
242
- { type: 'datetime',
243
- name: 'createdAt',
244
- header: i18next.t('field.wl-submitted-at'),
245
- record: { editable: false
246
- },
247
- sortable: true,
248
- filter: false,
249
- width: 180
250
- },
251
- { type: 'string',
252
- name: 'viewSource',
253
- header: i18next.t('field.wl-view-source'),
254
- record: { editable: false,
255
- renderer: function (value, column, record, rowIndex, field) {
256
- const { viewType, viewSource } = record.activity || {};
257
- var type = viewType !== 'board' ? 'string' : 'board';
258
- return getRenderer(type)(viewSource, column, record, rowIndex, field);
259
- }
260
- },
261
- width: 140,
262
- hidden: true
263
- },
264
- { type: 'image',
265
- name: 'thumbnail',
266
- header: i18next.t('field.thumbnail'),
267
- record: { editable: false },
268
- hidden: true
269
- }
270
- ],
271
- rows: { appendable: false,
272
- editable: false,
273
- handlers: { click: (columns, data, column, record, rowIndex) => {
274
- this.openActivityThreadViewPage(record);
275
- }
276
- }
277
- },
278
- sorters: [
279
- { name: 'terminatedAt',
280
- desc: true
281
- }
282
- ]
283
- };
284
- }
285
- async pageUpdated(changes, lifecycle, changedBefore) {
286
- if (this.active) {
287
- this.grist?.fetch();
288
- }
289
- }
290
- /* 읽은 것에 그림이 하나도 없으면 카드마다 빈 그림 칸을 세우지 않는다(§ list-thumbnail.ts). */
291
- async fetchHandler(options) {
292
- const fetched = await this.fetchRows(options);
293
- this.gristConfig = listWithThumbnail(this.gristConfig, fetched?.records || []);
294
- return fetched;
295
- }
296
- async fetchRows({ page, limit, sortings = [], filters = [] }) {
297
- if (this.filters?.includes('important')) {
298
- filters = adjustFilters(filters, importantFilters());
299
- }
300
- if (this.filters?.includes('recent')) { /* 최근 24시간 이내에 완료한 작업 */
301
- const since = new Date(Date.now() - 24 * 3600 * 1000).toISOString().replace('T', ' ');
302
- filters = adjustFilters(filters, [{ name: 'terminatedAt', operator: 'gte', value: since }]);
303
- }
304
- if (this.filters?.includes('aborted')) {
305
- filters = adjustFilters(filters, [{ name: 'state', operator: 'eq', value: ActivityThreadStatus.Aborted }]);
306
- }
307
- const response = await client.query({ query: gql `
308
- query ($filters: [Filter!], $pagination: Pagination, $sortings: [Sorting!]) { responses: doneList(filters: $filters, pagination: $pagination, sortings: $sortings) { items { id
309
- activityInstance { activityId: id
310
- name
311
- description
312
- priority
313
- input
314
- refBy
315
- activityType
316
- viewType
317
- viewSource
318
- thumbnail
319
- createdAt
320
- startedAt
321
- terminatedAt
322
- updatedAt
323
- createdAt
324
- creator { id
325
- name
326
- }
327
- }
328
- state
329
- output
330
- dueAt
331
- assignedAt
332
- startedAt
333
- terminatedAt
334
- }
335
- total
336
- }
337
- }
338
- `,
339
- variables: { filters,
340
- pagination: { page, limit },
341
- sortings
342
- }
343
- });
344
- return { total: response.data.responses.total || 0,
345
- records: (response.data.responses.items || []).map(item => {
346
- return { ...item.activityInstance,
347
- id: item.id,
348
- state: item.state,
349
- output: item.output,
350
- dueAt: item.dueAt,
351
- assignedAt: item.assignedAt,
352
- startedAt: item.startedAt,
353
- terminatedAt: item.terminatedAt
354
- };
355
- })
356
- };
357
- }
358
- openActivityThreadViewPage(activityThread) {
359
- navigate(`activity-thread-view/${activityThread.id}?title=${activityThread.name}`);
360
- }
361
- };
362
- __decorate([
363
- property({ type: Object }),
364
- __metadata("design:type", Object)
365
- ], DoneListPage.prototype, "gristConfig", void 0);
366
- __decorate([
367
- property({ type: String }),
368
- __metadata("design:type", String)
369
- ], DoneListPage.prototype, "mode", void 0);
370
- __decorate([
371
- query('ox-grist'),
372
- __metadata("design:type", DataGrist)
373
- ], DoneListPage.prototype, "grist", void 0);
374
- __decorate([
375
- state(),
376
- __metadata("design:type", Array)
377
- ], DoneListPage.prototype, "filters", void 0);
378
- DoneListPage = __decorate([
379
- customElement('done-list-page')
380
- ], DoneListPage);
381
- export { DoneListPage };
382
- //# sourceMappingURL=done-list-page.js.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"done-list-page.js","sourceRoot":"","sources":["../../../client/pages/todo/done-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 { DataGrist, FetchOption, getRenderer } from '@operato/data-grist'\nimport { client } from '@operato/graphql'\nimport { 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 { CommonHeaderStyles, ScrollbarStyles, WorkSurfacePageStyles } from '@operato/styles'\nimport { adjustFilters, isMobileDevice } from '@operato/utils'\n\nimport { ActivityThreadStatus } from '../../types/activity-thread.js'\n\nimport { priorityCell, subjectCell } from '../../activity-cells.js'\n\n@customElement('done-list-page')\nexport class DoneListPage extends localize(i18next)(PageView) { static styles = [\n /* The work surface frame for a list screen (ADR-0060 decision 8). */\n WorkSurfacePageStyles,\n ScrollbarStyles,\n CommonHeaderStyles,\n css`\n :host {\n --grid-record-emphasized-background-color: #8b0000;\n --grid-record-emphasized-color: #ff6b6b;\n }\n\n .header { 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: Object }) gristConfig?: any\n @property({ type: String }) mode: 'GRID' | 'LIST' | 'CARD' = isMobileDevice() ? 'CARD' : 'GRID'\n\n @query('ox-grist') grist!: DataGrist\n\n @state() filters?: string[]\n\n get context() { return { title: i18next.t('title.done 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: { handler: () => { this.grist.toggleHeadroom()\n }\n },\n help: 'worklist/done-list-page',\n actions: []\n }\n }\n\n render() { const mode = this.mode || (isMobileDevice() ? 'CARD' : 'GRID')\n\n return html`\n <ox-grist class=\"page-fill\" .mode=${mode} .config=${this.gristConfig} .fetchHandler=${this.fetchHandler.bind(this)}>\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 { display: i18next.t('label.filter-recent'),\n value: 'recent'\n },\n { display: i18next.t('label.filter-aborted'),\n value: 'aborted'\n }\n ]}\n @change=${(e: CustomEvent) => { 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 </ox-grist>\n `\n }\n\n async pageInitialized(lifecycle) { this.gristConfig = { list: { thumbnail: 'thumbnail',\n fields: ['name', 'description'],\n details: ['createdAt', 'due']\n },\n columns: [\n { type: 'gutter', gutterName: 'sequence', fixed: true },\n { type: 'string',\n name: 'name',\n fixed: true,\n header: i18next.t('field.wl-subject'),\n record: {\n editable: false,\n renderer: subjectCell()\n },\n filter: 'search',\n sortable: true,\n width: 225\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 { type: 'resource-object',\n name: 'creator',\n header: i18next.t('field.wl-drafter'),\n record: { editable: false\n },\n sortable: true,\n width: 85\n },\n /*\n * 기한 — 여기서는 **다른 날짜 열과 같이** 시각만 적는다.\n *\n * 할 일 · 내 결재함은 dueCell 을 쓴다. 그 셀은 Date.now() 를 기준으로 「4일 13시간 지남」을\n * 내고 1분마다 다시 센다. 아직 안 끝난 일에는 그게 물음이다 — 지금부터 얼마 남았나.\n *\n * 끝난 일에는 그 물음이 없고, 그대로 두면 **거짓을 말한다.** 기한 안에 끝낸 건도 오늘 날짜가\n * 흐르면 빨간 「N일 지남」으로 바뀐다. 끝난 일 목록에서 타이머가 도는 것도 셈만 하는 일이다.\n *\n * 이 줄에는 날짜가 넷이다(기한 · 시작 · 완료 · 상신일). 그중 하나만 빨갛게 소리치고 스스로\n * 갱신하던 것이 어긋남이었고, 값 자체는 남을 자리가 있다.\n *\n * 「기한을 지켰나」는 줄마다가 아니라 모아서 보는 물음이다 — activity-stats 의 자리다.\n *\n * No renderer either. A custom one (recordedDueCell) stood here first, and its\n * toLocaleString call carried no hour12 option, so grist's datetime columns (hour12: false)\n * and this one printed the same row two ways — 기한 as 「오후 3:04」 beside 시작 · 완료 ·\n * 상신일 as 「15:04」. Written as \"like the other date columns\" and drawn unlike them. With\n * no reason to draw this column specially, the shared renderer is the one that decides.\n */\n { type: 'datetime',\n name: 'dueAt',\n header: i18next.t('field.wl-due'),\n record: { editable: false\n },\n sortable: true,\n width: 180\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 width: 75\n },\n { type: 'select',\n name: 'state',\n header: i18next.t('field.wl-state'),\n record: { editable: false,\n options: [\n { display: i18next.t('label.activity-state-draft'), value: 'draft' },\n { display: i18next.t('label.activity-state-posted'), value: 'posted' },\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-pending'), value: 'pending' },\n { display: i18next.t('label.activity-state-escalated'), value: 'escalated' },\n { display: i18next.t('label.activity-state-ended'), value: 'ended' },\n { display: i18next.t('label.activity-state-aborted'), value: 'aborted' }\n ]\n },\n width: 80\n },\n { type: 'datetime',\n name: 'startedAt',\n header: i18next.t('field.wl-started-at'),\n record: { editable: false\n },\n sortable: true,\n width: 180\n },\n { type: 'datetime',\n name: 'terminatedAt',\n header: i18next.t('field.wl-terminated-at'),\n record: { editable: false\n },\n sortable: true,\n width: 180\n },\n { type: 'datetime',\n name: 'createdAt',\n header: i18next.t('field.wl-submitted-at'),\n record: { editable: false\n },\n sortable: true,\n filter: false,\n width: 180\n },\n { type: 'string',\n name: 'viewSource',\n header: i18next.t('field.wl-view-source'),\n record: { editable: false,\n renderer: function (value, column, record, rowIndex, field) { const { viewType, viewSource } = record.activity || {}\n var type = viewType !== 'board' ? 'string' : 'board'\n return getRenderer(type)(viewSource, column, record, rowIndex, field)\n }\n },\n width: 140,\n hidden: true\n },\n { type: 'image',\n name: 'thumbnail',\n header: i18next.t('field.thumbnail'),\n record: { editable: false },\n hidden: true\n }\n ],\n rows: { appendable: false,\n editable: false,\n handlers: { click: (columns, data, column, record, rowIndex) => { this.openActivityThreadViewPage(record)\n }\n }\n },\n sorters: [\n { name: 'terminatedAt',\n desc: true\n }\n ]\n }\n }\n\n async pageUpdated(changes, lifecycle, changedBefore) { if (this.active) { 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) { if (this.filters?.includes('important')) { filters = adjustFilters(filters, importantFilters())\n }\n\n if (this.filters?.includes('recent')) { /* 최근 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')) { filters = adjustFilters(filters, [{ name: 'state', operator: 'eq', value: ActivityThreadStatus.Aborted }])\n }\n\n const response = await client.query({ query: gql`\n query ($filters: [Filter!], $pagination: Pagination, $sortings: [Sorting!]) { responses: doneList(filters: $filters, pagination: $pagination, sortings: $sortings) { items { id\n activityInstance { activityId: id\n name\n description\n priority\n input\n refBy\n activityType\n viewType\n viewSource\n thumbnail\n createdAt\n startedAt\n terminatedAt\n updatedAt\n createdAt\n creator { 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,\n pagination: { page, limit },\n sortings\n }\n })\n\n return { total: response.data.responses.total || 0,\n records: (response.data.responses.items || []).map(item => { return { ...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 openActivityThreadViewPage(activityThread) { navigate(`activity-thread-view/${activityThread.id}?title=${activityThread.name}`)\n }\n}\n"]}