@things-factory/dataset 7.0.0-alpha.3 → 7.0.0-alpha.30

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 (165) hide show
  1. package/client/activities/activity-data-collect-edit.ts +1 -7
  2. package/client/activities/activity-data-collect-view.ts +7 -0
  3. package/client/activities/activity-data-review-edit.ts +66 -32
  4. package/client/activities/activity-data-review-view.ts +75 -29
  5. package/client/activities/activity-ooc-resolve-edit.ts +44 -48
  6. package/client/activities/activity-ooc-resolve-view.ts +25 -35
  7. package/client/activities/activity-ooc-review-edit.ts +36 -29
  8. package/client/activities/activity-ooc-review-view.ts +9 -19
  9. package/client/bootstrap.ts +5 -9
  10. package/client/pages/data-entry/data-entry-list-page.ts +8 -23
  11. package/client/pages/data-ooc/data-ooc-list-page.ts +71 -27
  12. package/client/pages/data-ooc/{data-ooc-view-page.ts → data-ooc-page.ts} +45 -1
  13. package/client/pages/data-ooc/data-ooc-view.ts +198 -41
  14. package/client/pages/data-ooc/data-oocs-page.ts +200 -0
  15. package/client/pages/data-sample/data-sample-list-page.ts +53 -31
  16. package/client/pages/data-sample/{data-sample-view-page.ts → data-sample-page.ts} +8 -1
  17. package/client/pages/data-sample/data-sample-search-page.ts +34 -29
  18. package/client/pages/data-sample/data-sample-view.ts +192 -21
  19. package/client/pages/data-sample/data-samples-page.ts +249 -0
  20. package/client/pages/data-sensor/data-sensor-list-page.ts +28 -6
  21. package/client/pages/data-set/data-item-list.ts +2 -2
  22. package/client/pages/data-summary/data-summary-list-page.ts +12 -24
  23. package/client/route.ts +10 -2
  24. package/dist-client/activities/activity-data-collect-edit.js +1 -7
  25. package/dist-client/activities/activity-data-collect-edit.js.map +1 -1
  26. package/dist-client/activities/activity-data-collect-view.js +7 -0
  27. package/dist-client/activities/activity-data-collect-view.js.map +1 -1
  28. package/dist-client/activities/activity-data-review-edit.d.ts +1 -1
  29. package/dist-client/activities/activity-data-review-edit.js +63 -33
  30. package/dist-client/activities/activity-data-review-edit.js.map +1 -1
  31. package/dist-client/activities/activity-data-review-view.d.ts +1 -1
  32. package/dist-client/activities/activity-data-review-view.js +72 -30
  33. package/dist-client/activities/activity-data-review-view.js.map +1 -1
  34. package/dist-client/activities/activity-ooc-resolve-edit.d.ts +1 -1
  35. package/dist-client/activities/activity-ooc-resolve-edit.js +44 -48
  36. package/dist-client/activities/activity-ooc-resolve-edit.js.map +1 -1
  37. package/dist-client/activities/activity-ooc-resolve-view.d.ts +13 -0
  38. package/dist-client/activities/activity-ooc-resolve-view.js +24 -34
  39. package/dist-client/activities/activity-ooc-resolve-view.js.map +1 -1
  40. package/dist-client/activities/activity-ooc-review-edit.js +39 -29
  41. package/dist-client/activities/activity-ooc-review-edit.js.map +1 -1
  42. package/dist-client/activities/activity-ooc-review-view.js +9 -19
  43. package/dist-client/activities/activity-ooc-review-view.js.map +1 -1
  44. package/dist-client/bootstrap.d.ts +4 -4
  45. package/dist-client/bootstrap.js +4 -4
  46. package/dist-client/bootstrap.js.map +1 -1
  47. package/dist-client/pages/data-entry/data-entry-list-page.js +3 -15
  48. package/dist-client/pages/data-entry/data-entry-list-page.js.map +1 -1
  49. package/dist-client/pages/data-ooc/data-ooc-list-page.d.ts +6 -0
  50. package/dist-client/pages/data-ooc/data-ooc-list-page.js +67 -24
  51. package/dist-client/pages/data-ooc/data-ooc-list-page.js.map +1 -1
  52. package/dist-client/pages/data-ooc/{data-ooc-view-page.js → data-ooc-page.js} +46 -2
  53. package/dist-client/pages/data-ooc/data-ooc-page.js.map +1 -0
  54. package/dist-client/pages/data-ooc/data-ooc-view.d.ts +11 -4
  55. package/dist-client/pages/data-ooc/data-ooc-view.js +193 -48
  56. package/dist-client/pages/data-ooc/data-ooc-view.js.map +1 -1
  57. package/dist-client/pages/data-ooc/data-oocs-page.d.ts +18 -0
  58. package/dist-client/pages/data-ooc/data-oocs-page.js +200 -0
  59. package/dist-client/pages/data-ooc/data-oocs-page.js.map +1 -0
  60. package/dist-client/pages/data-sample/data-sample-list-page.d.ts +6 -1
  61. package/dist-client/pages/data-sample/data-sample-list-page.js +51 -28
  62. package/dist-client/pages/data-sample/data-sample-list-page.js.map +1 -1
  63. package/dist-client/pages/data-sample/{data-sample-view-page.js → data-sample-page.js} +9 -2
  64. package/dist-client/pages/data-sample/data-sample-page.js.map +1 -0
  65. package/dist-client/pages/data-sample/data-sample-search-page.d.ts +6 -13
  66. package/dist-client/pages/data-sample/data-sample-search-page.js +32 -26
  67. package/dist-client/pages/data-sample/data-sample-search-page.js.map +1 -1
  68. package/dist-client/pages/data-sample/data-sample-view.d.ts +18 -0
  69. package/dist-client/pages/data-sample/data-sample-view.js +186 -19
  70. package/dist-client/pages/data-sample/data-sample-view.js.map +1 -1
  71. package/dist-client/pages/data-sample/data-samples-page.d.ts +21 -0
  72. package/dist-client/pages/data-sample/data-samples-page.js +249 -0
  73. package/dist-client/pages/data-sample/data-samples-page.js.map +1 -0
  74. package/dist-client/pages/data-sensor/data-sensor-list-page.js +28 -6
  75. package/dist-client/pages/data-sensor/data-sensor-list-page.js.map +1 -1
  76. package/dist-client/pages/data-set/data-item-list.js +2 -2
  77. package/dist-client/pages/data-set/data-item-list.js.map +1 -1
  78. package/dist-client/pages/data-summary/data-summary-list-page.js +12 -21
  79. package/dist-client/pages/data-summary/data-summary-list-page.js.map +1 -1
  80. package/dist-client/route.js +8 -2
  81. package/dist-client/route.js.map +1 -1
  82. package/dist-client/tsconfig.tsbuildinfo +1 -1
  83. package/dist-server/activities/activity-data-collect.js.map +1 -1
  84. package/dist-server/activities/activity-data-review.js.map +1 -1
  85. package/dist-server/activities/activity-ooc-review.js +3 -2
  86. package/dist-server/activities/activity-ooc-review.js.map +1 -1
  87. package/dist-server/controllers/create-data-sample.js +28 -30
  88. package/dist-server/controllers/create-data-sample.js.map +1 -1
  89. package/dist-server/controllers/issue-collect-data.js +55 -0
  90. package/dist-server/controllers/issue-collect-data.js.map +1 -0
  91. package/dist-server/engine/index.js +4 -0
  92. package/dist-server/engine/index.js.map +1 -0
  93. package/dist-server/engine/task/create-data-sample.js +81 -0
  94. package/dist-server/engine/task/create-data-sample.js.map +1 -0
  95. package/dist-server/engine/task/index.js +5 -0
  96. package/dist-server/engine/task/index.js.map +1 -0
  97. package/dist-server/engine/task/issue-collect-data.js +40 -0
  98. package/dist-server/engine/task/issue-collect-data.js.map +1 -0
  99. package/dist-server/index.js +1 -0
  100. package/dist-server/index.js.map +1 -1
  101. package/dist-server/routes.js +39 -65
  102. package/dist-server/routes.js.map +1 -1
  103. package/dist-server/service/data-ooc/data-ooc-query.js +32 -0
  104. package/dist-server/service/data-ooc/data-ooc-query.js.map +1 -1
  105. package/dist-server/service/data-ooc/data-ooc.js +44 -37
  106. package/dist-server/service/data-ooc/data-ooc.js.map +1 -1
  107. package/dist-server/service/data-sample/data-sample-query.js +24 -0
  108. package/dist-server/service/data-sample/data-sample-query.js.map +1 -1
  109. package/dist-server/service/data-sample/data-sample.js +30 -31
  110. package/dist-server/service/data-sample/data-sample.js.map +1 -1
  111. package/dist-server/service/data-sensor/data-sensor-query.js +16 -1
  112. package/dist-server/service/data-sensor/data-sensor-query.js.map +1 -1
  113. package/dist-server/service/data-sensor/data-sensor-type.js +8 -0
  114. package/dist-server/service/data-sensor/data-sensor-type.js.map +1 -1
  115. package/dist-server/service/data-sensor/data-sensor.js +15 -1
  116. package/dist-server/service/data-sensor/data-sensor.js.map +1 -1
  117. package/dist-server/service/data-set/data-item-type.js +1 -0
  118. package/dist-server/service/data-set/data-item-type.js.map +1 -1
  119. package/dist-server/service/data-set/data-set-query.js +2 -2
  120. package/dist-server/service/data-set/data-set-query.js.map +1 -1
  121. package/dist-server/service/data-summary/data-summary.js +8 -8
  122. package/dist-server/service/data-summary/data-summary.js.map +1 -1
  123. package/dist-server/tsconfig.tsbuildinfo +1 -1
  124. package/helps/dataset/task/create-data-sample.ja.md +28 -0
  125. package/helps/dataset/task/create-data-sample.ko.md +28 -0
  126. package/helps/dataset/task/create-data-sample.md +28 -0
  127. package/helps/dataset/task/create-data-sample.ms.md +30 -0
  128. package/helps/dataset/task/create-data-sample.zh.md +28 -0
  129. package/helps/dataset/task/issue-collect-data.ja.md +35 -0
  130. package/helps/dataset/task/issue-collect-data.ko.md +32 -0
  131. package/helps/dataset/task/issue-collect-data.md +32 -0
  132. package/helps/dataset/task/issue-collect-data.ms.md +34 -0
  133. package/helps/dataset/task/issue-collect-data.zh.md +32 -0
  134. package/package.json +15 -12
  135. package/server/activities/activity-data-collect.ts +3 -11
  136. package/server/activities/activity-data-review.ts +1 -5
  137. package/server/activities/activity-ooc-review.ts +6 -16
  138. package/server/controllers/create-data-sample.ts +32 -39
  139. package/server/controllers/issue-collect-data.ts +61 -0
  140. package/server/engine/index.ts +1 -0
  141. package/server/engine/task/create-data-sample.ts +93 -0
  142. package/server/engine/task/index.ts +2 -0
  143. package/server/engine/task/issue-collect-data.ts +45 -0
  144. package/server/index.ts +1 -0
  145. package/server/routes.ts +52 -77
  146. package/server/service/data-ooc/data-ooc-query.ts +17 -0
  147. package/server/service/data-ooc/data-ooc.ts +39 -51
  148. package/server/service/data-sample/data-sample-query.ts +17 -17
  149. package/server/service/data-sample/data-sample.ts +29 -52
  150. package/server/service/data-sensor/data-sensor-query.ts +13 -1
  151. package/server/service/data-sensor/data-sensor-type.ts +6 -0
  152. package/server/service/data-sensor/data-sensor.ts +13 -11
  153. package/server/service/data-set/data-item-type.ts +1 -0
  154. package/server/service/data-set/data-set-query.ts +7 -7
  155. package/server/service/data-summary/data-summary.ts +10 -23
  156. package/things-factory.config.js +10 -2
  157. package/translations/en.json +15 -2
  158. package/translations/ja.json +12 -1
  159. package/translations/ko.json +14 -1
  160. package/translations/ms.json +11 -0
  161. package/translations/zh.json +12 -1
  162. package/dist-client/pages/data-ooc/data-ooc-view-page.js.map +0 -1
  163. package/dist-client/pages/data-sample/data-sample-view-page.js.map +0 -1
  164. /package/dist-client/pages/data-ooc/{data-ooc-view-page.d.ts → data-ooc-page.d.ts} +0 -0
  165. /package/dist-client/pages/data-sample/{data-sample-view-page.d.ts → data-sample-page.d.ts} +0 -0
