@things-factory/dataset 6.0.25 → 6.0.28

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 (193) hide show
  1. package/README.md +26 -11
  2. package/assets/images/data-collect.png +0 -0
  3. package/assets/images/ooc.png +0 -0
  4. package/assets/images/oos.png +0 -0
  5. package/client/{bootstrap.js → bootstrap.ts} +5 -1
  6. package/client/components/data-collect-activity-view.ts +100 -0
  7. package/client/components/{data-entry-form.js → data-entry-form.ts} +30 -33
  8. package/client/components/ooc-resolve-activity-view.ts +174 -0
  9. package/client/components/ooc-review-activity-view.ts +153 -0
  10. package/client/pages/data-archive/{data-archive-list-page.js → data-archive-list-page.ts} +67 -53
  11. package/client/pages/data-archive/{data-archive-request-popup.js → data-archive-request-popup.ts} +41 -39
  12. package/client/pages/data-entry/{data-entry-list-page.js → data-entry-list-page.ts} +41 -38
  13. package/client/pages/data-key-set/{data-key-item-list.js → data-key-item-list.ts} +31 -39
  14. package/client/pages/data-key-set/data-key-set-importer.ts +95 -0
  15. package/client/pages/data-key-set/{data-key-set-list-page.js → data-key-set-list-page.ts} +54 -35
  16. package/client/pages/data-ooc/{data-ooc-list-page.js → data-ooc-list-page.ts} +56 -36
  17. package/client/pages/data-ooc/data-ooc-view-page.ts +115 -0
  18. package/client/pages/data-ooc/data-ooc-view.ts +124 -0
  19. package/client/pages/data-report/{data-report-embed-page.js → data-report-embed-page.ts} +25 -34
  20. package/client/pages/data-report/{data-report-list-page.js → data-report-list-page.ts} +49 -43
  21. package/client/pages/data-report/{data-report-samples-page.js → data-report-samples-page.ts} +29 -43
  22. package/client/pages/data-report/{jasper-report-oocs-page.js → jasper-report-oocs-page.ts} +22 -34
  23. package/client/pages/data-report/{jasper-report-samples-crosstab-page.js → jasper-report-samples-crosstab-page.ts} +22 -34
  24. package/client/pages/data-report/{jasper-report-samples-page.js → jasper-report-samples-page.ts} +22 -34
  25. package/client/pages/data-sample/{data-sample-list-page.js → data-sample-list-page.ts} +49 -36
  26. package/client/pages/data-sample/{data-sample-search-page.js → data-sample-search-page.ts} +53 -39
  27. package/client/pages/data-sample/{data-sample-view.js → data-sample-view.ts} +29 -33
  28. package/client/pages/data-sensor/{data-sensor-list-page.js → data-sensor-list-page.ts} +41 -35
  29. package/client/pages/data-set/{data-item-list.js → data-item-list.ts} +31 -37
  30. package/client/pages/data-set/data-set-importer.ts +96 -0
  31. package/client/pages/data-set/{data-set-list-page.js → data-set-list-page.ts} +173 -40
  32. package/client/{route.js → route.ts} +5 -1
  33. package/client/tsconfig.json +11 -0
  34. package/config/config.development.js +30 -30
  35. package/config/config.production.js +31 -31
  36. package/dist-client/bootstrap.d.ts +5 -0
  37. package/dist-client/bootstrap.js +16 -0
  38. package/dist-client/bootstrap.js.map +1 -0
  39. package/dist-client/components/data-collect-activity-view.d.ts +19 -0
  40. package/dist-client/components/data-collect-activity-view.js +101 -0
  41. package/dist-client/components/data-collect-activity-view.js.map +1 -0
  42. package/dist-client/components/data-entry-form.d.ts +15 -0
  43. package/dist-client/components/data-entry-form.js +83 -0
  44. package/dist-client/components/data-entry-form.js.map +1 -0
  45. package/dist-client/components/data-ooc-activity-view.d.ts +1 -0
  46. package/dist-client/components/data-ooc-activity-view.js +154 -0
  47. package/dist-client/components/data-ooc-activity-view.js.map +1 -0
  48. package/dist-client/components/ooc-resolve-activity-view.d.ts +1 -0
  49. package/dist-client/components/ooc-resolve-activity-view.js +175 -0
  50. package/dist-client/components/ooc-resolve-activity-view.js.map +1 -0
  51. package/dist-client/components/ooc-review-activity-view.d.ts +1 -0
  52. package/dist-client/components/ooc-review-activity-view.js +155 -0
  53. package/dist-client/components/ooc-review-activity-view.js.map +1 -0
  54. package/dist-client/index.d.ts +1 -0
  55. package/dist-client/index.js +2 -0
  56. package/dist-client/index.js.map +1 -0
  57. package/dist-client/pages/data-archive/data-archive-list-page.d.ts +71 -0
  58. package/dist-client/pages/data-archive/data-archive-list-page.js +287 -0
  59. package/dist-client/pages/data-archive/data-archive-list-page.js.map +1 -0
  60. package/dist-client/pages/data-archive/data-archive-request-popup.d.ts +1 -0
  61. package/dist-client/pages/data-archive/data-archive-request-popup.js +161 -0
  62. package/dist-client/pages/data-archive/data-archive-request-popup.js.map +1 -0
  63. package/dist-client/pages/data-entry/data-entry-list-page.d.ts +36 -0
  64. package/dist-client/pages/data-entry/data-entry-list-page.js +383 -0
  65. package/dist-client/pages/data-entry/data-entry-list-page.js.map +1 -0
  66. package/dist-client/pages/data-key-set/data-key-item-list.d.ts +18 -0
  67. package/dist-client/pages/data-key-set/data-key-item-list.js +188 -0
  68. package/dist-client/pages/data-key-set/data-key-item-list.js.map +1 -0
  69. package/dist-client/pages/data-key-set/data-key-set-importer.d.ts +9 -0
  70. package/dist-client/pages/data-key-set/data-key-set-importer.js +100 -0
  71. package/dist-client/pages/data-key-set/data-key-set-importer.js.map +1 -0
  72. package/dist-client/pages/data-key-set/data-key-set-list-page.d.ts +60 -0
  73. package/dist-client/pages/data-key-set/data-key-set-list-page.js +450 -0
  74. package/dist-client/pages/data-key-set/data-key-set-list-page.js.map +1 -0
  75. package/dist-client/pages/data-ooc/data-ooc-list-page.d.ts +58 -0
  76. package/dist-client/pages/data-ooc/data-ooc-list-page.js +479 -0
  77. package/dist-client/pages/data-ooc/data-ooc-list-page.js.map +1 -0
  78. package/dist-client/pages/data-ooc/data-ooc-view-page.d.ts +18 -0
  79. package/dist-client/pages/data-ooc/data-ooc-view-page.js +114 -0
  80. package/dist-client/pages/data-ooc/data-ooc-view-page.js.map +1 -0
  81. package/dist-client/pages/data-ooc/data-ooc-view.d.ts +15 -0
  82. package/dist-client/pages/data-ooc/data-ooc-view.js +130 -0
  83. package/dist-client/pages/data-ooc/data-ooc-view.js.map +1 -0
  84. package/dist-client/pages/data-report/data-report-embed-page.d.ts +36 -0
  85. package/dist-client/pages/data-report/data-report-embed-page.js +101 -0
  86. package/dist-client/pages/data-report/data-report-embed-page.js.map +1 -0
  87. package/dist-client/pages/data-report/data-report-list-page.d.ts +36 -0
  88. package/dist-client/pages/data-report/data-report-list-page.js +431 -0
  89. package/dist-client/pages/data-report/data-report-list-page.js.map +1 -0
  90. package/dist-client/pages/data-report/data-report-samples-page.d.ts +32 -0
  91. package/dist-client/pages/data-report/data-report-samples-page.js +164 -0
  92. package/dist-client/pages/data-report/data-report-samples-page.js.map +1 -0
  93. package/dist-client/pages/data-report/jasper-report-oocs-page.d.ts +2 -0
  94. package/dist-client/pages/data-report/jasper-report-oocs-page.js +101 -0
  95. package/dist-client/pages/data-report/jasper-report-oocs-page.js.map +1 -0
  96. package/dist-client/pages/data-report/jasper-report-samples-crosstab-page.d.ts +2 -0
  97. package/dist-client/pages/data-report/jasper-report-samples-crosstab-page.js +101 -0
  98. package/dist-client/pages/data-report/jasper-report-samples-crosstab-page.js.map +1 -0
  99. package/dist-client/pages/data-report/jasper-report-samples-page.d.ts +2 -0
  100. package/dist-client/pages/data-report/jasper-report-samples-page.js +101 -0
  101. package/dist-client/pages/data-report/jasper-report-samples-page.js.map +1 -0
  102. package/dist-client/pages/data-sample/data-sample-list-page.d.ts +58 -0
  103. package/dist-client/pages/data-sample/data-sample-list-page.js +412 -0
  104. package/dist-client/pages/data-sample/data-sample-list-page.js.map +1 -0
  105. package/dist-client/pages/data-sample/data-sample-search-page.d.ts +63 -0
  106. package/dist-client/pages/data-sample/data-sample-search-page.js +413 -0
  107. package/dist-client/pages/data-sample/data-sample-search-page.js.map +1 -0
  108. package/dist-client/pages/data-sample/data-sample-view.d.ts +1 -0
  109. package/dist-client/pages/data-sample/data-sample-view.js +109 -0
  110. package/dist-client/pages/data-sample/data-sample-view.js.map +1 -0
  111. package/dist-client/pages/data-sensor/data-sensor-list-page.d.ts +49 -0
  112. package/dist-client/pages/data-sensor/data-sensor-list-page.js +419 -0
  113. package/dist-client/pages/data-sensor/data-sensor-list-page.js.map +1 -0
  114. package/dist-client/pages/data-set/data-item-list.d.ts +1 -0
  115. package/dist-client/pages/data-set/data-item-list.js +267 -0
  116. package/dist-client/pages/data-set/data-item-list.js.map +1 -0
  117. package/dist-client/pages/data-set/data-set-importer.d.ts +10 -0
  118. package/dist-client/pages/data-set/data-set-importer.js +103 -0
  119. package/dist-client/pages/data-set/data-set-importer.js.map +1 -0
  120. package/dist-client/pages/data-set/data-set-list-page.d.ts +73 -0
  121. package/dist-client/pages/data-set/data-set-list-page.js +861 -0
  122. package/dist-client/pages/data-set/data-set-list-page.js.map +1 -0
  123. package/dist-client/route.d.ts +1 -0
  124. package/dist-client/route.js +50 -0
  125. package/dist-client/route.js.map +1 -0
  126. package/dist-client/tsconfig.tsbuildinfo +1 -0
  127. package/dist-server/controllers/activity-template/activity-data-collect.js +82 -0
  128. package/dist-server/controllers/activity-template/activity-data-collect.js.map +1 -0
  129. package/dist-server/controllers/activity-template/activity-ooc-resolve.js +100 -0
  130. package/dist-server/controllers/activity-template/activity-ooc-resolve.js.map +1 -0
  131. package/dist-server/controllers/activity-template/activity-ooc-review.js +107 -0
  132. package/dist-server/controllers/activity-template/activity-ooc-review.js.map +1 -0
  133. package/dist-server/controllers/activity-template/activity-ooc.js +59 -0
  134. package/dist-server/controllers/activity-template/activity-ooc.js.map +1 -0
  135. package/dist-server/controllers/create-data-sample.js +53 -14
  136. package/dist-server/controllers/create-data-sample.js.map +1 -1
  137. package/dist-server/controllers/data-use-case.js +1 -1
  138. package/dist-server/controllers/data-use-case.js.map +1 -1
  139. package/dist-server/controllers/index.js +7 -0
  140. package/dist-server/controllers/index.js.map +1 -1
  141. package/dist-server/index.js +1 -2
  142. package/dist-server/index.js.map +1 -1
  143. package/dist-server/routes.js +47 -3
  144. package/dist-server/routes.js.map +1 -1
  145. package/dist-server/service/data-ooc/data-ooc-query.js +22 -2
  146. package/dist-server/service/data-ooc/data-ooc-query.js.map +1 -1
  147. package/dist-server/service/data-ooc/data-ooc.js +26 -0
  148. package/dist-server/service/data-ooc/data-ooc.js.map +1 -1
  149. package/dist-server/service/data-set/data-set-mutation.js +88 -0
  150. package/dist-server/service/data-set/data-set-mutation.js.map +1 -1
  151. package/dist-server/service/data-set/data-set-query.js +38 -4
  152. package/dist-server/service/data-set/data-set-query.js.map +1 -1
  153. package/dist-server/service/data-set/data-set-type.js +16 -0
  154. package/dist-server/service/data-set/data-set-type.js.map +1 -1
  155. package/dist-server/service/data-set/data-set.js +55 -3
  156. package/dist-server/service/data-set/data-set.js.map +1 -1
  157. package/dist-server/service/data-set-history/data-set-history-query.js +4 -3
  158. package/dist-server/service/data-set-history/data-set-history-query.js.map +1 -1
  159. package/dist-server/tsconfig.tsbuildinfo +1 -1
  160. package/helps/dataset/data-ooc.md +5 -4
  161. package/package.json +17 -12
  162. package/server/controllers/activity-template/activity-data-collect.ts +84 -0
  163. package/server/controllers/activity-template/activity-ooc-resolve.ts +114 -0
  164. package/server/controllers/activity-template/activity-ooc-review.ts +118 -0
  165. package/server/controllers/create-data-sample.ts +61 -21
  166. package/server/controllers/data-use-case.ts +1 -1
  167. package/server/controllers/index.ts +11 -0
  168. package/server/index.ts +1 -2
  169. package/server/routes.ts +62 -5
  170. package/server/service/data-ooc/data-ooc-query.ts +12 -2
  171. package/server/service/data-ooc/data-ooc.ts +23 -0
  172. package/server/service/data-set/data-set-mutation.ts +99 -0
  173. package/server/service/data-set/data-set-query.ts +39 -5
  174. package/server/service/data-set/data-set-type.ts +14 -0
  175. package/server/service/data-set/data-set.ts +43 -2
  176. package/server/service/data-set-history/data-set-history-query.ts +4 -3
  177. package/server/tsconfig.json +10 -0
  178. package/things-factory.config.js +6 -2
  179. package/translations/en.json +3 -1
  180. package/translations/ko.json +3 -1
  181. package/translations/ms.json +3 -0
  182. package/translations/zh.json +3 -0
  183. package/client/pages/data-key-set/data-key-set-importer.js +0 -105
  184. package/client/pages/data-ooc/data-ooc-view.js +0 -188
  185. package/client/pages/data-set/data-set-importer.js +0 -103
  186. package/server/middlewares/index.ts +0 -3
  187. package/server/migrations/index.ts +0 -9
  188. package/tsconfig.json +0 -9
  189. /package/assets/{data-report.jpg → images/data-report.jpg} +0 -0
  190. /package/assets/{data-samples.jpg → images/data-samples.jpg} +0 -0
  191. /package/assets/{diagram.jpg → images/dataset-diagram.jpg} +0 -0
  192. /package/assets/{glue-table-indices.png → images/glue-table-indices-for-dataset.png} +0 -0
  193. /package/client/{index.js → index.ts} +0 -0
