@things-factory/dataset 8.0.0-alpha.9 → 8.0.0-beta.1

Sign up to get free protection for your applications and to get access to all the features.
Files changed (81) hide show
  1. package/client/activities/activity-ooc-resolve-edit.ts +1 -1
  2. package/client/activities/activity-ooc-review-edit.ts +1 -1
  3. package/client/pages/data-entry/data-entry-list-page.ts +12 -4
  4. package/client/pages/data-sensor/data-sensor-list-page.ts +1 -1
  5. package/client/pages/data-set/data-item-list.ts +1 -1
  6. package/client/pages/data-set/data-set-list-page.ts +25 -16
  7. package/dist-client/activities/activity-ooc-resolve-edit.js +1 -1
  8. package/dist-client/activities/activity-ooc-resolve-edit.js.map +1 -1
  9. package/dist-client/activities/activity-ooc-review-edit.js +1 -1
  10. package/dist-client/activities/activity-ooc-review-edit.js.map +1 -1
  11. package/dist-client/pages/data-entry/data-entry-list-page.js +11 -4
  12. package/dist-client/pages/data-entry/data-entry-list-page.js.map +1 -1
  13. package/dist-client/pages/data-sensor/data-sensor-list-page.js +1 -1
  14. package/dist-client/pages/data-sensor/data-sensor-list-page.js.map +1 -1
  15. package/dist-client/pages/data-set/data-item-list.js +1 -1
  16. package/dist-client/pages/data-set/data-item-list.js.map +1 -1
  17. package/dist-client/pages/data-set/data-set-list-page.js +25 -16
  18. package/dist-client/pages/data-set/data-set-list-page.js.map +1 -1
  19. package/dist-client/tsconfig.tsbuildinfo +1 -1
  20. package/dist-server/activities/activity-data-collect.d.ts +1 -0
  21. package/dist-server/activities/activity-data-collect.js +1 -0
  22. package/dist-server/activities/activity-data-collect.js.map +1 -1
  23. package/dist-server/activities/activity-data-review.d.ts +1 -0
  24. package/dist-server/activities/activity-data-review.js +1 -0
  25. package/dist-server/activities/activity-data-review.js.map +1 -1
  26. package/dist-server/activities/activity-ooc-resolve.d.ts +1 -0
  27. package/dist-server/activities/activity-ooc-resolve.js +2 -1
  28. package/dist-server/activities/activity-ooc-resolve.js.map +1 -1
  29. package/dist-server/activities/activity-ooc-review.d.ts +1 -0
  30. package/dist-server/activities/activity-ooc-review.js +14 -5
  31. package/dist-server/activities/activity-ooc-review.js.map +1 -1
  32. package/dist-server/controllers/create-data-sample.js +18 -12
  33. package/dist-server/controllers/create-data-sample.js.map +1 -1
  34. package/dist-server/controllers/issue-data-collection-task.js +6 -6
  35. package/dist-server/controllers/issue-data-collection-task.js.map +1 -1
  36. package/dist-server/service/data-ooc/data-ooc-query.js +1 -1
  37. package/dist-server/service/data-ooc/data-ooc-query.js.map +1 -1
  38. package/dist-server/service/data-ooc/data-ooc.js +12 -3
  39. package/dist-server/service/data-ooc/data-ooc.js.map +1 -1
  40. package/dist-server/service/data-sample/data-sample-query.js +1 -1
  41. package/dist-server/service/data-sample/data-sample-query.js.map +1 -1
  42. package/dist-server/service/data-sample/data-sample.js +4 -1
  43. package/dist-server/service/data-sample/data-sample.js.map +1 -1
  44. package/dist-server/service/data-set/data-set-mutation.js +7 -36
  45. package/dist-server/service/data-set/data-set-mutation.js.map +1 -1
  46. package/dist-server/service/data-set/data-set-query.d.ts +1 -0
  47. package/dist-server/service/data-set/data-set-query.js +16 -3
  48. package/dist-server/service/data-set/data-set-query.js.map +1 -1
  49. package/dist-server/service/data-set/data-set-type.d.ts +4 -3
  50. package/dist-server/service/data-set/data-set-type.js +20 -6
  51. package/dist-server/service/data-set/data-set-type.js.map +1 -1
  52. package/dist-server/service/data-set/data-set.d.ts +3 -0
  53. package/dist-server/service/data-set/data-set.js +20 -0
  54. package/dist-server/service/data-set/data-set.js.map +1 -1
  55. package/dist-server/service/data-set-history/data-set-history.js +7 -2
  56. package/dist-server/service/data-set-history/data-set-history.js.map +1 -1
  57. package/dist-server/service/data-summary/data-summary-query.js +1 -1
  58. package/dist-server/service/data-summary/data-summary-query.js.map +1 -1
  59. package/dist-server/tsconfig.tsbuildinfo +1 -1
  60. package/package.json +26 -26
  61. package/server/activities/activity-data-collect.ts +12 -2
  62. package/server/activities/activity-data-review.ts +6 -1
  63. package/server/activities/activity-ooc-resolve.ts +2 -1
  64. package/server/activities/activity-ooc-review.ts +30 -8
  65. package/server/controllers/create-data-sample.ts +18 -12
  66. package/server/controllers/issue-data-collection-task.ts +6 -7
  67. package/server/service/data-ooc/data-ooc-query.ts +1 -1
  68. package/server/service/data-ooc/data-ooc.ts +12 -3
  69. package/server/service/data-sample/data-sample-query.ts +1 -1
  70. package/server/service/data-sample/data-sample.ts +4 -1
  71. package/server/service/data-set/data-set-mutation.ts +3 -40
  72. package/server/service/data-set/data-set-query.ts +13 -3
  73. package/server/service/data-set/data-set-type.ts +16 -5
  74. package/server/service/data-set/data-set.ts +17 -0
  75. package/server/service/data-set-history/data-set-history.ts +8 -2
  76. package/server/service/data-summary/data-summary-query.ts +1 -1
  77. package/translations/en.json +2 -0
  78. package/translations/ja.json +2 -0
  79. package/translations/ko.json +2 -0
  80. package/translations/ms.json +2 -0
  81. package/translations/zh.json +2 -0
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@things-factory/dataset",
3
- "version": "8.0.0-alpha.9",
3
+ "version": "8.0.0-beta.1",
4
4
  "main": "dist-server/index.js",
