@things-factory/organization 10.0.19 → 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 (78) hide show
  1. package/dist-client/component/approval-line-brief.js +93 -36
  2. package/dist-client/component/approval-line-brief.js.map +1 -1
  3. package/dist-client/component/approval-line-items-editor-popup.d.ts +2 -0
  4. package/dist-client/component/approval-line-items-editor-popup.js +27 -9
  5. package/dist-client/component/approval-line-items-editor-popup.js.map +1 -1
  6. package/dist-client/component/approval-line-items-editor.d.ts +7 -1
  7. package/dist-client/component/approval-line-items-editor.js +67 -3
  8. package/dist-client/component/approval-line-items-editor.js.map +1 -1
  9. package/dist-client/component/approval-line-selector.d.ts +2 -0
  10. package/dist-client/component/approval-line-selector.js +40 -9
  11. package/dist-client/component/approval-line-selector.js.map +1 -1
  12. package/dist-client/component/approval-line-view.d.ts +15 -0
  13. package/dist-client/component/approval-line-view.js +177 -41
  14. package/dist-client/component/approval-line-view.js.map +1 -1
  15. package/dist-client/component/assignees-editor-popup.d.ts +2 -0
  16. package/dist-client/component/assignees-editor-popup.js +27 -8
  17. package/dist-client/component/assignees-editor-popup.js.map +1 -1
  18. package/dist-client/component/department-selector.d.ts +2 -0
  19. package/dist-client/component/department-selector.js +27 -8
  20. package/dist-client/component/department-selector.js.map +1 -1
  21. package/dist-client/component/recipients-editor-popup.d.ts +2 -0
  22. package/dist-client/component/recipients-editor-popup.js +27 -8
  23. package/dist-client/component/recipients-editor-popup.js.map +1 -1
  24. package/dist-client/filters-form/ox-filter-department-object.js +11 -1
  25. package/dist-client/filters-form/ox-filter-department-object.js.map +1 -1
  26. package/dist-client/pages/approval-line/approval-line-list-page.d.ts +121 -0
  27. package/dist-client/pages/approval-line/approval-line-list-page.js +583 -0
  28. package/dist-client/pages/approval-line/approval-line-list-page.js.map +1 -0
  29. package/dist-client/pages/approval-line/common-approval-line-templates-page.d.ts +0 -2
  30. package/dist-client/pages/approval-line/common-approval-line-templates-page.js +27 -11
  31. package/dist-client/pages/approval-line/common-approval-line-templates-page.js.map +1 -1
  32. package/dist-client/pages/approval-line/my-approval-line-templates-page.d.ts +0 -2
  33. package/dist-client/pages/approval-line/my-approval-line-templates-page.js +33 -9
  34. package/dist-client/pages/approval-line/my-approval-line-templates-page.js.map +1 -1
  35. package/dist-client/pages/department/department-list-page.d.ts +0 -2
  36. package/dist-client/pages/department/department-list-page.js +2 -6
  37. package/dist-client/pages/department/department-list-page.js.map +1 -1
  38. package/dist-client/pages/department/department-tree-page.d.ts +0 -10
  39. package/dist-client/pages/department/department-tree-page.js +35 -16
  40. package/dist-client/pages/department/department-tree-page.js.map +1 -1
  41. package/dist-client/pages/employee/employee-list-page.d.ts +0 -2
  42. package/dist-client/pages/employee/employee-list-page.js +2 -6
  43. package/dist-client/pages/employee/employee-list-page.js.map +1 -1
  44. package/dist-client/route.d.ts +1 -1
  45. package/dist-client/route.js +9 -0
  46. package/dist-client/route.js.map +1 -1
  47. package/dist-client/tsconfig.tsbuildinfo +1 -1
  48. package/dist-client/types/approval-line.d.ts +64 -0
  49. package/dist-client/types/approval-line.js +67 -0
  50. package/dist-client/types/approval-line.js.map +1 -1
  51. package/dist-server/service/approval-line/approval-line-item.d.ts +40 -0
  52. package/dist-server/service/approval-line/approval-line-item.js +42 -2
  53. package/dist-server/service/approval-line/approval-line-item.js.map +1 -1
  54. package/dist-server/service/approval-line/approval-line-mutation.js +24 -33
  55. package/dist-server/service/approval-line/approval-line-mutation.js.map +1 -1
  56. package/dist-server/service/approval-line/approval-line-query.js +36 -21
  57. package/dist-server/service/approval-line/approval-line-query.js.map +1 -1
  58. package/dist-server/service/employee/employee-query.d.ts +25 -0
  59. package/dist-server/service/employee/employee-query.js +41 -0
  60. package/dist-server/service/employee/employee-query.js.map +1 -1
  61. package/dist-server/service/employee/index.d.ts +1 -0
  62. package/dist-server/service/employee/index.js +3 -0
  63. package/dist-server/service/employee/index.js.map +1 -1
  64. package/dist-server/service/employee/my-employee-refusal.d.ts +22 -0
  65. package/dist-server/service/employee/my-employee-refusal.js +56 -0
  66. package/dist-server/service/employee/my-employee-refusal.js.map +1 -0
  67. package/dist-server/service/employee/my-employee.d.ts +22 -0
  68. package/dist-server/service/employee/my-employee.js +43 -0
  69. package/dist-server/service/employee/my-employee.js.map +1 -0
  70. package/dist-server/tsconfig.tsbuildinfo +1 -1
  71. package/package.json +6 -6
  72. package/spec/unit/my-employee.spec.ts +102 -0
  73. package/things-factory.config.js +1 -0
  74. package/translations/en.json +44 -17
  75. package/translations/ja.json +44 -17
  76. package/translations/ko.json +46 -19
  77. package/translations/ms.json +43 -16
  78. package/translations/zh.json +43 -16
