@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
@@ -1,4 +1,5 @@
1
1
  import '@operato/data-grist'
2
+ import './data-sample-view.js'
2
3
 
3
4
  import gql from 'graphql-tag'
4
5
  import { css, html } from 'lit'
@@ -6,12 +7,12 @@ import { connect } from 'pwa-helpers/connect-mixin'
6
7
 
7
8
  import { client } from '@operato/graphql'
8
9
  import { i18next, localize } from '@operato/i18n'
9
- import { notify } from '@operato/layout'
10
+ import { openPopup } from '@operato/layout'
10
11
  import { PageView, store } from '@operato/shell'
11
- import { CommonButtonStyles, ScrollbarStyles } from '@operato/styles'
12
+ import { ScrollbarStyles } from '@operato/styles'
12
13
  import { isMobileDevice } from '@operato/utils'
13
14
 
14
- export class DataSample extends connect(store)(localize(i18next)(PageView)) {
15
+ export class DataSampleListPage extends connect(store)(localize(i18next)(PageView)) {
15
16
  static get properties() {
16
17
  return {
17
18
  active: String,
@@ -53,14 +54,12 @@ export class DataSample extends connect(store)(localize(i18next)(PageView)) {
53
54
  get context() {
54
55
  return {
55
56
  title: i18next.t('title.data-sample list'),
56
- help: 'integration/ui/data-sample',
57
- actions: [
58
- {
59
- title: i18next.t('button.delete'),
60
- action: this._deleteDataSample.bind(this),
61
- ...CommonButtonStyles.delete
62
- }
63
- ]
57
+ help: 'dataset/data-sample',
58
+ actions: [],
59
+ exportable: {
60
+ name: i18next.t('title.data-sample list'),
61
+ data: this._exportableData.bind(this)
62
+ }
64
63
  }
65
64
  }
66
65
 
@@ -111,17 +110,35 @@ export class DataSample extends connect(store)(localize(i18next)(PageView)) {
111
110
  columns: [
112
111
  { type: 'gutter', gutterName: 'sequence' },
113
112
  { type: 'gutter', gutterName: 'row-selector', multiple: true },
113
+ {
114
+ type: 'gutter',
115
+ gutterName: 'button',
116
+ icon: 'assignment',
117
+ handlers: {
118
+ click: (columns, data, column, record, rowIndex) => {
119
+ openPopup(
120
+ html` <data-sample-view .dataSample=${record} style="background-color: white;"></data-sample-view> `,
121
+ {
122
+ backdrop: true,
123
+ size: 'large',
124
+ title: i18next.t('title.data-sample view')
125
+ }
126
+ )
127
+ }
128
+ }
129
+ },
114
130
  {
115
131
  type: 'string',
116
132
  name: 'name',
117
133
  label: true,
118
134
  header: i18next.t('field.name'),
119
135
  record: {
120
- editable: true
136
+ editable: false
121
137
  },
122
138
  filter: 'search',
123
139
  sortable: true,
124
- width: 120
140
+ width: 120,
141
+ imex: true
125
142
  },
126
143
  {
127
144
  type: 'string',
@@ -129,97 +146,143 @@ export class DataSample extends connect(store)(localize(i18next)(PageView)) {
129
146
  label: true,
130
147
  header: i18next.t('field.description'),
131
148
  record: {
132
- editable: true
149
+ editable: false
133
150
  },
134
151
  filter: 'search',
135
- width: 150
152
+ width: 150,
153
+ imex: true
136
154
  },
137
155
  {
138
- type: 'object',
156
+ type: 'resource-object',
139
157
  name: 'dataSet',
140
- header: i18next.t('field.dataSet'),
158
+ header: i18next.t('field.data-set'),
141
159
  record: {
142
160
  editable: false
143
161
  },
144
162
  sortable: true,
145
- width: 120
163
+ width: 120,
164
+ imex: true
146
165
  },
147
166
  {
148
- type: 'json',
167
+ type: 'json5',
149
168
  name: 'partitionKeys',
150
- header: i18next.t('field.partitionKeys'),
169
+ header: i18next.t('field.partition-keys'),
151
170
  record: {
152
- editable: false,
153
- renderer: (value, column, record, rowIndex, field) => {
154
- return typeof value === 'string' ? value : typeof value === 'object' ? JSON.stringify(value) : ''
155
- }
171
+ editable: false
156
172
  },
157
- width: 200
173
+ width: 200,
174
+ imex: true
158
175
  },
159
176
  {
160
- type: 'json',
177
+ type: 'checkbox',
178
+ name: 'ooc',
179
+ header: i18next.t('field.ooc'),
180
+ record: {
181
+ editable: false
182
+ },
183
+ width: 30
184
+ },
185
+ {
186
+ type: 'checkbox',
187
+ name: 'oos',
188
+ header: i18next.t('field.oos'),
189
+ record: {
190
+ editable: false
191
+ },
192
+ width: 30
193
+ },
194
+ {
195
+ type: 'json5',
161
196
  name: 'data',
162
197
  header: i18next.t('field.data'),
163
198
  record: {
164
- editable: false,
165
- renderer: (value, column, record, rowIndex, field) => {
166
- return typeof value === 'string' ? value : typeof value === 'object' ? JSON.stringify(value) : ''
167
- }
199
+ editable: false
168
200
  },
169
- width: 200
201
+ width: 200,
202
+ imex: true
170
203
  },
171
204
  {
172
- type: 'json',
205
+ type: 'json5',
173
206
  name: 'spec',
174
207
  header: i18next.t('field.spec'),
175
208
  record: {
176
- editable: false,
177
- renderer: (value, column, record, rowIndex, field) => {
178
- return typeof value === 'string' ? value : typeof value === 'object' ? JSON.stringify(value) : ''
179
- }
209
+ editable: false
180
210
  },
181
211
  width: 200
182
212
  },
183
213
  {
184
- type: 'code',
214
+ type: 'text',
185
215
  name: 'rawData',
186
216
  header: i18next.t('field.raw-data'),
187
217
  record: {
188
218
  editable: false
189
219
  },
190
- width: 200
220
+ width: 200,
221
+ imex: true
191
222
  },
192
223
  {
193
- type: 'object',
194
- name: 'updater',
195
- header: i18next.t('field.updater'),
224
+ type: 'string',
225
+ name: 'workDate',
226
+ header: i18next.t('field.work-date'),
196
227
  sortable: true,
197
- width: 120
228
+ width: 80,
229
+ imex: true
198
230
  },
199
231
  {
200
- type: 'datetime',
201
- name: 'updatedAt',
202
- header: i18next.t('field.updated_at'),
232
+ type: 'string',
233
+ name: 'workShift',
234
+ header: i18next.t('field.work-shift'),
203
235
  sortable: true,
204
- width: 180
236
+ width: 40,
237
+ imex: true
205
238
  },
206
239
  {
207
240
  type: 'datetime',
208
241
  name: 'collectedAt',
209
- header: i18next.t('field.collected_at'),
242
+ header: i18next.t('field.collected-at'),
243
+ sortable: true,
244
+ width: 180,
245
+ imex: true
246
+ },
247
+ {
248
+ type: 'resource-object',
249
+ name: 'updater',
250
+ header: i18next.t('field.updater'),
251
+ sortable: true,
252
+ width: 120,
253
+ imex: true
254
+ },
255
+ {
256
+ type: 'datetime',
257
+ name: 'updatedAt',
258
+ header: i18next.t('field.updated_at'),
210
259
  sortable: true,
211
- width: 180
260
+ width: 180,
261
+ imex: true
212
262
  }
213
263
  ],
214
264
  rows: {
215
265
  appendable: false,
216
266
  selectable: {
217
267
  multiple: true
268
+ },
269
+ classifier: function (record, rowIndex) {
270
+ var emphasized
271
+ if (record['oos']) {
272
+ emphasized = ['red']
273
+ } else if (record['ooc']) {
274
+ emphasized = 'orange'
275
+ }
276
+
277
+ return {
278
+ emphasized
279
+ }
218
280
  }
219
281
  },
220
282
  sorters: [
221
283
  {
222
- name: 'name'
284
+ name: 'updatedAt',
285
+ desc: true
223
286
  }
224
287
  ]
225
288
  }
@@ -255,7 +318,12 @@ export class DataSample extends connect(store)(localize(i18next)(PageView)) {
255
318
  }
256
319
  partitionKeys
257
320
  data
321
+ rawData
258
322
  spec
323
+ ooc
324
+ oos
325
+ workDate
326
+ workShift
259
327
  updater {
260
328
  id
261
329
  name
@@ -280,37 +348,44 @@ export class DataSample extends connect(store)(localize(i18next)(PageView)) {
280
348
  }
281
349
  }
282
350
 
283
- async _deleteDataSample() {
284
- if (confirm(i18next.t('text.sure_to_x', { x: i18next.t('text.delete') }))) {
285
- const ids = this.grist.selected.map(record => record.id)
286
- if (ids && ids.length > 0) {
287
- const response = await client.mutate({
288
- mutation: gql`
289
- mutation ($ids: [String!]!) {
290
- deleteDataSamples(ids: $ids)
351
+ _exportableData() {
352
+ let records = []
353
+ if (this.grist.selected && this.grist.selected.length > 0) {
354
+ records = this.grist.selected
355
+ } else {
356
+ records = this.grist.data.records
357
+ }
358
+
359
+ var headerSetting = this.grist.compiledConfig.columns
360
+ .filter(column => column.type !== 'gutter' && column.record !== undefined && column.imex !== undefined)
361
+ .map(column => {
362
+ return column.imex === true
363
+ ? {
364
+ header: column.header.renderer(),
365
+ key: column.name,
366
+ width: column.width,
367
+ type: column.type
291
368
  }
292
- `,
293
- variables: {
294
- ids
295
- }
296
- })
369
+ : column.imex
370
+ })
297
371
 
298
- if (!response.errors) {
299
- this.grist.fetch()
300
- notify({
301
- message: i18next.t('text.info_x_successfully', { x: i18next.t('text.delete') })
302
- })
303
- }
372
+ var data = records.map(item => {
373
+ return {
374
+ id: item.id,
375
+ ...this.gristConfig.columns
376
+ .filter(column => column.type !== 'gutter' && column.record !== undefined && column.imex !== undefined)
377
+ .reduce((record, column) => {
378
+ const key = column.imex === true ? column.name : column.imex.key
379
+ record[key] = key
380
+ .split('.')
381
+ .reduce((obj, key) => (obj && obj[key] !== 'undefined' ? obj[key] : undefined), item)
382
+ return record
383
+ }, {})
304
384
  }
305
- }
306
- }
385
+ })
307
386
 
308
- async stateChanged(state) {
309
- if (this.active && this._currentPopupName && !state.layout.viewparts[this._currentPopupName]) {
310
- this.grist.fetch()
311
- this._currentPopupName = null
312
- }
387
+ return { header: headerSetting, data: data }
313
388
  }
314
389
  }
315
390
 
316
- window.customElements.define('data-sample-page', DataSample)
391
+ window.customElements.define('data-sample-list-page', DataSampleListPage)
@@ -0,0 +1,97 @@
1
+ import '@operato/dataset/ox-data-sample-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 DataSampleView extends localize(i18next)(LitElement) {
11
+ static get properties() {
12
+ return {
13
+ dataSet: Object,
14
+ dataSample: Object
15
+ }
16
+ }
17
+
18
+ static get styles() {
19
+ return [
20
+ ScrollbarStyles,
21
+ css`
22
+ :host {
23
+ display: flex;
24
+ flex-direction: column;
25
+
26
+ background-color: #fff;
27
+ }
28
+
29
+ div[content] {
30
+ flex: 1;
31
+
32
+ display: flex;
33
+ overflow: auto;
34
+ }
35
+
36
+ ox-data-sample-view {
37
+ flex: 1;
38
+ padding: var(--padding-wide);
39
+ }
40
+ `
41
+ ]
42
+ }
43
+
44
+ get sampleView() {
45
+ return this.renderRoot.querySelector('ox-data-sample-view')
46
+ }
47
+
48
+ render() {
49
+ return html`
50
+ <div content>
51
+ <ox-data-sample-view .dataSet=${this.dataSet} .dataSample=${this.dataSample}></ox-data-sample-view>
52
+ </div>
53
+ `
54
+ }
55
+
56
+ updated(changes) {
57
+ if (changes.has('dataSample')) {
58
+ this.fetchDataSet()
59
+ }
60
+ }
61
+
62
+ async fetchDataSet() {
63
+ const id = this.dataSample?.dataSet?.id
64
+
65
+ if (id) {
66
+ const response = await client.query({
67
+ query: gql`
68
+ query ($id: String!) {
69
+ dataSet(id: $id) {
70
+ id
71
+ name
72
+ description
73
+ useCase
74
+ dataItems {
75
+ id
76
+ name
77
+ description
78
+ active
79
+ unit
80
+ tag
81
+ type
82
+ spec
83
+ }
84
+ }
85
+ }
86
+ `,
87
+ variables: {
88
+ id: this.dataSample.dataSet.id
89
+ }
90
+ })
91
+
92
+ this.dataSet = response.data.dataSet
93
+ }
94
+ }
95
+ }
96
+
97
+ window.customElements.define('data-sample-view', DataSampleView)
@@ -11,7 +11,7 @@ import { PageView, store } from '@operato/shell'
11
11
  import { CommonButtonStyles, ScrollbarStyles } from '@operato/styles'
12
12
  import { isMobileDevice } from '@operato/utils'
13
13
 
14
- export class DataSensor extends connect(store)(localize(i18next)(PageView)) {
14
+ export class DataSensorListPage extends connect(store)(localize(i18next)(PageView)) {
15
15
  static get properties() {
16
16
  return {
17
17
  active: String,
@@ -53,7 +53,7 @@ export class DataSensor extends connect(store)(localize(i18next)(PageView)) {
53
53
  get context() {
54
54
  return {
55
55
  title: i18next.t('title.data-sensor list'),
56
- help: 'integration/ui/data-sensor',
56
+ help: 'dataset/data-sensor',
57
57
  actions: [
58
58
  {
59
59
  title: i18next.t('button.copy'),
@@ -153,6 +153,7 @@ export class DataSensor extends connect(store)(localize(i18next)(PageView)) {
153
153
  editable: true
154
154
  },
155
155
  sortable: true,
156
+ filter: true,
156
157
  width: 60
157
158
  },
158
159
  {
@@ -176,6 +177,7 @@ export class DataSensor extends connect(store)(localize(i18next)(PageView)) {
176
177
  editable: true
177
178
  },
178
179
  sortable: true,
180
+ filter: 'search',
179
181
  width: 150
180
182
  },
181
183
  {
@@ -194,7 +196,7 @@ export class DataSensor extends connect(store)(localize(i18next)(PageView)) {
194
196
  {
195
197
  type: 'object',
196
198
  name: 'dataSet',
197
- header: i18next.t('field.dataSet'),
199
+ header: i18next.t('field.data-set'),
198
200
  record: {
199
201
  editable: true,
200
202
  options: {
@@ -272,7 +274,7 @@ export class DataSensor extends connect(store)(localize(i18next)(PageView)) {
272
274
  {
273
275
  type: 'datetime',
274
276
  name: 'collectedAt',
275
- header: i18next.t('field.collected_at'),
277
+ header: i18next.t('field.collected-at'),
276
278
  record: {
277
279
  editable: false
278
280
  },
@@ -382,13 +384,6 @@ export class DataSensor extends connect(store)(localize(i18next)(PageView)) {
382
384
  }
383
385
  }
384
386
 
385
- async stateChanged(state) {
386
- if (this.active && this._currentPopupName && !state.layout.viewparts[this._currentPopupName]) {
387
- this.grist.fetch()
388
- this._currentPopupName = null
389
- }
390
- }
391
-
392
387
  async _copyDataSensor() {
393
388
  var selected = this.grist.selected
394
389
  if (selected.length == 0) return
@@ -443,4 +438,4 @@ export class DataSensor extends connect(store)(localize(i18next)(PageView)) {
443
438
  }
444
439
  }
445
440
 
446
- window.customElements.define('data-sensor-page', DataSensor)
441
+ window.customElements.define('data-sensor-list-page', DataSensorListPage)
@@ -1,8 +1,8 @@
1
- import gql from 'graphql-tag'
2
- import { css, html, LitElement } from 'lit'
1
+ import { LitElement, css, html } from 'lit'
2
+ import { i18next, localize } from '@operato/i18n'
3
3
 
4
4
  import { client } from '@operato/graphql'
5
- import { i18next, localize } from '@operato/i18n'
5
+ import gql from 'graphql-tag'
6
6
  import { isMobileDevice } from '@operato/utils'
7
7
 
8
8
  class DataItemList extends localize(i18next)(LitElement) {
@@ -61,8 +61,6 @@ class DataItemList extends localize(i18next)(LitElement) {
61
61
  `
62
62
  }
63
63
 
64
- async updated(changedProps) {}
65
-
66
64
  async firstUpdated() {
67
65
  this.gristConfig = {
68
66
  list: { fields: ['name', 'description', 'active'] },
@@ -132,6 +130,17 @@ class DataItemList extends localize(i18next)(LitElement) {
132
130
  sortable: true,
133
131
  width: 60
134
132
  },
133
+ {
134
+ type: 'checkbox',
135
+ name: 'hidden',
136
+ label: true,
137
+ header: i18next.t('field.hidden'),
138
+ record: {
139
+ editable: true
140
+ },
141
+ sortable: true,
142
+ width: 60
143
+ },
135
144
  {
136
145
  type: 'string',
137
146
  name: 'tag',
@@ -157,9 +166,7 @@ class DataItemList extends localize(i18next)(LitElement) {
157
166
  header: i18next.t('field.options'),
158
167
  record: {
159
168
  editable: true,
160
- renderer: (value, column, record, rowIndex, field) => {
161
- return typeof value === 'string' ? value : typeof value === 'object' ? JSON.stringify(value) : ''
162
- },
169
+ renderer: 'json5',
163
170
  options: async (value, column, record, row, field) => {
164
171
  return {
165
172
  name: record.type,
@@ -168,7 +175,7 @@ class DataItemList extends localize(i18next)(LitElement) {
168
175
  record.type === 'select'
169
176
  ? [
170
177
  {
171
- type: 'options',
178
+ type: 'options' /* property-editor type */,
172
179
  name: 'options',
173
180
  label: 'options'
174
181
  }
@@ -181,6 +188,15 @@ class DataItemList extends localize(i18next)(LitElement) {
181
188
  },
182
189
  width: 120
183
190
  },
191
+ {
192
+ type: 'string',
193
+ name: 'unit',
194
+ header: i18next.t('field.unit'),
195
+ record: {
196
+ editable: true
197
+ },
198
+ width: 120
199
+ },
184
200
  {
185
201
  type: 'number',
186
202
  name: 'quota',
@@ -191,11 +207,16 @@ class DataItemList extends localize(i18next)(LitElement) {
191
207
  width: 60
192
208
  },
193
209
  {
194
- type: 'json',
210
+ type: 'data-item-spec',
195
211
  name: 'spec',
196
212
  header: i18next.t('field.spec'),
197
213
  record: {
198
- editable: true
214
+ editable: true,
215
+ options: {
216
+ name: '',
217
+ help: '',
218
+ objectified: true /* prevent from stringifying */
219
+ }
199
220
  },
200
221
  width: 200
201
222
  }
@@ -234,9 +255,11 @@ class DataItemList extends localize(i18next)(LitElement) {
234
255
  description
235
256
  sequence
236
257
  active
258
+ hidden
237
259
  tag
238
260
  type
239
261
  options
262
+ unit
240
263
  quota
241
264
  spec
242
265
  }
@@ -279,7 +302,9 @@ class DataItemList extends localize(i18next)(LitElement) {
279
302
  }
280
303
  })
281
304
 
282
- if (!response.errors) this.grist.fetch()
305
+ if (!response.errors) {
306
+ this.grist.fetch()
307
+ }
283
308
  }
284
309
  }
285
310