5
5
  "browser": "dist-client/index.js",
6
6
  "things-factory": true,
@@ -27,34 +27,34 @@
27
27
  "migration:create": "node ../../node_modules/typeorm/cli.js migration:create ./server/migrations/migration"
28
28
  },
29
29
  "dependencies": {
30
- "@operato/app": "^8.0.0-alpha",
31
- "@operato/data-grist": "^8.0.0-alpha",
32
- "@operato/dataset": "^8.0.0-alpha",
33
- "@operato/ghost-print": "^8.0.0-alpha",
34
- "@operato/graphql": "^8.0.0-alpha",
35
- "@operato/grist-editor": "^8.0.0-alpha",
36
- "@operato/i18n": "^8.0.0-alpha",
37
- "@operato/layout": "^8.0.0-alpha",
38
- "@operato/moment-timezone-es": "^8.0.0-alpha",
39
- "@operato/p13n": "^8.0.0-alpha",
40
- "@operato/shell": "^8.0.0-alpha",
41
- "@operato/styles": "^8.0.0-alpha",
42
- "@operato/utils": "^8.0.0-alpha",
43
- "@things-factory/auth-base": "^8.0.0-alpha.8",
44
- "@things-factory/aws-base": "^8.0.0-alpha.8",
45
- "@things-factory/board-service": "^8.0.0-alpha.8",
46
- "@things-factory/env": "^8.0.0-alpha.8",
47
- "@things-factory/integration-base": "^8.0.0-alpha.8",
48
- "@things-factory/organization": "^8.0.0-alpha.8",
49
- "@things-factory/personalization": "^8.0.0-alpha.8",
50
- "@things-factory/scheduler-client": "^8.0.0-alpha.8",
51
- "@things-factory/shell": "^8.0.0-alpha.8",
52
- "@things-factory/work-shift": "^8.0.0-alpha.8",
53
- "@things-factory/worklist": "^8.0.0-alpha.8",
30
+ "@operato/app": "^8.0.0-beta",
31
+ "@operato/data-grist": "^8.0.0-beta",
32
+ "@operato/dataset": "^8.0.0-beta",
33
+ "@operato/ghost-print": "^8.0.0-beta",
34
+ "@operato/graphql": "^8.0.0-beta",
35
+ "@operato/grist-editor": "^8.0.0-beta",
36
+ "@operato/i18n": "^8.0.0-beta",
37
+ "@operato/layout": "^8.0.0-beta",
38
+ "@operato/moment-timezone-es": "^8.0.0-beta",
39
+ "@operato/p13n": "^8.0.0-beta",
40
+ "@operato/shell": "^8.0.0-beta",
41
+ "@operato/styles": "^8.0.0-beta",
42
+ "@operato/utils": "^8.0.0-beta",
43
+ "@things-factory/auth-base": "^8.0.0-beta.1",
44
+ "@things-factory/aws-base": "^8.0.0-beta.1",
45
+ "@things-factory/board-service": "^8.0.0-beta.1",
46
+ "@things-factory/env": "^8.0.0-beta.1",
47
+ "@things-factory/integration-base": "^8.0.0-beta.1",
48
+ "@things-factory/organization": "^8.0.0-beta.1",
49
+ "@things-factory/personalization": "^8.0.0-beta.1",
50
+ "@things-factory/scheduler-client": "^8.0.0-beta.1",
51
+ "@things-factory/shell": "^8.0.0-beta.1",
52
+ "@things-factory/work-shift": "^8.0.0-beta.1",
53
+ "@things-factory/worklist": "^8.0.0-beta.1",
54
54
  "cron-parser": "^4.3.0",
55
55
  "moment-timezone": "^0.5.45",
56
56
  "simple-statistics": "^7.8.3",
57
57
  "statistics": "^3.3.0"
58
58
  },
