@things-factory/dataset 5.0.0-alpha.32 → 5.0.0-alpha.35

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.
@@ -1,16 +1,18 @@
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
3
  import {
2
4
  OxGristRendererJson5,
3
5
  registerEditor as registerGristEditor,
4
6
  registerRenderer as registerGristRenderer
5
7
  } from '@operato/data-grist'
6
-
7
8
  import { OxGristEditorDataItemSpec } from '@operato/dataset/grist-editor'
8
- import { OxGristEditorPartitionKeys } from '@operato/app/grist-editor/ox-grist-editor-partition-keys.js'
9
9
 
10
10
  export default function bootstrap() {
11
11
  registerGristEditor('data-item-spec', OxGristEditorDataItemSpec)
12
12
  registerGristRenderer('data-item-spec', OxGristRendererJson5)
13
13
 
14
+ registerGristEditor('script', OxGristEditorCode)
15
+
14
16
  registerGristEditor('partition-keys', OxGristEditorPartitionKeys)
15
17
  registerGristRenderer('partition-keys', OxGristRendererJson5)
16
18
  }
@@ -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,54 +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-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
77
  export class DataEntryListPage extends connect(store)(localize(i18next)(PageView)) {
126
78
  static get properties() {
127
79
  return {
@@ -214,14 +166,6 @@ export class DataEntryListPage extends connect(store)(localize(i18next)(PageView
214
166
  click: showEntryView
215
167
  }
216
168
  },
217
- {
218
- type: 'gutter',
219
- gutterName: 'button',
220
- icon: 'analytics',
221
- handlers: {
222
- click: showMonitorView
223
- }
224
- },
225
169
  {
226
170
  type: 'string',
227
171
  name: 'name',
@@ -253,11 +197,11 @@ export class DataEntryListPage extends connect(store)(localize(i18next)(PageView
253
197
  options: [
254
198
  {},
255
199
  {
256
- display: 'Manually Collected',
200
+ display: i18next.t('text.manually collected'),
257
201
  value: 'manual'
258
202
  },
259
203
  {
260
- display: 'Automatically Collected',
204
+ display: i18next.t('text.automatically collected'),
261
205
  value: 'automatic'
262
206
  }
263
207
  ]
@@ -293,6 +237,15 @@ export class DataEntryListPage extends connect(store)(localize(i18next)(PageView
293
237
  width: 80,
294
238
  label: true
295
239
  },
240
+ {
241
+ type: 'resource-object',
242
+ name: 'entryRole',
243
+ header: i18next.t('field.entry-role'),
244
+ record: {
245
+ editable: false
246
+ },
247
+ width: 120
248
+ },
296
249
  {
297
250
  type: 'resource-object',
298
251
  name: 'supervisoryRole',
@@ -411,6 +364,10 @@ export class DataEntryListPage extends connect(store)(localize(i18next)(PageView
411
364
  useCase
412
365
  schedule
413
366
  timezone
367
+ entryRole {
368
+ id
369
+ name
370
+ }
414
371
  supervisoryRole {
415
372
  id
416
373
  name
@@ -426,6 +383,8 @@ export class DataEntryListPage extends connect(store)(localize(i18next)(PageView
426
383
  id
427
384
  name
428
385
  }
386
+ reportType
387
+ reportView
429
388
  updatedAt
430
389
  dataItems {
431
390
  name
@@ -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 gql from 'graphql-tag'
5
+ import JSON5 from 'json5'
6
+ import { css, html } from 'lit'
7
+ import { connect } from 'pwa-helpers/connect-mixin'
8
+
9
+ import { OxDataUseCase } from '@operato/dataset'
10
+ import { client } from '@operato/graphql'
11
+ import { i18next, localize } from '@operato/i18n'
12
+ import { openPopup } from '@operato/layout'
13
+ import { navigate, PageView, store } from '@operato/shell'
14
+ import { CommonGristStyles, ScrollbarStyles } from '@operato/styles'
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: dataSetsForEntry(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
  },