@@ -1,10 +1,11 @@
1
1
  # DataOOC
2
- 데이타 이탈 내역을 조회하고 조치합니다.
2
+
3
+ 데이타 이탈 내역을 조회하고 조치합니다.
3
4
 
4
5
  - 데이타 이탈점 상세: 데이타 이탈점 상세 팝업 화면을 띄웁니다.
5
- - 데이타 셋 아이템 별 CCP, QC 이탈 여부를 조회합니다.
6
- - 데이타 이탈점 생성 부터 조치 이력을 조회합니다.
7
- - 조치, 조치완료 내용을 입력하고 저장합니다.
6
+ - 데이타 셋 아이템 별 CCP, QC 이탈 여부를 조회합니다.
7
+ - 데이타 이탈점 생성 부터 조치 이력을 조회합니다.
8
+ - 조치, 조치완료 내용을 입력하고 저장합니다.
8
9
  - 상태: 생성, 조치, 조치완료 상태를 보여줍니다.
9
10
  - 조치 활동: 조치 내용을 보여줍니다.
10
11
 
package/package.json CHANGED
@@ -1,8 +1,8 @@
1
1
  {
2
2
  "name": "@things-factory/dataset",
3
- "version": "6.0.25",
3
+ "version": "6.0.28",
4
4
  "main": "dist-server/index.js",
5
- "browser": "client/index.js",
5
+ "browser": "dist-client/index.js",
6
6
  "things-factory": true,
7
7
  "author": "heartyoh <heartyoh@hatiolab.com>",
8
8
  "description": "module for handling data collection",
@@ -16,10 +16,12 @@
16
16
  "directory": "packages/dataset"
17
17
  },