59
- "gitHead": "4addaa10e75135d3ef6b6340102f7664743a5ac2"
59
+ "gitHead": "36c494e587640c1490318ef7b95adab02606e0c2"
60
60
  }
@@ -1,11 +1,20 @@
1
1
  import { In } from 'typeorm'
2
2
 
3
3
  import { User } from '@things-factory/auth-base'
4
- import { Activity, ActivityInstance, ActivityInstanceStatus, UpdateActivityInstanceStateAddendum } from '@things-factory/worklist'
4
+ import {
5
+ Activity,
6
+ ActivityInstance,
7
+ ActivityInstanceStatus,
8
+ UpdateActivityInstanceStateAddendum
9
+ } from '@things-factory/worklist'
5
10
  import { NewDataSample } from 'service/data-sample/data-sample-type'
6
11
  import { createDataSample } from '../controllers/create-data-sample'
7
12
 
8
- async function callback(activityInstance: ActivityInstance, addendum: UpdateActivityInstanceStateAddendum, context: ResolverContext) {
13
+ async function callback(
14
+ activityInstance: ActivityInstance,
15
+ addendum: UpdateActivityInstanceStateAddendum,
16
+ context: ResolverContext
17
+ ) {
9
18
  const { domain, tx } = context.state
10
19
  const { input, output, state } = activityInstance
11
20
 
@@ -86,5 +95,6 @@ export const ActivityDataCollect = {
86
95
  reportType: 'custom-element',
87
96
  reportSource: 'activity-data-collect-view',
88
97
  thumbnail: '/assets/images/data-collect.png',
98
+ standardTime: 24 * 60 * 60, // seconds
89
99
  callback /* Called when there is a change in the lifecycle of a task (activity-instance). */
90
100
  }
@@ -3,7 +3,11 @@ import { ActivityInstance, ActivityInstanceStatus, UpdateActivityInstanceStateAd
3
3
  import { DataOocStatus } from '../service/data-ooc/data-ooc'
4
4
  import { DataSample } from '../service/data-sample/data-sample'
5
5
 
6
- async function callback(activityInstance: ActivityInstance, addendum: UpdateActivityInstanceStateAddendum, context: ResolverContext) {
6
+ async function callback(
7
+ activityInstance: ActivityInstance,
8
+ addendum: UpdateActivityInstanceStateAddendum,
9
+ context: ResolverContext
10
+ ) {
7
11
  const { domain, tx, user } = context.state
8
12
  const { input, output, state } = activityInstance
9
13
 
@@ -73,5 +77,6 @@ export const ActivityDataReview = {
73
77
  reportType: 'custom-element',
74
78
  reportSource: 'activity-data-review-view',
75
79
  thumbnail: '/assets/images/data-collect.png',
80
+ standardTime: 24 * 60 * 60, // seconds
76
81
  callback /* Called when there is a change in the lifecycle of a task (activity-instance). */
77
82
  }
@@ -30,7 +30,7 @@ async function callback(
30
30
  const corrector = activityThreads[0]?.assignee
31
31
 
32
32
  const { dataOocId } = input
33
- const correctiveAction = output.action
33
+ const correctiveAction = output?.action
34
34
 
35
35
  var dataOoc = await tx.getRepository(DataOoc).findOne({
36
36
  where: {
@@ -118,5 +118,6 @@ export const ActivityOocResolve = {
118
118
  reportType: 'custom-element',
119
119
  reportSource: 'data-ooc-report-page',
120
120
  thumbnail: '/assets/images/ooc.png',
121
+ standardTime: 24 * 60 * 60, // seconds
121
122
  callback /* Called when there is a change in the lifecycle of a task (activity-instance). */
122
123
  }
@@ -1,10 +1,20 @@
1
1
  import { In } from 'typeorm'
2
- import { Activity, ActivityInstance, ActivityInstanceStatus, UpdateActivityInstanceStateAddendum } from '@things-factory/worklist'
2
+ import {
3
+ Activity,
4
+ ActivityInstance,
5
+ ActivityInstanceStatus,
6
+ UpdateActivityInstanceStateAddendum
7
+ } from '@things-factory/worklist'
3
8
  import { issue } from '@things-factory/worklist/dist-server/controllers/activity-instance/issue'
9
+ import { Role } from '@things-factory/auth-base'
4
10
 
5
11
  import { DataOoc, DataOocStatus } from '../service/data-ooc/data-ooc'
6
12
 
7
- async function callback(activityInstance: ActivityInstance, addendum: UpdateActivityInstanceStateAddendum, context: ResolverContext) {
13
+ async function callback(
14
+ activityInstance: ActivityInstance,
15
+ addendum: UpdateActivityInstanceStateAddendum,
16
+ context: ResolverContext
17
+ ) {
8
18
  const { domain, user, tx } = context.state
9
19
  const { input, output, state, terminatedAt } = activityInstance
10
20
  const { causedBy } = addendum || {}
@@ -28,7 +38,7 @@ async function callback(activityInstance: ActivityInstance, addendum: UpdateActi
28
38
  })
29
39
 
30
40
  const dataSet = dataOoc.dataSet
31
- const { assignees, outlierApprovalLine } = dataSet
41
+ const { resolverRoleId, outlierApprovalLine } = dataSet
32
42
 
33
43
  /* dataOoc Review 결과를 dataOoc 엔티티에 반영한다. */
34
44
  dataOoc = await tx.getRepository(DataOoc).save({
@@ -39,25 +49,36 @@ async function callback(activityInstance: ActivityInstance, addendum: UpdateActi
39
49
  state: DataOocStatus.REVIEWED
40
50
  })
41
51
 
42
- /* 해당 dataset의 작업 담당자(assignees)에게 OOC 해결을 위한 태스크를 지시한다. */
43
- if (assignees && assignees instanceof Array && assignees.length > 0) {
52
+ const assigneeRole =
53
+ resolverRoleId &&
54
+ (await tx.getRepository(Role).findOneBy({
55
+ domain: { id: In([domain.id, domain.parentId].filter(Boolean)) },
56
+ id: resolverRoleId
57
+ }))
58
+
59
+ /* 해당 dataset의 작업 담당자(resolverRole)에게 OOC 해결을 위한 태스크를 지시한다. */
60
+ if (assigneeRole) {
44
61
  const activityInstance = {
45
62
  name: `[OOC 조치] ${dataSet.name}`,
46
63
  description: dataSet.description,
47
64
  activityId: activity.id,
48
- dueAt: new Date(terminatedAt.getTime() + 24 * 60 * 60 * 1000),
65
+ dueAt: new Date(terminatedAt.getTime() + (activity.standardTime || 24 * 60 * 60) * 1000),
49
66
  input: {
50
67
  dataOocId,
51
68
  instruction: correctiveInstruction
52
69
  },
53
- assignees,
70
+ assigneeRole,
71
+ threadsMin: 1,
72
+ threadsMax: 1,
54
73
  approvalLine: outlierApprovalLine
55
74
  }
56
75
 
57
76
  dataOoc.resolveActivityInstance = await issue(activityInstance, context)
58
77
  await tx.getRepository(DataOoc).save(dataOoc)
59
78
  } else {
60
- console.error(`Assignees are not set. So, Data OOC Resolve task for ${dataOoc.name}(${dataOoc.id}) could not be issued.`)
79
+ console.error(
80
+ `Assignees are not set. So, Data OOC Resolve task for ${dataOoc.name}(${dataOoc.id}) could not be issued.`
81
+ )
61
82
  }
62
83
  } else {
63
84
  console.error('OOC Resolve Activity not installed.')
@@ -118,5 +139,6 @@ export const ActivityOocReview = {
118
139
  reportType: 'custom-element',
119
140
  reportSource: 'data-ooc-report-page',
120
141
  thumbnail: '/assets/images/ooc.png',
142
+ standardTime: 24 * 60 * 60, // seconds
121
143
  callback /* Called when there is a change in the lifecycle of a task (activity-instance). */
122
144
  }
@@ -260,26 +260,30 @@ export async function createDataSample(newDataSample: NewDataSample, context: Re
260
260
  })) as Activity
261
261
 
262
262
  if (activity) {
263
- const assignee =
263
+ const assigneeRole =
264
264
  dataSet.supervisoryRoleId &&
265
265
  (await tx.getRepository(Role).findOneBy({
266
266
  domain: { id: In([domain.id, domain.parentId].filter(Boolean)) },
267
267
  id: dataSet.supervisoryRoleId
268
268
  }))
269
269
 
270
- const assignees = dataSet.supervisoryRoleId ? [{ type: 'Role', value: dataSet.supervisoryRoleId, assignee }] : []
270
+ // const assignees = dataSet.supervisoryRoleId
271
+ // ? [{ type: 'Role', value: dataSet.supervisoryRoleId, assigneeRole }]
272
+ // : []
271
273
 
272
274
  /* 해당 dataset의 supervisor로 하여금, OOC를 리뷰하고 instruction을 작성해서, OOC 해결을 위한 태스크를 dataset assignees에게 지시하도록 한다. */
273
- if (assignees && assignees instanceof Array && assignees.length > 0) {
275
+ if (assigneeRole) {
274
276
  const activityInstance = {
275
277
  name: `[OOC 검토] ${dataSet.name}`,
276
278
  description: dataSet.description,
277
279
  activityId: activity.id,
278
- dueAt: new Date(collectedAt.getTime() + 24 * 60 * 60 * 1000),
280
+ dueAt: new Date(collectedAt.getTime() + (activity.standardTime || 24 * 60 * 60) * 1000),
279
281
  input: {
280
282
  dataOocId: dataOoc.id
281
283
  },
282
- assignees,
284
+ assigneeRole,
285
+ threadsMin: 1,
286
+ threadsMax: 1,
283
287
  approvalLine: []
284
288
  }
285
289
 
@@ -362,29 +366,31 @@ export async function createDataSample(newDataSample: NewDataSample, context: Re
362
366
  })) as Activity
363
367
 
364
368
  if (activity) {
365
- const assignee =
369
+ const assigneeRole =
366
370
  dataSet.supervisoryRoleId &&
367
371
  (await tx.getRepository(Role).findOneBy({
368
372
  domain: { id: In([domain.id, domain.parentId].filter(Boolean)) },
369
373
  id: dataSet.supervisoryRoleId
370
374
  }))
371
375
 
372
- const assignees = dataSet.supervisoryRoleId
373
- ? [{ type: 'Role', value: dataSet.supervisoryRoleId, assignee }]
374
- : []
376
+ // const assignees = dataSet.supervisoryRoleId
377
+ // ? [{ type: 'Role', value: dataSet.supervisoryRoleId, assigneeRole }]
378
+ // : []
375
379
 
376
380
  /* 해당 dataset의 supervisor로 하여금, data를 리뷰하고 instruction을 작성해서, approvalLine을 이용해서 승인을 한다. */
377
- if (assignees && assignees instanceof Array && assignees.length > 0) {
381
+ if (assigneeRole) {
378
382
  dataSample.dataItems = dataItems
379
383
  const activityInstance = {
380
384
  name: `[Data 검토] ${dataSet.name}`,
381
385
  description: dataSet.description,
382
386
  activityId: activity.id,
383
- dueAt: new Date(collectedAt.getTime() + 24 * 60 * 60 * 1000),
387
+ dueAt: new Date(collectedAt.getTime() + (activity.standardTime || 24 * 60 * 60) * 1000),
384
388
  input: {
385
389
  dataSampleId: dataSample.id
386
390
  },
387
- assignees,
391
+ assigneeRole,
392
+ threadsMin: 1,
393
+ threadsMax: 1,
388
394
  approvalLine: dataSet.reviewApprovalLine
389
395
  }
390
396
 
@@ -4,7 +4,6 @@ import { Domain, getDataSource } from '@things-factory/shell'
4
4
  import { Activity, ActivityInstance, issue } from '@things-factory/worklist'
5
5
 
6
6
  import { DataSet } from '../service/data-set/data-set'
7
- import { OrgMemberTargetType } from '@things-factory/organization'
8
7
 
9
8
  export async function issueDataCollectionTask(
10
9
  domainId: string,
@@ -34,22 +33,22 @@ export async function issueDataCollectionTask(
34
33
  })) as Activity
35
34
 
36
35
  if (activity) {
37
- const { entryRole } = dataSet
38
-
39
- const assignees = entryRole ? [{ type: OrgMemberTargetType.Role, value: entryRole.id, assignee: entryRole }] : []
36
+ const { entryRole, timeLimit } = dataSet
40
37
 
41
38
  /* 해당 dataset에 대한 데이타 수집 태스크를 dataset entryRole에게 할당한다. */
42
- if (assignees && assignees instanceof Array && assignees.length > 0) {
39
+ if (entryRole) {
43
40
  const activityInstance = {
44
41
  name: `[Data 수집] ${dataSet.name}`,
45
42
  description: dataSet.description,
46
43
  activityId: activity.id,
47
- dueAt: new Date(Date.now() + 24 * 60 * 60 * 1000),
44
+ dueAt: new Date(Date.now() + (timeLimit || activity.standardTime || 24 * 60 * 60) * 1000),
48
45
  input: {
49
46
  dataSetId: dataSet.id,
50
47
  dataSetName: dataSet.name
51
48
  },
52
- assignees
49
+ assigneeRole: entryRole,
50
+ threadsMin: 1,
51
+ threadsMax: 1
53
52
  }
54
53
 
55
54
  context.state = {
@@ -50,7 +50,7 @@ export class DataOocQuery {
50
50
  version: dataOoc.dataSetVersion
51
51
  }
52
52
  }))
53
- return dataSetHistory?.dataItems || []
53
+ return dataSetHistory?.dataItems.filter(item => item.active) || []
54
54
  }
55
55
 
56
56
  @FieldResolver(type => DataSample)
@@ -88,7 +88,10 @@ export class DataOoc {
88
88
  ? 'longtext'
89
89
  : DATABASE_TYPE == 'oracle'
90
90
  ? 'clob'
91
- : 'varchar'
91
+ : DATABASE_TYPE == 'mssql'
92
+ ? 'nvarchar'
93
+ : 'varchar',
94
+ length: DATABASE_TYPE == 'mssql' ? 'MAX' : undefined
92
95
  })
93
96
  @Field({ nullable: true })
94
97
  correctiveInstruction?: string
@@ -100,7 +103,10 @@ export class DataOoc {
100
103
  ? 'longtext'
101
104
  : DATABASE_TYPE == 'oracle'
102
105
  ? 'clob'
103
- : 'varchar'
106
+ : DATABASE_TYPE == 'mssql'
107
+ ? 'nvarchar'
108
+ : 'varchar',
109
+ length: DATABASE_TYPE == 'mssql' ? 'MAX' : undefined
104
110
  })
105
111
  @Field({ nullable: true })
106
112
  correctiveAction?: string
@@ -159,7 +165,10 @@ export class DataOoc {
159
165
  ? 'longtext'
160
166
  : DATABASE_TYPE == 'oracle'
161
167
  ? 'clob'
162
- : 'varchar'
168
+ : DATABASE_TYPE == 'mssql'
169
+ ? 'nvarchar'
170
+ : 'varchar',
171
+ length: DATABASE_TYPE == 'mssql' ? 'MAX' : undefined
163
172
  })
164
173
  @Field({ nullable: true })
165
174
  rawData?: string
@@ -175,7 +175,7 @@ export class DataSampleQuery {
175
175
  }
176
176
  }))
177
177
 
178
- return dataSetHistory?.dataItems || []
178
+ return dataSetHistory?.dataItems.filter(item => item.active) || []
179
179
  }
180
180
 
181
181
  @FieldResolver(type => DataSet)
@@ -104,7 +104,10 @@ export class DataSample {
104
104
  ? 'longtext'
105
105
  : DATABASE_TYPE == 'oracle'
106
106
  ? 'clob'
107
- : 'varchar',
107
+ : DATABASE_TYPE == 'mssql'
108
+ ? 'nvarchar'
109
+ : 'varchar',
110
+ length: DATABASE_TYPE == 'mssql' ? 'MAX' : undefined,
108
111
  transformer: json5Transformer
109
112
  })
110
113
  @Field({ nullable: true })
@@ -6,7 +6,6 @@ import { User } from '@things-factory/auth-base'
6
6
  import { createAttachment, deleteAttachmentsByRef } from '@things-factory/attachment-base'
7
7
  import { ApprovalLineItem, OrgMemberTargetType } from '@things-factory/organization'
8
8
  import { Application, CallbackBase, registerSchedule, unregisterSchedule } from '@things-factory/scheduler-client'
9
- import { Activity, AssigneeItem, issue } from '@things-factory/worklist'
10
9
 
11
10
  import { getDataFinalizeCrontabSchedule } from '../../controllers/finalize-data-collection'
12
11
  import { DataSet } from './data-set'
@@ -81,39 +80,6 @@ function getOutlierApprovalLineValue(patch: NewDataSet | DataSetPatch): Approval
81
80
  })
82
81
  }
83
82
 
84
- function getAssigneesValue(patch: NewDataSet | DataSetPatch): AssigneeItem[] {
85
- const { assignees } = patch
86
-
87
- if (!('assignees' in patch)) {
88
- /* assignees이 언급되지 않았다면, 업데이트하지 않는다. */
89
- return
90
- }
91
-
92
- if (!assignees || !(assignees instanceof Array)) {
93
- /* assignees의 값이 없거나 배열이 아니라면, 클리어시킨다. */
94
- return null
95
- }
96
-
97
- return assignees
98
- .map(m => {
99
- return {
100
- type: m.type,
101
- assignee: m.assignee
102
- }
103
- })
104
- .filter(m => m.type)
105
- .filter(m => {
106
- switch (m.type) {
107
- case OrgMemberTargetType.Employee:
108
- case OrgMemberTargetType.Department:
109
- case OrgMemberTargetType.Role:
110
- return !!m.assignee?.id
111
- default:
112
- return true
113
- }
114
- })
115
- }
116
-
117
83
  @Resolver(DataSet)
118
84
  export class DataSetMutation {
119
85
  @Directive('@privilege(category: "data-set", privilege: "mutation", domainOwnerGranted: true)')
@@ -126,7 +92,6 @@ export class DataSetMutation {
126
92
  const result = await dataSetRepo.save({
127
93
  ...dataSet,
128
94
  approvalLine: getApprovalLineValue(dataSet),
129
- assignees: getAssigneesValue(dataSet),
130
95
  outlierApprovalLineValue: getOutlierApprovalLineValue(dataSet),
131
96
  version: 1,
132
97
  domain,
@@ -161,7 +126,6 @@ export class DataSetMutation {
161
126
  ...patch,
162
127
  approvalLine: getApprovalLineValue(patch),
163
128
  outlierApprovalLineValue: getOutlierApprovalLineValue(patch),
164
- assignees: getAssigneesValue(patch),
165
129
  updater: user
166
130
  })
167
131
 
@@ -192,7 +156,6 @@ export class DataSetMutation {
192
156
  const result = await dataSetRepo.save({
193
157
  ...newRecord,
194
158
  approvalLine: getApprovalLineValue(newRecord),
195
- assignees: getAssigneesValue(newRecord),
196
159
  outlierApprovalLineValue: getOutlierApprovalLineValue(newRecord),
197
160
  domain,
198
161
  creator: user,
@@ -223,7 +186,6 @@ export class DataSetMutation {
223
186
  ...updateRecord,
224
187
  approvalLine: getApprovalLineValue(updateRecord),
225
188
  outlierApprovalLineValue: getOutlierApprovalLineValue(updateRecord),
226
- assignees: getAssigneesValue(updateRecord),
227
189
  updater: user
228
190
  })
229
191
 
@@ -281,14 +243,15 @@ export class DataSetMutation {
281
243
  }
282
244
  })
283
245
 
284
- const { supervisoryRoleId } = dataSet
246
+ const { supervisoryRoleId, entryRoleId } = dataSet
247
+ const allowedRoles = [supervisoryRoleId, entryRoleId].filter(Boolean)
285
248
 
286
249
  const me = await getRepository(User, tx).findOne({
287
250
  where: { id: user.id },
288
251
  relations: ['roles']
289
252
  })
290
253
 
291
- if (!me.roles.find(role => role.id == supervisoryRoleId)) {
254
+ if (!me.roles.find(role => allowedRoles.includes(role.id))) {
292
255
  throw new Error(`You don't have permission to issue data collection task for this dataset.`)
293
256
  }
294
257
 
@@ -92,9 +92,7 @@ export class DataSetQuery {
92
92
  .andWhere('dataset.active = :active', { active: true })
93
93
  .andWhere(
94
94
  new Brackets(qb => {
95
- qb.where('dataset.supervisoryRole IN (:...roles)', { roles }).orWhere('dataset.entryRole IN (:...roles)', {
96
- roles
97
- })
95
+ qb.where('dataset.supervisoryRole IN (:...roles)').orWhere('dataset.entryRole IN (:...roles)')
98
96
  })
99
97
  )
100
98
  .setParameter('roles', roles)
@@ -186,6 +184,18 @@ export class DataSetQuery {
186
184
  )
187
185
  }
188
186
 
187
+ // 데이터셋의 resolver 역할을 조회
188
+ @FieldResolver(type => Role, { description: 'Retrieves the resolver role for the dataset' })
189
+ async resolverRole(@Root() dataSet: DataSet): Promise<Role> {
190
+ return (
191
+ dataSet.resolverRole ||
192
+ (dataSet.resolverRoleId &&
193
+ (await getRepository(Role).findOneBy({
194
+ id: dataSet.resolverRoleId
195
+ })))
196
+ )
197
+ }
198
+
189
199
  @FieldResolver(type => [AssigneeItem], { description: 'Retrieves the assignee items for the dataset' })
190
200
  async assignees(@Root() dataSet: DataSet, @Ctx() context: ResolverContext): Promise<AssigneeItem[]> {
191
201
  const { domain, user } = context.state
@@ -4,7 +4,6 @@ import { Field, ID, InputType, Int, ObjectType } from 'type-graphql'
4
4
 
5
5
  import { ApprovalLineItem } from '@things-factory/organization'
6
6
  import { ObjectRef, ScalarObject } from '@things-factory/shell'
7
- import { AssigneeItem } from '@things-factory/worklist'
8
7
 
9
8
  import { DataItemPatch } from './data-item-type'
10
9
  import { DataSet, DataSetEntryType, DataSetMonitorType, DataSetReportType, DataSetSummaryPeriodType } from './data-set'
@@ -29,8 +28,8 @@ export class NewDataSet {
29
28
  @Field(type => ObjectRef, { nullable: true })
30
29
  supervisoryRole?: ObjectRef
31
30
 
32
- @Field(type => ScalarObject, { nullable: true })
33
- assignees?: AssigneeItem[]
31
+ @Field(type => ObjectRef, { nullable: true })
32
+ resolverRole?: ObjectRef
34
33
 
35
34
  @Field(type => ScalarObject, { nullable: true })
36
35
  reviewApprovalLine?: ApprovalLineItem[]
@@ -91,6 +90,12 @@ export class NewDataSet {
91
90
 
92
91
  @Field({ nullable: true })
93
92
  summaryPeriod?: DataSetSummaryPeriodType
93
+
94
+ @Field({
95
+ nullable: true,
96
+ description: 'The maximum allowed time limit (in seconds) for completing the data entry operation'
97
+ })
98
+ timeLimit?: number
94
99
  }
95
100
 
96
101
  @InputType()
@@ -116,8 +121,8 @@ export class DataSetPatch {
116
121
  @Field(type => ObjectRef, { nullable: true })
117
122
  entryRole?: ObjectRef
118
123
 
119
- @Field(type => ScalarObject, { nullable: true })
120
- assignees?: AssigneeItem[]
124
+ @Field(type => ObjectRef, { nullable: true })
125
+ resolverRole?: ObjectRef
121
126
 
122
127
  @Field(type => ScalarObject, { nullable: true })
123
128
  reviewApprovalLine?: ApprovalLineItem[]
@@ -179,6 +184,12 @@ export class DataSetPatch {
179
184
  @Field({ nullable: true })
180
185
  summaryPeriod?: DataSetSummaryPeriodType
181
186
 
187
+ @Field({
188
+ nullable: true,
189
+ description: 'The maximum allowed time limit (in seconds) for completing the data entry operation'
190
+ })
191
+ timeLimit?: number
192
+
182
193
  @Field()
183
194
  cuFlag: string
184
195
  }
@@ -150,6 +150,16 @@ export class DataSet {
150
150
  @RelationId((dataSet: DataSet) => dataSet.supervisoryRole)
151
151
  supervisoryRoleId?: string
152
152
 
153
+ @ManyToOne(type => Role, { nullable: true })
154
+ @Field(type => Role, {
155
+ nullable: true,
156
+ description: 'The final authority on resolving outlier related to that dataset.'
157
+ })
158
+ resolverRole?: Role
159
+
160
+ @RelationId((dataSet: DataSet) => dataSet.resolverRole)
161
+ resolverRoleId?: string
162
+
153
163
  @Column('simple-json', { nullable: true })
154
164
  @Field(type => [AssigneeItem], { nullable: true, description: 'Who to contact for OOC issues' })
155
165
  assignees?: AssigneeItem[]
@@ -285,6 +295,13 @@ export class DataSet {
285
295
  @Field({ nullable: true, description: 'The summary schedule ID of the dataset' })
286
296
  summaryScheduleId?: string
287
297
 
298
+ @Column({ nullable: true })
299
+ @Field({
300
+ nullable: true,
301
+ description: 'The maximum allowed time limit (in seconds) for completing the data entry operation'
302
+ })
303
+ timeLimit?: number
304
+
288
305
  @CreateDateColumn()
289
306
  @Field({ nullable: true, description: 'The date and time the dataset was created' })
290
307
  createdAt?: Date
@@ -204,8 +204,14 @@ export class DataSetHistory implements HistoryEntityInterface<DataSet> {
204
204
  ? 'enum'
205
205
  : DATABASE_TYPE == 'oracle'
206
206
  ? 'varchar2'
207
- : 'smallint',
208
- enum: HistoryActionType
207
+ : DATABASE_TYPE == 'mssql'
208
+ ? 'nvarchar'
209
+ : 'varchar',
210
+ enum:
211
+ DATABASE_TYPE == 'postgres' || DATABASE_TYPE == 'mysql' || DATABASE_TYPE == 'mariadb'
212
+ ? HistoryActionType
213
+ : undefined,
214
+ length: DATABASE_TYPE == 'postgres' || DATABASE_TYPE == 'mysql' || DATABASE_TYPE == 'mariadb' ? undefined : 10
209
215
  })
210
216
  public action!: HistoryActionType
211
217
  }
@@ -154,7 +154,7 @@ export class DataSummaryQuery {
154
154
  async dataItems(@Root() dataSummary: DataSummary): Promise<DataItem[]> {
155
155
  const dataSet = dataSummary.dataSetId && (await getRepository(DataSet).findOneBy({ id: dataSummary.dataSetId }))
156
156
 
157
- return dataSet?.dataItems || []
157
+ return dataSet?.dataItems.filter(item => item.active) || []
158
158
  }
159
159
 
160
160
  @FieldResolver(type => DataSet)
@@ -70,6 +70,7 @@
70
70
  "field.report-view": "report view",
71
71
  "field.request-params": "request parameters",
72
72
  "field.requires-review": "requires review",
73
+ "field.resolver-role": "resolver role",
73
74
  "field.review-approval-line": "review approval line",
74
75
  "field.role": "role",
75
76
  "field.serial-no": "serial #",
@@ -82,6 +83,7 @@
82
83
  "field.supervisory-role": "supervisory role",
83
84
  "field.t-key": "translation key",
84
85
  "field.tag": "tag name",
86
+ "field.time-limit": "time limit",
85
87
  "field.time-period": "time period",
86
88
  "field.unit": "unit",
87
89
  "field.use-case": "use case",