@things-factory/dataset 5.0.0-alpha.26 → 5.0.0-alpha.29

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 (35) hide show
  1. package/client/pages/{data-entry-form.js → data-entry/data-entry-form.js} +1 -0
  2. package/client/pages/data-entry/data-entry-list-page.js +464 -0
  3. package/client/pages/{data-ooc.js → data-ooc/data-ooc-list-page.js} +3 -3
  4. package/client/pages/{data-ooc-view.js → data-ooc/data-ooc-view.js} +0 -0
  5. package/client/pages/{data-sample.js → data-sample/data-sample-list-page.js} +3 -3
  6. package/client/pages/{data-sample-view.js → data-sample/data-sample-view.js} +0 -0
  7. package/client/pages/{data-sensor.js → data-sensor/data-sensor-list-page.js} +3 -3
  8. package/client/pages/{data-item-list.js → data-set/data-item-list.js} +12 -0
  9. package/client/pages/{data-set-importer.js → data-set/data-set-importer.js} +0 -0
  10. package/client/pages/{data-set.js → data-set/data-set-list-page.js} +113 -32
  11. package/client/route.js +12 -8
  12. package/dist-server/controllers/create-data-sample.js +15 -10
  13. package/dist-server/controllers/create-data-sample.js.map +1 -1
  14. package/dist-server/service/data-item/data-item-type.js +4 -0
  15. package/dist-server/service/data-item/data-item-type.js.map +1 -1
  16. package/dist-server/service/data-item/data-item.js +7 -0
  17. package/dist-server/service/data-item/data-item.js.map +1 -1
  18. package/dist-server/service/data-set/data-set-query.js +98 -1
  19. package/dist-server/service/data-set/data-set-query.js.map +1 -1
  20. package/dist-server/service/data-set/data-set-type.js +32 -4
  21. package/dist-server/service/data-set/data-set-type.js.map +1 -1
  22. package/dist-server/service/data-set/data-set.js +39 -7
  23. package/dist-server/service/data-set/data-set.js.map +1 -1
  24. package/package.json +18 -16
  25. package/server/controllers/create-data-sample.ts +23 -14
  26. package/server/service/data-item/data-item-type.ts +3 -0
  27. package/server/service/data-item/data-item.ts +6 -0
  28. package/server/service/data-set/data-set-query.ts +79 -1
  29. package/server/service/data-set/data-set-type.ts +26 -4
  30. package/server/service/data-set/data-set.ts +36 -6
  31. package/things-factory.config.js +12 -8
  32. package/translations/en.json +9 -0
  33. package/translations/ko.json +8 -0
  34. package/translations/ms.json +8 -0
  35. package/translations/zh.json +8 -0
@@ -21,6 +21,7 @@ class DataEntryForm extends localize(i18next)(LitElement) {
21
21
  flex-direction: column;
22
22
 
23
23
  background-color: #fff;
24
+ overflow: auto;
24
25
  }
25
26
 
