@things-factory/dataset 5.0.0-alpha.33 → 5.0.0-alpha.36

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