@things-factory/dataset 5.0.0-alpha.9 → 5.0.0-zeta.1

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 (105) hide show
  1. package/README.md +9 -0
  2. package/assets/data-samples.jpg +0 -0
  3. package/client/bootstrap.js +21 -1
  4. package/client/pages/{data-entry-form.js → data-entry/data-entry-form.js} +15 -3
  5. package/client/pages/data-entry/data-entry-list-page.js +390 -0
  6. package/client/pages/data-ooc/data-ooc-list-page.js +416 -0
  7. package/client/pages/data-ooc/data-ooc-view.js +183 -0
  8. package/client/pages/data-report/data-report-embed-page.js +113 -0
  9. package/client/pages/data-report/data-report-list-page.js +432 -0
  10. package/client/pages/data-report/jasper-report-oocs-page.js +122 -0
  11. package/client/pages/data-report/jasper-report-samples-crosstab-page.js +122 -0
  12. package/client/pages/data-report/jasper-report-samples-page.js +122 -0
  13. package/client/pages/data-sample/data-sample-list-page.js +372 -0
  14. package/client/pages/data-sample/data-sample-view.js +98 -0
  15. package/client/pages/{data-sensor.js → data-sensor/data-sensor-list-page.js} +43 -68
  16. package/client/pages/{data-item-list.js → data-set/data-item-list.js} +36 -11
  17. package/client/pages/{data-set-importer.js → data-set/data-set-importer.js} +0 -0
  18. package/client/pages/data-set/data-set-list-page.js +739 -0
  19. package/client/route.js +34 -6
  20. package/config/config.development.js +13 -0
  21. package/config/config.production.js +1 -0
  22. package/dist-server/controllers/create-data-sample.js +133 -0
  23. package/dist-server/controllers/create-data-sample.js.map +1 -0
  24. package/dist-server/controllers/data-use-case.js +57 -0
  25. package/dist-server/controllers/data-use-case.js.map +1 -0
  26. package/dist-server/controllers/index.js +18 -0
  27. package/dist-server/controllers/index.js.map +1 -1
  28. package/dist-server/controllers/jasper-report.js +156 -0
  29. package/dist-server/controllers/jasper-report.js.map +1 -0
  30. package/dist-server/index.js +1 -0
  31. package/dist-server/index.js.map +1 -1
  32. package/dist-server/routes.js +13 -24
  33. package/dist-server/routes.js.map +1 -1
  34. package/dist-server/service/data-item/data-item-query.js +6 -2
  35. package/dist-server/service/data-item/data-item-query.js.map +1 -1
  36. package/dist-server/service/data-item/data-item-type.js +15 -7
  37. package/dist-server/service/data-item/data-item-type.js.map +1 -1
  38. package/dist-server/service/data-item/data-item.js +17 -3
  39. package/dist-server/service/data-item/data-item.js.map +1 -1
  40. package/dist-server/service/data-ooc/data-ooc-mutation.js +92 -0
  41. package/dist-server/service/data-ooc/data-ooc-mutation.js.map +1 -0
  42. package/dist-server/service/data-ooc/data-ooc-query.js +120 -0
  43. package/dist-server/service/data-ooc/data-ooc-query.js.map +1 -0
  44. package/dist-server/service/data-ooc/data-ooc-subscription.js +65 -0
  45. package/dist-server/service/data-ooc/data-ooc-subscription.js.map +1 -0
  46. package/dist-server/service/data-ooc/data-ooc-type.js +107 -0
  47. package/dist-server/service/data-ooc/data-ooc-type.js.map +1 -0
  48. package/dist-server/service/data-ooc/data-ooc.js +237 -0
  49. package/dist-server/service/data-ooc/data-ooc.js.map +1 -0
  50. package/dist-server/service/data-ooc/index.js +10 -0
  51. package/dist-server/service/data-ooc/index.js.map +1 -0
  52. package/dist-server/service/data-sample/data-sample-mutation.js +2 -138
  53. package/dist-server/service/data-sample/data-sample-mutation.js.map +1 -1
  54. package/dist-server/service/data-sample/data-sample-query.js +7 -2
  55. package/dist-server/service/data-sample/data-sample-query.js.map +1 -1
  56. package/dist-server/service/data-sample/data-sample-type.js +12 -42
  57. package/dist-server/service/data-sample/data-sample-type.js.map +1 -1
  58. package/dist-server/service/data-sample/data-sample.js +34 -3
  59. package/dist-server/service/data-sample/data-sample.js.map +1 -1
  60. package/dist-server/service/data-sensor/data-sensor-query.js +7 -2
  61. package/dist-server/service/data-sensor/data-sensor-query.js.map +1 -1
  62. package/dist-server/service/data-set/data-set-mutation.js +40 -14
  63. package/dist-server/service/data-set/data-set-mutation.js.map +1 -1
  64. package/dist-server/service/data-set/data-set-query.js +190 -3
  65. package/dist-server/service/data-set/data-set-query.js.map +1 -1
  66. package/dist-server/service/data-set/data-set-type.js +84 -3
  67. package/dist-server/service/data-set/data-set-type.js.map +1 -1
  68. package/dist-server/service/data-set/data-set.js +110 -15
  69. package/dist-server/service/data-set/data-set.js.map +1 -1
  70. package/dist-server/service/index.js +6 -2
  71. package/dist-server/service/index.js.map +1 -1
  72. package/package.json +19 -13
  73. package/server/controllers/create-data-sample.ts +177 -0
  74. package/server/controllers/data-use-case.ts +85 -0
  75. package/server/controllers/index.ts +2 -0
  76. package/server/controllers/jasper-report.ts +170 -0
  77. package/server/index.ts +1 -0
  78. package/server/routes.ts +21 -31
  79. package/server/service/data-item/data-item-query.ts +8 -3
  80. package/server/service/data-item/data-item-type.ts +10 -6
  81. package/server/service/data-item/data-item.ts +15 -4
  82. package/server/service/data-ooc/data-ooc-mutation.ts +150 -0
  83. package/server/service/data-ooc/data-ooc-query.ts +69 -0
  84. package/server/service/data-ooc/data-ooc-subscription.ts +51 -0
  85. package/server/service/data-ooc/data-ooc-type.ts +68 -0
  86. package/server/service/data-ooc/data-ooc.ts +204 -0
  87. package/server/service/data-ooc/index.ts +7 -0
  88. package/server/service/data-sample/data-sample-mutation.ts +3 -168
  89. package/server/service/data-sample/data-sample-query.ts +9 -3
  90. package/server/service/data-sample/data-sample-type.ts +7 -28
  91. package/server/service/data-sample/data-sample.ts +33 -3
  92. package/server/service/data-sensor/data-sensor-query.ts +9 -3
  93. package/server/service/data-set/data-set-mutation.ts +53 -14
  94. package/server/service/data-set/data-set-query.ts +161 -4
  95. package/server/service/data-set/data-set-type.ts +65 -4
  96. package/server/service/data-set/data-set.ts +100 -12
  97. package/server/service/index.ts +6 -2
  98. package/things-factory.config.js +35 -7
  99. package/translations/en.json +46 -3
  100. package/translations/ko.json +45 -3
  101. package/translations/ms.json +44 -3
  102. package/translations/zh.json +44 -3
  103. package/client/pages/data-sample.js +0 -307
  104. package/client/pages/data-set.js +0 -457
  105. package/yarn-error.log +0 -23244
