@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.
- package/client/pages/{data-entry-form.js → data-entry/data-entry-form.js} +1 -0
- package/client/pages/data-entry/data-entry-list-page.js +464 -0
- package/client/pages/{data-ooc.js → data-ooc/data-ooc-list-page.js} +3 -3
- package/client/pages/{data-ooc-view.js → data-ooc/data-ooc-view.js} +0 -0
- package/client/pages/{data-sample.js → data-sample/data-sample-list-page.js} +3 -3
- package/client/pages/{data-sample-view.js → data-sample/data-sample-view.js} +0 -0
- package/client/pages/{data-sensor.js → data-sensor/data-sensor-list-page.js} +3 -3
- package/client/pages/{data-item-list.js → data-set/data-item-list.js} +12 -0
- package/client/pages/{data-set-importer.js → data-set/data-set-importer.js} +0 -0
- package/client/pages/{data-set.js → data-set/data-set-list-page.js} +113 -32
- package/client/route.js +12 -8
- package/dist-server/controllers/create-data-sample.js +15 -10
- package/dist-server/controllers/create-data-sample.js.map +1 -1
- package/dist-server/service/data-item/data-item-type.js +4 -0
- package/dist-server/service/data-item/data-item-type.js.map +1 -1
- package/dist-server/service/data-item/data-item.js +7 -0
- package/dist-server/service/data-item/data-item.js.map +1 -1
- package/dist-server/service/data-set/data-set-query.js +98 -1
- package/dist-server/service/data-set/data-set-query.js.map +1 -1
- package/dist-server/service/data-set/data-set-type.js +32 -4
- package/dist-server/service/data-set/data-set-type.js.map +1 -1
- package/dist-server/service/data-set/data-set.js +39 -7
- package/dist-server/service/data-set/data-set.js.map +1 -1
- package/package.json +18 -16
- package/server/controllers/create-data-sample.ts +23 -14
- package/server/service/data-item/data-item-type.ts +3 -0
- package/server/service/data-item/data-item.ts +6 -0
- package/server/service/data-set/data-set-query.ts +79 -1
- package/server/service/data-set/data-set-type.ts +26 -4
- package/server/service/data-set/data-set.ts +36 -6
- package/things-factory.config.js +12 -8
- package/translations/en.json +9 -0
- package/translations/ko.json +8 -0
- package/translations/ms.json +8 -0
- package/translations/zh.json +8 -0
@@ -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
|
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: '
|
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',
|
488
|
+
window.customElements.define('data-ooc-list-page', DataOocListPage)
|
File without changes
|
@@ -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
|
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: '
|
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',
|
391
|
+
window.customElements.define('data-sample-list-page', DataSampleListPage)
|
File without changes
|
@@ -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
|
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: '
|
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',
|
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
|
File without changes
|