@things-factory/dataset 5.0.0-alpha.9 → 5.0.0-y.0

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 +423 -0
  6. package/client/pages/data-ooc/data-ooc-list-page.js +483 -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 +465 -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 +386 -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 -64
  16. package/client/pages/{data-item-list.js → data-set/data-item-list.js} +35 -10
  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 +743 -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 +189 -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 +164 -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
package/README.md ADDED
@@ -0,0 +1,9 @@
1
+ # dataset
2
+ ## Architecture for data-samples
3
+ ![Architecture for data-samples](./assets/data-samples.jpg)
4
+ ## Partition Keys
5
+ At the early stage, partition keys are desinged for dynamic partitioning for Athena. But It will be required so many AWS Glue crawlers also by each 'data-sets'.
6
+
7
+ Partition keys are related for S3 request limitations.
8
+ > __3,500 PUT/COPY/POST/DELETE or 5,500 GET/HEAD requests per second per prefix in a bucket__
9
+ - https://docs.aws.amazon.com/AmazonS3/latest/userguide/optimizing-performance.html
Binary file
@@ -1 +1,21 @@
1
- export default function bootstrap() {}
1
+ import '@operato/app/filter-renderer.js' /* register resource-object filter renderer */
2
+
3
+ import {
4
+ OxGristRendererJson5,
5
+ registerEditor as registerGristEditor,
6
+ registerRenderer as registerGristRenderer
7
+ } from '@operato/data-grist'
8
+
9
+ import { OxGristEditorCode } from '@operato/app/grist-editor/ox-grist-editor-code.js'
10
+ import { OxGristEditorDataItemSpec } from '@operato/dataset/grist-editor'
11
+ import { OxGristEditorPartitionKeys } from '@operato/app/grist-editor/ox-grist-editor-partition-keys.js'
12
+
13
+ export default function bootstrap() {
14
+ registerGristEditor('data-item-spec', OxGristEditorDataItemSpec)
15
+ registerGristRenderer('data-item-spec', OxGristRendererJson5)
16
+
17
+ registerGristEditor('script', OxGristEditorCode)
18
+
19
+ registerGristEditor('partition-keys', OxGristEditorPartitionKeys)
20
+ registerGristRenderer('partition-keys', OxGristRendererJson5)
21
+ }
@@ -1,9 +1,11 @@
1
+ import '@operato/dataset/ox-data-entry-form.js'
2
+
1
3
  import gql from 'graphql-tag'
2
4
  import { css, html, LitElement } from 'lit'
3
5
 
4
6
  import { client } from '@operato/graphql'
5
7
  import { i18next, localize } from '@operato/i18n'
6
- import '@operato/dataset/ox-data-entry-form.js'
8
+ import { ScrollbarStyles } from '@operato/styles'
7
9
 