18
18
  "scripts": {
19
- "build": "tsc --p tsconfig.json",
20
- "build:server": "npm run clean:server && tsc",
21
- "clean:server": "rm -rf dist-server",
22
- "clean": "npm run clean:server",
19
+ "build": "npm run build:server && npm run build:client",
20
+ "build:client": "npx tsc --p ./client/tsconfig.json",
21
+ "build:server": "npx tsc --p ./server/tsconfig.json",
22
+ "clean:client": "npx rimraf dist-client",
23
+ "clean:server": "npx rimraf dist-server",
24
+ "clean": "npm run clean:server && npm run clean:client",
23
25
  "migration:create": "node ../../node_modules/typeorm/cli.js migration:create -d ./server/migrations"
24
26
  },
25
27
  "dependencies": {
@@ -33,14 +35,17 @@
33
35
  "@operato/shell": "^1.0.1",
34
36
  "@operato/styles": "^1.0.0",
35
37
  "@operato/utils": "^1.0.1",
36
- "@things-factory/auth-base": "^6.0.25",
37
- "@things-factory/aws-base": "^6.0.25",
38
- "@things-factory/board-service": "^6.0.25",
38
+ "@things-factory/auth-base": "^6.0.28",
39
+ "@things-factory/aws-base": "^6.0.28",
40
+ "@things-factory/board-service": "^6.0.28",
39
41
  "@things-factory/env": "^6.0.7",
40
- "@things-factory/shell": "^6.0.25",
41
- "@things-factory/work-shift": "^6.0.25",
42
+ "@things-factory/organization": "^6.0.28",
43
+ "@things-factory/scheduler-client": "^6.0.28",
44
+ "@things-factory/shell": "^6.0.28",
45
+ "@things-factory/work-shift": "^6.0.28",
46
+ "@things-factory/worklist": "^6.0.28",
42
47
  "cron-parser": "^4.3.0",
43
48
  "moment-timezone": "^0.5.40"
44
49
  },
