@things-factory/dataset 5.0.0-alpha.4 → 5.0.0-alpha.40

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 (97) hide show
  1. package/README.md +13 -0
  2. package/assets/data-samples.jpg +0 -0
  3. package/client/bootstrap.js +21 -1
  4. package/client/pages/{data-entry-form.js → data-entry/data-entry-form.js} +15 -2
  5. package/client/pages/data-entry/data-entry-list-page.js +423 -0
  6. package/client/pages/data-ooc/data-ooc-list-page.js +488 -0
  7. package/client/pages/data-ooc/data-ooc-view.js +182 -0
  8. package/client/pages/data-report/data-report-list-page.js +463 -0
  9. package/client/pages/{data-sample.js → data-sample/data-sample-list-page.js} +151 -76
  10. package/client/pages/data-sample/data-sample-view.js +97 -0
  11. package/client/pages/{data-sensor.js → data-sensor/data-sensor-list-page.js} +7 -12
  12. package/client/pages/{data-item-list.js → data-set/data-item-list.js} +37 -12
  13. package/client/pages/{data-set-importer.js → data-set/data-set-importer.js} +0 -0
  14. package/client/pages/data-set/data-set-list-page.js +727 -0
  15. package/client/route.js +18 -6
  16. package/dist-server/controllers/create-data-sample.js +133 -0
  17. package/dist-server/controllers/create-data-sample.js.map +1 -0
  18. package/dist-server/controllers/data-use-case.js +57 -0
  19. package/dist-server/controllers/data-use-case.js.map +1 -0
  20. package/dist-server/controllers/index.js +17 -0
  21. package/dist-server/controllers/index.js.map +1 -1
  22. package/dist-server/index.js +1 -0
  23. package/dist-server/index.js.map +1 -1
  24. package/dist-server/routes.js +9 -24
  25. package/dist-server/routes.js.map +1 -1
  26. package/dist-server/service/data-item/data-item-mutation.js +5 -1
  27. package/dist-server/service/data-item/data-item-mutation.js.map +1 -1
  28. package/dist-server/service/data-item/data-item-query.js +7 -2
  29. package/dist-server/service/data-item/data-item-query.js.map +1 -1
  30. package/dist-server/service/data-item/data-item-type.js +15 -7
  31. package/dist-server/service/data-item/data-item-type.js.map +1 -1
  32. package/dist-server/service/data-item/data-item.js +17 -3
  33. package/dist-server/service/data-item/data-item.js.map +1 -1
  34. package/dist-server/service/data-ooc/data-ooc-mutation.js +92 -0
  35. package/dist-server/service/data-ooc/data-ooc-mutation.js.map +1 -0
  36. package/dist-server/service/data-ooc/data-ooc-query.js +120 -0
  37. package/dist-server/service/data-ooc/data-ooc-query.js.map +1 -0
  38. package/dist-server/service/data-ooc/data-ooc-subscription.js +65 -0
  39. package/dist-server/service/data-ooc/data-ooc-subscription.js.map +1 -0
  40. package/dist-server/service/data-ooc/data-ooc-type.js +107 -0
  41. package/dist-server/service/data-ooc/data-ooc-type.js.map +1 -0
  42. package/dist-server/service/data-ooc/data-ooc.js +237 -0
  43. package/dist-server/service/data-ooc/data-ooc.js.map +1 -0
  44. package/dist-server/service/data-ooc/index.js +10 -0
  45. package/dist-server/service/data-ooc/index.js.map +1 -0
  46. package/dist-server/service/data-sample/data-sample-mutation.js +2 -138
  47. package/dist-server/service/data-sample/data-sample-mutation.js.map +1 -1
  48. package/dist-server/service/data-sample/data-sample-query.js +7 -2
  49. package/dist-server/service/data-sample/data-sample-query.js.map +1 -1
  50. package/dist-server/service/data-sample/data-sample-type.js +12 -42
  51. package/dist-server/service/data-sample/data-sample-type.js.map +1 -1
  52. package/dist-server/service/data-sample/data-sample.js +34 -3
  53. package/dist-server/service/data-sample/data-sample.js.map +1 -1
  54. package/dist-server/service/data-sensor/data-sensor-query.js +7 -2
  55. package/dist-server/service/data-sensor/data-sensor-query.js.map +1 -1
  56. package/dist-server/service/data-set/data-set-mutation.js +1 -2
  57. package/dist-server/service/data-set/data-set-mutation.js.map +1 -1
  58. package/dist-server/service/data-set/data-set-query.js +162 -3
  59. package/dist-server/service/data-set/data-set-query.js.map +1 -1
  60. package/dist-server/service/data-set/data-set-type.js +75 -3
  61. package/dist-server/service/data-set/data-set-type.js.map +1 -1
  62. package/dist-server/service/data-set/data-set.js +106 -15
  63. package/dist-server/service/data-set/data-set.js.map +1 -1
  64. package/dist-server/service/index.js +6 -2
  65. package/dist-server/service/index.js.map +1 -1
  66. package/package.json +18 -13
  67. package/server/controllers/create-data-sample.ts +177 -0
  68. package/server/controllers/data-use-case.ts +85 -0
  69. package/server/controllers/index.ts +1 -0
  70. package/server/index.ts +1 -0
  71. package/server/routes.ts +17 -31
  72. package/server/service/data-item/data-item-mutation.ts +6 -1
  73. package/server/service/data-item/data-item-query.ts +9 -3
  74. package/server/service/data-item/data-item-type.ts +10 -6
  75. package/server/service/data-item/data-item.ts +15 -4
  76. package/server/service/data-ooc/data-ooc-mutation.ts +150 -0
  77. package/server/service/data-ooc/data-ooc-query.ts +69 -0
  78. package/server/service/data-ooc/data-ooc-subscription.ts +51 -0
  79. package/server/service/data-ooc/data-ooc-type.ts +68 -0
  80. package/server/service/data-ooc/data-ooc.ts +204 -0
  81. package/server/service/data-ooc/index.ts +7 -0
  82. package/server/service/data-sample/data-sample-mutation.ts +3 -172
  83. package/server/service/data-sample/data-sample-query.ts +9 -3
  84. package/server/service/data-sample/data-sample-type.ts +7 -28
  85. package/server/service/data-sample/data-sample.ts +33 -3
  86. package/server/service/data-sensor/data-sensor-query.ts +9 -3
  87. package/server/service/data-set/data-set-mutation.ts +1 -4
  88. package/server/service/data-set/data-set-query.ts +135 -4
  89. package/server/service/data-set/data-set-type.ts +58 -4
  90. package/server/service/data-set/data-set.ts +97 -12
  91. package/server/service/index.ts +6 -2
  92. package/things-factory.config.js +18 -6
  93. package/translations/en.json +45 -3
  94. package/translations/ko.json +44 -3
  95. package/translations/ms.json +44 -3
  96. package/translations/zh.json +44 -3
  97. package/client/pages/data-set.js +0 -457
