@things-factory/dataset 8.0.0-beta.9 → 8.0.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (147) hide show
  1. package/client/activities/activity-data-collect-edit.ts +105 -0
  2. package/client/activities/activity-data-collect-view.ts +91 -0
  3. package/client/activities/activity-data-review-edit.ts +133 -0
  4. package/client/activities/activity-data-review-view.ts +145 -0
  5. package/client/activities/activity-ooc-resolve-edit.ts +195 -0
  6. package/client/activities/activity-ooc-resolve-view.ts +143 -0
  7. package/client/activities/activity-ooc-review-edit.ts +173 -0
  8. package/client/activities/activity-ooc-review-view.ts +129 -0
  9. package/client/bootstrap.ts +35 -0
  10. package/client/components/data-entry-form.ts +109 -0
  11. package/client/index.ts +1 -0
  12. package/client/pages/data-archive/data-archive-list-page.ts +277 -0
  13. package/client/pages/data-archive/data-archive-request-popup.ts +177 -0
  14. package/client/pages/data-entry/data-entry-list-page.ts +464 -0
  15. package/client/pages/data-key-set/data-key-item-list.ts +183 -0
  16. package/client/pages/data-key-set/data-key-set-importer.ts +89 -0
  17. package/client/pages/data-key-set/data-key-set-list-page.ts +413 -0
  18. package/client/pages/data-ooc/data-ooc-list-page.ts +549 -0
  19. package/client/pages/data-ooc/data-ooc-page.ts +164 -0
  20. package/client/pages/data-ooc/data-ooc-view.ts +236 -0
  21. package/client/pages/data-ooc/data-oocs-page.ts +200 -0
  22. package/client/pages/data-report/data-report-embed-page.ts +108 -0
  23. package/client/pages/data-report/data-report-list-page.ts +454 -0
  24. package/client/pages/data-report/data-report-samples-page.ts +174 -0
  25. package/client/pages/data-report/jasper-report-oocs-page.ts +110 -0
  26. package/client/pages/data-report/jasper-report-samples-crosstab-page.ts +110 -0
  27. package/client/pages/data-report/jasper-report-samples-page.ts +110 -0
  28. package/client/pages/data-sample/data-sample-list-page.ts +442 -0
  29. package/client/pages/data-sample/data-sample-page.ts +55 -0
  30. package/client/pages/data-sample/data-sample-search-page.ts +424 -0
  31. package/client/pages/data-sample/data-sample-view.ts +292 -0
  32. package/client/pages/data-sample/data-samples-page.ts +249 -0
  33. package/client/pages/data-sensor/data-sensor-list-page.ts +456 -0
  34. package/client/pages/data-set/data-item-list.ts +304 -0
  35. package/client/pages/data-set/data-set-importer.ts +89 -0
  36. package/client/pages/data-set/data-set-list-page.ts +1078 -0
  37. package/client/pages/data-summary/data-summary-list-page.ts +363 -0
  38. package/client/pages/data-summary/data-summary-period-page.ts +439 -0
  39. package/client/pages/data-summary/data-summary-search-page.ts +426 -0
  40. package/client/pages/data-summary/data-summary-view.ts +133 -0
  41. package/client/route.ts +91 -0
  42. package/client/tsconfig.json +13 -0
  43. package/dist-client/activities/activity-data-review-edit.d.ts +1 -5
  44. package/dist-client/activities/activity-data-review-edit.js +5 -143
  45. package/dist-client/activities/activity-data-review-edit.js.map +1 -1
  46. package/dist-client/pages/data-entry/data-entry-list-page.js +2 -2
  47. package/dist-client/pages/data-entry/data-entry-list-page.js.map +1 -1
  48. package/dist-client/tsconfig.tsbuildinfo +1 -1
  49. package/dist-server/activities/activity-data-review.js +5 -18
  50. package/dist-server/activities/activity-data-review.js.map +1 -1
  51. package/dist-server/activities/activity-ooc-review.js +52 -13
  52. package/dist-server/activities/activity-ooc-review.js.map +1 -1
  53. package/dist-server/controllers/create-data-sample.js +94 -4
  54. package/dist-server/controllers/create-data-sample.js.map +1 -1
  55. package/dist-server/controllers/index.d.ts +0 -3
  56. package/dist-server/controllers/index.js +0 -3
  57. package/dist-server/controllers/index.js.map +1 -1
  58. package/dist-server/service/data-sample/data-sample-query.d.ts +1 -1
  59. package/dist-server/service/data-sample/data-sample-query.js +3 -3
  60. package/dist-server/service/data-sample/data-sample-query.js.map +1 -1
  61. package/dist-server/service/index.d.ts +1 -1
  62. package/dist-server/tsconfig.tsbuildinfo +1 -1
  63. package/package.json +26 -26
  64. package/server/activities/activity-data-collect.ts +100 -0
  65. package/server/activities/activity-data-review.ts +82 -0
  66. package/server/activities/activity-ooc-resolve.ts +123 -0
  67. package/server/activities/activity-ooc-review.ts +144 -0
  68. package/server/activities/index.ts +11 -0
  69. package/server/controllers/create-data-sample.ts +426 -0
  70. package/server/controllers/data-use-case.ts +98 -0
  71. package/server/controllers/finalize-data-collection.ts +388 -0
  72. package/server/controllers/index.ts +3 -0
  73. package/server/controllers/issue-data-collection-task.ts +70 -0
  74. package/server/controllers/jasper-report.ts +186 -0
  75. package/server/controllers/query-data-summary-by-period.ts +178 -0
  76. package/server/controllers/shiny-report.ts +54 -0
  77. package/server/engine/index.ts +1 -0
  78. package/server/engine/task/create-data-sample.ts +100 -0
  79. package/server/engine/task/index.ts +2 -0
  80. package/server/engine/task/issue-collect-data.ts +45 -0
  81. package/server/index.ts +8 -0
  82. package/server/routes.ts +188 -0
  83. package/server/service/data-archive/data-archive-mutation.ts +273 -0
  84. package/server/service/data-archive/data-archive-query.ts +58 -0
  85. package/server/service/data-archive/data-archive-type.ts +48 -0
  86. package/server/service/data-archive/data-archive.ts +69 -0
  87. package/server/service/data-archive/index.ts +6 -0
  88. package/server/service/data-key-set/data-key-item-type.ts +31 -0
  89. package/server/service/data-key-set/data-key-set-mutation.ts +201 -0
  90. package/server/service/data-key-set/data-key-set-query.ts +68 -0
  91. package/server/service/data-key-set/data-key-set-type.ts +70 -0
  92. package/server/service/data-key-set/data-key-set.ts +86 -0
  93. package/server/service/data-key-set/index.ts +6 -0
  94. package/server/service/data-ooc/data-ooc-mutation.ts +154 -0
  95. package/server/service/data-ooc/data-ooc-query.ts +106 -0
  96. package/server/service/data-ooc/data-ooc-subscription.ts +48 -0
  97. package/server/service/data-ooc/data-ooc-type.ts +71 -0
  98. package/server/service/data-ooc/data-ooc.ts +259 -0
  99. package/server/service/data-ooc/index.ts +7 -0
  100. package/server/service/data-sample/data-sample-mutation.ts +18 -0
  101. package/server/service/data-sample/data-sample-query.ts +215 -0
  102. package/server/service/data-sample/data-sample-type.ts +47 -0
  103. package/server/service/data-sample/data-sample.ts +193 -0
  104. package/server/service/data-sample/index.ts +6 -0
  105. package/server/service/data-sensor/data-sensor-mutation.ts +116 -0
  106. package/server/service/data-sensor/data-sensor-query.ts +76 -0
  107. package/server/service/data-sensor/data-sensor-type.ts +104 -0
  108. package/server/service/data-sensor/data-sensor.ts +126 -0
  109. package/server/service/data-sensor/index.ts +6 -0
  110. package/server/service/data-set/data-item-type.ts +155 -0
  111. package/server/service/data-set/data-set-mutation.ts +552 -0
  112. package/server/service/data-set/data-set-query.ts +461 -0
  113. package/server/service/data-set/data-set-type.ts +204 -0
  114. package/server/service/data-set/data-set.ts +326 -0
  115. package/server/service/data-set/index.ts +6 -0
  116. package/server/service/data-set-history/data-set-history-query.ts +126 -0
  117. package/server/service/data-set-history/data-set-history-type.ts +12 -0
  118. package/server/service/data-set-history/data-set-history.ts +217 -0
  119. package/server/service/data-set-history/event-subscriber.ts +17 -0
  120. package/server/service/data-set-history/index.ts +7 -0
  121. package/server/service/data-spec/data-spec-manager.ts +21 -0
  122. package/server/service/data-spec/data-spec-query.ts +21 -0
  123. package/server/service/data-spec/data-spec.ts +45 -0
  124. package/server/service/data-spec/index.ts +5 -0
  125. package/server/service/data-summary/data-summary-mutation.ts +45 -0
  126. package/server/service/data-summary/data-summary-query.ts +179 -0
  127. package/server/service/data-summary/data-summary-type.ts +86 -0
  128. package/server/service/data-summary/data-summary.ts +170 -0
  129. package/server/service/data-summary/index.ts +7 -0
  130. package/server/service/index.ts +57 -0
  131. package/server/tsconfig.json +10 -0
  132. package/server/utils/config-resolver.ts +29 -0
  133. package/server/utils/index.ts +1 -0
  134. package/translations/en.json +0 -3
  135. package/translations/ja.json +0 -3
  136. package/translations/ko.json +0 -3
  137. package/translations/ms.json +0 -3
  138. package/translations/zh.json +0 -3
  139. package/dist-server/controllers/create-data-ooc.d.ts +0 -4
  140. package/dist-server/controllers/create-data-ooc.js +0 -65
  141. package/dist-server/controllers/create-data-ooc.js.map +0 -1
  142. package/dist-server/controllers/issue-ooc-resolve.d.ts +0 -3
  143. package/dist-server/controllers/issue-ooc-resolve.js +0 -49
  144. package/dist-server/controllers/issue-ooc-resolve.js.map +0 -1
  145. package/dist-server/controllers/issue-ooc-review.d.ts +0 -3
  146. package/dist-server/controllers/issue-ooc-review.js +0 -47
  147. package/dist-server/controllers/issue-ooc-review.js.map +0 -1