@@ -0,0 +1,583 @@
1
+ import { __decorate, __metadata } from "tslib";
2
+ import '@operato/data-grist';
3
+ import '../../component/approval-line-items-editor-popup';
4
+ import { CommonHeaderStyles, ScrollbarStyles } from '@operato/styles';
5
+ import { navigate, PageView } from '@operato/shell';
6
+ import { css, html } from 'lit';
7
+ import { customElement, property, query, state } from 'lit/decorators.js';
8
+ import { ScopedElementsMixin } from '@open-wc/scoped-elements';
9
+ import { DataGrist } from '@operato/data-grist';
10
+ import { client } from '@operato/graphql';
11
+ import { i18next, localize } from '@operato/i18n';
12
+ import { notify, openPopup } from '@operato/layout';
13
+ import { isMobileDevice } from '@operato/utils';
14
+ import { hasPrivilege } from '@things-factory/auth-base/dist-client';
15
+ import { isReferenceStep } from '../../types/approval-line';
16
+ import gql from 'graphql-tag';
17
+ /**
18
+ * 축마다 자기 질의와 자기 뮤테이션을 갖는다.
19
+ *
20
+ * 이것이 축으로 가른다는 말의 실제 내용이다 — 목록도 저장도 삭제도 섞이지 않는다. 한 「저장」이 두 종류를
21
+ * 함께 바꾸는 일이 구조적으로 일어나지 않는다.
22
+ */
23
+ const AXES = {
24
+ common: {
25
+ list: 'commonApprovalLines',
26
+ updateMultiple: 'updateMultipleApprovalLine',
27
+ update: 'updateApprovalLine',
28
+ remove: 'deleteApprovalLines'
29
+ },
30
+ mine: {
31
+ list: 'myApprovalLines',
32
+ updateMultiple: 'updateMultipleMyApprovalLine',
33
+ update: 'updateMyApprovalLine',
34
+ remove: 'deleteMyApprovalLines'
35
+ }
36
+ };
37
+ /**
38
+ * 결재선 — **한 화면, 두 축.**
39
+ *
40
+ * ── 왜 한 화면인가 ─────────────────────────────────────────────────────────
41
+ * 전에는 「공용 결재선」과 「내 결재선」이 각각 메뉴였다. 같은 것을 관리하는 두 자리라, 찾을 때마다
42
+ * 어느 쪽에 있었는지를 먼저 기억해야 했다.
43
+ *
44
+ * ── 왜 섞지 않고 축으로 가르는가 ────────────────────────────────────────────
45
+ * 두 결재선은 **바꾸는 행위의 무게가 다르다.**
46
+ *
47
+ * 공용 조직의 규정이다. 바꾸면 남의 결재 경로가 바뀐다. 권한이 있어야 고친다
48
+ * 내 결재선 내 편의다. 바꿔도 나만 영향받는다
49
+ *
50
+ * 한 목록에 섞으면 「저장」 한 번이 내 편의 설정과 조직 규정을 함께 저지른다. 축으로 가르면 축마다
51
+ * 질의도 저장도 따로여서 그 일이 일어나지 않는다.
52
+ *
53
+ * 공용 축을 감추지는 않는다 — **누구나 참조할 수 있고, 권한이 있으면 고칠 수도 있다.** 권한이 없으면
54
+ * 그 축에서 고칠 수만 없게 한다.
55
+ *
56
+ * ── 주소가 축을 갖는다 ──────────────────────────────────────────────────────
57
+ * /approval-line-list 공용
58
+ * /approval-line-list/mine 내 결재선
59
+ *
60
+ * 대상이 바뀌는 것이므로 필터와 달리 주소에 담는다. 붙여 보낼 수 있고, 뒤로 가기가 앞 축으로 돌아간다.
61
+ *
62
+ * ── 줄마다 그 결재선이 보인다 ───────────────────────────────────────────────
63
+ * 결재선의 내용은 **누가 몇 번째로 결재하나**다. 이름만 늘어놓고 내용을 팝업에 두면 「팀장만 거치는
64
+ * 게 있었나」를 알려고 줄마다 열어 봐야 한다.
65
+ *
66
+ * 오세진 → 윤가람 [참조] → 한동수
67
+ *
68
+ * 결재자가 하나도 없으면 상신이 곧 완료된다 — 승인 게이트가 있는 척만 하게 된다. 그것도 줄에 적는다.
69
+ */
70
+ let ApprovalLineListPage = class ApprovalLineListPage extends localize(i18next)(ScopedElementsMixin(PageView)) {
71
+ constructor() {
72
+ super(...arguments);
73
+ this.mode = isMobileDevice() ? 'CARD' : 'GRID';
74
+ this.axis = 'common';
75
+ /**
76
+ * 이 사람이 공용 결재선을 고칠 수 있나.
77
+ *
78
+ * `hasPrivilege` 는 프로필을 기다리는 비동기 함수인데 그리스트의 `editable` 은 동기로 불린다. 그래서
79
+ * 한 번 물어 여기에 담는다.
80
+ *
81
+ * **기본값이 false 인 것이 중요하다.** 답이 오기 전 한 순간을 「고칠 수 있음」으로 그리면 그 사이에
82
+ * 누른 사람이 거절당한다.
83
+ */
84
+ this.mayEditCommon = false;
85
+ /**
86
+ * 내가 사원으로 등록되어 있나.
87
+ *
88
+ * 내 결재선은 사원 기록에 매인다 — 서버가 `ownerValue` 를 그 기록의 id 로 채운다. 등록되어 있지
89
+ * 않으면 **만들 수가 없다.** 그것을 미리 알지 못하면 화면이 입력을 다 받아 놓고 저장할 때 실패한다.
90
+ *
91
+ * 없을 수도 있고 둘 이상일 수도 있다(`(domain, user)` 유일 제약이 없다). 여기서 필요한 것은 하나라도
92
+ * 있느냐뿐이다.
93
+ */
94
+ this.amEmployee = false;
95
+ }
96
+ static { this.styles = [
97
+ ScrollbarStyles,
98
+ CommonHeaderStyles,
99
+ css `
100
+ :host {
101
+ display: flex;
102
+ flex-direction: column;
103
+
104
+ width: 100%;
105
+ }
106
+
107
+ ox-grist {
108
+ flex: 1;
109
+ }
110
+
111
+ /* 축 — 표 바깥 위. 결재함의 묶음 탭과 같은 어휘다. */
112
+ .axes {
113
+ flex: none;
114
+ display: flex;
115
+ gap: var(--spacing-large);
116
+ padding: 0 var(--spacing-medium);
117
+ border-bottom: 1px solid var(--ui-line, #d6dbe0);
118
+ }
119
+
120
+ .axes button {
121
+ border: none;
122
+ background: none;
123
+ padding: var(--spacing-medium) 2px calc(var(--spacing-medium) - 2px);
124
+ border-bottom: 2px solid transparent;
125
+ font: inherit;
126
+ font-size: 14px;
127
+ color: var(--ui-muted, #57676f);
128
+ cursor: pointer;
129
+ }
130
+
131
+ .axes button:hover:not([data-selected]) {
132
+ color: var(--ui-ink, #17272f);
133
+ }
134
+
135
+ /* 색은 밑줄이 말한다 — 브랜드 초록은 14px 글자로는 안 읽힌다(대비 3.91). */
136
+ .axes button[data-selected] {
137
+ font-weight: 600;
138
+ color: var(--ui-ink, #17272f);
139
+ border-bottom-color: var(--ui-accent, #262e38);
140
+ }
141
+ `
142
+ ]; }
143
+ /** 지금 축을 고칠 수 있나. 공용은 권한이 있어야 하고, 내 결재선은 언제나 된다. */
144
+ get editable() {
145
+ return this.axis === 'mine' ? this.amEmployee : this.mayEditCommon;
146
+ }
147
+ get context() {
148
+ return {
149
+ title: i18next.t('title.approval-line'),
150
+ search: {
151
+ handler: (search) => {
152
+ this.grist.searchText = search;
153
+ },
154
+ value: this.grist?.searchText || ''
155
+ },
156
+ filter: {
157
+ handler: () => {
158
+ this.grist.toggleHeadroom();
159
+ }
160
+ },
161
+ help: 'organization/approval-line',
162
+ /*
163
+ * 고칠 수 없는 축에서는 저장·삭제 버튼을 두지 않는다.
164
+ *
165
+ * 눌러 놓고 거절당하는 것보다 처음부터 없는 편이 낫다. 그리고 이 축은 **보러 온 자리**라는 것이
166
+ * 버튼 없음으로 말해진다.
167
+ */
168
+ actions: this.editable
169
+ ? [
170
+ {
171
+ icon: 'save',
172
+ title: i18next.t('button.save'),
173
+ action: this.save.bind(this)
174
+ },
175
+ {
176
+ icon: 'delete',
177
+ title: i18next.t('button.delete'),
178
+ action: this.delete.bind(this),
179
+ emphasis: { danger: true }
180
+ }
181
+ ]
182
+ : []
183
+ };
184
+ }
185
+ render() {
186
+ const mode = this.mode || (isMobileDevice() ? 'CARD' : 'GRID');
187
+ return html `
188
+ <div class="axes">
189
+ ${[
190
+ ['common', 'label.approval-line-common'],
191
+ ['mine', 'label.approval-line-mine']
192
+ ].map(([axis, label]) => html `
193
+ <button ?data-selected=${this.axis === axis} @click=${() => this.selectAxis(axis)}>
194
+ ${i18next.t(label)}
195
+ </button>
196
+ `)}
197
+ </div>
198
+
199
+ <ox-grist .mode=${mode} .config=${this.gristConfig} .fetchHandler=${this.fetchHandler.bind(this)}></ox-grist>
200
+ `;
201
+ }
202
+ /**
203
+ * 축을 고른다 — **주소만 바꾼다.**
204
+ *
205
+ * 값을 여기서 세우지 않는다. 바뀐 주소를 `pageUpdated` 가 받아 세운다. 그래야 뒤로 가기와 새로 고침이
206
+ * 같은 자리로 온다.
207
+ */
208
+ selectAxis(axis) {
209
+ if (axis === this.axis) {
210
+ return;
211
+ }
212
+ const page = this.lifecycle?.page || 'approval-line-list';
213
+ navigate(axis === 'common' ? page : `${page}/${axis}`);
214
+ }
215
+ /** 한 사람을 무엇으로 부를까. 이름이 없으면 관리번호라도 보인다 — 빈 칸으로 두지 않는다. */
216
+ approverText(item) {
217
+ return item?.approver?.name || item?.approver?.controlNo || i18next.t('text.approver-unknown');
218
+ }
219
+ async pageInitialized(lifecycle) {
220
+ /*
221
+ * 권한을 먼저 묻는다. 서버 지시자와 **같은 인자**다 —
222
+ * `@privilege(category: "organization", privilege: "mutation", domainOwnerGranted: true)`.
223
+ *
224
+ * `superUserGranted` 는 넣지 않는다. 지시자에 없기 때문이다. 넣으면 슈퍼유저에게 고칠 수 있는 줄로
225
+ * 그려 놓고 서버가 거절한다.
226
+ */
227
+ this.mayEditCommon = !!(await hasPrivilege({
228
+ category: 'organization',
229
+ privilege: 'mutation',
230
+ domainOwnerGranted: true
231
+ }));
232
+ this.amEmployee = await this.askAmEmployee();
233
+ this.axis = lifecycle?.resourceId === 'mine' ? 'mine' : 'common';
234
+ this.applyConfig();
235
+ }
236
+ /**
237
+ * 내가 사원인가를 서버에 묻는다.
238
+ *
239
+ * `myEmployees` 는 권한이 없다 — 「나는 누구인가」는 권한으로 가릴 사실이 아니다. `employees` 는
240
+ * `employee:query` 를 요구해서, 정작 답이 필요한 일반 사원이 물을 수 없다.
241
+ */
242
+ async askAmEmployee() {
243
+ const response = await client.query({
244
+ query: gql `
245
+ query {
246
+ myEmployees {
247
+ id
248
+ }
249
+ }
250
+ `
251
+ });
252
+ return (response.data?.myEmployees || []).length > 0;
253
+ }
254
+ async pageUpdated(changes, after, before) {
255
+ if (after?.resourceId === before?.resourceId) {
256
+ return;
257
+ }
258
+ this.axis = after?.resourceId === 'mine' ? 'mine' : 'common';
259
+ this.applyConfig();
260
+ await this.grist?.fetch();
261
+ }
262
+ applyConfig() {
263
+ /* 고칠 수 있는 축에서만 빈 줄을 내민다 — 적을 수 없는 자리에 적을 칸을 두지 않는다. */
264
+ const editable = this.editable;
265
+ this.gristConfig = {
266
+ list: {
267
+ fields: ['name', 'model'],
268
+ details: ['updatedAt']
269
+ },
270
+ /*
271
+ * 빈 화면이 **왜 비었는지**를 말한다.
272
+ *
273
+ * 사원이 아닌 사람의 「내 결재선」은 「없는 것」이 아니라 **가질 수 없는 것**이다. 그 둘을 같은
274
+ * 문장으로 말하면, 읽은 사람은 만들면 되는 줄 알고 적다가 저장에서 막힌다.
275
+ */
276
+ emptyNote: this.emptyNote(),
277
+ rows: {
278
+ appendable: editable,
279
+ selectable: { multiple: true }
280
+ },
281
+ columns: [
282
+ { type: 'gutter', gutterName: 'sequence', fixed: true },
283
+ ...(editable ? [{ type: 'gutter', gutterName: 'row-selector', fixed: true, multiple: true }] : []),
284
+ {
285
+ type: 'gutter',
286
+ gutterName: 'button',
287
+ fixed: true,
288
+ /*
289
+ * 고칠 수 없는 축에서는 「고치기」가 아니라 「보기」다. 버튼을 없애지는 않는다 — 공용 결재선이
290
+ * 무엇을 거치는지는 누구나 봐야 한다.
291
+ */
292
+ icon: (record) => (!record?.id ? '' : editable ? 'reorder' : 'visibility'),
293
+ iconOnly: false,
294
+ title: (record) => !record?.id ? '' : editable ? i18next.t('button.edit') : i18next.t('button.view'),
295
+ width: 72,
296
+ handlers: {
297
+ click: (columns, data, column, record) => {
298
+ if (!record.id) {
299
+ return;
300
+ }
301
+ const popup = openPopup(html `
302
+ <approval-line-items-editor-popup
303
+ .confirmCallback=${editable
304
+ ? async (model) => {
305
+ await this.updateModel(record, model);
306
+ await this.grist.fetch();
307
+ return false;
308
+ }
309
+ : undefined}
310
+ .value=${record.model}
311
+ ></approval-line-items-editor-popup>
312
+ `, {
313
+ backdrop: true,
314
+ help: 'organization/approval-line-items-editor',
315
+ size: 'large',
316
+ title: editable ? i18next.t('title.approval-line item list') : record.name
317
+ });
318
+ popup.onclosed = () => {
319
+ this.grist?.fetch();
320
+ };
321
+ }
322
+ }
323
+ },
324
+ {
325
+ type: 'string',
326
+ name: 'name',
327
+ fixed: true,
328
+ header: i18next.t('field.name'),
329
+ record: { editable },
330
+ filter: 'search',
331
+ sortable: true,
332
+ width: 220
333
+ },
334
+ {
335
+ /*
336
+ * ── 결재선 자체 ──────────────────────────────────────────────────
337
+ * 이 칸이 이 화면의 이유다. 참조는 결재를 막지 않으므로 결재자와 같은 무게로 읽히면 안 된다 —
338
+ * 표식을 붙여 가른다.
339
+ *
340
+ * 넘치면 잘리므로 `title` 에 전문을 담는다.
341
+ */
342
+ type: 'string',
343
+ name: 'model',
344
+ header: i18next.t('field.approval-line'),
345
+ record: {
346
+ editable: false,
347
+ renderer: (value, column, record) => {
348
+ /* 아직 없는 줄(맨 아래 빈 줄)에는 아무 말도 하지 않는다. */
349
+ if (!record?.id) {
350
+ return html ``;
351
+ }
352
+ const items = Array.isArray(value) ? value : [];
353
+ if (!items.length) {
354
+ /* 결재자가 없으면 상신이 곧 완료된다. 조용히 빈 칸으로 두지 않는다. */
355
+ return html `<span style="color: var(--md-sys-color-error)"
356
+ >${i18next.t('text.approval-line-empty')}</span
357
+ >`;
358
+ }
359
+ const plain = items
360
+ .map(item => isReferenceStep(item)
361
+ ? `${this.approverText(item)} (${i18next.t('label.participation-reference')})`
362
+ : this.approverText(item))
363
+ .join(' → ');
364
+ return html `
365
+ <span
366
+ title=${plain}
367
+ style="display:flex; align-items:center; gap:4px; overflow:hidden; white-space:nowrap"
368
+ >
369
+ ${items.map((item, index) => html `
370
+ ${index > 0 ? html `<span style="color: var(--ui-faint, #8a959c)">→</span>` : ''}
371
+ <span style=${isReferenceStep(item) ? 'color: var(--ui-muted, #57676f)' : ''}
372
+ >${this.approverText(item)}</span
373
+ >
374
+ ${isReferenceStep(item)
375
+ ? html `<em
376
+ style="font-style:normal; font-size:11px; padding:0 4px; border-radius:999px;
377
+ border:1px solid var(--ui-line, #d6dbe0); color: var(--ui-muted, #57676f)"
378
+ >${i18next.t('label.participation-reference')}</em
379
+ >`
380
+ : ''}
381
+ `)}
382
+ </span>
383
+ `;
384
+ }
385
+ },
386
+ width: 340
387
+ },
388
+ {
389
+ type: 'string',
390
+ name: 'description',
391
+ header: i18next.t('field.description'),
392
+ record: { editable },
393
+ filter: 'search',
394
+ width: 220
395
+ },
396
+ {
397
+ type: 'resource-object',
398
+ name: 'updater',
399
+ header: i18next.t('field.updater'),
400
+ record: { editable: false },
401
+ sortable: true,
402
+ width: 90
403
+ },
404
+ {
405
+ type: 'datetime',
406
+ name: 'updatedAt',
407
+ header: i18next.t('field.updated_at'),
408
+ record: { editable: false },
409
+ sortable: true,
410
+ width: 180
411
+ }
412
+ ],
413
+ sorters: [{ name: 'name' }]
414
+ };
415
+ }
416
+ emptyNote() {
417
+ if (this.axis === 'common') {
418
+ return {
419
+ icon: 'approval',
420
+ title: i18next.t('text.no-common-approval-line-title'),
421
+ description: i18next.t('text.no-common-approval-line-description')
422
+ };
423
+ }
424
+ if (!this.amEmployee) {
425
+ return {
426
+ icon: 'badge',
427
+ title: i18next.t('text.not-an-employee-title'),
428
+ description: i18next.t('text.not-an-employee-description')
429
+ };
430
+ }
431
+ return {
432
+ icon: 'approval',
433
+ title: i18next.t('text.no-my-approval-line-title'),
434
+ description: i18next.t('text.no-my-approval-line-description')
435
+ };
436
+ }
437
+ async fetchHandler({ page = 1, limit = 100, sortings = [], filters = [] }) {
438
+ const response = await client.query({
439
+ query: gql `
440
+ query ($filters: [Filter!], $pagination: Pagination, $sortings: [Sorting!]) {
441
+ responses: ${AXES[this.axis].list}(filters: $filters, pagination: $pagination, sortings: $sortings) {
442
+ items {
443
+ id
444
+ name
445
+ description
446
+ ownerType
447
+ model {
448
+ type
449
+ participation
450
+ notifyAfter
451
+ approver {
452
+ id
453
+ name
454
+ description
455
+ controlNo
456
+ }
457
+ }
458
+ updater {
459
+ id
460
+ name
461
+ }
462
+ updatedAt
463
+ }
464
+ total
465
+ }
466
+ }
467
+ `,
468
+ variables: { filters, pagination: { page, limit }, sortings }
469
+ });
470
+ return {
471
+ total: response.data.responses.total || 0,
472
+ records: response.data.responses.items || []
473
+ };
474
+ }
475
+ async save() {
476
+ const dirty = this.grist.dirtyRecords;
477
+ if (!dirty?.length) {
478
+ return;
479
+ }
480
+ const patches = dirty.map((record) => {
481
+ const patch = record.id ? { id: record.id } : {};
482
+ const dirtyFields = record.__dirtyfields__ || {};
483
+ for (const key in dirtyFields) {
484
+ patch[key] = dirtyFields[key].after;
485
+ }
486
+ patch.cuFlag = record.__dirty__;
487
+ /* 공용 축에서 새로 만드는 것은 공용이다 — 서버가 그것을 값으로 안다. */
488
+ if (this.axis === 'common') {
489
+ patch.ownerType = 'Common';
490
+ }
491
+ return patch;
492
+ });
493
+ const response = await client.mutate({
494
+ mutation: gql `
495
+ mutation ($patches: [ApprovalLinePatch!]!) {
496
+ ${AXES[this.axis].updateMultiple}(patches: $patches) {
497
+ name
498
+ }
499
+ }
500
+ `,
501
+ variables: { patches }
502
+ });
503
+ if (response.errors) {
504
+ notify({ level: 'error', message: response.errors.map(error => error.message).join('\n') });
505
+ }
506
+ else {
507
+ notify({ message: i18next.t('text.saved') });
508
+ }
509
+ this.grist.fetch();
510
+ }
511
+ async delete() {
512
+ const ids = (this.grist.selected || []).map((record) => record.id).filter(Boolean);
513
+ if (!ids.length) {
514
+ return;
515
+ }
516
+ if (!confirm(i18next.t('text.sure_to_x', { x: i18next.t('text.delete') }))) {
517
+ return;
518
+ }
519
+ const response = await client.mutate({
520
+ mutation: gql `
521
+ mutation ($ids: [String!]!) {
522
+ ${AXES[this.axis].remove}(ids: $ids)
523
+ }
524
+ `,
525
+ variables: { ids }
526
+ });
527
+ if (response.errors) {
528
+ notify({ level: 'error', message: response.errors.map(error => error.message).join('\n') });
529
+ }
530
+ else {
531
+ notify({ message: i18next.t('text.deleted') });
532
+ }
533
+ this.grist.fetch();
534
+ }
535
+ /** 결재선의 내용(누가 몇 번째로 결재하나)을 저장한다. */
536
+ async updateModel(record, model) {
537
+ const response = await client.mutate({
538
+ mutation: gql `
539
+ mutation ($id: String!, $patch: ApprovalLinePatch!) {
540
+ ${AXES[this.axis].update}(id: $id, patch: $patch) {
541
+ id
542
+ }
543
+ }
544
+ `,
545
+ variables: { id: record.id, patch: { model, cuFlag: 'M' } }
546
+ });
547
+ if (response.errors) {
548
+ notify({ level: 'error', message: response.errors.map(error => error.message).join('\n') });
549
+ }
550
+ else {
551
+ notify({ message: i18next.t('text.saved') });
552
+ }
553
+ }
554
+ };
555
+ __decorate([
556
+ property({ type: Object }),
557
+ __metadata("design:type", Object)
558
+ ], ApprovalLineListPage.prototype, "gristConfig", void 0);
559
+ __decorate([
560
+ property({ type: String }),
561
+ __metadata("design:type", String)
562
+ ], ApprovalLineListPage.prototype, "mode", void 0);
563
+ __decorate([
564
+ query('ox-grist'),
565
+ __metadata("design:type", DataGrist)
566
+ ], ApprovalLineListPage.prototype, "grist", void 0);
567
+ __decorate([
568
+ state(),
569
+ __metadata("design:type", String)
570
+ ], ApprovalLineListPage.prototype, "axis", void 0);
571
+ __decorate([
572
+ state(),
573
+ __metadata("design:type", Object)
574
+ ], ApprovalLineListPage.prototype, "mayEditCommon", void 0);
575
+ __decorate([
576
+ state(),
577
+ __metadata("design:type", Object)
578
+ ], ApprovalLineListPage.prototype, "amEmployee", void 0);
579
+ ApprovalLineListPage = __decorate([
580
+ customElement('approval-line-list-page')
581
+ ], ApprovalLineListPage);
582
+ export { ApprovalLineListPage };
583
+ //# sourceMappingURL=approval-line-list-page.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"approval-line-list-page.js","sourceRoot":"","sources":["../../../client/pages/approval-line/approval-line-list-page.ts"],"names":[],"mappings":"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","sourcesContent":["import '@operato/data-grist'\nimport '../../component/approval-line-items-editor-popup'\n\nimport { CommonHeaderStyles, ScrollbarStyles } from '@operato/styles'\nimport { navigate, PageView } from '@operato/shell'\nimport { css, html } from 'lit'\n\nimport { customElement, property, query, state } from 'lit/decorators.js'\nimport { ScopedElementsMixin } from '@open-wc/scoped-elements'\nimport { DataGrist, FetchOption } from '@operato/data-grist'\nimport { client } from '@operato/graphql'\nimport { i18next, localize } from '@operato/i18n'\nimport { notify, openPopup } from '@operato/layout'\nimport { isMobileDevice } from '@operato/utils'\nimport { hasPrivilege } from '@things-factory/auth-base/dist-client'\n\nimport { ApprovalParticipation, isReferenceStep } from '../../types/approval-line'\n\nimport gql from 'graphql-tag'\n\n/** 어느 축을 보고 있나. 주소의 두 번째 토막이 이 값이다. */\ntype Axis = 'common' | 'mine'\n\n/**\n * 축마다 자기 질의와 자기 뮤테이션을 갖는다.\n *\n * 이것이 축으로 가른다는 말의 실제 내용이다 — 목록도 저장도 삭제도 섞이지 않는다. 한 「저장」이 두 종류를\n * 함께 바꾸는 일이 구조적으로 일어나지 않는다.\n */\nconst AXES: Record<Axis, { list: string; updateMultiple: string; update: string; remove: string }> = {\n common: {\n list: 'commonApprovalLines',\n updateMultiple: 'updateMultipleApprovalLine',\n update: 'updateApprovalLine',\n remove: 'deleteApprovalLines'\n },\n mine: {\n list: 'myApprovalLines',\n updateMultiple: 'updateMultipleMyApprovalLine',\n update: 'updateMyApprovalLine',\n remove: 'deleteMyApprovalLines'\n }\n}\n\n/**\n * 결재선 — **한 화면, 두 축.**\n *\n * ── 왜 한 화면인가 ─────────────────────────────────────────────────────────\n * 전에는 「공용 결재선」과 「내 결재선」이 각각 메뉴였다. 같은 것을 관리하는 두 자리라, 찾을 때마다\n * 어느 쪽에 있었는지를 먼저 기억해야 했다.\n *\n * ── 왜 섞지 않고 축으로 가르는가 ────────────────────────────────────────────\n * 두 결재선은 **바꾸는 행위의 무게가 다르다.**\n *\n * 공용 조직의 규정이다. 바꾸면 남의 결재 경로가 바뀐다. 권한이 있어야 고친다\n * 내 결재선 내 편의다. 바꿔도 나만 영향받는다\n *\n * 한 목록에 섞으면 「저장」 한 번이 내 편의 설정과 조직 규정을 함께 저지른다. 축으로 가르면 축마다\n * 질의도 저장도 따로여서 그 일이 일어나지 않는다.\n *\n * 공용 축을 감추지는 않는다 — **누구나 참조할 수 있고, 권한이 있으면 고칠 수도 있다.** 권한이 없으면\n * 그 축에서 고칠 수만 없게 한다.\n *\n * ── 주소가 축을 갖는다 ──────────────────────────────────────────────────────\n * /approval-line-list 공용\n * /approval-line-list/mine 내 결재선\n *\n * 대상이 바뀌는 것이므로 필터와 달리 주소에 담는다. 붙여 보낼 수 있고, 뒤로 가기가 앞 축으로 돌아간다.\n *\n * ── 줄마다 그 결재선이 보인다 ───────────────────────────────────────────────\n * 결재선의 내용은 **누가 몇 번째로 결재하나**다. 이름만 늘어놓고 내용을 팝업에 두면 「팀장만 거치는\n * 게 있었나」를 알려고 줄마다 열어 봐야 한다.\n *\n * 오세진 → 윤가람 [참조] → 한동수\n *\n * 결재자가 하나도 없으면 상신이 곧 완료된다 — 승인 게이트가 있는 척만 하게 된다. 그것도 줄에 적는다.\n */\n@customElement('approval-line-list-page')\nexport class ApprovalLineListPage extends localize(i18next)(ScopedElementsMixin(PageView)) {\n static styles = [\n ScrollbarStyles,\n CommonHeaderStyles,\n css`\n :host {\n display: flex;\n flex-direction: column;\n\n width: 100%;\n }\n\n ox-grist {\n flex: 1;\n }\n\n /* 축 — 표 바깥 위. 결재함의 묶음 탭과 같은 어휘다. */\n .axes {\n flex: none;\n display: flex;\n gap: var(--spacing-large);\n padding: 0 var(--spacing-medium);\n border-bottom: 1px solid var(--ui-line, #d6dbe0);\n }\n\n .axes button {\n border: none;\n background: none;\n padding: var(--spacing-medium) 2px calc(var(--spacing-medium) - 2px);\n border-bottom: 2px solid transparent;\n font: inherit;\n font-size: 14px;\n color: var(--ui-muted, #57676f);\n cursor: pointer;\n }\n\n .axes button:hover:not([data-selected]) {\n color: var(--ui-ink, #17272f);\n }\n\n /* 색은 밑줄이 말한다 — 브랜드 초록은 14px 글자로는 안 읽힌다(대비 3.91). */\n .axes button[data-selected] {\n font-weight: 600;\n color: var(--ui-ink, #17272f);\n border-bottom-color: var(--ui-accent, #262e38);\n }\n `\n ]\n\n @property({ type: Object }) gristConfig: any\n @property({ type: String }) mode: 'CARD' | 'GRID' | 'LIST' = isMobileDevice() ? 'CARD' : 'GRID'\n\n @query('ox-grist') private grist!: DataGrist\n\n @state() private axis: Axis = 'common'\n\n /**\n * 이 사람이 공용 결재선을 고칠 수 있나.\n *\n * `hasPrivilege` 는 프로필을 기다리는 비동기 함수인데 그리스트의 `editable` 은 동기로 불린다. 그래서\n * 한 번 물어 여기에 담는다.\n *\n * **기본값이 false 인 것이 중요하다.** 답이 오기 전 한 순간을 「고칠 수 있음」으로 그리면 그 사이에\n * 누른 사람이 거절당한다.\n */\n @state() private mayEditCommon = false\n\n /**\n * 내가 사원으로 등록되어 있나.\n *\n * 내 결재선은 사원 기록에 매인다 — 서버가 `ownerValue` 를 그 기록의 id 로 채운다. 등록되어 있지\n * 않으면 **만들 수가 없다.** 그것을 미리 알지 못하면 화면이 입력을 다 받아 놓고 저장할 때 실패한다.\n *\n * 없을 수도 있고 둘 이상일 수도 있다(`(domain, user)` 유일 제약이 없다). 여기서 필요한 것은 하나라도\n * 있느냐뿐이다.\n */\n @state() private amEmployee = false\n\n /** 지금 축을 고칠 수 있나. 공용은 권한이 있어야 하고, 내 결재선은 언제나 된다. */\n private get editable() {\n return this.axis === 'mine' ? this.amEmployee : this.mayEditCommon\n }\n\n get context() {\n return {\n title: i18next.t('title.approval-line'),\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: 'organization/approval-line',\n /*\n * 고칠 수 없는 축에서는 저장·삭제 버튼을 두지 않는다.\n *\n * 눌러 놓고 거절당하는 것보다 처음부터 없는 편이 낫다. 그리고 이 축은 **보러 온 자리**라는 것이\n * 버튼 없음으로 말해진다.\n */\n actions: this.editable\n ? [\n {\n icon: 'save',\n title: i18next.t('button.save'),\n action: this.save.bind(this)\n },\n {\n icon: 'delete',\n title: i18next.t('button.delete'),\n action: this.delete.bind(this),\n emphasis: { danger: true }\n }\n ]\n : []\n }\n }\n\n render() {\n const mode = this.mode || (isMobileDevice() ? 'CARD' : 'GRID')\n\n return html`\n <div class=\"axes\">\n ${(\n [\n ['common', 'label.approval-line-common'],\n ['mine', 'label.approval-line-mine']\n ] as [Axis, string][]\n ).map(\n ([axis, label]) => html`\n <button ?data-selected=${this.axis === axis} @click=${() => this.selectAxis(axis)}>\n ${i18next.t(label)}\n </button>\n `\n )}\n </div>\n\n <ox-grist .mode=${mode} .config=${this.gristConfig} .fetchHandler=${this.fetchHandler.bind(this)}></ox-grist>\n `\n }\n\n /**\n * 축을 고른다 — **주소만 바꾼다.**\n *\n * 값을 여기서 세우지 않는다. 바뀐 주소를 `pageUpdated` 가 받아 세운다. 그래야 뒤로 가기와 새로 고침이\n * 같은 자리로 온다.\n */\n private selectAxis(axis: Axis) {\n if (axis === this.axis) {\n return\n }\n\n const page = this.lifecycle?.page || 'approval-line-list'\n navigate(axis === 'common' ? page : `${page}/${axis}`)\n }\n\n /** 한 사람을 무엇으로 부를까. 이름이 없으면 관리번호라도 보인다 — 빈 칸으로 두지 않는다. */\n private approverText(item: any) {\n return item?.approver?.name || item?.approver?.controlNo || i18next.t('text.approver-unknown')\n }\n\n async pageInitialized(lifecycle: any) {\n /*\n * 권한을 먼저 묻는다. 서버 지시자와 **같은 인자**다 —\n * `@privilege(category: \"organization\", privilege: \"mutation\", domainOwnerGranted: true)`.\n *\n * `superUserGranted` 는 넣지 않는다. 지시자에 없기 때문이다. 넣으면 슈퍼유저에게 고칠 수 있는 줄로\n * 그려 놓고 서버가 거절한다.\n */\n this.mayEditCommon = !!(await hasPrivilege({\n category: 'organization',\n privilege: 'mutation',\n domainOwnerGranted: true\n }))\n\n this.amEmployee = await this.askAmEmployee()\n\n this.axis = lifecycle?.resourceId === 'mine' ? 'mine' : 'common'\n this.applyConfig()\n }\n\n /**\n * 내가 사원인가를 서버에 묻는다.\n *\n * `myEmployees` 는 권한이 없다 — 「나는 누구인가」는 권한으로 가릴 사실이 아니다. `employees` 는\n * `employee:query` 를 요구해서, 정작 답이 필요한 일반 사원이 물을 수 없다.\n */\n private async askAmEmployee() {\n const response = await client.query({\n query: gql`\n query {\n myEmployees {\n id\n }\n }\n `\n })\n\n return (response.data?.myEmployees || []).length > 0\n }\n\n async pageUpdated(changes: any, after: any, before: any) {\n if (after?.resourceId === before?.resourceId) {\n return\n }\n\n this.axis = after?.resourceId === 'mine' ? 'mine' : 'common'\n this.applyConfig()\n await this.grist?.fetch()\n }\n\n private applyConfig() {\n /* 고칠 수 있는 축에서만 빈 줄을 내민다 — 적을 수 없는 자리에 적을 칸을 두지 않는다. */\n const editable = this.editable\n\n this.gristConfig = {\n list: {\n fields: ['name', 'model'],\n details: ['updatedAt']\n },\n /*\n * 빈 화면이 **왜 비었는지**를 말한다.\n *\n * 사원이 아닌 사람의 「내 결재선」은 「없는 것」이 아니라 **가질 수 없는 것**이다. 그 둘을 같은\n * 문장으로 말하면, 읽은 사람은 만들면 되는 줄 알고 적다가 저장에서 막힌다.\n */\n emptyNote: this.emptyNote(),\n rows: {\n appendable: editable,\n selectable: { multiple: true }\n },\n columns: [\n { type: 'gutter', gutterName: 'sequence', fixed: true },\n ...(editable ? [{ type: 'gutter', gutterName: 'row-selector', fixed: true, multiple: true }] : []),\n {\n type: 'gutter',\n gutterName: 'button',\n fixed: true,\n /*\n * 고칠 수 없는 축에서는 「고치기」가 아니라 「보기」다. 버튼을 없애지는 않는다 — 공용 결재선이\n * 무엇을 거치는지는 누구나 봐야 한다.\n */\n icon: (record: any) => (!record?.id ? '' : editable ? 'reorder' : 'visibility'),\n iconOnly: false,\n title: (record: any) =>\n !record?.id ? '' : editable ? i18next.t('button.edit') : i18next.t('button.view'),\n width: 72,\n handlers: {\n click: (columns: any, data: any, column: any, record: any) => {\n if (!record.id) {\n return\n }\n\n const popup = openPopup(\n html`\n <approval-line-items-editor-popup\n .confirmCallback=${editable\n ? async (model: any) => {\n await this.updateModel(record, model)\n await this.grist.fetch()\n\n return false\n }\n : undefined}\n .value=${record.model}\n ></approval-line-items-editor-popup>\n `,\n {\n backdrop: true,\n help: 'organization/approval-line-items-editor',\n size: 'large',\n title: editable ? i18next.t('title.approval-line item list') : record.name\n }\n )\n popup.onclosed = () => {\n this.grist?.fetch()\n }\n }\n }\n },\n {\n type: 'string',\n name: 'name',\n fixed: true,\n header: i18next.t('field.name'),\n record: { editable },\n filter: 'search',\n sortable: true,\n width: 220\n },\n {\n /*\n * ── 결재선 자체 ──────────────────────────────────────────────────\n * 이 칸이 이 화면의 이유다. 참조는 결재를 막지 않으므로 결재자와 같은 무게로 읽히면 안 된다 —\n * 표식을 붙여 가른다.\n *\n * 넘치면 잘리므로 `title` 에 전문을 담는다.\n */\n type: 'string',\n name: 'model',\n header: i18next.t('field.approval-line'),\n record: {\n editable: false,\n renderer: (value: any, column: any, record: any) => {\n /* 아직 없는 줄(맨 아래 빈 줄)에는 아무 말도 하지 않는다. */\n if (!record?.id) {\n return html``\n }\n\n const items = Array.isArray(value) ? value : []\n\n if (!items.length) {\n /* 결재자가 없으면 상신이 곧 완료된다. 조용히 빈 칸으로 두지 않는다. */\n return html`<span style=\"color: var(--md-sys-color-error)\"\n >${i18next.t('text.approval-line-empty')}</span\n >`\n }\n\n const plain = items\n .map(item =>\n isReferenceStep(item)\n ? `${this.approverText(item)} (${i18next.t('label.participation-reference')})`\n : this.approverText(item)\n )\n .join(' → ')\n\n return html`\n <span\n title=${plain}\n style=\"display:flex; align-items:center; gap:4px; overflow:hidden; white-space:nowrap\"\n >\n ${items.map(\n (item, index) => html`\n ${index > 0 ? html`<span style=\"color: var(--ui-faint, #8a959c)\">→</span>` : ''}\n <span style=${isReferenceStep(item) ? 'color: var(--ui-muted, #57676f)' : ''}\n >${this.approverText(item)}</span\n >\n ${isReferenceStep(item)\n ? html`<em\n style=\"font-style:normal; font-size:11px; padding:0 4px; border-radius:999px;\n border:1px solid var(--ui-line, #d6dbe0); color: var(--ui-muted, #57676f)\"\n >${i18next.t('label.participation-reference')}</em\n >`\n : ''}\n `\n )}\n </span>\n `\n }\n },\n width: 340\n },\n {\n type: 'string',\n name: 'description',\n header: i18next.t('field.description'),\n record: { editable },\n filter: 'search',\n width: 220\n },\n {\n type: 'resource-object',\n name: 'updater',\n header: i18next.t('field.updater'),\n record: { editable: false },\n sortable: true,\n width: 90\n },\n {\n type: 'datetime',\n name: 'updatedAt',\n header: i18next.t('field.updated_at'),\n record: { editable: false },\n sortable: true,\n width: 180\n }\n ],\n sorters: [{ name: 'name' }]\n }\n }\n\n private emptyNote() {\n if (this.axis === 'common') {\n return {\n icon: 'approval',\n title: i18next.t('text.no-common-approval-line-title'),\n description: i18next.t('text.no-common-approval-line-description')\n }\n }\n\n if (!this.amEmployee) {\n return {\n icon: 'badge',\n title: i18next.t('text.not-an-employee-title'),\n description: i18next.t('text.not-an-employee-description')\n }\n }\n\n return {\n icon: 'approval',\n title: i18next.t('text.no-my-approval-line-title'),\n description: i18next.t('text.no-my-approval-line-description')\n }\n }\n\n async fetchHandler({ page = 1, limit = 100, sortings = [], filters = [] }: FetchOption) {\n const response = await client.query({\n query: gql`\n query ($filters: [Filter!], $pagination: Pagination, $sortings: [Sorting!]) {\n responses: ${AXES[this.axis].list}(filters: $filters, pagination: $pagination, sortings: $sortings) {\n items {\n id\n name\n description\n ownerType\n model {\n type\n participation\n notifyAfter\n approver {\n id\n name\n description\n controlNo\n }\n }\n updater {\n id\n name\n }\n updatedAt\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 || []\n }\n }\n\n private async save() {\n const dirty = this.grist.dirtyRecords\n if (!dirty?.length) {\n return\n }\n\n const patches = dirty.map((record: any) => {\n const patch: any = record.id ? { id: record.id } : {}\n const dirtyFields = record.__dirtyfields__ || {}\n for (const key in dirtyFields) {\n patch[key] = dirtyFields[key].after\n }\n patch.cuFlag = record.__dirty__\n\n /* 공용 축에서 새로 만드는 것은 공용이다 — 서버가 그것을 값으로 안다. */\n if (this.axis === 'common') {\n patch.ownerType = 'Common'\n }\n\n return patch\n })\n\n const response = await client.mutate({\n mutation: gql`\n mutation ($patches: [ApprovalLinePatch!]!) {\n ${AXES[this.axis].updateMultiple}(patches: $patches) {\n name\n }\n }\n `,\n variables: { patches }\n })\n\n if (response.errors) {\n notify({ level: 'error', message: response.errors.map(error => error.message).join('\\n') })\n } else {\n notify({ message: i18next.t('text.saved') })\n }\n\n this.grist.fetch()\n }\n\n private async delete() {\n const ids = (this.grist.selected || []).map((record: any) => record.id).filter(Boolean)\n if (!ids.length) {\n return\n }\n\n if (!confirm(i18next.t('text.sure_to_x', { x: i18next.t('text.delete') }))) {\n return\n }\n\n const response = await client.mutate({\n mutation: gql`\n mutation ($ids: [String!]!) {\n ${AXES[this.axis].remove}(ids: $ids)\n }\n `,\n variables: { ids }\n })\n\n if (response.errors) {\n notify({ level: 'error', message: response.errors.map(error => error.message).join('\\n') })\n } else {\n notify({ message: i18next.t('text.deleted') })\n }\n\n this.grist.fetch()\n }\n\n /** 결재선의 내용(누가 몇 번째로 결재하나)을 저장한다. */\n private async updateModel(record: any, model: any) {\n const response = await client.mutate({\n mutation: gql`\n mutation ($id: String!, $patch: ApprovalLinePatch!) {\n ${AXES[this.axis].update}(id: $id, patch: $patch) {\n id\n }\n }\n `,\n variables: { id: record.id, patch: { model, cuFlag: 'M' } }\n })\n\n if (response.errors) {\n notify({ level: 'error', message: response.errors.map(error => error.message).join('\\n') })\n } else {\n notify({ message: i18next.t('text.saved') })\n }\n }\n}\n"]}
@@ -1,5 +1,4 @@
1
1
  import '@operato/data-grist';
2
- import '@operato/context/ox-context-page-toolbar.js';
3
2
  import '../../component/approval-line-items-editor-popup';
4
3
  import { PageView } from '@operato/shell';
5
4
  import { FetchOption } from '@operato/data-grist';
@@ -32,7 +31,6 @@ export declare class CommonApprovalLineTemplatesPage extends CommonApprovalLineT
32
31
  danger: boolean;
33
32
  };
34
33
  })[];
35
- toolbar: boolean;
36
34
  };
37
35
  render(): import("lit-html").TemplateResult<1>;
38
36
  pageInitialized(lifecycle: any): Promise<void>;