@things-factory/dataset 6.0.27 → 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/assets/images/data-collect.png +0 -0
- package/client/bootstrap.ts +4 -2
- package/client/components/data-collect-activity-view.ts +100 -0
- package/client/components/ooc-resolve-activity-view.ts +174 -0
- package/client/components/{data-ooc-activity-view.ts → ooc-review-activity-view.ts} +16 -16
- package/client/pages/data-ooc/data-ooc-list-page.ts +6 -0
- package/client/pages/data-ooc/data-ooc-view-page.ts +115 -0
- package/client/pages/data-ooc/data-ooc-view.ts +7 -61
- package/client/pages/data-set/data-set-list-page.ts +111 -4
- package/client/route.ts +4 -0
- package/config/config.development.js +30 -30
- package/config/config.production.js +31 -31
- package/dist-client/bootstrap.d.ts +3 -1
- package/dist-client/bootstrap.js +4 -2
- package/dist-client/bootstrap.js.map +1 -1
- 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/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/pages/data-ooc/data-ooc-list-page.js +6 -0
- package/dist-client/pages/data-ooc/data-ooc-list-page.js.map +1 -1
- 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 -1
- package/dist-client/pages/data-ooc/data-ooc-view.js +9 -58
- package/dist-client/pages/data-ooc/data-ooc-view.js.map +1 -1
- package/dist-client/pages/data-set/data-set-list-page.d.ts +2 -0
- package/dist-client/pages/data-set/data-set-list-page.js +106 -4
- package/dist-client/pages/data-set/data-set-list-page.js.map +1 -1
- package/dist-client/route.js +3 -0
- package/dist-client/route.js.map +1 -1
- package/dist-client/tsconfig.tsbuildinfo +1 -1
- 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/create-data-sample.js +44 -42
- 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 +4 -2
- package/dist-server/controllers/index.js.map +1 -1
- package/dist-server/middlewares/index.js +8 -0
- package/dist-server/middlewares/index.js.map +1 -0
- package/dist-server/migrations/index.js +12 -0
- package/dist-server/migrations/index.js.map +1 -0
- package/dist-server/routes.js +45 -1
- 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 +33 -0
- 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 +52 -3
- package/dist-server/service/data-set/data-set.js.map +1 -1
- package/dist-server/tsconfig.tsbuildinfo +1 -1
- package/helps/dataset/data-ooc.md +5 -4
- package/package.json +10 -8
- 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 +48 -53
- package/server/controllers/data-use-case.ts +1 -1
- package/server/controllers/index.ts +4 -2
- package/server/routes.ts +61 -2
- 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 +34 -1
- package/server/service/data-set/data-set-type.ts +14 -0
- package/server/service/data-set/data-set.ts +40 -2
- package/things-factory.config.js +4 -0
- package/translations/en.json +2 -0
- package/translations/ko.json +2 -0
- package/translations/ms.json +2 -0
- package/translations/zh.json +2 -0
- package/server/controllers/activity-template/activity-ooc.ts +0 -55
@@ -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,6 +1,6 @@
|
|
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
5
|
"browser": "dist-client/index.js",
|
6
6
|
"things-factory": true,
|
@@ -35,15 +35,17 @@
|
|
35
35
|
"@operato/shell": "^1.0.1",
|
36
36
|
"@operato/styles": "^1.0.0",
|
37
37
|
"@operato/utils": "^1.0.1",
|
38
|
-
"@things-factory/auth-base": "^6.0.
|
39
|
-
"@things-factory/aws-base": "^6.0.
|
40
|
-
"@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",
|
41
41
|
"@things-factory/env": "^6.0.7",
|
42
|
-
"@things-factory/
|
43
|
-
"@things-factory/
|
44
|
-
"@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",
|
45
47
|
"cron-parser": "^4.3.0",
|
46
48
|
"moment-timezone": "^0.5.40"
|
47
49
|
},
|
48
|
-
"gitHead": "
|
50
|
+
"gitHead": "8b4e03229444e38fc3f3487227a96837eef85099"
|
49
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'
|
@@ -12,7 +12,7 @@ import { DataSet } from '../service/data-set/data-set'
|
|
12
12
|
import { DataUseCase } from './data-use-case'
|
13
13
|
import { Activity } from '@things-factory/worklist'
|
14
14
|
|
15
|
-
import {
|
15
|
+
import { post } from '@things-factory/worklist/dist-server/controllers/activity-instance/post'
|
16
16
|
|
17
17
|
// See README.md at ## Data Samples
|
18
18
|
process.env.TZ = 'UTC'
|
@@ -53,10 +53,7 @@ const formatDate = (keys, _moment) => {
|
|
53
53
|
return keys
|
54
54
|
}
|
55
55
|
|
56
|
-
export async function createDataSample(
|
57
|
-
dataSample: NewDataSample,
|
58
|
-
context: { state: { domain: Domain; user: User; tx: EntityManager } }
|
59
|
-
): Promise<DataSample> {
|
56
|
+
export async function createDataSample(dataSample: NewDataSample, context: ResolverContext): Promise<DataSample> {
|
60
57
|
const { domain, user, tx } = context.state
|
61
58
|
|
62
59
|
const dataSet = await tx.getRepository(DataSet).findOne({
|
@@ -125,17 +122,12 @@ export async function createDataSample(
|
|
125
122
|
name: user.name
|
126
123
|
},
|
127
124
|
state: DataOocStatus.CREATED,
|
128
|
-
timestamp:
|
125
|
+
timestamp: collectedAt
|
129
126
|
}
|
130
127
|
],
|
131
128
|
state: DataOocStatus.CREATED
|
132
129
|
})
|
133
130
|
|
134
|
-
// 여기쯤에서, worklist로 TODO로 보낸다.
|
135
|
-
// 입력담당역할에게 assign한다.
|
136
|
-
// 결재라인은 시설관리자을 포함한다. 결재라인을 dataset에 추가한다.
|
137
|
-
// Dataset용 Installable Activity 를 만든다.
|
138
|
-
|
139
131
|
const activity = (await tx.getRepository(Activity).findOneBy({
|
140
132
|
domain: { id: domain.id },
|
141
133
|
name: 'OOC Review'
|
@@ -143,51 +135,54 @@ export async function createDataSample(
|
|
143
135
|
|
144
136
|
if (activity) {
|
145
137
|
const assignee =
|
146
|
-
dataSet.entryRoleId &&
|
147
|
-
(await tx.getRepository(Role)).findOneBy({ domain: { id: domain.id }, id: dataSet.entryRoleId })
|
148
|
-
|
149
|
-
const approver =
|
150
138
|
dataSet.supervisoryRoleId &&
|
151
|
-
(await tx.getRepository(Role)
|
152
|
-
|
153
|
-
const assignees = dataSet.
|
154
|
-
|
155
|
-
|
156
|
-
|
157
|
-
|
158
|
-
|
159
|
-
|
160
|
-
|
161
|
-
|
162
|
-
|
163
|
-
|
164
|
-
|
165
|
-
|
166
|
-
|
167
|
-
|
168
|
-
}
|
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
|
+
}
|
169
156
|
|
170
|
-
|
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
|
+
)
|
162
|
+
}
|
171
163
|
} else {
|
172
|
-
console.
|
164
|
+
console.error('OOC Review Activity not installed.')
|
173
165
|
}
|
174
|
-
//
|
175
166
|
|
176
|
-
|
177
|
-
|
178
|
-
|
179
|
-
|
167
|
+
try {
|
168
|
+
pubsub.publish('data-ooc', {
|
169
|
+
dataOoc,
|
170
|
+
supervisoryRoleId: dataSet.supervisoryRoleId
|
171
|
+
})
|
180
172
|
|
181
|
-
|
182
|
-
|
183
|
-
|
184
|
-
|
185
|
-
|
186
|
-
|
187
|
-
|
188
|
-
|
189
|
-
|
190
|
-
|
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
|
+
}
|
191
186
|
}
|
192
187
|
|
193
188
|
return result
|
@@ -1,9 +1,11 @@
|
|
1
1
|
import { ActivityInstallations } from '@things-factory/worklist'
|
2
2
|
|
3
|
-
import {
|
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'
|
4
6
|
|
5
7
|
/* activity templates installation */
|
6
|
-
;[
|
8
|
+
;[ActivityOocReview, ActivityOocResolve, ActivityDataCollect].forEach(template => {
|
7
9
|
ActivityInstallations.installActivityTemplate(template)
|
8
10
|
})
|
9
11
|
|
package/server/routes.ts
CHANGED
@@ -1,10 +1,13 @@
|
|
1
|
-
import { getDataSource } from '@things-factory/shell'
|
1
|
+
import { Domain, getDataSource } from '@things-factory/shell'
|
2
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'
|
3
5
|
|
4
6
|
import { createDataSample } from './controllers/create-data-sample'
|
5
7
|
import { renderJasperReport } from './controllers/jasper-report'
|
6
8
|
import { renderShinyReport } from './controllers/shiny-report'
|
7
9
|
import { DataSensor } from './service/data-sensor/data-sensor'
|
10
|
+
import { DataSet } from './service/data-set/data-set'
|
8
11
|
|
9
12
|
process.on('bootstrap-module-global-public-route' as any, (app, globalPublicRouter) => {
|
10
13
|
/*
|
@@ -54,6 +57,12 @@ process.on('bootstrap-module-global-public-route' as any, (app, globalPublicRout
|
|
54
57
|
}
|
55
58
|
})
|
56
59
|
|
60
|
+
context.state = {
|
61
|
+
...context.state,
|
62
|
+
domain,
|
63
|
+
tx
|
64
|
+
}
|
65
|
+
|
57
66
|
return await createDataSample(
|
58
67
|
{
|
59
68
|
dataSet,
|
@@ -62,12 +71,62 @@ process.on('bootstrap-module-global-public-route' as any, (app, globalPublicRout
|
|
62
71
|
source: deviceId,
|
63
72
|
collectedAt: new Date(timestamp)
|
64
73
|
},
|
65
|
-
|
74
|
+
context
|
66
75
|
)
|
67
76
|
})
|
68
77
|
|
69
78
|
context.status = 200
|
70
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
|
+
})
|
71
130
|
})
|
72
131
|
|
73
132
|
process.on('bootstrap-module-global-private-route' as any, (app, globalPrivateRouter) => {
|
@@ -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
|
}
|