@things-factory/worklist 6.0.12 → 6.0.16

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (100) hide show
  1. package/client/pages/activity-approval/activity-approval-page.ts +17 -3
  2. package/client/pages/activity-thread/activity-thread-page.ts +93 -3
  3. package/dist-client/pages/activity-approval/activity-approval-page.js +19 -5
  4. package/dist-client/pages/activity-approval/activity-approval-page.js.map +1 -1
  5. package/dist-client/pages/activity-thread/activity-thread-page.d.ts +4 -0
  6. package/dist-client/pages/activity-thread/activity-thread-page.js +67 -6
  7. package/dist-client/pages/activity-thread/activity-thread-page.js.map +1 -1
  8. package/dist-client/tsconfig.tsbuildinfo +1 -1
  9. package/dist-server/controllers/activity-approval/approve.js +3 -4
  10. package/dist-server/controllers/activity-approval/approve.js.map +1 -1
  11. package/dist-server/controllers/activity-approval/delegate.js +10 -4
  12. package/dist-server/controllers/activity-approval/delegate.js.map +1 -1
  13. package/dist-server/controllers/activity-approval/reject.js +5 -3
  14. package/dist-server/controllers/activity-approval/reject.js.map +1 -1
  15. package/dist-server/controllers/activity-thread/delegate.js +2 -3
  16. package/dist-server/controllers/activity-thread/delegate.js.map +1 -1
  17. package/dist-server/controllers/activity-thread/end.js +1 -2
  18. package/dist-server/controllers/activity-thread/end.js.map +1 -1
  19. package/dist-server/controllers/activity-thread/index.js +1 -0
  20. package/dist-server/controllers/activity-thread/index.js.map +1 -1
  21. package/dist-server/controllers/activity-thread/restart.js +25 -0
  22. package/dist-server/controllers/activity-thread/restart.js.map +1 -0
  23. package/dist-server/controllers/activity-thread/save.js +6 -2
  24. package/dist-server/controllers/activity-thread/save.js.map +1 -1
  25. package/dist-server/controllers/activity-thread/start.js +3 -4
  26. package/dist-server/controllers/activity-thread/start.js.map +1 -1
  27. package/dist-server/controllers/activity-thread/submit.js +2 -1
  28. package/dist-server/controllers/activity-thread/submit.js.map +1 -1
  29. package/dist-server/controllers/activity-thread/terminate.js +2 -3
  30. package/dist-server/controllers/activity-thread/terminate.js.map +1 -1
  31. package/dist-server/service/activity-approval/activity-approval-mutation.js +10 -8
  32. package/dist-server/service/activity-approval/activity-approval-mutation.js.map +1 -1
  33. package/dist-server/service/activity-approval/activity-approval-query.js +21 -1
  34. package/dist-server/service/activity-approval/activity-approval-query.js.map +1 -1
  35. package/dist-server/service/activity-approval/activity-approval-subscription.js +48 -0
  36. package/dist-server/service/activity-approval/activity-approval-subscription.js.map +1 -0
  37. package/dist-server/service/activity-approval/activity-approval.js +23 -2
  38. package/dist-server/service/activity-approval/activity-approval.js.map +1 -1
  39. package/dist-server/service/activity-approval/index.js +2 -1
  40. package/dist-server/service/activity-approval/index.js.map +1 -1
  41. package/dist-server/service/activity-instance/activity-instance-subscription.js +2 -2
  42. package/dist-server/service/activity-instance/activity-instance-subscription.js.map +1 -1
  43. package/dist-server/service/activity-summary/activity-summary-query.js +154 -0
  44. package/dist-server/service/activity-summary/activity-summary-query.js.map +1 -0
  45. package/dist-server/service/activity-summary/activity-summary.js +28 -0
  46. package/dist-server/service/activity-summary/activity-summary.js.map +1 -0
  47. package/dist-server/service/activity-summary/index.js +8 -0
  48. package/dist-server/service/activity-summary/index.js.map +1 -0
  49. package/dist-server/service/activity-thread/activity-thread-history.js +194 -0
  50. package/dist-server/service/activity-thread/activity-thread-history.js.map +1 -0
  51. package/dist-server/service/activity-thread/activity-thread-mutation.js +15 -1
  52. package/dist-server/service/activity-thread/activity-thread-mutation.js.map +1 -1
  53. package/dist-server/service/activity-thread/activity-thread-query.js +18 -5
  54. package/dist-server/service/activity-thread/activity-thread-query.js.map +1 -1
  55. package/dist-server/service/activity-thread/activity-thread-subscription.js +2 -2
  56. package/dist-server/service/activity-thread/activity-thread-subscription.js.map +1 -1
  57. package/dist-server/service/activity-thread/activity-thread.js +21 -22
  58. package/dist-server/service/activity-thread/activity-thread.js.map +1 -1
  59. package/dist-server/service/activity-thread/event-subscriber.js +15 -1
  60. package/dist-server/service/activity-thread/event-subscriber.js.map +1 -1
  61. package/dist-server/service/activity-thread/index.js +3 -2
  62. package/dist-server/service/activity-thread/index.js.map +1 -1
  63. package/dist-server/service/index.js +6 -2
  64. package/dist-server/service/index.js.map +1 -1
  65. package/dist-server/tsconfig.tsbuildinfo +1 -1
  66. package/package.json +3 -3
  67. package/server/controllers/activity-approval/approve.ts +5 -4
  68. package/server/controllers/activity-approval/delegate.ts +21 -6
  69. package/server/controllers/activity-approval/reject.ts +12 -4
  70. package/server/controllers/activity-thread/delegate.ts +2 -3
  71. package/server/controllers/activity-thread/end.ts +1 -2
  72. package/server/controllers/activity-thread/index.ts +1 -0
  73. package/server/controllers/activity-thread/restart.ts +42 -0
  74. package/server/controllers/activity-thread/save.ts +9 -2
  75. package/server/controllers/activity-thread/start.ts +3 -4
  76. package/server/controllers/activity-thread/submit.ts +2 -1
  77. package/server/controllers/activity-thread/terminate.ts +2 -3
  78. package/server/service/activity-approval/activity-approval-mutation.ts +6 -4
  79. package/server/service/activity-approval/activity-approval-query.ts +11 -1
  80. package/server/service/activity-approval/activity-approval-subscription.ts +46 -0
  81. package/server/service/activity-approval/activity-approval.ts +16 -0
  82. package/server/service/activity-approval/index.ts +2 -1
  83. package/server/service/activity-instance/activity-instance-subscription.ts +2 -2
  84. package/server/service/activity-summary/activity-summary-query.ts +132 -0
  85. package/server/service/activity-summary/activity-summary.ts +16 -0
  86. package/server/service/activity-summary/index.ts +5 -0
  87. package/server/service/activity-thread/activity-thread-history.ts +177 -0
  88. package/server/service/activity-thread/activity-thread-mutation.ts +21 -2
  89. package/server/service/activity-thread/activity-thread-query.ts +13 -5
  90. package/server/service/activity-thread/activity-thread-subscription.ts +2 -2
  91. package/server/service/activity-thread/activity-thread.ts +13 -15
  92. package/server/service/activity-thread/event-subscriber.ts +17 -1
  93. package/server/service/activity-thread/index.ts +4 -3
  94. package/server/service/index.ts +14 -6
  95. package/translations/en.json +3 -0
  96. package/translations/ko.json +3 -0
  97. package/translations/ms.json +3 -0
  98. package/translations/zh.json +3 -0
  99. package/server/controllers/activity-approval/abort.ts +0 -33
  100. package/server/controllers/activity-approval/escalate.ts +0 -33
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@things-factory/worklist",
3
- "version": "6.0.12",
3
+ "version": "6.0.16",
4
4
  "main": "dist-server/index.js",