@@ -0,0 +1,464 @@
1
+ import '@material/web/icon/icon.js'
2
+ import '@operato/data-grist'
3
+ import '@operato/context/ox-context-page-toolbar.js'
4
+ import '@operato/board/ox-board-viewer.js'
5
+ import '../../components/data-entry-form.js'
6
+
7
+ import gql from 'graphql-tag'
8
+ import { css, html } from 'lit'
9
+ import { customElement, property, query, state } from 'lit/decorators.js'
10
+
11
+ import { connect } from 'pwa-helpers/connect-mixin'
12
+
13
+ import { ColumnConfig, DataGrist, FetchOption, SortersControl, getRenderer } from '@operato/data-grist'
14
+ import { OxDataUseCase } from '@operato/dataset'
15
+ import { client } from '@operato/graphql'
16
+ import { i18next, localize } from '@operato/i18n'
17
+ import { openPopup, notify } from '@operato/layout'
18
+ import { InheritedValueType, navigate, PageView, store } from '@operato/shell'
19
+ import { CommonHeaderStyles, ScrollbarStyles } from '@operato/styles'
20
+ import { provider } from '@things-factory/board-ui/dist-client'
21
+ import { OxPopup } from '@operato/popup'
22
+
23
+ const USECASE_OPTIONS = () => {
24
+ return ['', ...OxDataUseCase.getUseCaseNames()].map(name => {
25
+ return {
26
+ display: name,
27
+ value: name
28
+ }
29
+ })
30
+ }
31
+
32
+ const showEntryView = async (columns, data, column, record, rowIndex) => {
33
+ if (!record.isEntryAllowed) {
34
+ notify({
35
+ message: 'You are not allowed to enter data for this dataset',
36
+ level: 'error'
37
+ })
38
+ return
39
+ }
40
+
41
+ const { name, entryType, entryView } = record
42
+ const title = `${name} - ${i18next.t('title.data-entry-form')}`
43
+
44
+ switch (entryType) {
45
+ case 'generated':
46
+ openPopup(html` <data-entry-form .dataSet=${record} style="background-color: white;"></data-entry-form> `, {
47
+ closable: true,
48
+ backdrop: true,
49
+ size: 'large',
50
+ title
51
+ })
52
+ break
53
+
54
+ case 'board':
55
+ const board = {
56
+ id: entryView
57
+ }
58
+ openPopup(
59
+ html`
60
+ <ox-board-viewer
61
+ style="background-color: white;"
62
+ .board=${board}
63
+ .provider=${provider}
64
+ hide-fullscreen
65
+ hide-navigation
66
+ ></ox-board-viewer>
67
+ `,
68
+ {
69
+ closable: true,
70
+ backdrop: true,
71
+ size: 'large',
72
+ title
73
+ }
74
+ )
75
+
76
+ // navigate(`board-viewer/${entryView}?interactive=true&title=${title}`)
77
+ break
78
+
79
+ case 'custom-element':
80
+ break
81
+
82
+ case 'page':
83
+ navigate(entryView)
84
+ break
85
+
86
+ case 'external':
87
+ window.open(entryView, '_blank')
88
+ break
89
+ }
90
+ }
91
+
92
+ const issueDataEntry = async (columns, data, column, record, rowIndex) => {
93
+ if (!record.isSupervisor) {
94
+ notify({
95
+ message: 'You are not allowed to issue data collection for this dataset',
96
+ level: 'error'
97
+ })
98
+ return
99
+ }
100
+
101
+ const response = await client.mutate({
102
+ mutation: gql`
103
+ mutation ($dataSetId: String!) {
104
+ issueDataCollection(dataSetId: $dataSetId)
105
+ }
106
+ `,
107
+ variables: { dataSetId: record.id }
108
+ })
109
+
110
+ if (response.errors) {
111
+ notify({
112
+ message: response.errors[0].message,
113
+ level: 'error'
114
+ })
115
+ } else {
116
+ notify({
117
+ message: 'Data entry task issued successfully'
118
+ })
119
+ }
120
+ }
121
+
122
+ @customElement('data-entry-list-page')
123
+ export class DataEntryListPage extends connect(store)(localize(i18next)(PageView)) {
124
+ static styles = [
125
+ ScrollbarStyles,
126
+ CommonHeaderStyles,
127
+ css`
128
+ :host {
129
+ display: flex;
130
+
131
+ width: 100%;
132
+
133
+ --grid-record-emphasized-background-color: #8b0000;
134
+ --grid-record-emphasized-color: #ff6b6b;
135
+ }
136
+
137
+ ox-grist {
138
+ overflow-y: auto;
139
+ flex: 1;
140
+ }
141
+
142
+ .header {
143
+ grid-template-areas: 'filters actions';
144
+ }
145
+ `
146
+ ]
147
+
148
+ @state() private gristConfig: any
149
+
150
+ @query('ox-grist') private grist!: DataGrist
151
+
152
+ get context() {
153
+ return {
154
+ title: i18next.t('title.data-entry list'),
155
+ search: {
156
+ handler: (search: string) => {
157
+ this.grist.searchText = search
158
+ },
159
+ value: this.grist?.searchText || ''
160
+ },
161
+ filter: {
162
+ handler: () => {
163
+ this.grist.toggleHeadroom()
164
+ }
165
+ },
166
+ help: 'dataset/data-entry-list',
167
+ toolbar: false
168
+ }
169
+ }
170
+
171
+ render() {
172
+ return html`
173
+ <ox-grist
174
+ mode="CARD"
175
+ .config=${this.gristConfig}
176
+ .fetchHandler=${this.fetchHandler.bind(this)}
177
+ ?url-params-sensitive=${this.active}
178
+ >
179
+ <div slot="headroom" class="header">
180
+ <div class="filters">
181
+ <ox-filters-form autofocus without-search></ox-filters-form>
182
+ </div>
183
+ </div>
184
+ </ox-grist>
185
+ `
186
+ }
187
+
188
+ async pageInitialized(lifecycle) {
189
+ this.gristConfig = {
190
+ list: {
191
+ thumbnail: 'entryView',
192
+ fields: ['name', 'description'],
193
+ details: ['schedule', 'type', 'useCase', 'latestCollectedAt', 'prevSchedule', 'nextSchedule']
194
+ },
195
+ columns: [
196
+ {
197
+ type: 'gutter',
198
+ gutterName: 'button',
199
+ icon: record => (record?.isSupervisor || record?.isEntryAllowed ? 'assignment_add' : ''),
200
+ iconOnly: false,
201
+ width: 96,
202
+ fixed: true,
203
+ title: record =>
204
+ record?.isSupervisor || record?.isEntryAllowed ? i18next.t('button.assign-data-collection') : '',
205
+ handlers: {
206
+ click: issueDataEntry
207
+ }
208
+ },
209
+ {
210
+ type: 'gutter',
211
+ gutterName: 'button',
212
+ icon: record => (record?.isEntryAllowed ? 'fact_check' : ''),
213
+ iconOnly: false,
214
+ width: 96,
215
+ fixed: true,
216
+ title: record => (record?.isEntryAllowed ? i18next.t('button.enter-data') : ''),
217
+ handlers: {
218
+ click: showEntryView
219
+ }
220
+ },
221
+ {
222
+ type: 'string',
223
+ name: 'name',
224
+ header: i18next.t('field.name'),
225
+ record: {
226
+ editable: false
227
+ },
228
+ filter: 'search',
229
+ sortable: true,
230
+ width: 150
231
+ },
232
+ {
233
+ type: 'string',
234
+ name: 'description',
235
+ header: i18next.t('field.description'),
236
+ record: {
237
+ editable: false
238
+ },
239
+ filter: 'search',
240
+ width: 200
241
+ },
242
+ {
243
+ type: 'select',
244
+ name: 'type',
245
+ label: true,
246
+ header: i18next.t('field.type'),
247
+ record: {
248
+ editable: false,
249
+ options: [
250
+ {},
251
+ {
252
+ display: i18next.t('text.manually collected'),
253
+ value: 'manual'
254
+ },
255
+ {
256
+ display: i18next.t('text.automatically collected'),
257
+ value: 'automatic'
258
+ }
259
+ ]
260
+ },
261
+ sortable: true,
262
+ filter: true,
263
+ width: 60
264
+ },
265
+ {
266
+ type: 'select',
267
+ name: 'useCase',
268
+ label: true,
269
+ header: i18next.t('field.use-case'),
270
+ record: {
271
+ editable: false,
272
+ options: USECASE_OPTIONS
273
+ },
274
+ sortable: true,
275
+ filter: {
276
+ operator: 'eq',
277
+ options: USECASE_OPTIONS /* in case select options type is a function, filter should have its own options */
278
+ },
279
+ width: 80
280
+ },
281
+ {
282
+ type: 'crontab',
283
+ name: 'schedule',
284
+ label: true,
285
+ header: i18next.t('field.schedule'),
286
+ record: {
287
+ editable: false
288
+ },
289
+ width: 80
290
+ },
291
+ {
292
+ type: 'resource-object',
293
+ name: 'entryRole',
294
+ header: i18next.t('field.entry-role'),
295
+ record: {
296
+ editable: false
297
+ },
298
+ width: 120
299
+ },
300
+ {
301
+ type: 'resource-object',
302
+ name: 'supervisoryRole',
303
+ header: i18next.t('field.supervisory-role'),
304
+ record: {
305
+ editable: false
306
+ },
307
+ width: 120
308
+ },
309
+ {
310
+ type: 'datetime',
311
+ name: 'latestCollectedAt',
312
+ label: true,
313
+ header: i18next.t('field.latest-collected-at'),
314
+ record: {
315
+ editable: false
316
+ },
317
+ width: 180
318
+ },
319
+ {
320
+ type: 'datetime',
321
+ name: 'prevSchedule',
322
+ label: true,
323
+ header: i18next.t('field.prev-schedule'),
324
+ record: {
325
+ editable: false
326
+ },
327
+ width: 180
328
+ },
329
+ {
330
+ type: 'datetime',
331
+ name: 'nextSchedule',
332
+ label: true,
333
+ header: i18next.t('field.next-schedule'),
334
+ record: {
335
+ editable: false
336
+ },
337
+ width: 180
338
+ },
339
+ {
340
+ type: 'string',
341
+ name: 'entryView',
342
+ hidden: true,
343
+ record: {
344
+ editable: false,
345
+ renderer: function (value, column, record, rowIndex, field) {
346
+ const type = record.entryType !== 'board' ? 'string' : 'image'
347
+
348
+ let renderedValue
349
+
350
+ if (record.entryType === 'board' && record.entryBoard?.thumbnail) {
351
+ renderedValue = record.entryBoard.thumbnail
352
+ } else {
353
+ renderedValue = html`<md-icon style="--md-icon-size: 64px;">assignment</md-icon>`
354
+ }
355
+
356
+ return getRenderer(type)(renderedValue, column, record, rowIndex, field)
357
+ }
358
+ },
359
+ handlers: {
360
+ click: (columns, data, column, record, rowIndex) => {
361
+ if (record?.isEntryAllowed) {
362
+ showEntryView(columns, data, column, record, rowIndex)
363
+ }
364
+ }
365
+ }
366
+ }
367
+ ],
368
+ rows: {
369
+ appendable: false,
370
+ editable: false,
371
+ selectable: {
372
+ multiple: false
373
+ },
374
+ classifier: function (record, rowIndex) {}
375
+ },
376
+ sorters: [
377
+ {
378
+ name: 'name'
379
+ }
380
+ ]
381
+ }
382
+ }
383
+
384
+ async fetchHandler({ page, limit, sortings = [], filters = [] }: FetchOption) {
385
+ const response = await client.query({
386
+ query: gql`
387
+ query ($filters: [Filter!], $pagination: Pagination, $sortings: [Sorting!], $inherited: InheritedValueType) {
388
+ responses: dataSetsForEntry(
389
+ filters: $filters
390
+ pagination: $pagination
391
+ sortings: $sortings
392
+ inherited: $inherited
393
+ ) {
394
+ items {
395
+ id
396
+ name
397
+ description
398
+ partitionKeys
399
+ active
400
+ type
401
+ useCase
402
+ schedule
403
+ timezone
404
+ isSupervisor
405
+ isEntryAllowed
406
+ entryRole {
407
+ id
408
+ name
409
+ }
410
+ supervisoryRole {
411
+ id
412
+ name
413
+ }
414
+ entryType
415
+ entryView
416
+ entryBoard {
417
+ thumbnail
418
+ }
419
+ monitorType
420
+ monitorView
421
+ updater {
422
+ id
423
+ name
424
+ }
425
+ reportType
426
+ reportView
427
+ updatedAt
428
+ dataItems {
429
+ name
430
+ description
431
+ active
432
+ hidden
433
+ tag
434
+ group
435
+ type
436
+ unit
437
+ options
438
+ quota
439
+ spec
440
+ stat
441
+ }
442
+ latestCollectedAt
443
+ nextSchedule
444
+ prevSchedule
445
+ nextSummarySchedule
446
+ }
447
+ total
448
+ }
449
+ }
450
+ `,
451
+ variables: {
452
+ filters,
453
+ pagination: { page, limit },
454
+ sortings,
455
+ inherited: InheritedValueType.Include
456
+ }
457
+ })
458
+
459
+ return {
460
+ total: response.data.responses.total || 0,
461
+ records: response.data.responses.items || []
462
+ }
463
+ }
464
+ }
@@ -0,0 +1,183 @@
1
+ import '@material/web/icon/icon.js'
2
+
3
+ import gql from 'graphql-tag'
4
+ import { css, html, LitElement } from 'lit'
5
+ import { customElement, property, query, state } from 'lit/decorators.js'
6
+
7
+ import { client } from '@operato/graphql'
8
+ import { i18next, localize } from '@operato/i18n'
9
+ import { isMobileDevice } from '@operato/utils'
10
+ import { DataGrist, FetchOption } from '@operato/data-grist'
11
+ import { CommonHeaderStyles } from '@operato/styles'
12
+
13
+ @customElement('data-key-item-list')
14
+ export class DataKeyItemList extends localize(i18next)(LitElement) {
15
+ static styles = [
16
+ CommonHeaderStyles,
17
+ css`
18
+ :host {
19
+ display: flex;
20
+ flex-direction: column;
21
+
22
+ background-color: var(--md-sys-color-surface);
23
+ }
24
+
25
+ ox-grist {
26
+ flex: 1;
27
+ }
28
+ `
29
+ ]
30
+
31
+ @property({ type: Object }) dataKeySet: any
32
+ @state() gristConfig: any
33
+ @query('ox-grist') private grist!: DataGrist
34
+
35
+ render() {
36
+ return html`
37
+ <ox-grist
38
+ .mode=${isMobileDevice() ? 'LIST' : 'GRID'}
39
+ .config=${this.gristConfig}
40
+ .fetchHandler=${this.fetchHandler.bind(this)}
41
+ ></ox-grist>
42
+
43
+ <div class="footer">
44
+ <div filler></div>
45
+ <button danger @click=${this._deleteDataKeyItems.bind(this)}>
46
+ <md-icon>delete_forever</md-icon>${i18next.t('button.delete')}
47
+ </button>
48
+ <button @click=${this._updateDataKeyItems.bind(this)} done>
49
+ <md-icon>save</md-icon>${i18next.t('button.save')}
50
+ </button>
51
+ </div>
52
+ `
53
+ }
54
+
55
+ async firstUpdated() {
56
+ this.gristConfig = {
57
+ list: { fields: ['name', 'description', 'active'] },
58
+ columns: [
59
+ { type: 'gutter', gutterName: 'row-selector', multiple: true },
60
+ {
61
+ type: 'gutter',
62
+ gutterName: 'button',
63
+ icon: 'add',
64
+ handlers: {
65
+ click: 'record-copy'
66
+ }
67
+ },
68
+ { type: 'gutter', gutterName: 'sequence' },
69
+ {
70
+ type: 'gutter',
71
+ gutterName: 'button',
72
+ icon: 'arrow_upward',
73
+ handlers: {
74
+ click: 'move-up'
75
+ }
76
+ },
77
+ {
78
+ type: 'gutter',
79
+ gutterName: 'button',
80
+ icon: 'arrow_downward',
81
+ handlers: {
82
+ click: 'move-down'
83
+ }
84
+ },
85
+ {
86
+ type: 'string',
87
+ name: 'name',
88
+ header: i18next.t('field.name'),
89
+ record: {
90
+ editable: true
91
+ },
92
+ width: 140
93
+ },
94
+ {
95
+ type: 'string',
96
+ name: 'description',
97
+ header: i18next.t('field.description'),
98
+ record: {
99
+ editable: true
100
+ },
101
+ width: 180
102
+ },
103
+ {
104
+ type: 'string',
105
+ name: 'dataKey',
106
+ header: i18next.t('field.data-key'),
107
+ record: {
108
+ editable: true
109
+ },
110
+ width: 180
111
+ },
112
+ {
113
+ type: 'string',
114
+ name: 'tKey',
115
+ header: i18next.t('field.t-key'),
116
+ record: {
117
+ editable: true
118
+ },
119
+ width: 180
120
+ }
121
+ ],
122
+ rows: {
123
+ selectable: {
124
+ multiple: true
125
+ }
126
+ },
127
+ pagination: {
128
+ infinite: true
129
+ },
130
+ sorters: []
131
+ }
132
+ }
133
+
134
+ async fetchHandler({ filters, page, limit, sortings = [] }: FetchOption) {
135
+ const dataKeyItems = this.dataKeySet.dataKeyItems || []
136
+
137
+ return {
138
+ total: dataKeyItems.length,
139
+ records: dataKeyItems
140
+ }
141
+ }
142
+
143
+ async _updateDataKeyItems() {
144
+ this.grist.commit()
145
+
146
+ const response = await client.mutate({
147
+ mutation: gql`
148
+ mutation ($id: String!, $patch: DataKeySetPatch!) {
149
+ updateDataKeySet(id: $id, patch: $patch) {
150
+ name
151
+ }
152
+ }
153
+ `,
154
+ variables: {
155
+ id: this.dataKeySet.id,
156
+ patch: {
157
+ dataKeyItems: this.grist.data.records,
158
+ cuFlag: 'M'
159
+ }
160
+ }
161
+ })
162
+
163
+ if (!response.errors) {
164
+ await document.dispatchEvent(
165
+ new CustomEvent('notify', {
166
+ detail: {
167
+ message: i18next.t('text.info_x_successfully', {
168
+ x: i18next.t('button.save')
169
+ })
170
+ }
171
+ })
172
+ )
173
+ }
174
+ }
175
+
176
+ async _deleteDataKeyItems() {
177
+ if (!confirm(i18next.t('text.sure_to_x', { x: i18next.t('text.delete') }))) {
178
+ return
179
+ }
180
+
181
+ this.grist.deleteSelectedRecords(false)
182
+ }
183
+ }