26
27
  ox-data-entry-form {
@@ -0,0 +1,464 @@
1
+ import '@operato/data-grist'
2
+ import './data-entry-form'
3
+ import '@operato/board/ox-board-viewer.js'
4
+
5
+ import gql from 'graphql-tag'
6
+ import JSON5 from 'json5'
7
+ import { css, html } from 'lit'
8
+ import { connect } from 'pwa-helpers/connect-mixin'
9
+
10
+ import { getRenderer } from '@operato/data-grist'
11
+ import { OxDataUseCase } from '@operato/dataset'
12
+ import { client } from '@operato/graphql'
13
+ import { i18next, localize } from '@operato/i18n'
14
+ import { openPopup } from '@operato/layout'
15
+ import { navigate, PageView, store } from '@operato/shell'
16
+ import { CommonGristStyles, ScrollbarStyles } from '@operato/styles'
17
+ import { provider } from '@things-factory/board-ui'
18
+
19
+ const USECASE_OPTIONS = () => {
20
+ return ['', ...OxDataUseCase.getUseCaseNames()].map(name => {
21
+ return {
22
+ display: name,
23
+ value: name
24
+ }
25
+ })
26
+ }
27
+
28
+ const showEntryView = async (columns, data, column, record, rowIndex) => {
29
+ const { name, entryType, entryView } = record
30
+ const title = `${name} - ${i18next.t('title.data-entry-form')}`
31
+
32
+ switch (entryType) {
33
+ case 'generated':
34
+ openPopup(html` <data-entry-form .dataSet=${record} style="background-color: white;"></data-entry-form> `, {
35
+ closable: true,
36
+ backdrop: true,
37
+ size: 'large',
38
+ title
39
+ })
40
+ break
41
+
42
+ case 'board':
43
+ const board = {
44
+ id: entryView
45
+ }
46
+ openPopup(
47
+ html`
48
+ <ox-board-viewer
49
+ style="background-color: white;"
50
+ .board=${board}
51
+ .provider=${provider}
52
+ hide-fullscreen
53
+ hide-navigation
54
+ ></ox-board-viewer>
55
+ `,
56
+ {
57
+ closable: true,
58
+ backdrop: true,
59
+ size: 'large',
60
+ title
61
+ }
62
+ )
63
+
64
+ // navigate(`board-viewer/${entryView}?interactive=true&title=${title}`)
65
+ break
66
+
67
+ case 'page':
68
+ navigate(entryView)
69
+ break
70
+
71
+ case 'external':
72
+ window.open(entryView, '_blank')
73
+ break
74
+ }
75
+ }
76
+
77
+ const showMonitorView = (columns, data, column, record, rowIndex) => {
78
+ const { name, monitorType, monitorView } = record
79
+ const title = `${name} - ${i18next.t('title.data-entry-form')}`
80
+
81
+ switch (monitorType) {
82
+ case 'generated':
83
+ openPopup(html` <div style="background-color: white;">Under construction</div> `, {
84
+ backdrop: true,
85
+ size: 'large',
86
+ title
87
+ })
88
+ break
89
+
90
+ case 'board':
91
+ const board = {
92
+ id: monitorView
93
+ }
94
+ openPopup(
95
+ html`
96
+ <ox-board-viewer
97
+ style="background-color: white;"
98
+ .board=${board}
99
+ .provider=${provider}
100
+ hide-fullscreen
101
+ hide-navigation
102
+ ></ox-board-viewer>
103
+ `,
104
+ {
105
+ closable: true,
106
+ backdrop: true,
107
+ size: 'large',
108
+ title
109
+ }
110
+ )
111
+
112
+ // navigate(`board-viewer/${monitorView}?interactive=true&title=${title}`)
113
+ break
114
+
115
+ case 'page':
116
+ navigate(monitorView)
117
+ break
118
+
119
+ case 'external':
120
+ window.open(monitorView, '_blank')
121
+ break
122
+ }
123
+ }
124
+
125
+ export class DataEntryListPage extends connect(store)(localize(i18next)(PageView)) {
126
+ static get properties() {
127
+ return {
128
+ active: String,
129
+ gristConfig: Object,
130
+ filters: Object,
131
+ sorters: Object,
132
+ mode: String
133
+ }
134
+ }
135
+
136
+ static get styles() {
137
+ return [
138
+ ScrollbarStyles,
139
+ CommonGristStyles,
140
+ css`
141
+ :host {
142
+ display: flex;
143
+
144
+ width: 100%;
145
+
146
+ --grid-record-emphasized-background-color: red;
147
+ --grid-record-emphasized-color: yellow;
148
+ }
149
+ `
150
+ ]
151
+ }
152
+
153
+ get context() {
154
+ return {
155
+ title: i18next.t('title.data-entry list'),
156
+ help: 'dataset/data-entry-list'
157
+ }
158
+ }
159
+
160
+ render() {
161
+ const mode = 'CARD'
162
+
163
+ return html`
164
+ <ox-grist
165
+ .mode=${mode}
166
+ .config=${this.gristConfig}
167
+ .filters=${this.filters}
168
+ .orders=${this.orders}
169
+ .fetchHandler=${this.fetchHandler.bind(this)}
170
+ >
171
+ <div slot="headroom" id="filters">
172
+ <div id="filters">
173
+ <ox-filters-form></ox-filters-form>
174
+ </div>
175
+
176
+ <div id="sorters">
177
+ Sort
178
+ <mwc-icon
179
+ @click=${e => {
180
+ const target = e.currentTarget
181
+ this.renderRoot.querySelector('#sorter-control').open({
182
+ right: 0,
183
+ top: target.offsetTop + target.offsetHeight
184
+ })
185
+ }}
186
+ >expand_more</mwc-icon
187
+ >
188
+ <ox-popup id="sorter-control">
189
+ <ox-sorters-control> </ox-sorters-control>
190
+ </ox-popup>
191
+ </div>
192
+ </div>
193
+ </ox-grist>
194
+ `
195
+ }
196
+
197
+ get grist() {
198
+ return this.renderRoot.querySelector('ox-grist')
199
+ }
200
+
201
+ async pageInitialized(lifecycle) {
202
+ this.gristConfig = {
203
+ list: {
204
+ thumbnail: 'entryView',
205
+ fields: ['name', 'description'],
206
+ details: ['schedule', 'type', 'useCase', 'latestCollectedAt', 'prevSchedule', 'nextSchedule']
207
+ },
208
+ columns: [
209
+ {
210
+ type: 'gutter',
211
+ gutterName: 'button',
212
+ icon: 'fact_check',
213
+ handlers: {
214
+ click: showEntryView
215
+ }
216
+ },
217
+ {
218
+ type: 'gutter',
219
+ gutterName: 'button',
220
+ icon: 'analytics',
221
+ handlers: {
222
+ click: showMonitorView
223
+ }
224
+ },
225
+ {
226
+ type: 'string',
227
+ name: 'name',
228
+ header: i18next.t('field.name'),
229
+ record: {
230
+ editable: false
231
+ },
232
+ filter: 'search',
233
+ sortable: true,
234
+ width: 150
235
+ },
236
+ {
237
+ type: 'string',
238
+ name: 'description',
239
+ header: i18next.t('field.description'),
240
+ record: {
241
+ editable: false
242
+ },
243
+ filter: 'search',
244
+ width: 200
245
+ },
246
+ {
247
+ type: 'select',
248
+ name: 'type',
249
+ label: true,
250
+ header: i18next.t('field.type'),
251
+ record: {
252
+ editable: false,
253
+ options: [
254
+ {},
255
+ {
256
+ display: 'Manually Collected',
257
+ value: 'manual'
258
+ },
259
+ {
260
+ display: 'Automatically Collected',
261
+ value: 'automatic'
262
+ }
263
+ ]
264
+ },
265
+ sortable: true,
266
+ filter: true,
267
+ width: 60
268
+ },
269
+ {
270
+ type: 'select',
271
+ name: 'useCase',
272
+ label: true,
273
+ header: i18next.t('field.use-case'),
274
+ record: {
275
+ editable: false,
276
+ options: USECASE_OPTIONS
277
+ },
278
+ sortable: true,
279
+ filter: {
280
+ operator: 'eq',
281
+ options: USECASE_OPTIONS /* in case select options type is a function, filter should have its own options */
282
+ },
283
+ width: 80
284
+ },
285
+ {
286
+ type: 'crontab',
287
+ name: 'schedule',
288
+ label: true,
289
+ header: i18next.t('field.schedule'),
290
+ record: {
291
+ editable: false
292
+ },
293
+ width: 80,
294
+ label: true
295
+ },
296
+ {
297
+ type: 'resource-object',
298
+ name: 'supervisoryRole',
299
+ header: i18next.t('field.supervisory-role'),
300
+ record: {
301
+ editable: false
302
+ },
303
+ width: 120
304
+ },
305
+ {
306
+ type: 'datetime',
307
+ name: 'latestCollectedAt',
308
+ label: true,
309
+ header: i18next.t('field.latest-collected-at'),
310
+ record: {
311
+ editable: false
312
+ },
313
+ width: 180
314
+ },
315
+ {
316
+ type: 'datetime',
317
+ name: 'prevSchedule',
318
+ label: true,
319
+ header: i18next.t('field.prev-schedule'),
320
+ record: {
321
+ editable: false
322
+ },
323
+ width: 180
324
+ },
325
+ {
326
+ type: 'datetime',
327
+ name: 'nextSchedule',
328
+ label: true,
329
+ header: i18next.t('field.next-schedule'),
330
+ record: {
331
+ editable: false
332
+ },
333
+ width: 180
334
+ },
335
+ {
336
+ type: 'string',
337
+ name: 'entryView',
338
+ hidden: true,
339
+ record: {
340
+ editable: false,
341
+ renderer: function (value, column, record, rowIndex, field) {
342
+ const type = record.entryType !== 'board' ? 'string' : 'image'
343
+ value = record.entryType !== 'board' ? value : record.entryBoard?.thumbnail
344
+
345
+ return getRenderer(type)(value, column, record, rowIndex, field)
346
+ }
347
+ }
348
+ }
349
+ ],
350
+ rows: {
351
+ selectable: {
352
+ multiple: false
353
+ },
354
+ handlers: {
355
+ click: showEntryView
356
+ },
357
+ classifier: function (record, rowIndex) {}
358
+ },
359
+ sorters: [
360
+ {
361
+ name: 'name'
362
+ }
363
+ ]
364
+ }
365
+
366
+ await this.updateComplete
367
+
368
+ this.grist.fetch()
369
+ }
370
+
371
+ async pageUpdated(changes, lifecycle) {
372
+ if (this.active) {
373
+ await this.updateComplete
374
+
375
+ var filters = lifecycle.params?.['filters']
376
+ if (filters) {
377
+ try {
378
+ filters = JSON5.parse(filters)
379
+ this.filters = filters
380
+ } catch (e) {
381
+ console.error(`filters parameter parsing error: ${e}`)
382
+ }
383
+ }
384
+
385
+ var sorters = lifecycle.params?.['sorters']
386
+ if (sorters) {
387
+ try {
388
+ sorters = JSON5.parse(sorters)
389
+ this.sorters = sorters
390
+ } catch (e) {
391
+ console.error(`sorters parameter parsing error: ${e}`)
392
+ }
393
+ }
394
+
395
+ this.grist.fetch()
396
+ }
397
+ }
398
+
399
+ async fetchHandler({ page, limit, sortings = [], filters = [] }) {
400
+ const response = await client.query({
401
+ query: gql`
402
+ query ($filters: [Filter!], $pagination: Pagination, $sortings: [Sorting!]) {
403
+ responses: dataSetsForEntry(filters: $filters, pagination: $pagination, sortings: $sortings) {
404
+ items {
405
+ id
406
+ name
407
+ description
408
+ partitionKeys
409
+ active
410
+ type
411
+ useCase
412
+ schedule
413
+ timezone
414
+ supervisoryRole {
415
+ id
416
+ name
417
+ }
418
+ entryType
419
+ entryView
420
+ entryBoard {
421
+ thumbnail
422
+ }
423
+ monitorType
424
+ monitorView
425
+ updater {
426
+ id
427
+ name
428
+ }
429
+ updatedAt
430
+ dataItems {
431
+ name
432
+ description
433
+ sequence
434
+ active
435
+ tag
436
+ type
437
+ unit
438
+ options
439
+ quota
440
+ spec
441
+ }
442
+ latestCollectedAt
443
+ nextSchedule
444
+ prevSchedule
445
+ }
446
+ total
447
+ }
448
+ }
449
+ `,
450
+ variables: {
451
+ filters,
452
+ pagination: { page, limit },
453
+ sortings
454
+ }
455
+ })
456
+
457
+ return {
458
+ total: response.data.responses.total || 0,
459
+ records: response.data.responses.items || []
460
+ }
461
+ }
462
+ }
463
+
464
+ window.customElements.define('data-entry-list-page', DataEntryListPage)
@@ -12,7 +12,7 @@ import { PageView, store } from '@operato/shell'
12
12
  import { ScrollbarStyles } from '@operato/styles'
13
13
  import { isMobileDevice } from '@operato/utils'
14
14
 
15
- export class DataOoc extends connect(store)(localize(i18next)(PageView)) {
15
+ export class DataOocListPage extends connect(store)(localize(i18next)(PageView)) {
16
16
  static get properties() {
17
17
  return {
18
18
  active: String,
@@ -54,7 +54,7 @@ export class DataOoc extends connect(store)(localize(i18next)(PageView)) {
54
54
  get context() {
55
55
  return {
56
56
  title: i18next.t('title.data-ooc list'),
57
- help: 'integration/ui/data-ooc',
57
+ help: 'dataset/data-ooc',
58
58
  actions: [
59
59
  // {
60
60
  // title: i18next.t('button.save'),
@@ -485,4 +485,4 @@ export class DataOoc extends connect(store)(localize(i18next)(PageView)) {
485
485
  }
486
486
  }
487
487
 
488
- window.customElements.define('data-ooc-page', DataOoc)
488
+ window.customElements.define('data-ooc-list-page', DataOocListPage)
@@ -12,7 +12,7 @@ import { PageView, store } from '@operato/shell'
12
12
  import { ScrollbarStyles } from '@operato/styles'
13
13
  import { isMobileDevice } from '@operato/utils'
14
14
 
15
- export class DataSample extends connect(store)(localize(i18next)(PageView)) {
15
+ export class DataSampleListPage extends connect(store)(localize(i18next)(PageView)) {
16
16
  static get properties() {
17
17
  return {
18
18
  active: String,
@@ -54,7 +54,7 @@ export class DataSample extends connect(store)(localize(i18next)(PageView)) {
54
54
  get context() {
55
55
  return {
56
56
  title: i18next.t('title.data-sample list'),
57
- help: 'integration/ui/data-sample',
57
+ help: 'dataset/data-sample',
58
58
  actions: [],
59
59
  exportable: {
60
60
  name: i18next.t('title.data-sample list'),
@@ -388,4 +388,4 @@ export class DataSample extends connect(store)(localize(i18next)(PageView)) {
388
388
  }
389
389
  }
390
390
 
391
- window.customElements.define('data-sample-page', DataSample)
391
+ window.customElements.define('data-sample-list-page', DataSampleListPage)
@@ -11,7 +11,7 @@ import gql from 'graphql-tag'
11
11
  import { isMobileDevice } from '@operato/utils'
12
12
  import { notify } from '@operato/layout'
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'),
@@ -438,4 +438,4 @@ export class DataSensor extends connect(store)(localize(i18next)(PageView)) {
438
438
  }
439
439
  }
440
440
 
441
- window.customElements.define('data-sensor-page', DataSensor)
441
+ window.customElements.define('data-sensor-list-page', DataSensorListPage)
@@ -130,6 +130,17 @@ class DataItemList extends localize(i18next)(LitElement) {
130
130
  sortable: true,
131
131
  width: 60
132
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
+ },
133
144
  {
134
145
  type: 'string',
135
146
  name: 'tag',
@@ -244,6 +255,7 @@ class DataItemList extends localize(i18next)(LitElement) {
244
255
  description
245
256
  sequence
246
257
  active
258
+ hidden
247
259
  tag
248
260
  type
249
261
  options