5
5
  "browser": "dist-client/index.js",
6
6
  "things-factory": true,
@@ -30,8 +30,8 @@
30
30
  "@things-factory/attachment-base": "^6.0.12",
31
31
  "@things-factory/auth-base": "^6.0.12",
32
32
  "@things-factory/board-service": "^6.0.12",
33
- "@things-factory/organization": "^6.0.12",
33
+ "@things-factory/organization": "^6.0.15",
34
34
  "@things-factory/shell": "^6.0.12"
35
35
  },
36
- "gitHead": "6dd9637de0444917aa5a3621ce1f361cfb483f36"
36
+ "gitHead": "b133bc7f47a51e8ad177c0c519ec136e27ab02e1"
37
37
  }
@@ -12,8 +12,7 @@ export async function approve(
12
12
  var repository = tx.getRepository(ActivityApproval)
13
13
 
14
14
  var activityApproval = await repository.findOne({
15
- where: { domain: { id: domain.id }, id },
16
- relations: ['domain', 'activityThread', 'updater', 'creator']
15
+ where: { domain: { id: domain.id }, id }
17
16
  })
18
17
 
19
18
  if (!activityApproval) {
@@ -26,7 +25,7 @@ export async function approve(
26
25
 
27
26
  const activityThread = await tx.getRepository(ActivityThread).findOne({
28
27
  where: { domain: { id: domain.id }, id: activityApproval.activityThreadId },
29
- relations: ['domain', 'activityInstance', 'assignee', 'creator', 'updater']
28
+ relations: ['activityInstance']
30
29
  })
31
30
 
32
31
  const approvalLine: ApprovalLineItem[] = activityThread.activityInstance.approvalLine
@@ -37,7 +36,9 @@ export async function approve(
37
36
  judgment: approvalLine[order] ? ActivityApprovalJudgment.Escalated : ActivityApprovalJudgment.Approved,
38
37
  comment,
39
38
  transaction: approvalLine[order] ? 'escalate' : 'approve',
40
- updater: user
39
+ updater: user,
40
+ terminatedAt: new Date(),
41
+ terminator: user
41
42
  })
42
43
 
43
44
  if (approvalLine && approvalLine.length > order) {
@@ -1,7 +1,9 @@
1
+ import { User } from '@things-factory/auth-base'
2
+ import { ObjectRef } from '@things-factory/shell'
1
3
  import { ActivityApproval, ActivityApprovalJudgment } from '../../service/activity-approval/activity-approval'
2
4
 
3
5
  export async function delegate(
4
- { id, comment }: { id: string; comment: string },
6
+ { id, to, comment }: { id: string; to: ObjectRef; comment: string },
5
7
  context: ResolverContext
6
8
  ): Promise<ActivityApproval> {
7
9
  const { domain, user, tx } = context.state
@@ -9,8 +11,7 @@ export async function delegate(
9
11
  var repository = tx.getRepository(ActivityApproval)
10
12
 
11
13
  var activityApproval = await repository.findOne({
12
- where: { domain: { id: domain.id }, id },
13
- relations: ['domain', 'activityThread', 'updater', 'creator']
14
+ where: { domain: { id: domain.id }, id }
14
15
  })
15
16
 
16
17
  if (!activityApproval) {
@@ -21,13 +22,27 @@ export async function delegate(
21
22
  )
22
23
  }
23
24
 
25
+ /* TODO user validation .. */
26
+ const approver = await tx.getRepository(User).findOneBy({ id: to.id })
27
+
28
+ /* create new delegated approval */
29
+ await repository.save({
30
+ ...activityApproval,
31
+ originalApproval: activityApproval,
32
+ comment,
33
+ approver,
34
+ creator: user,
35
+ updater: user
36
+ })
37
+
38
+ /* terminate origin approval */
24
39
  return await repository.save({
25
40
  ...activityApproval,
26
41
  judgment: ActivityApprovalJudgment.Delegated,
27
42
  comment,
28
- transaction: 'abort',
43
+ transaction: 'delegate',
29
44
  updater: user,
30
- terminatedAt: new Date(),
31
- terminator: user
45
+ terminator: user,
46
+ terminatedAt: new Date()
32
47
  })
33
48
  }
@@ -1,3 +1,4 @@
1
+ import { ActivityThread, ActivityThreadStatus } from '../../service/activity-thread/activity-thread'
1
2
  import { ActivityApproval, ActivityApprovalJudgment } from '../../service/activity-approval/activity-approval'
2
3
 
3
4
  export async function reject(
@@ -10,7 +11,7 @@ export async function reject(
10
11
 
11
12
  var activityApproval = await repository.findOne({
12
13
  where: { domain: { id: domain.id }, id },
13
- relations: ['domain', 'activityThread', 'updater', 'creator']
14
+ relations: ['activityThread']
14
15
  })
15
16
 
16
17
  if (!activityApproval) {
@@ -21,9 +22,7 @@ export async function reject(
21
22
  )
22
23
  }
23
24
 
24
- // TODO reject activityThread here..
25
-
26
- return await repository.save({
25
+ var result = await repository.save({
27
26
  ...activityApproval,
28
27
  judgment: ActivityApprovalJudgment.Rejected,
29
28
  comment,
@@ -32,4 +31,13 @@ export async function reject(
32
31
  terminatedAt: new Date(),
33
32
  terminator: user
34
33
  })
34
+
35
+ await tx.getRepository(ActivityThread).save({
36
+ ...activityApproval.activityThread,
37
+ transaction: 'reject',
38
+ state: ActivityThreadStatus.Rejected,
39
+ updater: user
40
+ })
41
+
42
+ return result
35
43
  }
@@ -20,13 +20,12 @@ export async function delegate(
20
20
  const repository = tx.getRepository(ActivityThread)
21
21
 
22
22
  var activityThread = await repository.findOne({
23
- where: { domain: { id: domain.id }, id },
24
- relations: ['domain', 'activityInstance', 'assignee', 'creator', 'updater']
23
+ where: { domain: { id: domain.id }, id }
25
24
  })
26
25
 
27
26
  if (!activityThread) {
28
27
  throw new Error(
29
- context.t('error.activity-instance not found', {
28
+ context.t('error.activity-thread not found', {
30
29
  activityThread: id
31
30
  })
32
31
  )
@@ -10,8 +10,7 @@ export async function end(
10
10
  const repository = tx.getRepository(ActivityThread)
11
11
 
12
12
  var activityThread = await repository.findOne({
13
- where: { domain: { id: domain.id }, id },
14
- relations: ['domain', 'activityInstance', 'assignee', 'creator', 'updater']
13
+ where: { domain: { id: domain.id }, id }
15
14
  })
16
15
 
17
16
  if (!activityThread) {
@@ -4,5 +4,6 @@ export * from './end'
4
4
  export * from './submit'
5
5
  export * from './save'
6
6
  export * from './start'
7
+ export * from './restart'
7
8
  export * from './terminate'
8
9
  export * from './adjust'
@@ -0,0 +1,42 @@
1
+ import { ActivityThread, ActivityThreadStatus } from '../../service/activity-thread/activity-thread'
2
+ import { updateActivityInstanceState } from '../common'
3
+
4
+ export async function restart(
5
+ id: string,
6
+ output: object,
7
+ reason: string,
8
+ context: ResolverContext
9
+ ): Promise<ActivityThread> {
10
+ const { domain, user, tx } = context.state
11
+
12
+ const repository = tx.getRepository(ActivityThread)
13
+ const activityThread = await repository.findOne({
14
+ where: { domain: { id: domain.id }, id }
15
+ })
16
+
17
+ if (!activityThread) {
18
+ throw new Error(
19
+ context.t('error.activity-thread not found', {
20
+ activityThread: id
21
+ })
22
+ )
23
+ }
24
+
25
+ if (output) {
26
+ activityThread.output = output
27
+ }
28
+
29
+ const result = await tx.getRepository(ActivityThread).save({
30
+ ...activityThread,
31
+ reason,
32
+ state: ActivityThreadStatus.Started,
33
+ transaction: 'restart',
34
+ round: activityThread.round + 1,
35
+ updater: user,
36
+ startedAt: new Date()
37
+ })
38
+
39
+ await updateActivityInstanceState(activityThread.activityInstanceId, context)
40
+
41
+ return result
42
+ }
@@ -7,10 +7,17 @@ export async function save(id: string, save: ActivityThreadSave, context: Resolv
7
7
  const repository = tx.getRepository(ActivityThread)
8
8
 
9
9
  const activityThread = await repository.findOne({
10
- where: { domain: { id: domain.id }, id },
11
- relations: ['domain', 'activityInstance', 'assignee', 'creator', 'updater']
10
+ where: { domain: { id: domain.id }, id }
12
11
  })
13
12
 
13
+ if (!activityThread) {
14
+ throw new Error(
15
+ context.t('error.activity-thread not found', {
16
+ activityThread: id
17
+ })
18
+ )
19
+ }
20
+
14
21
  const result = await repository.save({
15
22
  ...activityThread,
16
23
  ...save,
@@ -11,14 +11,13 @@ export async function start(
11
11
 
12
12
  const repository = tx.getRepository(ActivityThread)
13
13
  const activityThread = await repository.findOne({
14
- where: { domain: { id: domain.id }, id },
15
- relations: ['domain', 'activityInstance', 'assignee', 'creator', 'updater']
14
+ where: { domain: { id: domain.id }, id }
16
15
  })
17
16
 
18
17
  if (!activityThread) {
19
18
  throw new Error(
20
- context.t('error.activity-instance not found', {
21
- activityInstance: id
19
+ context.t('error.activity-thread not found', {
20
+ activityThread: id
22
21
  })
23
22
  )
24
23
  }
@@ -14,7 +14,7 @@ export async function submit(
14
14
 
15
15
  var activityThread = await repository.findOne({
16
16
  where: { domain: { id: domain.id }, id },
17
- relations: ['domain', 'activityInstance', 'assignee', 'creator', 'updater']
17
+ relations: ['activityInstance']
18
18
  })
19
19
 
20
20
  if (!activityThread) {
@@ -37,6 +37,7 @@ export async function submit(
37
37
  await tx.getRepository(ActivityApproval).save({
38
38
  domain,
39
39
  activityThread,
40
+ round: activityThread.round,
40
41
  order: 1,
41
42
  judgment: ActivityApprovalJudgment.Pending,
42
43
  transaction: 'submit',
@@ -9,13 +9,12 @@ export async function terminate(
9
9
  var repository = tx.getRepository(ActivityThread)
10
10
 
11
11
  var activityThread = await repository.findOne({
12
- where: { domain: { id: domain.id }, id },
13
- relations: ['domain', 'activityInstance', 'assignee', 'creator', 'updater']
12
+ where: { domain: { id: domain.id }, id }
14
13
  })
15
14
 
16
15
  if (!activityThread) {
17
16
  throw new Error(
18
- context.t('error.activity-instance not found', {
17
+ context.t('error.activity-thread not found', {
19
18
  activityThread: id
20
19
  })
21
20
  )
@@ -1,9 +1,10 @@
1
1
  import { Resolver, Mutation, Arg, Ctx, Directive } from 'type-graphql'
2
2
 
3
3
  import { ActivityApproval, ActivityApprovalJudgment } from './activity-approval'
4
- import { abort } from '../../controllers/activity-approval/abort'
5
4
  import { reject } from '../../controllers/activity-approval/reject'
6
5
  import { approve } from '../../controllers/activity-approval/approve'
6
+ import { delegate } from '../../controllers/activity-approval/delegate'
7
+ import { ObjectRef } from '@things-factory/shell'
7
8
 
8
9
  @Resolver(ActivityApproval)
9
10
  export class ActivityApprovalMutation {
@@ -60,12 +61,13 @@ export class ActivityApprovalMutation {
60
61
  }
61
62
 
62
63
  @Directive('@transaction')
63
- @Mutation(returns => ActivityApproval!, { nullable: true, description: 'To abort ActivityApproval' })
64
- async abortActivityApproval(
64
+ @Mutation(returns => ActivityApproval!, { nullable: true, description: 'To delegate ActivityApproval' })
65
+ async delegateActivityApproval(
65
66
  @Arg('id') id: string,
67
+ @Arg('to', type => ObjectRef) to: ObjectRef,
66
68
  @Arg('comment', { nullable: true }) comment: string,
67
69
  @Ctx() context: ResolverContext
68
70
  ): Promise<ActivityApproval> {
69
- return await abort({ id, comment }, context)
71
+ return await delegate({ id, to, comment }, context)
70
72
  }
71
73
  }
@@ -33,7 +33,7 @@ export class ActivityApprovalQuery {
33
33
  return { items, total }
34
34
  }
35
35
 
36
- @Query(returns => ActivityApprovalList, { description: 'To fetch my own ActivityApprovals' })
36
+ @Query(returns => ActivityApprovalList, { description: 'To fetch the list of work results I need to review' })
37
37
  async approvalWaitingList(@Args() params: ListParam, @Ctx() context: ResolverContext): Promise<ActivityApprovalList> {
38
38
  var { domain, user } = context.state
39
39
 
@@ -78,6 +78,11 @@ export class ActivityApprovalQuery {
78
78
  return await getRepository(Domain).findOneBy({ id: activityApproval.domainId })
79
79
  }
80
80
 
81
+ @FieldResolver(type => User)
82
+ async approver(@Root() activityApproval: ActivityApproval): Promise<User> {
83
+ return await getRepository(User).findOneBy({ id: activityApproval.approverId })
84
+ }
85
+
81
86
  @FieldResolver(type => User)
82
87
  async updater(@Root() activityApproval: ActivityApproval): Promise<User> {
83
88
  return await getRepository(User).findOneBy({ id: activityApproval.updaterId })
@@ -87,4 +92,9 @@ export class ActivityApprovalQuery {
87
92
  async creator(@Root() activityApproval: ActivityApproval): Promise<User> {
88
93
  return await getRepository(User).findOneBy({ id: activityApproval.creatorId })
89
94
  }
95
+
96
+ @FieldResolver(type => User)
97
+ async terminator(@Root() activityApproval: ActivityApproval): Promise<User> {
98
+ return await getRepository(User).findOneBy({ id: activityApproval.terminatorId })
99
+ }
90
100
  }
@@ -0,0 +1,46 @@
1
+ import { withFilter } from 'graphql-subscriptions'
2
+ import { Resolver, Root, Subscription } from 'type-graphql'
3
+
4
+ import { User } from '@things-factory/auth-base'
5
+ import { getRepository, pubsub } from '@things-factory/shell'
6
+
7
+ import { ActivityApproval } from './activity-approval'
8
+
9
+ @Resolver(ActivityApproval)
10
+ export class ActivityApprovalSubscription {
11
+ @Subscription({
12
+ subscribe: (_, args, context, info) => {
13
+ const { domain, user } = context.state
14
+ const subdomain = domain?.subdomain
15
+
16
+ if (!domain) {
17
+ throw new Error('domain required')
18
+ }
19
+
20
+ if (!user.domains?.find(d => d.subdomain === subdomain) && !process.superUserGranted(domain, user)) {
21
+ throw new Error(`domain(${subdomain}) is not working for user(${user.email}).`)
22
+ }
23
+
24
+ return withFilter(
25
+ () => pubsub.asyncIterator('activity-approval'),
26
+ async (payload, variables, context, info) => {
27
+ const { activityApproval } = payload
28
+ const { domainId } = activityApproval
29
+
30
+ if (domainId !== domain?.id) {
31
+ return false
32
+ }
33
+
34
+ if (activityApproval.approverId === user.id) {
35
+ return true
36
+ }
37
+
38
+ return false
39
+ }
40
+ )(_, args, context, info)
41
+ }
42
+ })
43
+ activityApproval(@Root() payload: { activityApproval: ActivityApproval }): ActivityApproval {
44
+ return payload.activityApproval
45
+ }
46
+ }
@@ -6,6 +6,7 @@ import {
6
6
  Column,
7
7
  RelationId,
8
8
  ManyToOne,
9
+ OneToMany,
9
10
  PrimaryGeneratedColumn
10
11
  } from 'typeorm'
11
12
  import { ObjectType, Field, Int, ID, registerEnumType } from 'type-graphql'
@@ -53,6 +54,17 @@ export class ActivityApproval {
53
54
  @RelationId((activityApproval: ActivityApproval) => activityApproval.domain)
54
55
  domainId?: string
55
56
 
57
+ @ManyToOne(type => ActivityApproval, { nullable: true })
58
+ @Field(type => ActivityApproval, { nullable: true })
59
+ originalApproval?: ActivityApproval
60
+
61
+ @RelationId((activityApproval: ActivityApproval) => activityApproval.originalApproval)
62
+ originalApprovalId?: string
63
+
64
+ @OneToMany(type => ActivityApproval, activityApproval => activityApproval.originalApproval)
65
+ @Field(type => [ActivityApproval])
66
+ derivedApprovals?: ActivityApproval
67
+
56
68
  @ManyToOne(type => ActivityThread, { nullable: true })
57
69
  @Field(type => ActivityThread, { nullable: true })
58
70
  activityThread?: ActivityThread
@@ -60,6 +72,10 @@ export class ActivityApproval {
60
72
  @RelationId((activityApproval: ActivityApproval) => activityApproval.activityThread)
61
73
  activityThreadId?: string
62
74
 
75
+ @Column({ nullable: true, default: 1 })
76
+ @Field({ nullable: true })
77
+ round: number = 1
78
+
63
79
  @Column({ nullable: true, default: 0 })
64
80
  @Field({ nullable: true, description: 'Nth order approval for given activity thread' })
65
81
  order?: number = 0
@@ -1,8 +1,9 @@
1
1
  import { ActivityApproval } from './activity-approval'
2
2
  import { ActivityApprovalQuery } from './activity-approval-query'
3
3
  import { ActivityApprovalMutation } from './activity-approval-mutation'
4
+ import { ActivityApprovalSubscription } from './activity-approval-subscription'
4
5
  import { ActivityApprovalSubscriber } from './event-subscriber'
5
6
 
6
7
  export const entities = [ActivityApproval]
7
- export const resolvers = [ActivityApprovalQuery, ActivityApprovalMutation]
8
+ export const resolvers = [ActivityApprovalQuery, ActivityApprovalMutation, ActivityApprovalSubscription]
8
9
  export const subscribers = [ActivityApprovalSubscriber]
@@ -25,9 +25,9 @@ export class ActivityInstanceSubscription {
25
25
  () => pubsub.asyncIterator('activity-instance'),
26
26
  async (payload, variables, context, info) => {
27
27
  const { activityInstance } = payload
28
- const { domain } = activityInstance
28
+ const { domainId } = activityInstance
29
29
 
30
- if (subdomain !== domain?.subdomain) {
30
+ if (domainId !== domain?.id) {
31
31
  return false
32
32
  }
33
33
 
@@ -0,0 +1,132 @@
1
+ import { Arg, Ctx, FieldResolver, Query, Resolver, Root } from 'type-graphql'
2
+
3
+ import { User } from '@things-factory/auth-base'
4
+ import { getQueryBuilderFromListParams, getRepository } from '@things-factory/shell'
5
+
6
+ import { ActivitySummary } from './activity-summary'
7
+ import { ActivityThread, ActivityThreadStatus } from '../activity-thread/activity-thread'
8
+ import { ActivityApproval, ActivityApprovalJudgment } from '../activity-approval/activity-approval'
9
+ import { ActivityInstance, ActivityInstanceStatus } from '../activity-instance/activity-instance'
10
+
11
+ @Resolver(ActivitySummary)
12
+ export class ActivitySummaryQuery {
13
+ @Query(returns => ActivitySummary!, { nullable: true, description: 'To fetch a Activity Summary' })
14
+ async activitySummary(@Ctx() context: ResolverContext): Promise<ActivitySummary> {
15
+ return {}
16
+ }
17
+
18
+ @FieldResolver(type => Number)
19
+ async numberOfToDos(@Root() activitySummary: ActivitySummary, @Ctx() context: ResolverContext): Promise<number> {
20
+ var { domain, user } = context.state
21
+
22
+ const status = [ActivityThreadStatus.Ended, ActivityThreadStatus.Aborted]
23
+
24
+ return await getQueryBuilderFromListParams({
25
+ repository: getRepository(ActivityThread),
26
+ params: {},
27
+ domain,
28
+ alias: 'at',
29
+ searchables: ['name', 'description'],
30
+ filtersMap: {
31
+ name: { columnName: 'name', relationColumn: 'activityInstance' },
32
+ description: { columnName: 'description', relationColumn: 'activityInstance' }
33
+ }
34
+ })
35
+ .andWhere('at.state NOT IN (:...status)', { status })
36
+ .andWhere('at.assignee = :user', { user: user.id })
37
+ .getCount()
38
+ }
39
+
40
+ @FieldResolver(type => Number)
41
+ async numberOfApprovalWaitings(
42
+ @Root() activitySummary: ActivitySummary,
43
+ @Ctx() context: ResolverContext
44
+ ): Promise<number> {
45
+ var { domain, user } = context.state
46
+
47
+ const judgment = [
48
+ ActivityApprovalJudgment.Escalated,
49
+ ActivityApprovalJudgment.Delegated,
50
+ ActivityApprovalJudgment.Approved,
51
+ ActivityApprovalJudgment.Rejected
52
+ ]
53
+
54
+ return await getQueryBuilderFromListParams({
55
+ repository: getRepository(ActivityApproval),
56
+ params: {},
57
+ domain,
58
+ alias: 'ap',
59
+ searchables: ['name', 'description'],
60
+ filtersMap: {
61
+ name: {
62
+ relationColumn: 'activityThread.activityInstance',
63
+ columnName: 'name'
64
+ },
65
+ description: {
66
+ relationColumn: 'activityThread.activityInstance',
67
+ columnName: 'description'
68
+ }
69
+ }
70
+ })
71
+ .andWhere('ap.judgment NOT IN (:...judgment)', { judgment })
72
+ .andWhere('ap.approver = :user', { user: user.id })
73
+ .getCount()
74
+ }
75
+
76
+ @FieldResolver(type => Number)
77
+ async numberOfPicks(@Root() activitySummary: ActivitySummary, @Ctx() context: ResolverContext): Promise<number> {
78
+ var { domain, user } = context.state
79
+
80
+ /*
81
+ activity-instance 중에서 아직 created 상태이면서,
82
+ activity-instance의 assigneeRole 이 지정되지 않았거나,
83
+ assigneeRole이 지정되었으면 그 Role에 내가 해당된 경우이면서,
84
+ 나는 아직 해당 activity-instance의 thread를 할당받지 않은 경우에 해당하는
85
+ activity-instance 리스트를 모두 가져오는 쿼리이다.
86
+ */
87
+
88
+ user = await getRepository(User).findOne({
89
+ where: { id: user.id },
90
+ relations: ['roles']
91
+ })
92
+ const roles = user.roles.filter(role => role.domainId === domain.id).map(role => role.id)
93
+
94
+ if (!roles.length) {
95
+ return 0
96
+ }
97
+
98
+ return await getQueryBuilderFromListParams({
99
+ repository: getRepository(ActivityInstance),
100
+ params: {},
101
+ domain,
102
+ alias: 'ai',
103
+ searchables: ['name', 'description']
104
+ })
105
+ .leftJoinAndSelect('ai.activityThreads', 'threads', 'threads.assignee = :user', { user: user.id })
106
+ .andWhere('ai.state IN (:...status)', {
107
+ status: [ActivityInstanceStatus.Posted, ActivityInstanceStatus.WaitingAssignment]
108
+ })
109
+ .andWhere('ai.assigneeRole IN (:...roles)', { roles })
110
+ .andWhere('threads.id IS NULL') /* 이미 내가 할당된 경우는 제외한다. */
111
+ .getCount()
112
+ }
113
+
114
+ @FieldResolver(type => Number)
115
+ async numberOfDrafts(@Root() activitySummary: ActivitySummary, @Ctx() context: ResolverContext): Promise<number> {
116
+ var { domain, user } = context.state
117
+
118
+ /* 생성자가 자신이면서, 아직 Draft 상태인 activity-instance 리스트만 반환 */
119
+ const status = [ActivityInstanceStatus.Draft]
120
+
121
+ return await getQueryBuilderFromListParams({
122
+ repository: getRepository(ActivityInstance),
123
+ params: {},
124
+ domain,
125
+ alias: 'ai',
126
+ searchables: ['name', 'description']
127
+ })
128
+ .andWhere('ai.state IN (:...status)', { status })
129
+ .andWhere('ai.creator = :user', { user: user.id })
130
+ .getCount()
131
+ }
132
+ }
@@ -0,0 +1,16 @@
1
+ import { Field, ObjectType } from 'type-graphql'
2
+
3
+ @ObjectType({ description: 'Object Type for My Activity Summary' })
4
+ export class ActivitySummary {
5
+ @Field({ nullable: true })
6
+ numberOfToDos?: number
7
+
8
+ @Field({ nullable: true })
9
+ numberOfApprovalWaitings?: number
10
+
11
+ @Field({ nullable: true })
12
+ numberOfPicks?: number
13
+
14
+ @Field({ nullable: true })
15
+ numberOfDrafts?: number
16
+ }
@@ -0,0 +1,5 @@
1
+ import { ActivitySummary } from './activity-summary'
2
+ import { ActivitySummaryQuery } from './activity-summary-query'
3
+
4
+ export const entities = [ActivitySummary]
5
+ export const resolvers = [ActivitySummaryQuery]