@@ -0,0 +1,122 @@
1
+ import '@operato/data-grist'
2
+ import '@operato/form'
3
+
4
+ import { css, html } from 'lit'
5
+
6
+ import { i18next, localize } from '@operato/i18n'
7
+ import { CommonButtonStyles, ScrollbarStyles } from '@operato/styles'
8
+ import { PageView } from '@things-factory/shell'
9
+
10
+ class JasperReportSamplesPage extends localize(i18next)(PageView) {
11
+ static get properties() {
12
+ return {
13
+ _grnNo: String,
14
+ _status: String,
15
+ resourceId: String,
16
+ params: Object
17
+ }
18
+ }
19
+
20
+ static get styles() {
21
+ return [
22
+ ScrollbarStyles,
23
+ css`
24
+ :host {
25
+ display: flex;
26
+ flex-direction: column;
27
+ padding: 0;
28
+ }
29
+
30
+ #container {
31
+ flex: 1;
32
+ padding: 0;
33
+ margin: 0;
34
+ border: 0;
35
+ }
36
+ `
37
+ ]
38
+ }
39
+
40
+ get context() {
41
+ const filters = [
42
+ {
43
+ name: 'workDateRange',
44
+ type: 'date',
45
+ label: 'date',
46
+ operator: 'between'
47
+ }
48
+ ]
49
+ var actions = [
50
+ {
51
+ title: i18next.t('button.print'),
52
+ action: () => {
53
+ this.renderRoot.querySelector('iframe').contentWindow.print()
54
+ },
55
+ ...CommonButtonStyles.print
56
+ }
57
+ ]
58
+ return {
59
+ title: 'jasper-report',
60
+ actions,
61
+ filters
62
+ }
63
+ }
64
+
65
+ render() {
66
+ return html`
67
+ <ox-filters-form-base
68
+ .filters=${this.context.filters}
69
+ @filters-change=${e => {
70
+ console.log('filters changed', e.detail)
71
+ this._reportTemplate(e.detail.filters)
72
+ }}
73
+ ?url-params-sensitive=${this.active}
74
+ ></ox-filters-form-base>
75
+ <iframe id="container"></iframe>
76
+ `
77
+ }
78
+
79
+ get searchForm() {
80
+ return this.renderRoot.querySelector('ox-filters-form-base')
81
+ }
82
+ async pageUpdated(changes, lifecycle) {
83
+ if (this.active) {
84
+ this.updateContext()
85
+ }
86
+ }
87
+
88
+ async _reportTemplate(filters) {
89
+ const params = filters.reduce((acc, curr) => ((acc[curr.name] = curr.value), acc), {})
90
+ Object.assign(params, this.lifecycle.params)
91
+
92
+ const { workDateRange, workShift, template } = params
93
+
94
+ /** ignoring date conditions */
95
+ if (!workDateRange[0] || !workDateRange[1] || workDateRange[0] > workDateRange[1]) {
96
+ return
97
+ }
98
+
99
+ /** urlencoded params including test values */
100
+ const urlParams = {
101
+ table: 'samples',
102
+ dataSetId: this.lifecycle.resourceId,
103
+ fromWorkDate: workDateRange[0],
104
+ toWorkDate: workDateRange[1],
105
+ workShift,
106
+ template,
107
+ templateType: 'normal'
108
+ }
109
+
110
+ const encodedUrlParams = Object.keys(urlParams)
111
+ .filter(key => {
112
+ // ignore empty
113
+ return !!urlParams[key]
114
+ })
115
+ .map(key => `${key}=${encodeURIComponent(urlParams[key])}`)
116
+ .join('&')
117
+
118
+ this.shadowRoot.querySelector('#container').src = `/data-report/jasper?${encodedUrlParams}`
119
+ }
120
+ }
121
+
122
+ window.customElements.define('jasper-report-samples-page', JasperReportSamplesPage)
@@ -0,0 +1,372 @@
1
+ import '@operato/data-grist'
2
+ import './data-sample-view.js'
3
+
4
+ import gql from 'graphql-tag'
5
+ import { css, html } from 'lit'
6
+ import { connect } from 'pwa-helpers/connect-mixin'
7
+
8
+ import { client } from '@operato/graphql'
9
+ import { i18next, localize } from '@operato/i18n'
10
+ import { openPopup } from '@operato/layout'
11
+ import { PageView, store } from '@operato/shell'
12
+ import { CommonGristStyles, ScrollbarStyles } from '@operato/styles'
13
+ import { isMobileDevice } from '@operato/utils'
14
+
15
+ export class DataSampleListPage extends connect(store)(localize(i18next)(PageView)) {
16
+ static get properties() {
17
+ return {
18
+ active: String,
19
+ gristConfig: Object,
20
+ mode: String
21
+ }
22
+ }
23
+
24
+ static get styles() {
25
+ return [
26
+ ScrollbarStyles,
27
+ CommonGristStyles,
28
+ css`
29
+ :host {
30
+ display: flex;
31
+ flex-direction: column;
32
+
33
+ overflow: hidden;
34
+ }
35
+
36
+ ox-grist {
37
+ overflow-y: auto;
38
+ flex: 1;
39
+ }
40
+ `
41
+ ]
42
+ }
43
+
44
+ get context() {
45
+ return {
46
+ title: i18next.t('title.data-sample list'),
47
+ help: 'dataset/data-sample',
48
+ actions: [],
49
+ exportable: {
50
+ name: i18next.t('title.data-sample list'),
51
+ data: this._exportableData.bind(this)
52
+ }
53
+ }
54
+ }
55
+
56
+ render() {
57
+ const mode = this.mode || (isMobileDevice() ? 'LIST' : 'GRID')
58
+
59
+ return html`
60
+ <ox-grist
61
+ .mode=${mode}
62
+ .config=${this.gristConfig}
63
+ .fetchHandler=${this.fetchHandler.bind(this)}
64
+ ?url-params-sensitive=${this.active}
65
+ >
66
+ <div slot="headroom">
67
+ <div id="filters">
68
+ <ox-filters-form></ox-filters-form>
69
+ </div>
70
+
71
+ <div id="sorters">
72
+ Sort
73
+ <mwc-icon
74
+ @click=${e => {
75
+ const target = e.currentTarget
76
+ this.renderRoot.querySelector('#sorter-control').open({
77
+ right: 0,
78
+ top: target.offsetTop + target.offsetHeight
79
+ })
80
+ }}
81
+ >expand_more</mwc-icon
82
+ >
83
+ <ox-popup id="sorter-control">
84
+ <ox-sorters-control> </ox-sorters-control>
85
+ </ox-popup>
86
+ </div>
87
+
88
+ <div id="modes">
89
+ <mwc-icon @click=${() => (this.mode = 'GRID')} ?active=${mode == 'GRID'}>grid_on</mwc-icon>
90
+ <mwc-icon @click=${() => (this.mode = 'LIST')} ?active=${mode == 'LIST'}>format_list_bulleted</mwc-icon>
91
+ <mwc-icon @click=${() => (this.mode = 'CARD')} ?active=${mode == 'CARD'}>apps</mwc-icon>
92
+ </div>
93
+ </div>
94
+ </ox-grist>
95
+ `
96
+ }
97
+
98
+ get grist() {
99
+ return this.renderRoot.querySelector('ox-grist')
100
+ }
101
+
102
+ async pageInitialized(lifecycle) {
103
+ this.gristConfig = {
104
+ list: { fields: ['dataSet', 'data', 'spec', 'updater', 'updatedAt'] },
105
+ columns: [
106
+ { type: 'gutter', gutterName: 'sequence' },
107
+ { type: 'gutter', gutterName: 'row-selector', multiple: true },
108
+ {
109
+ type: 'gutter',
110
+ gutterName: 'button',
111
+ icon: 'assignment',
112
+ handlers: {
113
+ click: (columns, data, column, record, rowIndex) => {
114
+ openPopup(
115
+ html` <data-sample-view .dataSample=${record} style="background-color: white;"></data-sample-view> `,
116
+ {
117
+ backdrop: true,
118
+ size: 'large',
119
+ title: i18next.t('title.data-sample view')
120
+ }
121
+ )
122
+ }
123
+ }
124
+ },
125
+ {
126
+ type: 'string',
127
+ name: 'name',
128
+ label: true,
129
+ header: i18next.t('field.name'),
130
+ record: {
131
+ editable: false
132
+ },
133
+ filter: 'search',
134
+ sortable: true,
135
+ width: 120,
136
+ imex: true
137
+ },
138
+ {
139
+ type: 'string',
140
+ name: 'description',
141
+ label: true,
142
+ header: i18next.t('field.description'),
143
+ record: {
144
+ editable: false
145
+ },
146
+ filter: 'search',
147
+ width: 150,
148
+ imex: true
149
+ },
150
+ {
151
+ type: 'resource-object',
152
+ name: 'dataSet',
153
+ header: i18next.t('field.data-set'),
154
+ record: {
155
+ editable: false
156
+ },
157
+ sortable: true,
158
+ width: 120,
159
+ imex: true
160
+ },
161
+ {
162
+ type: 'json5',
163
+ name: 'partitionKeys',
164
+ header: i18next.t('field.partition-keys'),
165
+ record: {
166
+ editable: false
167
+ },
168
+ width: 200,
169
+ imex: true
170
+ },
171
+ {
172
+ type: 'checkbox',
173
+ name: 'ooc',
174
+ header: i18next.t('field.ooc'),
175
+ record: {
176
+ editable: false
177
+ },
178
+ width: 30
179
+ },
180
+ {
181
+ type: 'checkbox',
182
+ name: 'oos',
183
+ header: i18next.t('field.oos'),
184
+ record: {
185
+ editable: false
186
+ },
187
+ width: 30
188
+ },
189
+ {
190
+ type: 'json5',
191
+ name: 'data',
192
+ header: i18next.t('field.data'),
193
+ record: {
194
+ editable: false
195
+ },
196
+ width: 200,
197
+ imex: true
198
+ },
199
+ {
200
+ type: 'json5',
201
+ name: 'spec',
202
+ header: i18next.t('field.spec'),
203
+ record: {
204
+ editable: false
205
+ },
206
+ width: 200
207
+ },
208
+ {
209
+ type: 'text',
210
+ name: 'rawData',
211
+ header: i18next.t('field.raw-data'),
212
+ record: {
213
+ editable: false
214
+ },
215
+ width: 200,
216
+ imex: true
217
+ },
218
+ {
219
+ type: 'string',
220
+ name: 'workDate',
221
+ header: i18next.t('field.work-date'),
222
+ sortable: true,
223
+ width: 80,
224
+ imex: true
225
+ },
226
+ {
227
+ type: 'string',
228
+ name: 'workShift',
229
+ header: i18next.t('field.work-shift'),
230
+ sortable: true,
231
+ width: 40,
232
+ imex: true
233
+ },
234
+ {
235
+ type: 'datetime',
236
+ name: 'collectedAt',
237
+ header: i18next.t('field.collected-at'),
238
+ sortable: true,
239
+ width: 180,
240
+ imex: true
241
+ },
242
+ {
243
+ type: 'resource-object',
244
+ name: 'updater',
245
+ header: i18next.t('field.updater'),
246
+ sortable: true,
247
+ width: 120,
248
+ imex: true
249
+ },
250
+ {
251
+ type: 'datetime',
252
+ name: 'updatedAt',
253
+ header: i18next.t('field.updated_at'),
254
+ sortable: true,
255
+ width: 180,
256
+ imex: true
257
+ }
258
+ ],
259
+ rows: {
260
+ appendable: false,
261
+ selectable: {
262
+ multiple: true
263
+ },
264
+ classifier: function (record, rowIndex) {
265
+ var emphasized
266
+ if (record['oos']) {
267
+ emphasized = ['red']
268
+ } else if (record['ooc']) {
269
+ emphasized = 'orange'
270
+ }
271
+
272
+ return {
273
+ emphasized
274
+ }
275
+ }
276
+ },
277
+ sorters: [
278
+ {
279
+ name: 'updatedAt',
280
+ desc: true
281
+ }
282
+ ]
283
+ }
284
+ }
285
+
286
+ async fetchHandler({ page, limit, sortings = [], filters = [] }) {
287
+ const response = await client.query({
288
+ query: gql`
289
+ query ($filters: [Filter!], $pagination: Pagination, $sortings: [Sorting!]) {
290
+ responses: dataSamples(filters: $filters, pagination: $pagination, sortings: $sortings) {
291
+ items {
292
+ id
293
+ name
294
+ description
295
+ dataSet {
296
+ id
297
+ name
298
+ description
299
+ }
300
+ partitionKeys
301
+ data
302
+ rawData
303
+ spec
304
+ ooc
305
+ oos
306
+ workDate
307
+ workShift
308
+ updater {
309
+ id
310
+ name
311
+ }
312
+ updatedAt
313
+ collectedAt
314
+ }
315
+ total
316
+ }
317
+ }
318
+ `,
319
+ variables: {
320
+ filters,
321
+ pagination: { page, limit },
322
+ sortings
323
+ }
324
+ })
325
+
326
+ return {
327
+ total: response.data.responses.total || 0,
328
+ records: response.data.responses.items || []
329
+ }
330
+ }
331
+
332
+ _exportableData() {
333
+ let records = []
334
+ if (this.grist.selected && this.grist.selected.length > 0) {
335
+ records = this.grist.selected
336
+ } else {
337
+ records = this.grist.data.records
338
+ }
339
+
340
+ var headerSetting = this.grist.compiledConfig.columns
341
+ .filter(column => column.type !== 'gutter' && column.record !== undefined && column.imex !== undefined)
342
+ .map(column => {
343
+ return column.imex === true
344
+ ? {
345
+ header: column.header.renderer(),
346
+ key: column.name,
347
+ width: column.width,
348
+ type: column.type
349
+ }
350
+ : column.imex
351
+ })
352
+
353
+ var data = records.map(item => {
354
+ return {
355
+ id: item.id,
356
+ ...this.gristConfig.columns
357
+ .filter(column => column.type !== 'gutter' && column.record !== undefined && column.imex !== undefined)
358
+ .reduce((record, column) => {
359
+ const key = column.imex === true ? column.name : column.imex.key
360
+ record[key] = key
361
+ .split('.')
362
+ .reduce((obj, key) => (obj && obj[key] !== 'undefined' ? obj[key] : undefined), item)
363
+ return record
364
+ }, {})
365
+ }
366
+ })
367
+
368
+ return { header: headerSetting, data: data }
369
+ }
370
+ }
371
+
372
+ window.customElements.define('data-sample-list-page', DataSampleListPage)
@@ -0,0 +1,98 @@
1
+ import '@operato/dataset/ox-data-sample-view.js'
2
+
3
+ import gql from 'graphql-tag'
4
+ import { css, html, LitElement } from 'lit'
5
+
6
+ import { client } from '@operato/graphql'
7
+ import { i18next, localize } from '@operato/i18n'
8
+ import { ScrollbarStyles } from '@operato/styles'
9
+
10
+ class DataSampleView extends localize(i18next)(LitElement) {
11
+ static get properties() {
12
+ return {
13
+ dataSet: Object,
14
+ dataSample: Object
15
+ }
16
+ }
17
+
18
+ static get styles() {
19
+ return [
20
+ ScrollbarStyles,
21
+ css`
22
+ :host {
23
+ display: flex;
24
+ flex-direction: column;
25
+
26
+ background-color: #fff;
27
+ }
28
+
29
+ div[content] {
30
+ flex: 1;
31
+
32
+ display: flex;
33
+ overflow: auto;
34
+ }
35
+
36
+ ox-data-sample-view {
37
+ flex: 1;
38
+ padding: var(--padding-wide);
39
+ overflow: auto;
40
+ }
41
+ `
42
+ ]
43
+ }
44
+
45
+ get sampleView() {
46
+ return this.renderRoot.querySelector('ox-data-sample-view')
47
+ }
48
+
49
+ render() {
50
+ return html`
51
+ <div content>
52
+ <ox-data-sample-view .dataSet=${this.dataSet} .dataSample=${this.dataSample}></ox-data-sample-view>
53
+ </div>
54
+ `
55
+ }
56
+
57
+ updated(changes) {
58
+ if (changes.has('dataSample')) {
59
+ this.fetchDataSet()
60
+ }
61
+ }
62
+
63
+ async fetchDataSet() {
64
+ const id = this.dataSample?.dataSet?.id
65
+
66
+ if (id) {
67
+ const response = await client.query({
68
+ query: gql`
69
+ query ($id: String!) {
70
+ dataSet(id: $id) {
71
+ id
72
+ name
73
+ description
74
+ useCase
75
+ dataItems {
76
+ id
77
+ name
78
+ description
79
+ active
80
+ unit
81
+ tag
82
+ type
83
+ spec
84
+ }
85
+ }
86
+ }
87
+ `,
88
+ variables: {
89
+ id: this.dataSample.dataSet.id
90
+ }
91
+ })
92
+
93
+ this.dataSet = response.data.dataSet
94
+ }
95
+ }
96
+ }
97
+
98
+ window.customElements.define('data-sample-view', DataSampleView)