@things-factory/dataset 5.0.0-alpha.31 → 5.0.0-alpha.34
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/bootstrap.js +4 -2
- package/client/pages/data-entry/data-entry-list-page.js +15 -56
- package/client/pages/data-report/data-report-list-page.js +462 -0
- package/client/pages/data-set/data-set-list-page.js +96 -3
- package/client/route.js +4 -0
- package/dist-server/service/data-set/data-set-query.js +34 -1
- package/dist-server/service/data-set/data-set-query.js.map +1 -1
- package/dist-server/service/data-set/data-set-type.js +28 -4
- package/dist-server/service/data-set/data-set-type.js.map +1 -1
- package/dist-server/service/data-set/data-set.js +62 -15
- package/dist-server/service/data-set/data-set.js.map +1 -1
- package/package.json +16 -16
- package/server/service/data-set/data-set-query.ts +26 -0
- package/server/service/data-set/data-set-type.ts +23 -5
- package/server/service/data-set/data-set.ts +51 -6
- package/things-factory.config.js +4 -0
- package/translations/en.json +8 -2
- package/translations/ko.json +8 -2
- package/translations/ms.json +8 -2
- package/translations/zh.json +8 -2
package/client/bootstrap.js
CHANGED
@@ -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
|
}
|
@@ -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',
|
@@ -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
|
@@ -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: 'Manually Collected',
|
242
|
+
value: 'manual'
|
243
|
+
},
|
244
|
+
{
|
245
|
+
display: '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)
|