@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.
- package/README.md +26 -11
- package/assets/images/data-collect.png +0 -0
- package/assets/images/ooc.png +0 -0
- package/assets/images/oos.png +0 -0
- package/client/{bootstrap.js → bootstrap.ts} +5 -1
- package/client/components/data-collect-activity-view.ts +100 -0
- package/client/components/{data-entry-form.js → data-entry-form.ts} +30 -33
- package/client/components/ooc-resolve-activity-view.ts +174 -0
- package/client/components/ooc-review-activity-view.ts +153 -0
- package/client/pages/data-archive/{data-archive-list-page.js → data-archive-list-page.ts} +67 -53
- package/client/pages/data-archive/{data-archive-request-popup.js → data-archive-request-popup.ts} +41 -39
- package/client/pages/data-entry/{data-entry-list-page.js → data-entry-list-page.ts} +41 -38
- package/client/pages/data-key-set/{data-key-item-list.js → data-key-item-list.ts} +31 -39
- package/client/pages/data-key-set/data-key-set-importer.ts +95 -0
- package/client/pages/data-key-set/{data-key-set-list-page.js → data-key-set-list-page.ts} +54 -35
- package/client/pages/data-ooc/{data-ooc-list-page.js → data-ooc-list-page.ts} +56 -36
- package/client/pages/data-ooc/data-ooc-view-page.ts +115 -0
- package/client/pages/data-ooc/data-ooc-view.ts +124 -0
- package/client/pages/data-report/{data-report-embed-page.js → data-report-embed-page.ts} +25 -34
- package/client/pages/data-report/{data-report-list-page.js → data-report-list-page.ts} +49 -43
- package/client/pages/data-report/{data-report-samples-page.js → data-report-samples-page.ts} +29 -43
- package/client/pages/data-report/{jasper-report-oocs-page.js → jasper-report-oocs-page.ts} +22 -34
- package/client/pages/data-report/{jasper-report-samples-crosstab-page.js → jasper-report-samples-crosstab-page.ts} +22 -34
- package/client/pages/data-report/{jasper-report-samples-page.js → jasper-report-samples-page.ts} +22 -34
- package/client/pages/data-sample/{data-sample-list-page.js → data-sample-list-page.ts} +49 -36
- package/client/pages/data-sample/{data-sample-search-page.js → data-sample-search-page.ts} +53 -39
- package/client/pages/data-sample/{data-sample-view.js → data-sample-view.ts} +29 -33
- package/client/pages/data-sensor/{data-sensor-list-page.js → data-sensor-list-page.ts} +41 -35
- package/client/pages/data-set/{data-item-list.js → data-item-list.ts} +31 -37
- package/client/pages/data-set/data-set-importer.ts +96 -0
- package/client/pages/data-set/{data-set-list-page.js → data-set-list-page.ts} +173 -40
- package/client/{route.js → route.ts} +5 -1
- package/client/tsconfig.json +11 -0
- package/config/config.development.js +30 -30
- package/config/config.production.js +31 -31
- package/dist-client/bootstrap.d.ts +5 -0
- package/dist-client/bootstrap.js +16 -0
- package/dist-client/bootstrap.js.map +1 -0
- package/dist-client/components/data-collect-activity-view.d.ts +19 -0
- package/dist-client/components/data-collect-activity-view.js +101 -0
- package/dist-client/components/data-collect-activity-view.js.map +1 -0
- package/dist-client/components/data-entry-form.d.ts +15 -0
- package/dist-client/components/data-entry-form.js +83 -0
- package/dist-client/components/data-entry-form.js.map +1 -0
- package/dist-client/components/data-ooc-activity-view.d.ts +1 -0
- package/dist-client/components/data-ooc-activity-view.js +154 -0
- package/dist-client/components/data-ooc-activity-view.js.map +1 -0
- package/dist-client/components/ooc-resolve-activity-view.d.ts +1 -0
- package/dist-client/components/ooc-resolve-activity-view.js +175 -0
- package/dist-client/components/ooc-resolve-activity-view.js.map +1 -0
- package/dist-client/components/ooc-review-activity-view.d.ts +1 -0
- package/dist-client/components/ooc-review-activity-view.js +155 -0
- package/dist-client/components/ooc-review-activity-view.js.map +1 -0
- package/dist-client/index.d.ts +1 -0
- package/dist-client/index.js +2 -0
- package/dist-client/index.js.map +1 -0
- package/dist-client/pages/data-archive/data-archive-list-page.d.ts +71 -0
- package/dist-client/pages/data-archive/data-archive-list-page.js +287 -0
- package/dist-client/pages/data-archive/data-archive-list-page.js.map +1 -0
- package/dist-client/pages/data-archive/data-archive-request-popup.d.ts +1 -0
- package/dist-client/pages/data-archive/data-archive-request-popup.js +161 -0
- package/dist-client/pages/data-archive/data-archive-request-popup.js.map +1 -0
- package/dist-client/pages/data-entry/data-entry-list-page.d.ts +36 -0
- package/dist-client/pages/data-entry/data-entry-list-page.js +383 -0
- package/dist-client/pages/data-entry/data-entry-list-page.js.map +1 -0
- package/dist-client/pages/data-key-set/data-key-item-list.d.ts +18 -0
- package/dist-client/pages/data-key-set/data-key-item-list.js +188 -0
- package/dist-client/pages/data-key-set/data-key-item-list.js.map +1 -0
- package/dist-client/pages/data-key-set/data-key-set-importer.d.ts +9 -0
- package/dist-client/pages/data-key-set/data-key-set-importer.js +100 -0
- package/dist-client/pages/data-key-set/data-key-set-importer.js.map +1 -0
- package/dist-client/pages/data-key-set/data-key-set-list-page.d.ts +60 -0
- package/dist-client/pages/data-key-set/data-key-set-list-page.js +450 -0
- package/dist-client/pages/data-key-set/data-key-set-list-page.js.map +1 -0
- package/dist-client/pages/data-ooc/data-ooc-list-page.d.ts +58 -0
- package/dist-client/pages/data-ooc/data-ooc-list-page.js +479 -0
- package/dist-client/pages/data-ooc/data-ooc-list-page.js.map +1 -0
- package/dist-client/pages/data-ooc/data-ooc-view-page.d.ts +18 -0
- package/dist-client/pages/data-ooc/data-ooc-view-page.js +114 -0
- package/dist-client/pages/data-ooc/data-ooc-view-page.js.map +1 -0
- package/dist-client/pages/data-ooc/data-ooc-view.d.ts +15 -0
- package/dist-client/pages/data-ooc/data-ooc-view.js +130 -0
- package/dist-client/pages/data-ooc/data-ooc-view.js.map +1 -0
- package/dist-client/pages/data-report/data-report-embed-page.d.ts +36 -0
- package/dist-client/pages/data-report/data-report-embed-page.js +101 -0
- package/dist-client/pages/data-report/data-report-embed-page.js.map +1 -0
- package/dist-client/pages/data-report/data-report-list-page.d.ts +36 -0
- package/dist-client/pages/data-report/data-report-list-page.js +431 -0
- package/dist-client/pages/data-report/data-report-list-page.js.map +1 -0
- package/dist-client/pages/data-report/data-report-samples-page.d.ts +32 -0
- package/dist-client/pages/data-report/data-report-samples-page.js +164 -0
- package/dist-client/pages/data-report/data-report-samples-page.js.map +1 -0
- package/dist-client/pages/data-report/jasper-report-oocs-page.d.ts +2 -0
- package/dist-client/pages/data-report/jasper-report-oocs-page.js +101 -0
- package/dist-client/pages/data-report/jasper-report-oocs-page.js.map +1 -0
- package/dist-client/pages/data-report/jasper-report-samples-crosstab-page.d.ts +2 -0
- package/dist-client/pages/data-report/jasper-report-samples-crosstab-page.js +101 -0
- package/dist-client/pages/data-report/jasper-report-samples-crosstab-page.js.map +1 -0
- package/dist-client/pages/data-report/jasper-report-samples-page.d.ts +2 -0
- package/dist-client/pages/data-report/jasper-report-samples-page.js +101 -0
- package/dist-client/pages/data-report/jasper-report-samples-page.js.map +1 -0
- package/dist-client/pages/data-sample/data-sample-list-page.d.ts +58 -0
- package/dist-client/pages/data-sample/data-sample-list-page.js +412 -0
- package/dist-client/pages/data-sample/data-sample-list-page.js.map +1 -0
- package/dist-client/pages/data-sample/data-sample-search-page.d.ts +63 -0
- package/dist-client/pages/data-sample/data-sample-search-page.js +413 -0
- package/dist-client/pages/data-sample/data-sample-search-page.js.map +1 -0
- package/dist-client/pages/data-sample/data-sample-view.d.ts +1 -0
- package/dist-client/pages/data-sample/data-sample-view.js +109 -0
- package/dist-client/pages/data-sample/data-sample-view.js.map +1 -0
- package/dist-client/pages/data-sensor/data-sensor-list-page.d.ts +49 -0
- package/dist-client/pages/data-sensor/data-sensor-list-page.js +419 -0
- package/dist-client/pages/data-sensor/data-sensor-list-page.js.map +1 -0
- package/dist-client/pages/data-set/data-item-list.d.ts +1 -0
- package/dist-client/pages/data-set/data-item-list.js +267 -0
- package/dist-client/pages/data-set/data-item-list.js.map +1 -0
- package/dist-client/pages/data-set/data-set-importer.d.ts +10 -0
- package/dist-client/pages/data-set/data-set-importer.js +103 -0
- package/dist-client/pages/data-set/data-set-importer.js.map +1 -0
- package/dist-client/pages/data-set/data-set-list-page.d.ts +73 -0
- package/dist-client/pages/data-set/data-set-list-page.js +861 -0
- package/dist-client/pages/data-set/data-set-list-page.js.map +1 -0
- package/dist-client/route.d.ts +1 -0
- package/dist-client/route.js +50 -0
- package/dist-client/route.js.map +1 -0
- package/dist-client/tsconfig.tsbuildinfo +1 -0
- package/dist-server/controllers/activity-template/activity-data-collect.js +82 -0
- package/dist-server/controllers/activity-template/activity-data-collect.js.map +1 -0
- package/dist-server/controllers/activity-template/activity-ooc-resolve.js +100 -0
- package/dist-server/controllers/activity-template/activity-ooc-resolve.js.map +1 -0
- package/dist-server/controllers/activity-template/activity-ooc-review.js +107 -0
- package/dist-server/controllers/activity-template/activity-ooc-review.js.map +1 -0
- package/dist-server/controllers/activity-template/activity-ooc.js +59 -0
- package/dist-server/controllers/activity-template/activity-ooc.js.map +1 -0
- package/dist-server/controllers/create-data-sample.js +53 -14
- package/dist-server/controllers/create-data-sample.js.map +1 -1
- package/dist-server/controllers/data-use-case.js +1 -1
- package/dist-server/controllers/data-use-case.js.map +1 -1
- package/dist-server/controllers/index.js +7 -0
- package/dist-server/controllers/index.js.map +1 -1
- package/dist-server/index.js +1 -2
- package/dist-server/index.js.map +1 -1
- package/dist-server/routes.js +47 -3
- package/dist-server/routes.js.map +1 -1
- package/dist-server/service/data-ooc/data-ooc-query.js +22 -2
- package/dist-server/service/data-ooc/data-ooc-query.js.map +1 -1
- package/dist-server/service/data-ooc/data-ooc.js +26 -0
- package/dist-server/service/data-ooc/data-ooc.js.map +1 -1
- package/dist-server/service/data-set/data-set-mutation.js +88 -0
- package/dist-server/service/data-set/data-set-mutation.js.map +1 -1
- package/dist-server/service/data-set/data-set-query.js +38 -4
- package/dist-server/service/data-set/data-set-query.js.map +1 -1
- package/dist-server/service/data-set/data-set-type.js +16 -0
- package/dist-server/service/data-set/data-set-type.js.map +1 -1
- package/dist-server/service/data-set/data-set.js +55 -3
- package/dist-server/service/data-set/data-set.js.map +1 -1
- package/dist-server/service/data-set-history/data-set-history-query.js +4 -3
- package/dist-server/service/data-set-history/data-set-history-query.js.map +1 -1
- package/dist-server/tsconfig.tsbuildinfo +1 -1
- package/helps/dataset/data-ooc.md +5 -4
- package/package.json +17 -12
- package/server/controllers/activity-template/activity-data-collect.ts +84 -0
- package/server/controllers/activity-template/activity-ooc-resolve.ts +114 -0
- package/server/controllers/activity-template/activity-ooc-review.ts +118 -0
- package/server/controllers/create-data-sample.ts +61 -21
- package/server/controllers/data-use-case.ts +1 -1
- package/server/controllers/index.ts +11 -0
- package/server/index.ts +1 -2
- package/server/routes.ts +62 -5
- package/server/service/data-ooc/data-ooc-query.ts +12 -2
- package/server/service/data-ooc/data-ooc.ts +23 -0
- package/server/service/data-set/data-set-mutation.ts +99 -0
- package/server/service/data-set/data-set-query.ts +39 -5
- package/server/service/data-set/data-set-type.ts +14 -0
- package/server/service/data-set/data-set.ts +43 -2
- package/server/service/data-set-history/data-set-history-query.ts +4 -3
- package/server/tsconfig.json +10 -0
- package/things-factory.config.js +6 -2
- package/translations/en.json +3 -1
- package/translations/ko.json +3 -1
- package/translations/ms.json +3 -0
- package/translations/zh.json +3 -0
- package/client/pages/data-key-set/data-key-set-importer.js +0 -105
- package/client/pages/data-ooc/data-ooc-view.js +0 -188
- package/client/pages/data-set/data-set-importer.js +0 -103
- package/server/middlewares/index.ts +0 -3
- package/server/migrations/index.ts +0 -9
- package/tsconfig.json +0 -9
- /package/assets/{data-report.jpg → images/data-report.jpg} +0 -0
- /package/assets/{data-samples.jpg → images/data-samples.jpg} +0 -0
- /package/assets/{diagram.jpg → images/dataset-diagram.jpg} +0 -0
- /package/assets/{glue-table-indices.png → images/glue-table-indices-for-dataset.png} +0 -0
- /package/client/{index.js → index.ts} +0 -0
@@ -1,10 +1,11 @@
|
|
1
1
|
# DataOOC
|
2
|
-
|
2
|
+
|
3
|
+
데이타 이탈 내역을 조회하고 조치합니다.
|
3
4
|
|
4
5
|
- 데이타 이탈점 상세: 데이타 이탈점 상세 팝업 화면을 띄웁니다.
|
5
|
-
|
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.
|
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": "
|
20
|
-
"build:
|
21
|
-
"
|
22
|
-
"clean": "
|
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.
|
37
|
-
"@things-factory/aws-base": "^6.0.
|
38
|
-
"@things-factory/board-service": "^6.0.
|
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/
|
41
|
-
"@things-factory/
|
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": "
|
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 {
|
5
|
-
import {
|
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:
|
125
|
+
timestamp: collectedAt
|
126
126
|
}
|
127
127
|
],
|
128
128
|
state: DataOocStatus.CREATED
|
129
129
|
})
|
130
130
|
|
131
|
-
|
132
|
-
|
133
|
-
|
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
|
-
|
137
|
-
|
138
|
-
|
139
|
-
|
140
|
-
|
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
|
@@ -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
package/server/routes.ts
CHANGED
@@ -1,11 +1,13 @@
|
|
1
|
-
import {
|
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
|
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
|
-
|
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
|
}
|