45
- "gitHead": "8a987a42de944dc915b8cfddb047eb7bc0d4ba41"
50
+ "gitHead": "8b4e03229444e38fc3f3487227a96837eef85099"
46
51
  }
@@ -0,0 +1,84 @@
1
+ import { Activity, ActivityInstance, ActivityInstanceStatus } from '@things-factory/worklist'
2
+ import { NewDataSample } from 'service/data-sample/data-sample-type'
3
+ import { createDataSample } from '../../controllers/create-data-sample'
4
+
5
+ async function callback(activityInstance: ActivityInstance, context: ResolverContext) {
6
+ const { domain, tx } = context.state
7
+ const { input, output, state } = activityInstance
8
+
9
+ if (state == ActivityInstanceStatus.Ended) {
10
+ const activity = (await tx.getRepository(Activity).findOneBy({
11
+ domain: { id: domain.id },
12
+ name: 'Collect Data'
13
+ })) as Activity
14
+
15
+ /* collect-data 액티비티는 한명의 assignee(thread)만 수행하도록 한다. 따라서, output 중에서 샘플 한개만을 data로 취한다. */
16
+ const assignees = Object.keys(output)
17
+ const data = assignees.length > 0 && output[assignees[0]]
18
+
19
+ if (activity) {
20
+ const dataSample: NewDataSample = {
21
+ dataSet: {
22
+ id: input.dataSetId
23
+ },
24
+ data
25
+ }
26
+
27
+ await createDataSample(dataSample, context)
28
+ } else {
29
+ console.error('Collect Data Activity not installed.')
30
+ }
31
+ }
32
+ }
33
+
34
+ export const ActivityDataCollect = {
35
+ name: 'Collect Data',
36
+ description: 'Tasks assigned for data collection',
37
+ release: '1.0.0',
38
+ provider: 'hatiolab.com',
39
+ category: 'quality',
40
+ activityType: 'user',
41
+ searchKeys: [
42
+ {
43
+ name: 'dataSetName',
44
+ description: 'DataSet name',
45
+ inputKey: 'dataSetName',
46
+ tKey: 'data-set-name'
47
+ }
48
+ ],
49
+ startable: true,
50
+ model: [
51
+ {
52
+ name: 'dataSetId',
53
+ description: 'DataSet Id.',
54
+ tag: 'dataSetId',
55
+ hidden: true,
56
+ mandatory: true,
57
+ inout: 'in',
58
+ type: 'string',
59
+ options: {},
60
+ unit: null,
61
+ quantifier: [1],
62
+ spec: {}
63
+ },
64
+ {
65
+ name: 'dataSetName',
66
+ description: 'DataSet name',
67
+ tag: 'dataSetName',
68
+ hidden: true,
69
+ mandatory: true,
70
+ inout: 'in',
71
+ type: 'string',
72
+ options: {},
73
+ unit: null,
74
+ quantifier: [1],
75
+ spec: {}
76
+ }
77
+ ],
78
+ uiType: 'custom-element',
79
+ uiSource: 'data-collect-activity-view',
80
+ reportType: 'page',
81
+ reportSource: 'data-collect-activity-view',
82
+ thumbnail: '/assets/images/data-collect.png',
83
+ callback /* Called when there is a change in the lifecycle of a task (activity-instance). */
84
+ }
@@ -0,0 +1,114 @@
1
+ import {
2
+ ActivityInstance,
3
+ ActivityInstanceStatus,
4
+ ActivityThread,
5
+ ActivityThreadStatus
6
+ } from '@things-factory/worklist'
7
+ import { DataOoc, DataOocStatus } from '../../service/data-ooc/data-ooc'
8
+
9
+ async function callback(activityInstance: ActivityInstance, context: ResolverContext) {
10
+ const { tx, user, domain } = context.state
11
+ const { id, input, output, state, terminatedAt } = activityInstance
12
+
13
+ /* Resolve Activity가 완료되면, 해당 data-ooc 엔티티의 correctiveAction, correctorId, correctedAt 을 update한다. */
14
+ if (state == ActivityInstanceStatus.Ended) {
15
+ const activityThreads = await tx.getRepository(ActivityThread).find({
16
+ where: {
17
+ domain: { id: domain.id },
18
+ activityInstance: { id },
19
+ state: ActivityThreadStatus.Ended
20
+ },
21
+ relations: ['assignee']
22
+ })
23
+
24
+ const corrector = activityThreads[0]?.assignee
25
+
26
+ const { dataOocId } = input
27
+ const correctiveAction = Object.values(output)
28
+ .map((o: any) => o.action)
29
+ .join('\n')
30
+
31
+ var dataOoc = await tx.getRepository(DataOoc).findOne({
32
+ where: {
33
+ domain: { id: domain.id },
34
+ id: dataOocId
35
+ },
36
+ relations: ['dataSet']
37
+ })
38
+
39
+ /* dataOoc Review 결과를 dataOoc 엔티티에 반영한다. */
40
+ dataOoc = await tx.getRepository(DataOoc).save({
41
+ ...dataOoc,
42
+ correctedAt: terminatedAt,
43
+ corrector: corrector,
44
+ correctiveAction,
45
+ updater: user,
46
+ state: DataOocStatus.CORRECTED
47
+ })
48
+ }
49
+ }
50
+
51
+ export const ActivityOocResolve = {
52
+ name: 'OOC Resolve',
53
+ description: 'Task to take remedial action based on Out Of Control data',
54
+ release: '1.0.0',
55
+ provider: 'hatiolab.com',
56
+ category: 'quality',
57
+ activityType: 'user',
58
+ searchKeys: [
59
+ {
60
+ name: 'dataOocId',
61
+ description: 'OOC Id.',
62
+ inputKey: 'dataOocId',
63
+ tKey: 'data-ooc-id'
64
+ }
65
+ ],
66
+ startable: true,
67
+ model: [
68
+ {
69
+ name: 'dataOocId',
70
+ description: 'OOC id',
71
+ tag: 'dataOocId',
72
+ hidden: true,
73
+ mandatory: true,
74
+ inout: 'in',
75
+ type: 'string',
76
+ options: {},
77
+ unit: null,
78
+ quantifier: [1],
79
+ spec: {}
80
+ },
81
+ {
82
+ name: 'instruction',
83
+ description: 'Instructions for resolving OOC',
84
+ tag: 'instruction',
85
+ hidden: false,
86
+ mandatory: true,
87
+ inout: 'in',
88
+ type: 'textarea',
89
+ options: {},
90
+ unit: null,
91
+ quantifier: [1],
92
+ spec: {}
93
+ },
94
+ {
95
+ name: 'action',
96
+ description: 'Action Description',
97
+ tag: 'action',
98
+ hidden: false,
99
+ mandatory: true,
100
+ inout: 'out',
101
+ type: 'textarea',
102
+ options: {},
103
+ unit: null,
104
+ quantifier: [1],
105
+ spec: {}
106
+ }
107
+ ],
108
+ uiType: 'custom-element',
109
+ uiSource: 'ooc-resolve-activity-view',
110
+ reportType: 'page',
111
+ reportSource: 'data-ooc-report-page',
112
+ thumbnail: '/assets/images/ooc.png',
113
+ callback /* Called when there is a change in the lifecycle of a task (activity-instance). */
114
+ }
@@ -0,0 +1,118 @@
1
+ import { Activity, ActivityInstance, ActivityInstanceStatus } from '@things-factory/worklist'
2
+ import { post } from '@things-factory/worklist/dist-server/controllers/activity-instance/post'
3
+ import { DataOoc, DataOocStatus } from '../../service/data-ooc/data-ooc'
4
+
5
+ async function callback(activityInstance: ActivityInstance, context: ResolverContext) {
6
+ const { domain, user, tx } = context.state
7
+ const { input, output, state, terminatedAt } = activityInstance
8
+
9
+ if (state == ActivityInstanceStatus.Ended) {
10
+ const activity = (await tx.getRepository(Activity).findOneBy({
11
+ domain: { id: domain.id },
12
+ name: 'OOC Resolve'
13
+ })) as Activity
14
+
15
+ if (activity) {
16
+ const { dataOocId } = input
17
+ const correctiveInstruction = Object.values(output)
18
+ .map((o: any) => o.instruction)
19
+ .join('\n')
20
+
21
+ var dataOoc = await tx.getRepository(DataOoc).findOne({
22
+ where: {
23
+ domain: { id: domain.id },
24
+ id: dataOocId
25
+ },
26
+ relations: ['dataSet']
27
+ })
28
+
29
+ const dataSet = dataOoc.dataSet
30
+ const { assignees, approvalLine } = dataSet
31
+
32
+ /* dataOoc Review 결과를 dataOoc 엔티티에 반영한다. */
33
+ dataOoc = await tx.getRepository(DataOoc).save({
34
+ ...dataOoc,
35
+ reviewedAt: terminatedAt,
36
+ reviewer: user,
37
+ correctiveInstruction,
38
+ state: DataOocStatus.REVIEWED
39
+ })
40
+
41
+ /* 해당 dataset의 작업 담당자(assignees)에게 OOC 해결을 위한 태스크를 지시한다. */
42
+ if (assignees && assignees instanceof Array && assignees.length > 0) {
43
+ const activityInstance = {
44
+ name: `[OOC 조치] ${dataSet.name}`,
45
+ activityId: activity.id,
46
+ description: `Data OOC occurred on '${dataSet.name}'`,
47
+ dueAt: new Date(terminatedAt.getTime() + 24 * 60 * 60 * 1000),
48
+ input: {
49
+ dataOocId,
50
+ instruction: correctiveInstruction
51
+ },
52
+ assignees,
53
+ approvalLine
54
+ }
55
+
56
+ await post(activityInstance, context)
57
+ } else {
58
+ console.error(
59
+ `Assignees are not set. So, Data OOC Resolve task for ${dataOoc.name}(${dataOoc.id}) could not be posted.`
60
+ )
61
+ }
62
+ } else {
63
+ console.error('OOC Resolve Activity not installed.')
64
+ }
65
+ }
66
+ }
67
+
68
+ export const ActivityOocReview = {
69
+ name: 'OOC Review',
70
+ description: 'Task to take remedial action based on Out Of Control data',
71
+ release: '1.0.0',
72
+ provider: 'hatiolab.com',
73
+ category: 'quality',
74
+ activityType: 'user',
75
+ searchKeys: [
76
+ {
77
+ name: 'dataOocId',
78
+ description: 'OOC Id.',
79
+ inputKey: 'dataOocId',
80
+ tKey: 'data-ooc-id'
81
+ }
82
+ ],
83
+ startable: true,
84
+ model: [
85
+ {
86
+ name: 'dataOocId',
87
+ description: 'OOC id',
88
+ tag: 'dataOocId',
89
+ hidden: true,
90
+ mandatory: true,
91
+ inout: 'in',
92
+ type: 'string',
93
+ options: {},
94
+ unit: null,
95
+ quantifier: [1],
96
+ spec: {}
97
+ },
98
+ {
99
+ name: 'Instruction',
100
+ description: 'Instructions for preventing OOC',
101
+ tag: 'instruction',
102
+ hidden: false,
103
+ mandatory: true,
104
+ inout: 'out',
105
+ type: 'textarea',
106
+ options: {},
107
+ unit: null,
108
+ quantifier: [1],
109
+ spec: {}
110
+ }
111
+ ],
112
+ uiType: 'custom-element',
113
+ uiSource: 'ooc-review-activity-view',
114
+ reportType: 'page',
115
+ reportSource: 'data-ooc-report-page',
116
+ thumbnail: '/assets/images/ooc.png',
117
+ callback /* Called when there is a change in the lifecycle of a task (activity-instance). */
118
+ }
@@ -1,8 +1,8 @@
1
1
  import moment from 'moment-timezone'