@@ -55,16 +55,16 @@ const formatDate = (keys, _moment) => {
55
55
  return keys
56
56
  }
57
57
 
58
- export async function createDataSample(dataSample: NewDataSample, context: ResolverContext): Promise<DataSample> {
58
+ export async function createDataSample(newDataSample: NewDataSample, context: ResolverContext): Promise<DataSample> {
59
59
  const { domain, user, tx } = context.state
60
60
 
61
61
  const dataSet = await tx.getRepository(DataSet).findOne({
62
- where: { domain: { id: In([domain.id, domain.parentId].filter(Boolean)) }, id: dataSample.dataSet.id },
62
+ where: { domain: { id: In([domain.id, domain.parentId].filter(Boolean)) }, id: newDataSample.dataSet.id },
63
63
  relations: ['dataKeySet']
64
64
  })
65
65
 
66
- const { dataItems, tag: publishTag, normalScenarioId, outlierScenarioId } = dataSet
67
- const collectedAt = dataSample.collectedAt || new Date()
66
+ const { dataItems = [], tag: publishTag, normalScenarioId, outlierScenarioId } = dataSet
67
+ const collectedAt = newDataSample.collectedAt || new Date()
68
68
 
69
69
  const timezone = dataSet.timezone || domain.timezone || 'UTC'
70
70
  const format = 'YYYY-MM-DD'
@@ -77,7 +77,7 @@ export async function createDataSample(dataSample: NewDataSample, context: Resol
77
77
  const localDateTz = moment(collectedAt).tz(timezone)
78
78
  const defaultPartitionKeys = {
79
79
  domain: domain.subdomain,
80
- datasetid: dataSample.dataSet.id /* It should not be 'data_set_id' as column name duplicated for Glue */,
80
+ datasetid: newDataSample.dataSet.id /* It should not be 'data_set_id' as column name duplicated for Glue */,
81
81
  date: localDateTz.format(format) /* local time date */,
82
82
  workdate: workDate /* working date */,
83
83
  workshift: workShift
@@ -89,11 +89,11 @@ export async function createDataSample(dataSample: NewDataSample, context: Resol
89
89
  }
90
90
 
91
91
  partitionKeys = formatDate(partitionKeys, localDateTz)
92
- partitionKeys = replaceVariables(partitionKeys, dataSample.data)
92
+ partitionKeys = replaceVariables(partitionKeys, newDataSample.data)
93
93
 
94
- const dataKeys = fillDataKeys(dataSet?.dataKeySet, dataSample.data)
94
+ const dataKeys = fillDataKeys(dataSet?.dataKeySet, newDataSample.data)
95
95
 
96
- const { ooc, oos, judgment } = DataUseCase.evaluate(dataSet, dataItems, dataSample.data) || {}
96
+ const { ooc, oos, judgment } = DataUseCase.evaluate(dataSet, dataItems, newDataSample.data) || {}
97
97
 
98
98
  const old = await tx.getRepository(DataSample).findOne({
99
99
  where: {
@@ -110,7 +110,7 @@ export async function createDataSample(dataSample: NewDataSample, context: Resol
110
110
  If [FileUpload[]] type needed, add 'files' type for dataset
111
111
  */
112
112
 
113
- const data = dataSample.data
113
+ const data = newDataSample.data
114
114
  const attachments = []
115
115
 
116
116
  for (let dataItem of dataItems) {
@@ -164,13 +164,13 @@ export async function createDataSample(dataSample: NewDataSample, context: Resol
164
164
  }
165
165
  }
166
166
 
167
- const result = await tx.getRepository(DataSample).save({
167
+ const dataSample = await tx.getRepository(DataSample).save({
168
168
  ...old,
169
169
  name: dataSet.name,
170
170
  description: dataSet.description,
171
171
  useCase: dataSet.useCase,
172
172
  type: dataSet.type,
173
- ...dataSample,
173
+ ...newDataSample,
174
174
  ...dataKeys,
175
175
  dataSetVersion: dataSet.version,
176
176
  domain,
@@ -197,13 +197,13 @@ export async function createDataSample(dataSample: NewDataSample, context: Resol
197
197
 
198
198
  /* post-process for for file attachment. */
199
199
  if (attachments.length > 0) {
200
- attachments.forEach(attachment => (attachment.refId = result.id))
200
+ attachments.forEach(attachment => (attachment.refId = dataSample.id))
201
201
  tx.getRepository(Attachment).save(attachments)
202
202
  }
203
203
 
204
204
  if (ooc || oos) {
205
205
  const dataOoc = await tx.getRepository(DataOoc).save({
206
- ...result,
206
+ ...dataSample,
207
207
  history: [
208
208
  {
209
209
  user: {
@@ -214,7 +214,8 @@ export async function createDataSample(dataSample: NewDataSample, context: Resol
214
214
  timestamp: collectedAt
215
215
  }
216
216
  ],
217
- state: DataOocStatus.ISSUED
217
+ state: DataOocStatus.ISSUED,
218
+ dataSample: dataSample
218
219
  })
219
220
 
220
221
  if (outlierScenarioId) {
@@ -227,9 +228,9 @@ export async function createDataSample(dataSample: NewDataSample, context: Resol
227
228
  })
228
229
 
229
230
  if (scenario) {
230
- scenario.start(scenario.name + ':' + dataSet.name + ':' + result.id, {
231
+ scenario.start(scenario.name + ':' + dataSet.name + ':' + dataSample.id, {
231
232
  dataOocId: dataOoc.id,
232
- dataSampleId: result.id,
233
+ dataSampleId: dataSample.id,
233
234
  dataSet: dataSet.id,
234
235
  data,
235
236
  ooc,
@@ -260,9 +261,7 @@ export async function createDataSample(dataSample: NewDataSample, context: Resol
260
261
  })) as Activity
261
262
 
262
263
  if (activity) {
263
- const assignee =
264
- dataSet.supervisoryRoleId &&
265
- (await tx.getRepository(Role).findOneBy({ domain: { id: domain.id }, id: dataSet.supervisoryRoleId }))
264
+ const assignee = dataSet.supervisoryRoleId && (await tx.getRepository(Role).findOneBy({ domain: { id: domain.id }, id: dataSet.supervisoryRoleId }))
266
265
 
267
266
  const assignees = dataSet.supervisoryRoleId ? [{ type: 'Role', value: dataSet.supervisoryRoleId, assignee }] : []
268
267
 
@@ -280,11 +279,10 @@ export async function createDataSample(dataSample: NewDataSample, context: Resol
280
279
  approvalLine: []
281
280
  }
282
281
 
283
- await issue(activityInstance, context)
282
+ dataOoc.reviewActivityInstance = await issue(activityInstance, context)
283
+ await tx.getRepository(DataOoc).save(dataOoc)
284
284
  } else {
285
- console.error(
286
- `Assignees are not set. So Data OOC Review task for ${dataOoc.name}(${dataOoc.id}) could not be issued.`
287
- )
285
+ console.error(`Assignees are not set. So Data OOC Review task for ${dataOoc.name}(${dataOoc.id}) could not be issued.`)
288
286
  }
289
287
  } else {
290
288
  console.error('OOC Review Activity not installed.')
@@ -320,8 +318,8 @@ export async function createDataSample(dataSample: NewDataSample, context: Resol
320
318
  })
321
319
 
322
320
  if (scenario) {
323
- scenario.start(scenario.name + ':' + dataSet.name + ':' + result.id, {
324
- dataSampleId: result.id,
321
+ scenario.start(scenario.name + ':' + dataSet.name + ':' + dataSample.id, {
322
+ dataSampleId: dataSample.id,
325
323
  dataSet: dataSet.id,
326
324
  data,
327
325
  ooc,
@@ -353,30 +351,27 @@ export async function createDataSample(dataSample: NewDataSample, context: Resol
353
351
  })) as Activity
354
352
 
355
353
  if (activity) {
356
- const assignee =
357
- dataSet.supervisoryRoleId &&
358
- (await tx.getRepository(Role).findOneBy({ domain: { id: domain.id }, id: dataSet.supervisoryRoleId }))
354
+ const assignee = dataSet.supervisoryRoleId && (await tx.getRepository(Role).findOneBy({ domain: { id: domain.id }, id: dataSet.supervisoryRoleId }))
359
355
 
360
- const assignees = dataSet.supervisoryRoleId
361
- ? [{ type: 'Role', value: dataSet.supervisoryRoleId, assignee }]
362
- : []
356
+ const assignees = dataSet.supervisoryRoleId ? [{ type: 'Role', value: dataSet.supervisoryRoleId, assignee }] : []
363
357
 
364
358
  /* 해당 dataset의 supervisor로 하여금, data를 리뷰하고 instruction을 작성해서, approvalLine을 이용해서 승인을 한다. */
365
359
  if (assignees && assignees instanceof Array && assignees.length > 0) {
366
- result.dataItems = dataItems
360
+ dataSample.dataItems = dataItems
367
361
  const activityInstance = {
368
362
  name: `[Data 검토] ${dataSet.name}`,
369
363
  description: dataSet.description,
370
364
  activityId: activity.id,
371
365
  dueAt: new Date(collectedAt.getTime() + 24 * 60 * 60 * 1000),
372
366
  input: {
373
- dataSample: result
367
+ dataSampleId: dataSample.id
374
368
  },
375
369
  assignees,
376
370
  approvalLine: dataSet.reviewApprovalLine
377
371
  }
378
372
 
379
- await issue(activityInstance, context)
373
+ dataSample.reviewActivityInstance = await issue(activityInstance, context)
374
+ await tx.getRepository(DataSample).save(dataSample)
380
375
 
381
376
  try {
382
377
  pubsub.publish('notification', {
@@ -385,7 +380,7 @@ export async function createDataSample(dataSample: NewDataSample, context: Resol
385
380
  type: 'info',
386
381
  title: `[Data Review] ${dataSet.name}`,
387
382
  body: `Data Review occurred on '${dataSet.name}'`,
388
- url: getRedirectSubdomainPath(context, domain.subdomain, `/data-sample/${result.id}`),
383
+ url: getRedirectSubdomainPath(context, domain.subdomain, `/data-sample/${dataSample.id}`),
389
384
  timestamp: collectedAt
390
385
  }
391
386
  })
@@ -393,9 +388,7 @@ export async function createDataSample(dataSample: NewDataSample, context: Resol
393
388
  logger.error('Notification', err)
394
389
  }
395
390
  } else {
396
- console.error(
397
- `Assignees are not set. So Data Review task for ${dataSet.name}(${dataSet.id}) could not be issued.`
398
- )
391
+ console.error(`Assignees are not set. So Data Review task for ${dataSet.name}(${dataSet.id}) could not be issued.`)
399
392
  }
400
393
  } else {
401
394
  console.error('Data Review Activity not installed.')
@@ -403,5 +396,5 @@ export async function createDataSample(dataSample: NewDataSample, context: Resol
403
396
  }
404
397
  }
405
398
 
406
- return result
399
+ return dataSample
407
400
  }
@@ -0,0 +1,61 @@
1
+ import { In } from 'typeorm'
2
+
3
+ import { Domain, getDataSource } from '@things-factory/shell'
4
+ import { Activity, ActivityInstance, issue } from '@things-factory/worklist'
5
+
6
+ import { DataSet } from '../service/data-set/data-set'
7
+
8
+ export async function issueCollectData(domainId: string, dataSetId: string, context: ResolverContext): Promise<ActivityInstance> {
9
+ await getDataSource().transaction(async tx => {
10
+ const domain = await tx.getRepository(Domain).findOneBy({ id: domainId })
11
+
12
+ if (!domain) {
13
+ throw new Error(`domain(${domainId}) not found`)
14
+ }
15
+
16
+ const dataSet = await tx.getRepository(DataSet).findOne({
17
+ where: {
18
+ domain: {
19
+ id: In([domain.id, domain.parentId].filter(Boolean))
20
+ },
21
+ id: dataSetId
22
+ }
23
+ })
24
+
25
+ const activity = (await tx.getRepository(Activity).findOneBy({
26
+ domain: { id: domain.id },
27
+ name: 'Collect Data'
28
+ })) as Activity
29
+
30
+ if (activity) {
31
+ const { assignees } = dataSet
32
+
33
+ /* 해당 dataset에 대한 데이타 수집 태스크를 dataset assignees에게 할당한다. */
34
+ if (assignees && assignees instanceof Array && assignees.length > 0) {
35
+ const activityInstance = {
36
+ name: `[Data 수집] ${dataSet.name}`,
37
+ description: dataSet.description,
38
+ activityId: activity.id,
39
+ dueAt: new Date(Date.now() + 24 * 60 * 60 * 1000),
40
+ input: {
41
+ dataSetId: dataSet.id,
42
+ dataSetName: dataSet.name
43
+ },
44
+ assignees
45
+ }
46
+
47
+ context.state = {
48
+ ...context.state,
49
+ domain,
50
+ tx
51
+ }
52
+
53
+ return await issue(activityInstance, context)
54
+ } else {
55
+ throw new Error(`Assignees not set. So Data Collect Activity for ${dataSet.name}($dataSet.id) could not be issued.`)
56
+ }
57
+ } else {
58
+ throw new Error(`Data Collect Activity is not installed.`)
59
+ }
60
+ })
61
+ }
@@ -0,0 +1 @@
1
+ import './task'
@@ -0,0 +1,93 @@
1
+ import { TaskRegistry, InputStep, Context } from '@things-factory/integration-base'
2
+ import { getDataSource } from '@things-factory/shell'
3
+ import { access } from '@things-factory/utils'
4
+ import i18next from 'i18next'
5
+
6
+ import { DataSet } from '../../service/data-set/data-set'
7
+
8
+ import { createDataSample } from '../../controllers/create-data-sample'
9
+
10
+ async function CreateDataSample(step: InputStep, context: Context) {
11
+ const { logger, data, domain, user, lng } = context
12
+ var {
13
+ params: { dataset: dataSetId, source: sourceAccessor, rawData: rawDataAccessor, data: dataAccessor, timestamp: timestampAccessor }
14
+ } = step
15
+
16
+ if (!dataSetId) {
17
+ throw new Error(`no dataset found`)
18
+ }
19
+
20
+ // make new data-sample
21
+ await getDataSource().transaction(async tx => {
22
+ const dataSet = await tx.getRepository(DataSet).findOne({
23
+ where: {
24
+ id: dataSetId
25
+ }
26
+ })
27
+
28
+ var source = await access(sourceAccessor, data)
29
+ var extractedData = await access(dataAccessor, data)
30
+ var extractedRawData = rawDataAccessor && (await access(rawDataAccessor, data))
31
+ var timestamp = timestampAccessor && (await access(timestampAccessor, data))
32
+
33
+ const dataSample = await createDataSample(
34
+ {
35
+ dataSet,
36
+ data: extractedData,
37
+ rawData: extractedRawData,
38
+ source,
39
+ collectedAt: new Date(timestamp || new Date())
40
+ },
41
+ {
42
+ t: i18next.t,
43
+ state: {
44
+ domain,
45
+ user,
46
+ lng,
47
+ tx
48
+ }
49
+ }
50
+ )
51
+
52
+ return {
53
+ data: dataSample
54
+ }
55
+ })
56
+ }
57
+
58
+ CreateDataSample.parameterSpec = [
59
+ {
60
+ type: 'entity-selector',
61
+ name: 'dataset',
62
+ label: 'data-set',
63
+ property: {
64
+ queryName: 'dataSets',
65
+ valueKey: 'id'
66
+ }
67
+ },
68
+ {
69
+ type: 'string',
70
+ name: 'source',
71
+ label: 'source'
72
+ },
73
+ {
74
+ type: 'string',
75
+ name: 'rawData',
76
+ label: 'raw-data'
77
+ },
78
+ {
79
+ type: 'string',
80
+ name: 'data',
81
+ label: 'data'
82
+ },
83
+ {
84
+ type: 'string',
85
+ name: 'timestamp',
86
+ label: 'timestamp'
87
+ }
88
+ ]
89
+
90
+ CreateDataSample.connectorFree = true
91
+ CreateDataSample.help = 'dataset/task/create-data-sample'
92
+
93
+ TaskRegistry.registerTaskHandler('create-data-sample', CreateDataSample)
@@ -0,0 +1,2 @@
1
+ import './create-data-sample'
2
+ import './issue-collect-data'
@@ -0,0 +1,45 @@
1
+ import { TaskRegistry, InputStep, Context } from '@things-factory/integration-base'
2
+ import { issueCollectData } from '../../controllers/issue-collect-data'
3
+ import i18next from 'i18next'
4
+
5
+ async function IssueCollectData(step: InputStep, context: Context) {
6
+ const { logger, data, domain, user, lng } = context
7
+ var {
8
+ params: { dataset: dataSetId }
9
+ } = step
10
+
11
+ if (!dataSetId) {
12
+ throw new Error(`no dataset found`)
13
+ }
14
+
15
+ const activityInstance = await issueCollectData(domain.id, dataSetId, {
16
+ t: i18next.t,
17
+ state: {
18
+ domain,
19
+ user,
20
+ lng,
21
+ tx: undefined
22
+ }
23
+ })
24
+
25
+ return {
26
+ data: activityInstance
27
+ }
28
+ }
29
+
30
+ IssueCollectData.parameterSpec = [
31
+ {
32
+ type: 'entity-selector',
33
+ name: 'dataset',
34
+ label: 'data-set',
35
+ property: {
36
+ queryName: 'dataSets',
37
+ valueKey: 'id'
38
+ }
39
+ }
40
+ ]
41
+
42
+ IssueCollectData.connectorFree = true
43
+ IssueCollectData.help = 'dataset/task/issue-collect-data'
44
+
45
+ TaskRegistry.registerTaskHandler('issue-collect-data', IssueCollectData)
package/server/index.ts CHANGED
@@ -1,5 +1,6 @@
1
1
  import './routes'
2
2
  import './activities'
3
+ import './engine'
3
4
 
4
5
  export * from './controllers'
5
6
  export * from './service'
package/server/routes.ts CHANGED
@@ -2,13 +2,13 @@ import { In } from 'typeorm'
2
2
 
3
3
  import { Domain, getDataSource } from '@things-factory/shell'
4
4
  import { User } from '@things-factory/auth-base'
5
- import { Activity } from '@things-factory/worklist'
6
- import { issue } from '@things-factory/worklist/dist-server/controllers/activity-instance/issue'
5
+ import { runScenario } from '@things-factory/integration-base'
7
6
  import { ScheduleRegisterRequest } from '@things-factory/scheduler-client'
8
7
 
9
8
  import { createDataSample } from './controllers/create-data-sample'
10
9
  import { renderJasperReport } from './controllers/jasper-report'
11
10
  import { renderShinyReport } from './controllers/shiny-report'
11
+ import { issueCollectData } from './controllers/issue-collect-data'
12
12
  import { DataSensor } from './service/data-sensor/data-sensor'
13
13
  import { DataSet } from './service/data-set/data-set'
14
14
 
@@ -23,8 +23,8 @@ process.on('bootstrap-module-global-public-route' as any, (app, globalPublicRout
23
23
  globalPublicRouter.post('/sensor-data', async (context, next) => {
24
24
  // 데이타 검증
25
25
  const { deviceId, data, rawData, timestamp = Date.now() } = context.request.body
26
- if (!deviceId || !data) {
27
- throw new Error(`deviceId(${deviceId}) and data(${JSON.stringify(data)}) properties are mandatory`)
26
+ if (!deviceId) {
27
+ throw new Error(`The deviceId(${deviceId}) property are mandatory`)
28
28
  }
29
29
 
30
30
  // make new data-sample
@@ -32,7 +32,7 @@ process.on('bootstrap-module-global-public-route' as any, (app, globalPublicRout
32
32
  // find sensor through deviceId
33
33
  const sensor = await tx.getRepository(DataSensor).findOne({
34
34
  where: { deviceId },
35
- relations: ['domain', 'appliance', 'dataSet']
35
+ relations: ['domain', 'appliance', 'dataSet', 'decoder']
36
36
  })
37
37
 
38
38
  if (!sensor) {
@@ -47,38 +47,63 @@ process.on('bootstrap-module-global-public-route' as any, (app, globalPublicRout
47
47
  throw new Error(`Appliance of the sensor given deviceId(${deviceId}) is not set up`)
48
48
  }
49
49
 
50
- if (!sensor.dataSet) {
51
- throw new Error(`DataSet of the sensor given deviceId(${deviceId}) is not set up`)
52
- }
53
-
54
50
  const domain = sensor.domain
55
51
  const dataSet = sensor.dataSet
56
- const user: User = await tx.getRepository(User).findOne({
57
- where: {
58
- reference: sensor.appliance.id,
59
- userType: 'appliance'
60
- }
61
- })
52
+
53
+ /*
54
+ 원칙적으로 user 인증정보를 가지고 요청해야 하지만, 인증정보를 보낼 수 없는 상황이라고 전제하여 처리한다.
55
+ 앞으로, 보완되어야 한다.
56
+ */
57
+ const user: User =
58
+ context.user ||
59
+ (await tx.getRepository(User).findOne({
60
+ where: {
61
+ reference: sensor.appliance.id,
62
+ userType: 'appliance'
63
+ }
64
+ }))
62
65
 
63
66
  context.state = {
67
+ user,
64
68
  ...context.state,
65
69
  domain,
66
70
  tx
67
71
  }
68
72
 
69
- return await createDataSample(
70
- {
71
- dataSet,
73
+ var decoded
74
+ if (sensor.decoder) {
75
+ const { name: scenarioName } = sensor.decoder
76
+ const variables = {
77
+ dataSensor: sensor,
78
+ source: deviceId,
72
79
  data,
73
80
  rawData,
74
- source: deviceId,
75
- collectedAt: new Date(timestamp)
76
- },
77
- context
78
- )
79
- })
81
+ timestamp
82
+ }
80
83
 
81
- context.status = 200
84
+ decoded = (await runScenario(null, scenarioName, variables, context))?.result
85
+ }
86
+
87
+ if (dataSet) {
88
+ await createDataSample(
89
+ {
90
+ dataSet,
91
+ data,
92
+ rawData,
93
+ source: deviceId,
94
+ collectedAt: new Date(timestamp),
95
+ ...decoded
96
+ },
97
+ context
98
+ )
99
+ }
100
+
101
+ context.status = 200
102
+ context.body = {
103
+ data,
104
+ ...decoded
105
+ }
106
+ })
82
107
  })
83
108
 
84
109
  /* When a callback occurs from the scheduler when a scheduled dataset is on schedule, data collection task for the dataset should be issued. */
@@ -95,55 +120,7 @@ process.on('bootstrap-module-global-public-route' as any, (app, globalPublicRout
95
120
  throw new Error(`group(${domainId}) and key(${dataSetId}) properties should not be empty`)
96
121
  }
97
122
 
98
- await getDataSource().transaction(async tx => {
99
- const domain = await tx.getRepository(Domain).findOneBy({ id: domainId })
100
-
101
- if (!domain) {
102
- throw new Error(`domain(${domainId}) not found`)
103
- }
104
-
105
- const dataSet = await tx
106
- .getRepository(DataSet)
107
- .findOne({ where: { domain: { id: In([domain.id, domain.parentId].filter(Boolean)) }, id: dataSetId } })
108
-
109
- const activity = (await tx.getRepository(Activity).findOneBy({
110
- domain: { id: domainId },
111
- name: 'Collect Data'
112
- })) as Activity
113
-
114
- if (activity) {
115
- const { assignees } = dataSet
116
-
117
- /* 해당 dataset에 대한 데이타 수집 태스크를 dataset assignees에게 할당한다. */
118
- if (assignees && assignees instanceof Array && assignees.length > 0) {
119
- const activityInstance = {
120
- name: `[Data 수집] ${dataSet.name}`,
121
- description: dataSet.description,
122
- activityId: activity.id,
123
- dueAt: new Date(Date.now() + 24 * 60 * 60 * 1000),
124
- input: {
125
- dataSetId: dataSet.id,
126
- dataSetName: dataSet.name
127
- },
128
- assignees
129
- }
130
-
131
- context.state = {
132
- ...context.state,
133
- domain,
134
- tx
135
- }
136
-
137
- await issue(activityInstance, context)
138
- } else {
139
- throw new Error(
140
- `Assignees not set. So Data Collect Activity for ${dataSet.name}($dataSet.id) could not be issued.`
141
- )
142
- }
143
- } else {
144
- throw new Error(`Data Collect Activity is not installed.`)
145
- }
146
- })
123
+ await issueCollectData(domainId, dataSetId, context)
147
124
 
148
125
  context.status = 200
149
126
  })
@@ -169,9 +146,7 @@ process.on('bootstrap-module-global-public-route' as any, (app, globalPublicRout
169
146
  throw new Error(`domain(${domainId}) not found`)
170
147
  }
171
148
 
172
- const dataSet = await tx
173
- .getRepository(DataSet)
174
- .findOne({ where: { domain: { id: In([domain.id, domain.parentId].filter(Boolean)) }, id: dataSetId } })
149
+ const dataSet = await tx.getRepository(DataSet).findOne({ where: { domain: { id: In([domain.id, domain.parentId].filter(Boolean)) }, id: dataSetId } })
175
150
 
176
151
  // do what you gotta do
177
152
  })
@@ -2,10 +2,12 @@ import { Arg, Args, Ctx, Directive, FieldResolver, Query, Resolver, Root } from
2
2
 
3
3
  import { User } from '@things-factory/auth-base'
4
4
  import { Domain, getQueryBuilderFromListParams, getRepository, ListParam } from '@things-factory/shell'
5
+ import { ActivityInstance } from '@things-factory/worklist'
5
6
 
6
7
  import { DataSetHistory } from '../data-set-history/data-set-history'
7
8
  import { DataItem } from '../data-set/data-item-type'
8
9
  import { DataSet } from '../data-set/data-set'
10
+ import { DataSample } from '../data-sample/data-sample'
9
11
  import { DataOoc } from './data-ooc'
10
12
  import { DataOocList } from './data-ooc-type'
11
13
 
@@ -51,11 +53,26 @@ export class DataOocQuery {
51
53
  return dataSetHistory?.dataItems || []
52
54
  }
53
55
 
56
+ @FieldResolver(type => DataSample)
57
+ async dataSample(@Root() dataOoc: DataOoc): Promise<DataSample> {
58
+ return dataOoc.dataSampleId && (await getRepository(DataSample).findOneBy({ id: dataOoc.dataSampleId }))
59
+ }
60
+
54
61
  @FieldResolver(type => DataSet)
55
62
  async dataSet(@Root() dataOoc: DataOoc): Promise<DataSet> {
56
63
  return dataOoc.dataSetId && (await getRepository(DataSet).findOneBy({ id: dataOoc.dataSetId }))
57
64
  }
58
65
 
66
+ @FieldResolver(type => ActivityInstance)
67
+ async reviewActivityInstance(@Root() dataOoc: DataOoc): Promise<ActivityInstance> {
68
+ return dataOoc.reviewActivityInstanceId && (await getRepository(ActivityInstance).findOneBy({ id: dataOoc.reviewActivityInstanceId }))
69
+ }
70
+
71
+ @FieldResolver(type => ActivityInstance)
72
+ async resolveActivityInstance(@Root() dataOoc: DataOoc): Promise<ActivityInstance> {
73
+ return dataOoc.resolveActivityInstanceId && (await getRepository(ActivityInstance).findOneBy({ id: dataOoc.resolveActivityInstanceId }))
74
+ }
75
+
59
76
  @FieldResolver(type => User)
60
77
  async corrector(@Root() dataOoc: DataOoc): Promise<User> {
61
78
  return dataOoc.correctorId && (await getRepository(User).findOneBy({ id: dataOoc.correctorId }))