@@ -0,0 +1,488 @@
1
+ import '@operato/data-grist'
2
+ import './data-ooc-view.js'
3
+
4
+ import gql from 'graphql-tag'
5
+ import { css, html } from 'lit'
6
+ import { connect } from 'pwa-helpers/connect-mixin'
7
+
8
+ import { client } from '@operato/graphql'
9
+ import { i18next, localize } from '@operato/i18n'
10
+ import { openPopup } from '@operato/layout'
11
+ import { PageView, store } from '@operato/shell'
12
+ import { ScrollbarStyles } from '@operato/styles'
13
+ import { isMobileDevice } from '@operato/utils'
14
+
15
+ export class DataOocListPage extends connect(store)(localize(i18next)(PageView)) {
16
+ static get properties() {
17
+ return {
18
+ active: String,
19
+ gristConfig: Object
20
+ }
21
+ }
22
+
23
+ static get styles() {
24
+ return [
25
+ ScrollbarStyles,
26
+ css`
27
+ :host {
28
+ display: flex;
29
+ flex-direction: column;
30
+
31
+ overflow: hidden;
32
+ }
33
+
34
+ ox-grist {
35
+ overflow-y: auto;
36
+ flex: 1;
37
+ }
38
+
39
+ #filters {
40
+ display: flex;
41
+ flex-direction: row;
42
+ justify-content: space-between;
43
+
44
+ background-color: white;
45
+ }
46
+
47
+ #filters > * {
48
+ padding: var(--padding-default) var(--padding-wide);
49
+ }
50
+ `
51
+ ]
52
+ }
53
+
54
+ get context() {
55
+ return {
56
+ title: i18next.t('title.data-ooc list'),
57
+ help: 'dataset/data-ooc',
58
+ actions: [
59
+ // {
60
+ // title: i18next.t('button.save'),
61
+ // action: this._updateDataOoc.bind(this),
62
+ // ...CommonButtonStyles.save
63
+ // }
64
+ ],
65
+ exportable: {
66
+ name: i18next.t('title.data-ooc list'),
67
+ data: this._exportableData.bind(this)
68
+ }
69
+ }
70
+ }
71
+
72
+ render() {
73
+ return html`
74
+ <ox-grist
75
+ .mode=${isMobileDevice() ? 'LIST' : 'GRID'}
76
+ .config=${this.gristConfig}
77
+ .fetchHandler=${this.fetchHandler.bind(this)}
78
+ >
79
+ <div slot="headroom" id="filters">
80
+ <ox-filters-form></ox-filters-form>
81
+ </div>
82
+ </ox-grist>
83
+ `
84
+ }
85
+
86
+ get grist() {
87
+ return this.renderRoot.querySelector('ox-grist')
88
+ }
89
+
90
+ // update with url params value
91
+ _updateSearchConfig(lifecycle) {
92
+ // this.searchConfig = this.searchConfig.map(conf => {
93
+ // if (conf.name in lifecycle.params) {
94
+ // conf.value = lifecycle.params[conf.name]
95
+ // } else {
96
+ // delete conf.value
97
+ // }
98
+ // return conf
99
+ // })
100
+ }
101
+
102
+ // set default field value to record with searchConfig
103
+ _setDefaultFieldsValue(fields) {
104
+ // this.searchConfig.forEach(conf => {
105
+ // if (!fields[conf.name] && conf.value) {
106
+ // fields[conf.name] = conf.value
107
+ // }
108
+ // })
109
+ }
110
+
111
+ async pageInitialized(lifecycle) {
112
+ this._updateSearchConfig(lifecycle)
113
+
114
+ this.gristConfig = {
115
+ list: {
116
+ fields: ['dataSet', 'data', 'spec', 'correctiveAction', 'corrector', 'correctedAt', 'collectedAt', 'creator']
117
+ },
118
+ columns: [
119
+ { type: 'gutter', gutterName: 'sequence' },
120
+ { type: 'gutter', gutterName: 'row-selector', multiple: true },
121
+ {
122
+ type: 'gutter',
123
+ gutterName: 'button',
124
+ icon: 'assignment_turned_in',
125
+ handlers: {
126
+ click: (columns, data, column, record, rowIndex) => {
127
+ const popup = openPopup(
128
+ html` <data-ooc-view .dataOoc=${record} style="background-color: white;"></data-ooc-view> `,
129
+ {
130
+ backdrop: true,
131
+ size: 'large',
132
+ title: i18next.t('title.data-ooc view')
133
+ }
134
+ )
135
+ popup.onclosed = () => {
136
+ this.grist.fetch()
137
+ }
138
+ }
139
+ }
140
+ },
141
+ {
142
+ type: 'string',
143
+ name: 'name',
144
+ label: true,
145
+ header: i18next.t('field.name'),
146
+ record: {
147
+ editable: true
148
+ },
149
+ filter: 'search',
150
+ sortable: true,
151
+ width: 120,
152
+ imex: true
153
+ },
154
+ {
155
+ type: 'string',
156
+ name: 'description',
157
+ label: true,
158
+ header: i18next.t('field.description'),
159
+ record: {
160
+ editable: true
161
+ },
162
+ filter: 'search',
163
+ width: 150,
164
+ imex: true
165
+ },
166
+ {
167
+ type: 'string',
168
+ name: 'history',
169
+ hidden: true,
170
+ imex: true
171
+ },
172
+ {
173
+ type: 'checkbox',
174
+ name: 'ooc',
175
+ header: i18next.t('field.ooc'),
176
+ record: {
177
+ editable: false
178
+ },
179
+ width: 30
180
+ },
181
+ {
182
+ type: 'checkbox',
183
+ name: 'oos',
184
+ header: i18next.t('field.oos'),
185
+ record: {
186
+ editable: false
187
+ },
188
+ width: 30
189
+ },
190
+ {
191
+ type: 'select',
192
+ name: 'state',
193
+ label: true,
194
+ header: i18next.t('field.state'),
195
+ record: {
196
+ editable: false,
197
+ options: ['', 'CREATED', 'REVIEWED', 'CORRECTED']
198
+ },
199
+ width: 100,
200
+ filter: true,
201
+ imex: true
202
+ },
203
+ {
204
+ type: 'textarea',
205
+ name: 'correctiveAction',
206
+ label: true,
207
+ header: i18next.t('field.corrective-action'),
208
+ record: {
209
+ editable: true
210
+ },
211
+ width: 150,
212
+ imex: true
213
+ },
214
+ {
215
+ type: 'resource-object',
216
+ name: 'dataSet',
217
+ header: i18next.t('field.data-set'),
218
+ record: {
219
+ editable: false
220
+ },
221
+ sortable: true,
222
+ width: 120,
223
+ imex: true
224
+ },
225
+ {
226
+ type: 'json5',
227
+ name: 'partitionKeys',
228
+ header: i18next.t('field.partition-keys'),
229
+ record: {
230
+ editable: false
231
+ },
232
+ width: 200,
233
+ imex: true
234
+ },
235
+ {
236
+ type: 'json5',
237
+ name: 'data',
238
+ header: i18next.t('field.data'),
239
+ record: {
240
+ editable: false
241
+ },
242
+ width: 200,
243
+ imex: true
244
+ },
245
+ {
246
+ type: 'json5',
247
+ name: 'spec',
248
+ header: i18next.t('field.spec'),
249
+ record: {
250
+ editable: false
251
+ },
252
+ width: 200
253
+ },
254
+ {
255
+ type: 'text',
256
+ name: 'rawData',
257
+ header: i18next.t('field.raw-data'),
258
+ record: {
259
+ editable: false
260
+ },
261
+ width: 200,
262
+ imex: true
263
+ },
264
+ {
265
+ type: 'string',
266
+ name: 'workDate',
267
+ header: i18next.t('field.work-date'),
268
+ sortable: true,
269
+ width: 80,
270
+ imex: true
271
+ },
272
+ {
273
+ type: 'string',
274
+ name: 'workShift',
275
+ header: i18next.t('field.work-shift'),
276
+ sortable: true,
277
+ width: 40,
278
+ imex: true
279
+ },
280
+ {
281
+ type: 'datetime',
282
+ name: 'collectedAt',
283
+ header: i18next.t('field.collected-at'),
284
+ sortable: true,
285
+ width: 180,
286
+ imex: true
287
+ },
288
+ {
289
+ type: 'resource-object',
290
+ name: 'updater',
291
+ header: i18next.t('field.updater'),
292
+ sortable: true,
293
+ width: 120,
294
+ imex: true
295
+ },
296
+ {
297
+ type: 'datetime',
298
+ name: 'updatedAt',
299
+ header: i18next.t('field.updated_at'),
300
+ sortable: true,
301
+ width: 180,
302
+ imex: true
303
+ }
304
+ ],
305
+ rows: {
306
+ appendable: false,
307
+ selectable: {
308
+ multiple: true
309
+ }
310
+ },
311
+ sorters: [
312
+ {
313
+ name: 'updatedAt',
314
+ desc: true
315
+ }
316
+ ]
317
+ }
318
+
319
+ await this.updateComplete
320
+
321
+ this.grist.fetch()
322
+ }
323
+
324
+ async pageUpdated(changes, lifecycle) {
325
+ if (this.active) {
326
+ // update with url params value
327
+ this._updateSearchConfig(lifecycle)
328
+ await this.updateComplete
329
+
330
+ this.grist.fetch()
331
+ }
332
+ }
333
+
334
+ async fetchHandler({ page, limit, sortings = [], filters = [] }) {
335
+ const response = await client.query({
336
+ query: gql`
337
+ query ($filters: [Filter!], $pagination: Pagination, $sortings: [Sorting!]) {
338
+ responses: dataOocs(filters: $filters, pagination: $pagination, sortings: $sortings) {
339
+ items {
340
+ id
341
+ name
342
+ description
343
+ dataSet {
344
+ id
345
+ name
346
+ }
347
+ dataSample {
348
+ id
349
+ name
350
+ }
351
+ partitionKeys
352
+ data
353
+ rawData
354
+ state
355
+ spec
356
+ ooc
357
+ oos
358
+ history
359
+ workDate
360
+ workShift
361
+ correctiveAction
362
+ correctedAt
363
+ corrector {
364
+ id
365
+ name
366
+ }
367
+ updater {
368
+ id
369
+ name
370
+ }
371
+ updatedAt
372
+ collectedAt
373
+ }
374
+ total
375
+ }
376
+ }
377
+ `,
378
+ variables: {
379
+ filters,
380
+ pagination: { page, limit },
381
+ sortings
382
+ }
383
+ })
384
+
385
+ return {
386
+ total: response.data.responses.total || 0,
387
+ records: response.data.responses.items || []
388
+ }
389
+ }
390
+
391
+ // async _updateDataOoc() {
392
+ // let patches = this.grist.dirtyRecords
393
+ // if (patches && patches.length) {
394
+ // patches = patches.map(patch => {
395
+ // let patchField = patch.id ? { id: patch.id } : {}
396
+ // const dirtyFields = patch.__dirtyfields__
397
+ // for (let key in dirtyFields) {
398
+ // patchField[key] = dirtyFields[key].after
399
+ // }
400
+ // this._setDefaultFieldsValue(patchField)
401
+ // patchField.cuFlag = patch.__dirty__
402
+
403
+ // return patchField
404
+ // })
405
+
406
+ // const response = await client.mutate({
407
+ // mutation: gql`
408
+ // mutation ($patches: [DataOocPatch!]!) {
409
+ // updateMultipleDataOoc(patches: $patches) {
410
+ // name
411
+ // }
412
+ // }
413
+ // `,
414
+ // variables: {
415
+ // patches
416
+ // }
417
+ // })
418
+
419
+ // if (!response.errors) this.grist.fetch()
420
+ // }
421
+ // }
422
+
423
+ // async _deleteDataOoc() {
424
+ // if (confirm(i18next.t('text.sure_to_x', { x: i18next.t('text.delete') }))) {
425
+ // const ids = this.grist.selected.map(record => record.id)
426
+ // if (ids && ids.length > 0) {
427
+ // const response = await client.mutate({
428
+ // mutation: gql`
429
+ // mutation ($ids: [String!]!) {
430
+ // deleteDataOocs(ids: $ids)
431
+ // }
432
+ // `,
433
+ // variables: {
434
+ // ids
435
+ // }
436
+ // })
437
+
438
+ // if (!response.errors) {
439
+ // this.grist.fetch()
440
+ // notify({
441
+ // message: i18next.t('text.info_x_successfully', { x: i18next.t('text.delete') })
442
+ // })
443
+ // }
444
+ // }
445
+ // }
446
+ // }
447
+
448
+ _exportableData() {
449
+ let records = []
450
+ if (this.grist.selected && this.grist.selected.length > 0) {
451
+ records = this.grist.selected
452
+ } else {
453
+ records = this.grist.data.records
454
+ }
455
+
456
+ var headerSetting = this.grist.compiledConfig.columns
457
+ .filter(column => column.type !== 'gutter' && column.record !== undefined && column.imex !== undefined)
458
+ .map(column => {
459
+ return column.imex === true
460
+ ? {
461
+ header: column.header.renderer(),
462
+ key: column.name,
463
+ width: column.width,
464
+ type: column.type
465
+ }
466
+ : column.imex
467
+ })
468
+
469
+ var data = records.map(item => {
470
+ return {
471
+ id: item.id,
472
+ ...this.gristConfig.columns
473
+ .filter(column => column.type !== 'gutter' && column.record !== undefined && column.imex !== undefined)
474
+ .reduce((record, column) => {
475
+ const key = column.imex === true ? column.name : column.imex.key
476
+ record[key] = key
477
+ .split('.')
478
+ .reduce((obj, key) => (obj && obj[key] !== 'undefined' ? obj[key] : undefined), item)
479
+ return record
480
+ }, {})
481
+ }
482
+ })
483
+
484
+ return { header: headerSetting, data: data }
485
+ }
486
+ }
487
+
488
+ window.customElements.define('data-ooc-list-page', DataOocListPage)
@@ -0,0 +1,182 @@
1
+ import '@operato/dataset/ox-data-ooc-view.js'
2
+
3
+ import { LitElement, css, html } from 'lit'
4
+ import { i18next, localize } from '@operato/i18n'
5
+
6
+ import { ScrollbarStyles } from '@operato/styles'
7
+ import { client } from '@operato/graphql'
8
+ import gql from 'graphql-tag'
9
+
10
+ class DataOocView extends localize(i18next)(LitElement) {
11
+ static get styles() {
12
+ return [
13
+ ScrollbarStyles,
14
+ css`
15
+ :host {
16
+ display: flex;
17
+ flex-direction: column;
18
+
19
+ background-color: #fff;
20
+ }
21
+
22
+ div[content] {
23
+ flex: 1;
24
+
25
+ display: flex;
26
+ overflow: auto;
27
+ }
28
+
29
+ ox-data-ooc-view {
30
+ flex: 1;
31
+ padding: var(--padding-wide);
32
+ }
33
+
34
+ label[comment] {
35
+ display: flex;
36
+ flex-direction: column;
37
+
38
+ padding: var(--padding-wide);
39
+ }
40
+
41
+ label[comment] div {
42
+ display: flex;
43
+ }
44
+
45
+ mwc-icon {
46
+ color: var(--status-danger-color);
47
+ }
48
+
49
+ textarea {
50
+ border: var(--input-field-border);
51
+ border-radius: var(--input-border-radius);
52
+ padding: var(--input-field-padding);
53
+ font: var(--input-field-font);
54
+ }
55
+
56
+ .button-container {
57
+ display: flex;
58
+ margin-left: auto;
59
+ padding: var(--padding-default);
60
+ }
61
+ `
62
+ ]
63
+ }
64
+
65
+ static get properties() {
66
+ return {
67
+ dataSet: Object,
68
+ dataOoc: Object
69
+ }
70
+ }
71
+
72
+ get sampleView() {
73
+ return this.renderRoot.querySelector('ox-data-ooc-view')
74
+ }
75
+
76
+ render() {
77
+ const state = this.dataOoc.state
78
+
79
+ return html`
80
+ <div content>
81
+ <ox-data-ooc-view .dataSet=${this.dataSet} .dataOoc=${this.dataOoc}></ox-data-ooc-view>
82
+ </div>
83
+
84
+ ${state === 'CREATED' || state === 'REVIEWED'
85
+ ? html`
86
+ <label comment>
87
+ <div><mwc-icon>build_circle</mwc-icon> <span>correction activity</span></div>
88
+ <textarea placeholder="조치 내용을 입력해주세요."></textarea>
89
+ </label>
90
+ `
91
+ : html``}
92
+
93
+ <div class="button-container">
94
+ ${state === 'CREATED'
95
+ ? html`<mwc-button raised @click=${() => this._processOoc('REVIEWED')}
96
+ >${i18next.t('button.reviewed')}</mwc-button
97
+ >`
98
+ : state === 'REVIEWED'
99
+ ? html`<mwc-button raised @click=${() => this._processOoc('CORRECTED')}
100
+ >${i18next.t('button.corrected')}</mwc-button
101
+ >`
102
+ : html``}
103
+ </div>
104
+ `
105
+ }
106
+
107
+ updated(changes) {
108
+ if (changes.has('dataOoc')) {
109
+ this.fetchDataSet()
110
+ }
111
+ }
112
+
113
+ async fetchDataSet() {
114
+ const id = this.dataOoc?.dataSet?.id
115
+
116
+ if (id) {
117
+ const response = await client.query({
118
+ query: gql`
119
+ query ($id: String!) {
120
+ dataSet(id: $id) {
121
+ id
122
+ name
123
+ description
124
+ useCase
125
+ dataItems {
126
+ id
127
+ name
128
+ description
129
+ active
130
+ unit
131
+ tag
132
+ type
133
+ spec
134
+ }
135
+ }
136
+ }
137
+ `,
138
+ variables: {
139
+ id: this.dataOoc.dataSet.id
140
+ }
141
+ })
142
+
143
+ this.dataSet = response.data.dataSet
144
+ }
145
+ }
146
+
147
+ async _processOoc(state) {
148
+ const commentTextArea = this.renderRoot.querySelector('textarea')
149
+ const comment = commentTextArea && commentTextArea.value
150
+ if (!comment || !comment.trim()) {
151
+ commentTextArea.focus()
152
+ return
153
+ }
154
+
155
+ const patch = {
156
+ state,
157
+ correctiveAction: comment
158
+ }
159
+
160
+ const response = await client.mutate({
161
+ mutation: gql`
162
+ mutation ($id: String!, $patch: DataOocPatch!) {
163
+ updateDataOoc(id: $id, patch: $patch) {
164
+ id
165
+ }
166
+ }
167
+ `,
168
+ variables: {
169
+ id: this.dataOoc.id,
170
+ patch
171
+ }
172
+ })
173
+
174
+ if (!response.errors) {
175
+ document.dispatchEvent(
176
+ new CustomEvent('notify', { detail: { message: i18next.t('text.data ooc updated successfully') } })
177
+ )
178
+ }
179
+ }
180
+ }
181
+
182
+ window.customElements.define('data-ooc-view', DataOocView)