2
- import { EntityManager } from 'typeorm'
3
2
 
4
- import { User } from '@things-factory/auth-base'
5
- import { Domain, getRedirectSubdomainPath, pubsub } from '@things-factory/shell'
3
+ import { Role } from '@things-factory/auth-base'
4
+ import { getRedirectSubdomainPath, pubsub } from '@things-factory/shell'
5
+ import { logger } from '@things-factory/env'
6
6
  import { getWorkDateAndShift } from '@things-factory/work-shift'
7
7
 
8
8
  import { DataOoc, DataOocStatus } from '../service/data-ooc/data-ooc'
@@ -10,6 +10,9 @@ import { DataSample } from '../service/data-sample/data-sample'
10
10
  import { NewDataSample } from '../service/data-sample/data-sample-type'
11
11
  import { DataSet } from '../service/data-set/data-set'
12
12
  import { DataUseCase } from './data-use-case'
13
+ import { Activity } from '@things-factory/worklist'
14
+
15
+ import { post } from '@things-factory/worklist/dist-server/controllers/activity-instance/post'
13
16
 
14
17
  // See README.md at ## Data Samples
15
18
  process.env.TZ = 'UTC'
@@ -50,10 +53,7 @@ const formatDate = (keys, _moment) => {
50
53
  return keys
51
54
  }
