@things-factory/dataset 8.0.0-beta.1 → 8.0.0-beta.2

Sign up to get free protection for your applications and to get access to all the features.
Files changed (113) hide show
  1. package/package.json +13 -13
  2. package/client/activities/activity-data-collect-edit.ts +0 -105
  3. package/client/activities/activity-data-collect-view.ts +0 -91
  4. package/client/activities/activity-data-review-edit.ts +0 -133
  5. package/client/activities/activity-data-review-view.ts +0 -145
  6. package/client/activities/activity-ooc-resolve-edit.ts +0 -195
  7. package/client/activities/activity-ooc-resolve-view.ts +0 -143
  8. package/client/activities/activity-ooc-review-edit.ts +0 -173
  9. package/client/activities/activity-ooc-review-view.ts +0 -129
  10. package/client/bootstrap.ts +0 -35
  11. package/client/components/data-entry-form.ts +0 -109
  12. package/client/index.ts +0 -1
  13. package/client/pages/data-archive/data-archive-list-page.ts +0 -277
  14. package/client/pages/data-archive/data-archive-request-popup.ts +0 -177
  15. package/client/pages/data-entry/data-entry-list-page.ts +0 -464
  16. package/client/pages/data-key-set/data-key-item-list.ts +0 -183
  17. package/client/pages/data-key-set/data-key-set-importer.ts +0 -89
  18. package/client/pages/data-key-set/data-key-set-list-page.ts +0 -413
  19. package/client/pages/data-ooc/data-ooc-list-page.ts +0 -549
  20. package/client/pages/data-ooc/data-ooc-page.ts +0 -164
  21. package/client/pages/data-ooc/data-ooc-view.ts +0 -236
  22. package/client/pages/data-ooc/data-oocs-page.ts +0 -200
  23. package/client/pages/data-report/data-report-embed-page.ts +0 -108
  24. package/client/pages/data-report/data-report-list-page.ts +0 -454
  25. package/client/pages/data-report/data-report-samples-page.ts +0 -174
  26. package/client/pages/data-report/jasper-report-oocs-page.ts +0 -110
  27. package/client/pages/data-report/jasper-report-samples-crosstab-page.ts +0 -110
  28. package/client/pages/data-report/jasper-report-samples-page.ts +0 -110
  29. package/client/pages/data-sample/data-sample-list-page.ts +0 -442
  30. package/client/pages/data-sample/data-sample-page.ts +0 -55
  31. package/client/pages/data-sample/data-sample-search-page.ts +0 -424
  32. package/client/pages/data-sample/data-sample-view.ts +0 -292
  33. package/client/pages/data-sample/data-samples-page.ts +0 -249
  34. package/client/pages/data-sensor/data-sensor-list-page.ts +0 -456
  35. package/client/pages/data-set/data-item-list.ts +0 -304
  36. package/client/pages/data-set/data-set-importer.ts +0 -89
  37. package/client/pages/data-set/data-set-list-page.ts +0 -1078
  38. package/client/pages/data-summary/data-summary-list-page.ts +0 -363
  39. package/client/pages/data-summary/data-summary-period-page.ts +0 -439
  40. package/client/pages/data-summary/data-summary-search-page.ts +0 -426
  41. package/client/pages/data-summary/data-summary-view.ts +0 -133
  42. package/client/route.ts +0 -91
  43. package/client/tsconfig.json +0 -13
  44. package/server/activities/activity-data-collect.ts +0 -100
  45. package/server/activities/activity-data-review.ts +0 -82
  46. package/server/activities/activity-ooc-resolve.ts +0 -123
  47. package/server/activities/activity-ooc-review.ts +0 -144
  48. package/server/activities/index.ts +0 -11
  49. package/server/controllers/create-data-sample.ts +0 -426
  50. package/server/controllers/data-use-case.ts +0 -98
  51. package/server/controllers/finalize-data-collection.ts +0 -388
  52. package/server/controllers/index.ts +0 -3
  53. package/server/controllers/issue-data-collection-task.ts +0 -70
  54. package/server/controllers/jasper-report.ts +0 -186
  55. package/server/controllers/query-data-summary-by-period.ts +0 -178
  56. package/server/controllers/shiny-report.ts +0 -54
  57. package/server/engine/index.ts +0 -1
  58. package/server/engine/task/create-data-sample.ts +0 -100
  59. package/server/engine/task/index.ts +0 -2
  60. package/server/engine/task/issue-collect-data.ts +0 -45
  61. package/server/index.ts +0 -8
  62. package/server/routes.ts +0 -188
  63. package/server/service/data-archive/data-archive-mutation.ts +0 -273
  64. package/server/service/data-archive/data-archive-query.ts +0 -58
  65. package/server/service/data-archive/data-archive-type.ts +0 -48
  66. package/server/service/data-archive/data-archive.ts +0 -69
  67. package/server/service/data-archive/index.ts +0 -6
  68. package/server/service/data-key-set/data-key-item-type.ts +0 -31
  69. package/server/service/data-key-set/data-key-set-mutation.ts +0 -201
  70. package/server/service/data-key-set/data-key-set-query.ts +0 -68
  71. package/server/service/data-key-set/data-key-set-type.ts +0 -70
  72. package/server/service/data-key-set/data-key-set.ts +0 -86
  73. package/server/service/data-key-set/index.ts +0 -6
  74. package/server/service/data-ooc/data-ooc-mutation.ts +0 -154
  75. package/server/service/data-ooc/data-ooc-query.ts +0 -106
  76. package/server/service/data-ooc/data-ooc-subscription.ts +0 -48
  77. package/server/service/data-ooc/data-ooc-type.ts +0 -71
  78. package/server/service/data-ooc/data-ooc.ts +0 -259
  79. package/server/service/data-ooc/index.ts +0 -7
  80. package/server/service/data-sample/data-sample-mutation.ts +0 -18
  81. package/server/service/data-sample/data-sample-query.ts +0 -215
  82. package/server/service/data-sample/data-sample-type.ts +0 -47
  83. package/server/service/data-sample/data-sample.ts +0 -193
  84. package/server/service/data-sample/index.ts +0 -6
  85. package/server/service/data-sensor/data-sensor-mutation.ts +0 -116
  86. package/server/service/data-sensor/data-sensor-query.ts +0 -76
  87. package/server/service/data-sensor/data-sensor-type.ts +0 -104
  88. package/server/service/data-sensor/data-sensor.ts +0 -126
  89. package/server/service/data-sensor/index.ts +0 -6
  90. package/server/service/data-set/data-item-type.ts +0 -155
  91. package/server/service/data-set/data-set-mutation.ts +0 -552
  92. package/server/service/data-set/data-set-query.ts +0 -461
  93. package/server/service/data-set/data-set-type.ts +0 -204
  94. package/server/service/data-set/data-set.ts +0 -326
  95. package/server/service/data-set/index.ts +0 -6
  96. package/server/service/data-set-history/data-set-history-query.ts +0 -126
  97. package/server/service/data-set-history/data-set-history-type.ts +0 -12
  98. package/server/service/data-set-history/data-set-history.ts +0 -217
  99. package/server/service/data-set-history/event-subscriber.ts +0 -17
  100. package/server/service/data-set-history/index.ts +0 -7
  101. package/server/service/data-spec/data-spec-manager.ts +0 -21
  102. package/server/service/data-spec/data-spec-query.ts +0 -21
  103. package/server/service/data-spec/data-spec.ts +0 -45
  104. package/server/service/data-spec/index.ts +0 -5
  105. package/server/service/data-summary/data-summary-mutation.ts +0 -45
  106. package/server/service/data-summary/data-summary-query.ts +0 -179
  107. package/server/service/data-summary/data-summary-type.ts +0 -86
  108. package/server/service/data-summary/data-summary.ts +0 -170
  109. package/server/service/data-summary/index.ts +0 -7
  110. package/server/service/index.ts +0 -57
  111. package/server/tsconfig.json +0 -10
  112. package/server/utils/config-resolver.ts +0 -29
  113. package/server/utils/index.ts +0 -1
@@ -1,464 +0,0 @@
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 ? 'note_alt' : ''),
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_add</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
- }
@@ -1,183 +0,0 @@
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
- }