8
10
  class DataEntryForm extends localize(i18next)(LitElement) {
9
11
  static get properties() {
@@ -14,6 +16,7 @@ class DataEntryForm extends localize(i18next)(LitElement) {
14
16
 
15
17
  static get styles() {
16
18
  return [
19
+ ScrollbarStyles,
17
20
  css`
18
21
  :host {
19
22
  display: flex;
@@ -24,7 +27,8 @@ class DataEntryForm extends localize(i18next)(LitElement) {
24
27
 
25
28
  ox-data-entry-form {
26
29
  flex: 1;
27
- margin: 10px;
30
+ padding: 10px;
31
+ overflow: auto;
28
32
  }
29
33
 
30
34
  .button-container {
@@ -52,7 +56,9 @@ class DataEntryForm extends localize(i18next)(LitElement) {
52
56
  async _updateDataItems() {
53
57
  const data = this.entryForm.buildValue()
54
58
  const dataSample = {
55
- dataSetId: this.dataSet.id,
59
+ dataSet: {
60
+ id: this.dataSet.id
61
+ },
56
62
  data
57
63
  }
58
64
 
@@ -69,6 +75,12 @@ class DataEntryForm extends localize(i18next)(LitElement) {
69
75
  dataSample
70
76
  }
71
77
  })
78
+
79
+ if (!response.errors) {
80
+ document.dispatchEvent(
81
+ new CustomEvent('notify', { detail: { message: i18next.t('text.data sample created successfully') } })
82
+ )
83
+ }
72
84
  }
73
85
  }
74
86
 
@@ -0,0 +1,423 @@
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
+ export class DataEntryListPage extends connect(store)(localize(i18next)(PageView)) {
78
+ static get properties() {
79
+ return {
80
+ active: String,
81
+ gristConfig: Object,
82
+ filters: Object,
83
+ sorters: Object,
84
+ mode: String
85
+ }
86
+ }
87
+
88
+ static get styles() {
89
+ return [
90
+ ScrollbarStyles,
91
+ CommonGristStyles,
92
+ css`
93
+ :host {
94
+ display: flex;
95
+
96
+ width: 100%;
97
+
98
+ --grid-record-emphasized-background-color: red;
99
+ --grid-record-emphasized-color: yellow;
100
+ }
101
+ `
102
+ ]
103
+ }
104
+
105
+ get context() {
106
+ return {
107
+ title: i18next.t('title.data-entry list'),
108
+ help: 'dataset/data-entry-list'
109
+ }
110
+ }
111
+
112
+ render() {
113
+ const mode = 'CARD'
114
+
115
+ return html`
116
+ <ox-grist
117
+ .mode=${mode}
118
+ .config=${this.gristConfig}
119
+ .filters=${this.filters}
120
+ .orders=${this.orders}
121
+ .fetchHandler=${this.fetchHandler.bind(this)}
122
+ >
123
+ <div slot="headroom" id="filters">
124
+ <div id="filters">
125
+ <ox-filters-form></ox-filters-form>
126
+ </div>
127
+
128
+ <div id="sorters">
129
+ Sort
130
+ <mwc-icon
131
+ @click=${e => {
132
+ const target = e.currentTarget
133
+ this.renderRoot.querySelector('#sorter-control').open({
134
+ right: 0,
135
+ top: target.offsetTop + target.offsetHeight
136
+ })
137
+ }}
138
+ >expand_more</mwc-icon
139
+ >
140
+ <ox-popup id="sorter-control">
141
+ <ox-sorters-control> </ox-sorters-control>
142
+ </ox-popup>
143
+ </div>
144
+ </div>
145
+ </ox-grist>
146
+ `
147
+ }
148
+
149
+ get grist() {
150
+ return this.renderRoot.querySelector('ox-grist')
151
+ }
152
+
153
+ async pageInitialized(lifecycle) {
154
+ this.gristConfig = {
155
+ list: {
156
+ thumbnail: 'entryView',
157
+ fields: ['name', 'description'],
158
+ details: ['schedule', 'type', 'useCase', 'latestCollectedAt', 'prevSchedule', 'nextSchedule']
159
+ },
160
+ columns: [
161
+ {
162
+ type: 'gutter',
163
+ gutterName: 'button',
164
+ icon: 'fact_check',
165
+ handlers: {
166
+ click: showEntryView
167
+ }
168
+ },
169
+ {
170
+ type: 'string',
171
+ name: 'name',
172
+ header: i18next.t('field.name'),
173
+ record: {
174
+ editable: false
175
+ },
176
+ filter: 'search',
177
+ sortable: true,
178
+ width: 150
179
+ },
180
+ {
181
+ type: 'string',
182
+ name: 'description',
183
+ header: i18next.t('field.description'),
184
+ record: {
185
+ editable: false
186
+ },
187
+ filter: 'search',
188
+ width: 200
189
+ },
190
+ {
191
+ type: 'select',
192
+ name: 'type',
193
+ label: true,
194
+ header: i18next.t('field.type'),
195
+ record: {
196
+ editable: false,
197
+ options: [
198
+ {},
199
+ {
200
+ display: i18next.t('text.manually collected'),
201
+ value: 'manual'
202
+ },
203
+ {
204
+ display: i18next.t('text.automatically collected'),
205
+ value: 'automatic'
206
+ }
207
+ ]
208
+ },
209
+ sortable: true,
210
+ filter: true,
211
+ width: 60
212
+ },
213
+ {
214
+ type: 'select',
215
+ name: 'useCase',
216
+ label: true,
217
+ header: i18next.t('field.use-case'),
218
+ record: {
219
+ editable: false,
220
+ options: USECASE_OPTIONS
221
+ },
222
+ sortable: true,
223
+ filter: {
224
+ operator: 'eq',
225
+ options: USECASE_OPTIONS /* in case select options type is a function, filter should have its own options */
226
+ },
227
+ width: 80
228
+ },
229
+ {
230
+ type: 'crontab',
231
+ name: 'schedule',
232
+ label: true,
233
+ header: i18next.t('field.schedule'),
234
+ record: {
235
+ editable: false
236
+ },
237
+ width: 80,
238
+ label: true
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
+ },
249
+ {
250
+ type: 'resource-object',
251
+ name: 'supervisoryRole',
252
+ header: i18next.t('field.supervisory-role'),
253
+ record: {
254
+ editable: false
255
+ },
256
+ width: 120
257
+ },
258
+ {
259
+ type: 'datetime',
260
+ name: 'latestCollectedAt',
261
+ label: true,
262
+ header: i18next.t('field.latest-collected-at'),
263
+ record: {
264
+ editable: false
265
+ },
266
+ width: 180
267
+ },
268
+ {
269
+ type: 'datetime',
270
+ name: 'prevSchedule',
271
+ label: true,
272
+ header: i18next.t('field.prev-schedule'),
273
+ record: {
274
+ editable: false
275
+ },
276
+ width: 180
277
+ },
278
+ {
279
+ type: 'datetime',
280
+ name: 'nextSchedule',
281
+ label: true,
282
+ header: i18next.t('field.next-schedule'),
283
+ record: {
284
+ editable: false
285
+ },
286
+ width: 180
287
+ },
288
+ {
289
+ type: 'string',
290
+ name: 'entryView',
291
+ hidden: true,
292
+ record: {
293
+ editable: false,
294
+ renderer: function (value, column, record, rowIndex, field) {
295
+ const type = record.entryType !== 'board' ? 'string' : 'image'
296
+ value = record.entryType !== 'board' ? value : record.entryBoard?.thumbnail
297
+
298
+ return getRenderer(type)(value, column, record, rowIndex, field)
299
+ }
300
+ }
301
+ }
302
+ ],
303
+ rows: {
304
+ selectable: {
305
+ multiple: false
306
+ },
307
+ handlers: {
308
+ click: showEntryView
309
+ },
310
+ classifier: function (record, rowIndex) {}
311
+ },
312
+ sorters: [
313
+ {
314
+ name: 'name'
315
+ }
316
+ ]
317
+ }
318
+
319
+ await this.updateComplete
320
+
321
+ this.grist.fetch()
322
+ }
323
+
324
+ async pageUpdated(changes, lifecycle) {
325
+ if (this.active) {
326
+ await this.updateComplete
327
+
328
+ var filters = lifecycle.params?.['filters']
329
+ if (filters) {
330
+ try {
331
+ filters = JSON5.parse(filters)
332
+ this.filters = filters
333
+ } catch (e) {
334
+ console.error(`filters parameter parsing error: ${e}`)
335
+ }
336
+ }
337
+
338
+ var sorters = lifecycle.params?.['sorters']
339
+ if (sorters) {
340
+ try {
341
+ sorters = JSON5.parse(sorters)
342
+ this.sorters = sorters
343
+ } catch (e) {
344
+ console.error(`sorters parameter parsing error: ${e}`)
345
+ }
346
+ }
347
+
348
+ this.grist.fetch()
349
+ }
350
+ }
351
+
352
+ async fetchHandler({ page, limit, sortings = [], filters = [] }) {
353
+ const response = await client.query({
354
+ query: gql`
355
+ query ($filters: [Filter!], $pagination: Pagination, $sortings: [Sorting!]) {
356
+ responses: dataSetsForEntry(filters: $filters, pagination: $pagination, sortings: $sortings) {
357
+ items {
358
+ id
359
+ name
360
+ description
361
+ partitionKeys
362
+ active
363
+ type
364
+ useCase
365
+ schedule
366
+ timezone
367
+ entryRole {
368
+ id
369
+ name
370
+ }
371
+ supervisoryRole {
372
+ id
373
+ name
374
+ }
375
+ entryType
376
+ entryView
377
+ entryBoard {
378
+ thumbnail
379
+ }
380
+ monitorType
381
+ monitorView
382
+ updater {
383
+ id
384
+ name
385
+ }
386
+ reportType
387
+ reportView
388
+ updatedAt
389
+ dataItems {
390
+ name
391
+ description
392
+ sequence
393
+ active
394
+ tag
395
+ type
396
+ unit
397
+ options
398
+ quota
399
+ spec
400
+ }
401
+ latestCollectedAt
402
+ nextSchedule
403
+ prevSchedule
404
+ }
405
+ total
406
+ }
407
+ }
408
+ `,
409
+ variables: {
410
+ filters,
411
+ pagination: { page, limit },
412
+ sortings
413
+ }
414
+ })
415
+
416
+ return {
417
+ total: response.data.responses.total || 0,
418
+ records: response.data.responses.items || []
419
+ }
420
+ }
421
+ }
422
+
423
+ window.customElements.define('data-entry-list-page', DataEntryListPage)