52
55
 
53
- export async function createDataSample(
54
- dataSample: NewDataSample,
55
- context: { state: { domain: Domain; user: User; tx: EntityManager } }
56
- ): Promise<DataSample> {
56
+ export async function createDataSample(dataSample: NewDataSample, context: ResolverContext): Promise<DataSample> {
57
57
  const { domain, user, tx } = context.state
58
58
 
59
59
  const dataSet = await tx.getRepository(DataSet).findOne({
@@ -122,27 +122,67 @@ export async function createDataSample(
122
122
  name: user.name
123
123
  },
124
124
  state: DataOocStatus.CREATED,
125
- timestamp: Date.now()
125
+ timestamp: collectedAt
126
126
  }
127
127
  ],
128
128
  state: DataOocStatus.CREATED
129
129
  })
130
130
 
131
- pubsub.publish('data-ooc', {
132
- dataOoc,
133
- supervisoryRoleId: dataSet.supervisoryRoleId
134
- })
131
+ const activity = (await tx.getRepository(Activity).findOneBy({
132
+ domain: { id: domain.id },
133
+ name: 'OOC Review'
134
+ })) as Activity
135
+
136
+ if (activity) {
137
+ const assignee =
138
+ dataSet.supervisoryRoleId &&
139
+ (await tx.getRepository(Role).findOneBy({ domain: { id: domain.id }, id: dataSet.supervisoryRoleId }))
140
+
141
+ const assignees = dataSet.supervisoryRoleId ? [{ type: 'Role', value: dataSet.supervisoryRoleId, assignee }] : []
142
+
143
+ /* 해당 dataset의 supervisor로 하여금, OOC를 리뷰하고 instruction을 작성해서, OOC 해결을 위한 태스크를 dataset assignees에게 지시하도록 한다. */
144
+ if (assignees && assignees instanceof Array && assignees.length > 0) {
145
+ const activityInstance = {
146
+ name: `[OOC 검토] ${dataSet.name}`,
147
+ activityId: activity.id,
148
+ description: `Data OOC occurred on '${dataSet.name}'`,
149
+ dueAt: new Date(collectedAt.getTime() + 24 * 60 * 60 * 1000),
150
+ input: {
151
+ dataOocId: dataOoc.id
152
+ },
153
+ assignees,
154
+ approvalLine: []
155
+ }
135
156
 
136
- pubsub.publish('notification', {
137
- notification: {
138
- domain,
139
- type: 'error',
140
- title: `Data OOC occurred on '${dataSet.name}'`,
141
- body: `Data OOC occurred on '${dataSet.name}'`,
142
- url: getRedirectSubdomainPath(context, domain.subdomain, `/data-ooc/${dataOoc.id}`),
143
- timestamp: collectedAt
157
+ await post(activityInstance, context)
158
+ } else {
159
+ console.error(
160
+ `Assignees are not set. So Data OOC Review task for ${dataOoc.name}(${dataOoc.id}) could not be posted.`
161
+ )
144
162
  }
145
- })
163
+ } else {
164
+ console.error('OOC Review Activity not installed.')
165
+ }
166
+
167
+ try {
168
+ pubsub.publish('data-ooc', {
169
+ dataOoc,
170
+ supervisoryRoleId: dataSet.supervisoryRoleId
171
+ })
172
+
173
+ pubsub.publish('notification', {
174
+ notification: {
175
+ domain,
176
+ type: 'error',
177
+ title: `[OOC] ${dataSet.name}`,
178
+ body: `Data OOC occurred on '${dataSet.name}'`,
179
+ url: getRedirectSubdomainPath(context, domain.subdomain, `/data-ooc/${dataOoc.id}`),
180
+ timestamp: collectedAt
181
+ }
182
+ })
183
+ } catch (err) {
184
+ logger.error('Notification', err)
185
+ }
146
186
  }
147
187
 
148
188
  return result
@@ -55,7 +55,7 @@ export abstract class DataUseCase {
55
55
  continue
56
56
  }
57
57
 
58
- let values: any | any[] = data[tag]
58
+ let values: any | any[] = data && data[tag]
59
59
  if (values == null) {
60
60
  continue // TODO what if in case no value ?
61
61
  }
@@ -1,2 +1,13 @@
1
+ import { ActivityInstallations } from '@things-factory/worklist'
2
+
3
+ import { ActivityOocReview } from './activity-template/activity-ooc-review'
4
+ import { ActivityOocResolve } from './activity-template/activity-ooc-resolve'
5
+ import { ActivityDataCollect } from './activity-template/activity-data-collect'
6
+
7
+ /* activity templates installation */
8
+ ;[ActivityOocReview, ActivityOocResolve, ActivityDataCollect].forEach(template => {
9
+ ActivityInstallations.installActivityTemplate(template)
10
+ })
11
+
1
12
  export * from './create-data-sample'
2
13
  export * from './data-use-case'
package/server/index.ts CHANGED
@@ -1,8 +1,7 @@
1
1
  import './routes'
2
+ // import './controllers'
2
3
 
3
4
  export * from './controllers'
4
- export * from './migrations'
5
- export * from './middlewares'
6
5
  export * from './service'
7
6
 
8
7
  export * from './service/data-spec/data-spec-manager'
package/server/routes.ts CHANGED
@@ -1,11 +1,13 @@
1
- import { getConnection } from 'typeorm'
2
-
1
+ import { Domain, getDataSource } from '@things-factory/shell'
3
2
  import { User } from '@things-factory/auth-base'
3
+ import { Activity } from '@things-factory/worklist'
4
+ import { post } from '@things-factory/worklist/dist-server/controllers/activity-instance/post'
4
5
 
5
6
  import { createDataSample } from './controllers/create-data-sample'
6
7
  import { renderJasperReport } from './controllers/jasper-report'
7
8
  import { renderShinyReport } from './controllers/shiny-report'
8
9
  import { DataSensor } from './service/data-sensor/data-sensor'
10
+ import { DataSet } from './service/data-set/data-set'
9
11
 
10
12
  process.on('bootstrap-module-global-public-route' as any, (app, globalPublicRouter) => {
11
13
  /*
@@ -23,7 +25,7 @@ process.on('bootstrap-module-global-public-route' as any, (app, globalPublicRout
23
25
  }
24
26
 
25
27
  // make new data-sample
26
- await getConnection().transaction(async tx => {
28
+ await getDataSource().transaction(async tx => {
27
29
  // find sensor through deviceId
28
30
  const sensor = await tx.getRepository(DataSensor).findOne({
29
31
  where: { deviceId },
@@ -55,6 +57,12 @@ process.on('bootstrap-module-global-public-route' as any, (app, globalPublicRout
55
57
  }
56
58
  })
57
59
 
60
+ context.state = {
61
+ ...context.state,
62
+ domain,
63
+ tx
64
+ }
65
+
58
66
  return await createDataSample(
59
67
  {
60
68
  dataSet,
@@ -63,12 +71,62 @@ process.on('bootstrap-module-global-public-route' as any, (app, globalPublicRout
63
71
  source: deviceId,
64
72
  collectedAt: new Date(timestamp)
65
73
  },
66
- { state: { domain, user, tx } }
74
+ context
67
75
  )
68
76
  })
69
77
 
70
78
  context.status = 200
71
79
  })
80
+
81
+ /* When a callback occurs from the scheduler when a scheduled dataset is on schedule, data collection task for the dataset should be issued. */
82
+ globalPublicRouter.post('/callback-schedule-for-dataset', async (context, next) => {
83
+ const { domainId, dataSetId } = context.request.body
84
+
85
+ getDataSource().transaction(async tx => {
86
+ const domain = await tx.getRepository(Domain).findOneBy({ id: domainId })
87
+ const dataSet = await tx.getRepository(DataSet).findOne({ where: { domain: { id: domainId }, id: dataSetId } })
88
+
89
+ const activity = (await tx.getRepository(Activity).findOneBy({
90
+ domain: { id: domainId },
91
+ name: 'Collect Data'
92
+ })) as Activity
93
+
94
+ if (activity) {
95
+ const { assignees } = dataSet
96
+
97
+ /* 해당 dataset에 대한 데이타 수집 태스크를 dataset assignees에게 할당한다. */
98
+ if (assignees && assignees instanceof Array && assignees.length > 0) {
99
+ const activityInstance = {
100
+ name: `[Data 수집] ${dataSet.name}`,
101
+ activityId: activity.id,
102
+ description: `Data Collect for '${dataSet.name}'`,
103
+ dueAt: new Date(Date.now() + 24 * 60 * 60 * 1000),
104
+ input: {
105
+ dataSetId: dataSet.id,
106
+ dataSetName: dataSet.name
107
+ },
108
+ assignees
109
+ }
110
+
111
+ context.state = {
112
+ ...context.state,
113
+ domain,
114
+ tx
115
+ }
116
+
117
+ await post(activityInstance, context)
118
+ } else {
119
+ console.error(
120
+ `Assignees not set. So Data Collec Activity for ${dataSet.name}($dataSet.id) could not be posted.`
121
+ )
122
+ }
123
+ } else {
124
+ console.error(`Data Collec Activity is not installed.`)
125
+ }
126
+ })
127
+
128
+ context.status = 200
129
+ })
72
130
  })
73
131
 
74
132
  process.on('bootstrap-module-global-private-route' as any, (app, globalPrivateRouter) => {
@@ -99,5 +157,4 @@ process.on('bootstrap-module-domain-private-route' as any, (app, domainPrivateRo
99
157
  let { reportType } = context.params
100
158
  context.body = `${reportType} Not Implemented.`
101
159
  })
102
-
103
160
  })
@@ -56,6 +56,16 @@ export class DataOocQuery {
56
56
  })
57
57
  }
58
58
 
59
+ @FieldResolver(type => User)
60
+ async corrector(@Root() dataOoc: DataOoc): Promise<User> {
61
+ return dataOoc.correctorId && (await getRepository(User).findOneBy({ id: dataOoc.correctorId }))
62
+ }
63
+
64
+ @FieldResolver(type => User)
65
+ async reviewer(@Root() dataOoc: DataOoc): Promise<User> {
66
+ return dataOoc.reviewerId && (await getRepository(User).findOneBy({ id: dataOoc.reviewerId }))
67
+ }
68
+
59
69
  @FieldResolver(type => Domain)
60
70
  async domain(@Root() dataOoc: DataOoc): Promise<Domain> {
61
71
  return await getRepository(Domain).findOneBy({ id: dataOoc.domainId })
@@ -63,11 +73,11 @@ export class DataOocQuery {
63
73
 
64
74
  @FieldResolver(type => User)
65
75
  async updater(@Root() dataOoc: DataOoc): Promise<User> {
66
- return await getRepository(User).findOneBy({ id: dataOoc.updaterId })
76
+ return dataOoc.updaterId && (await getRepository(User).findOneBy({ id: dataOoc.updaterId }))
67
77
  }
68
78
 
69
79
  @FieldResolver(type => User)
70
80
  async creator(@Root() dataOoc: DataOoc): Promise<User> {
71
- return await getRepository(User).findOneBy({ id: dataOoc.creatorId })
81
+ return dataOoc.creatorId && (await getRepository(User).findOneBy({ id: dataOoc.creatorId }))
72
82
  }
73
83
  }