@things-factory/worklist 6.0.21 → 6.0.25

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 (112) hide show
  1. package/client/activity-summary-generator.ts +132 -0
  2. package/client/components/activity-starter-form.ts +89 -3
  3. package/client/index.ts +1 -0
  4. package/client/pages/installable-activity/installable-activity-list-page.ts +410 -0
  5. package/client/pages/installable-activity/installable-activity-model-item-list.ts +18 -0
  6. package/client/pages/todo/draft-list-page.ts +9 -0
  7. package/client/route.ts +4 -0
  8. package/dist-client/activity-summary-generator.d.ts +2 -0
  9. package/dist-client/activity-summary-generator.js +114 -0
  10. package/dist-client/activity-summary-generator.js.map +1 -0
  11. package/dist-client/components/activity-starter-form.d.ts +1 -0
  12. package/dist-client/components/activity-starter-form.js +66 -4
  13. package/dist-client/components/activity-starter-form.js.map +1 -1
  14. package/dist-client/index.d.ts +1 -0
  15. package/dist-client/index.js +1 -0
  16. package/dist-client/index.js.map +1 -1
  17. package/dist-client/pages/installable-activity/installable-activity-list-page.d.ts +45 -0
  18. package/dist-client/pages/installable-activity/installable-activity-list-page.js +414 -0
  19. package/dist-client/pages/installable-activity/installable-activity-list-page.js.map +1 -0
  20. package/dist-client/pages/installable-activity/installable-activity-model-item-list.d.ts +1 -0
  21. package/dist-client/pages/installable-activity/installable-activity-model-item-list.js +20 -0
  22. package/dist-client/pages/installable-activity/installable-activity-model-item-list.js.map +1 -0
  23. package/dist-client/pages/installed-activity/installed-activity-list-page.d.ts +45 -0
  24. package/dist-client/pages/installed-activity/installed-activity-list-page.js +412 -0
  25. package/dist-client/pages/installed-activity/installed-activity-list-page.js.map +1 -0
  26. package/dist-client/pages/installed-activity/installed-activity-model-item-list.d.ts +1 -0
  27. package/dist-client/pages/installed-activity/installed-activity-model-item-list.js +20 -0
  28. package/dist-client/pages/installed-activity/installed-activity-model-item-list.js.map +1 -0
  29. package/dist-client/pages/todo/draft-list-page.js +9 -0
  30. package/dist-client/pages/todo/draft-list-page.js.map +1 -1
  31. package/dist-client/route.d.ts +1 -1
  32. package/dist-client/route.js +3 -0
  33. package/dist-client/route.js.map +1 -1
  34. package/dist-client/tsconfig.tsbuildinfo +1 -1
  35. package/dist-server/controllers/activity-installation-controller.js +17 -0
  36. package/dist-server/controllers/activity-installation-controller.js.map +1 -0
  37. package/dist-server/controllers/activity-instance/post.js +3 -6
  38. package/dist-server/controllers/activity-instance/post.js.map +1 -1
  39. package/dist-server/controllers/activity-thread/submit.js.map +1 -1
  40. package/dist-server/controllers/call-webhook.js +4 -2
  41. package/dist-server/controllers/call-webhook.js.map +1 -1
  42. package/dist-server/controllers/common.js +44 -4
  43. package/dist-server/controllers/common.js.map +1 -1
  44. package/dist-server/controllers/index.js +4 -0
  45. package/dist-server/controllers/index.js.map +1 -1
  46. package/dist-server/index.js +1 -1
  47. package/dist-server/index.js.map +1 -1
  48. package/dist-server/service/activity/activity-model-type.js +1 -1
  49. package/dist-server/service/activity/activity-model-type.js.map +1 -1
  50. package/dist-server/service/activity/activity-query.js +1 -0
  51. package/dist-server/service/activity/activity-query.js.map +1 -1
  52. package/dist-server/service/activity/activity.js +9 -0
  53. package/dist-server/service/activity/activity.js.map +1 -1
  54. package/dist-server/service/activity-approval/event-subscriber.js +21 -4
  55. package/dist-server/service/activity-approval/event-subscriber.js.map +1 -1
  56. package/dist-server/service/activity-instance/activity-instance-query.js +40 -0
  57. package/dist-server/service/activity-instance/activity-instance-query.js.map +1 -1
  58. package/dist-server/service/activity-instance/activity-instance-type.js +13 -1
  59. package/dist-server/service/activity-instance/activity-instance-type.js.map +1 -1
  60. package/dist-server/service/activity-instance/activity-instance.js +25 -1
  61. package/dist-server/service/activity-instance/activity-instance.js.map +1 -1
  62. package/dist-server/service/index.js +4 -0
  63. package/dist-server/service/index.js.map +1 -1
  64. package/dist-server/service/installable-activity/index.js +10 -0
  65. package/dist-server/service/installable-activity/index.js.map +1 -0
  66. package/dist-server/service/installable-activity/installable-activity-mutation.js +60 -0
  67. package/dist-server/service/installable-activity/installable-activity-mutation.js.map +1 -0
  68. package/dist-server/service/installable-activity/installable-activity-query.js +48 -0
  69. package/dist-server/service/installable-activity/installable-activity-query.js.map +1 -0
  70. package/dist-server/service/installable-activity/installable-activity-type.js +21 -0
  71. package/dist-server/service/installable-activity/installable-activity-type.js.map +1 -0
  72. package/dist-server/service/installable-activity/installable-activity.js +70 -0
  73. package/dist-server/service/installable-activity/installable-activity.js.map +1 -0
  74. package/dist-server/service/installed-activity/index.js +10 -0
  75. package/dist-server/service/installed-activity/index.js.map +1 -0
  76. package/dist-server/service/installed-activity/installed-activity-mutation.js +60 -0
  77. package/dist-server/service/installed-activity/installed-activity-mutation.js.map +1 -0
  78. package/dist-server/service/installed-activity/installed-activity-query.js +48 -0
  79. package/dist-server/service/installed-activity/installed-activity-query.js.map +1 -0
  80. package/dist-server/service/installed-activity/installed-activity-type.js +21 -0
  81. package/dist-server/service/installed-activity/installed-activity-type.js.map +1 -0
  82. package/dist-server/service/installed-activity/installed-activity.js +70 -0
  83. package/dist-server/service/installed-activity/installed-activity.js.map +1 -0
  84. package/dist-server/tsconfig.tsbuildinfo +1 -1
  85. package/package.json +7 -7
  86. package/server/controllers/activity-installation-controller.ts +17 -0
  87. package/server/controllers/activity-instance/bid.ts +52 -0
  88. package/server/controllers/activity-instance/post.ts +9 -9
  89. package/server/controllers/activity-thread/submit.ts +1 -1
  90. package/server/controllers/call-webhook.ts +40 -0
  91. package/server/controllers/common.ts +41 -5
  92. package/server/controllers/index.ts +1 -0
  93. package/server/index.ts +1 -1
  94. package/server/service/activity/activity-model-type.ts +3 -3
  95. package/server/service/activity/activity-query.ts +2 -1
  96. package/server/service/activity/activity.ts +7 -0
  97. package/server/service/activity-approval/event-subscriber.ts +22 -5
  98. package/server/service/activity-instance/activity-instance-query.ts +44 -1
  99. package/server/service/activity-instance/activity-instance-type.ts +12 -4
  100. package/server/service/activity-instance/activity-instance.ts +17 -1
  101. package/server/service/index.ts +7 -0
  102. package/server/service/installable-activity/index.ts +7 -0
  103. package/server/service/installable-activity/installable-activity-mutation.ts +61 -0
  104. package/server/service/installable-activity/installable-activity-query.ts +36 -0
  105. package/server/service/installable-activity/installable-activity-type.ts +12 -0
  106. package/server/service/installable-activity/installable-activity.ts +49 -0
  107. package/things-factory.config.js +1 -0
  108. package/translations/en.json +2 -0
  109. package/translations/ko.json +2 -0
  110. package/translations/ms.json +2 -0
  111. package/translations/zh.json +2 -0
  112. package/server/controllers/activity-extension-controller.ts +0 -12
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@things-factory/worklist",
3
- "version": "6.0.21",
3
+ "version": "6.0.25",
4
4
  "main": "dist-server/index.js",
5
5
  "browser": "dist-client/index.js",
6
6
  "things-factory": true,
@@ -27,11 +27,11 @@
27
27
  "dependencies": {
28
28
  "@operato/graphql": "^1.0.0",
29
29
  "@operato/grist-editor": "^1.0.0",
30
- "@things-factory/attachment-base": "^6.0.21",
31
- "@things-factory/auth-base": "^6.0.21",
32
- "@things-factory/board-service": "^6.0.21",
33
- "@things-factory/organization": "^6.0.21",
34
- "@things-factory/shell": "^6.0.21"
30
+ "@things-factory/attachment-base": "^6.0.25",
31
+ "@things-factory/auth-base": "^6.0.25",
32
+ "@things-factory/board-service": "^6.0.25",
33
+ "@things-factory/organization": "^6.0.25",
34
+ "@things-factory/shell": "^6.0.25"
35
35
  },
36
- "gitHead": "074a4f460d08fed4bc7e9882aa57f4c120cf0f11"
36
+ "gitHead": "8a987a42de944dc915b8cfddb047eb7bc0d4ba41"
37
37
  }
@@ -0,0 +1,17 @@
1
+ import { InstallableActivity } from '../service/installable-activity/installable-activity'
2
+
3
+ export class ActivityInstallations {
4
+ static templates: { [name: string]: InstallableActivity } = {}
5
+
6
+ static installActivityTemplate(template: InstallableActivity) {
7
+ ActivityInstallations.templates[template.name] = template
8
+ }
9
+
10
+ static get(name: string): InstallableActivity {
11
+ return ActivityInstallations.templates[name]
12
+ }
13
+
14
+ static list(): InstallableActivity[] {
15
+ return Object.values(ActivityInstallations.templates)
16
+ }
17
+ }
@@ -0,0 +1,52 @@
1
+ import { In } from 'typeorm'
2
+
3
+ import { User } from '@things-factory/auth-base'
4
+
5
+ import { ActivityInstance, ActivityInstanceStatus } from '../../service/activity-instance/activity-instance'
6
+ import { ActivityInstancePost } from '../../service/activity-instance/activity-instance-type'
7
+ import { createActivityThreadsForAllRoleUsers, createActivityThreadsForUsers } from '../common'
8
+
9
+ export async function bid(activityInstance: ActivityInstancePost, context: ResolverContext): Promise<ActivityInstance> {
10
+ const { domain, user, tx } = context.state
11
+ const { id, assignees } = activityInstance
12
+
13
+ var origin = id
14
+ ? await tx.getRepository(ActivityInstance).findOne({
15
+ where: { domain: { id: domain.id }, id },
16
+ relations: [
17
+ 'domain',
18
+ 'activity',
19
+ 'assigneeRole',
20
+ 'supervisoryRole',
21
+ 'updater',
22
+ 'creator',
23
+ 'starter',
24
+ 'terminator'
25
+ ]
26
+ })
27
+ : null
28
+
29
+ const bid = await tx.getRepository(ActivityInstance).save({
30
+ ...origin,
31
+ ...activityInstance,
32
+ transaction: 'bid',
33
+ state: ActivityInstanceStatus.Posted,
34
+ domain,
35
+ creator: user,
36
+ updater: user
37
+ })
38
+
39
+ const assignedUsers = await tx.getRepository(User).findBy({
40
+ email: In(assignees || [])
41
+ })
42
+
43
+ if (bid.threadsMin === 0 && bid.assigneeRoleId) {
44
+ await createActivityThreadsForAllRoleUsers('post', bid, context)
45
+ }
46
+
47
+ if (assignedUsers.length > 0) {
48
+ await createActivityThreadsForUsers('post', bid, assignedUsers, context)
49
+ }
50
+
51
+ return await tx.getRepository(ActivityInstance).findOneBy({ id: bid.id })
52
+ }
@@ -1,10 +1,10 @@
1
- import { In } from 'typeorm'
2
-
3
- import { User } from '@things-factory/auth-base'
4
-
5
1
  import { ActivityInstance, ActivityInstanceStatus } from '../../service/activity-instance/activity-instance'
6
2
  import { ActivityInstancePost } from '../../service/activity-instance/activity-instance-type'
7
- import { createActivityThreadsForAllRoleUsers, createActivityThreadsForUsers } from '../common'
3
+ import {
4
+ createActivityThreadsForAllRoleUsers,
5
+ createActivityThreadsForUsers,
6
+ getSystemUserFromAssigneeItem
7
+ } from '../common'
8
8
 
9
9
  export async function post(
10
10
  activityInstance: ActivityInstancePost,
@@ -39,11 +39,11 @@ export async function post(
39
39
  updater: user
40
40
  })
41
41
 
42
- const assignedUsers = await tx.getRepository(User).findBy({
43
- email: In(assignees || [])
44
- })
42
+ const assignedUsers = await Promise.all(assignees.map(assignee => getSystemUserFromAssigneeItem(assignee, context)))
43
+
44
+ assignees.map(async assignee => await getSystemUserFromAssigneeItem(assignee, context))
45
45
 
46
- if (posted.threadsMin === 0 && posted.assigneeRoleId) {
46
+ if (assignedUsers.length == 0 && posted.threadsMin === 0 && posted.assigneeRoleId) {
47
47
  await createActivityThreadsForAllRoleUsers('post', posted, context)
48
48
  }
49
49
 
@@ -2,7 +2,7 @@ import { ActivityThread, ActivityThreadStatus } from '../../service/activity-thr
2
2
  import { ActivityApproval, ActivityApprovalJudgment } from '../../service/activity-approval/activity-approval'
3
3
  import { getSystemUserFromApprovalLineItem, updateActivityInstanceState } from '../common'
4
4
  import { User } from '@things-factory/auth-base'
5
- import { Department, Employee, ApprovalLineItem, ApprovalLineItemType } from '@things-factory/organization'
5
+ import { Department, Employee, ApprovalLineItem, OrgMemberTargetType } from '@things-factory/organization'
6
6
 
7
7
  export async function submit(
8
8
  { id, output, reason }: { id: string; output?: object; reason?: string },
@@ -0,0 +1,40 @@
1
+ import { EntityManager } from 'typeorm'
2
+ import { Application } from '@things-factory/auth-base'
3
+ import { Domain, getRepository } from '@things-factory/shell'
4
+
5
+ export async function callWebhook(domain: Domain, tag: string, data: any, tx?: EntityManager) {
6
+ /*
7
+ TODO webhook callback의 다양한 subscription 조건을 지원한다.
8
+ - activity의 client에 해당하는 application
9
+ - activityInstance의 starter에 해당하는 application
10
+ - 모든 이벤트를 받고자하는 application
11
+ - 특정 activity들의 이벤트를 받고자하는 application
12
+ */
13
+
14
+ const applications = await (tx ? tx.getRepository(Application) : getRepository(Application)).findBy({
15
+ domain: { id: domain.id }
16
+ })
17
+ const options = {
18
+ method: 'post',
19
+ headers: {
20
+ 'x-things-factory-domain': domain.name,
21
+ 'Content-Type': 'application/json'
22
+ },
23
+ body: {
24
+ tag,
25
+ data
26
+ } as any
27
+ }
28
+
29
+ try {
30
+ applications
31
+ .filter(app => app.webhook)
32
+ .every(app => {
33
+ const webhook = app.webhook
34
+
35
+ fetch(webhook, options)
36
+ })
37
+ } catch (err) {
38
+ console.error(err)
39
+ }
40
+ }
@@ -1,8 +1,8 @@
1
1
  import { Role, User } from '@things-factory/auth-base'
2
2
 
3
- import { ActivityInstance, ActivityInstanceStatus } from '../service/activity-instance/activity-instance'
3
+ import { ActivityInstance, ActivityInstanceStatus, AssigneeItem } from '../service/activity-instance/activity-instance'
4
4
  import { ActivityThread, ActivityThreadStatus } from '../service/activity-thread/activity-thread'
5
- import { Department, Employee, ApprovalLineItem, ApprovalLineItemType } from '@things-factory/organization'
5
+ import { Department, Employee, ApprovalLineItem, OrgMemberTargetType } from '@things-factory/organization'
6
6
 
7
7
  export async function updateActivityInstanceState(id: string, context: ResolverContext) {
8
8
  const { tx } = context.state
@@ -120,20 +120,56 @@ export async function getSystemUserFromApprovalLineItem(
120
120
  const { type, value, approver } = approvalLineItem
121
121
  const { id: approverId, name, description, controlNo } = approver
122
122
 
123
- if (type == ApprovalLineItemType.Employee) {
123
+ if (type == OrgMemberTargetType.Employee) {
124
124
  const employee = await tx.getRepository(Employee).findOne({ where: { id: approverId }, relations: ['user'] })
125
125
 
126
126
  if (!employee || !employee.user) {
127
127
  return
128
128
  }
129
129
  return employee.user
130
- } else if (type == ApprovalLineItemType.Department) {
130
+ } else if (type == OrgMemberTargetType.Department) {
131
131
  const department = await tx.getRepository(Department).findOne({ where: { id: approverId }, relations: ['manager'] })
132
132
 
133
133
  if (!department || !department.manager) {
134
134
  return
135
135
  }
136
136
  return await tx.getRepository(User).findOneBy({ id: department.manager.userId })
137
- } else if (type == ApprovalLineItemType.Role) {
137
+ } else if (type == OrgMemberTargetType.Role) {
138
+ } else if (type == OrgMemberTargetType.Myself) {
139
+ return user
140
+ } else if (type == OrgMemberTargetType.MyDepartment) {
141
+ // return user
142
+ } else if (type == OrgMemberTargetType.MySupervisor) {
143
+ // return user
144
+ }
145
+ }
146
+
147
+ export async function getSystemUserFromAssigneeItem(assigneeItem: AssigneeItem, context: any): Promise<User> {
148
+ const { domain, user, tx } = context.state
149
+
150
+ const { type, value, assignee } = assigneeItem
151
+ const { id: assigneeId, name, description, controlNo } = assignee
152
+
153
+ if (type == OrgMemberTargetType.Employee) {
154
+ const employee = await tx.getRepository(Employee).findOne({ where: { id: assigneeId }, relations: ['user'] })
155
+
156
+ if (!employee || !employee.user) {
157
+ return
158
+ }
159
+ return employee.user
160
+ } else if (type == OrgMemberTargetType.Department) {
161
+ const department = await tx.getRepository(Department).findOne({ where: { id: assigneeId }, relations: ['manager'] })
162
+
163
+ if (!department || !department.manager) {
164
+ return
165
+ }
166
+ return await tx.getRepository(User).findOneBy({ id: department.manager.userId })
167
+ } else if (type == OrgMemberTargetType.Role) {
168
+ } else if (type == OrgMemberTargetType.Myself) {
169
+ return user
170
+ } else if (type == OrgMemberTargetType.MyDepartment) {
171
+ // return user
172
+ } else if (type == OrgMemberTargetType.MySupervisor) {
173
+ // return user
138
174
  }
139
175
  }
@@ -0,0 +1 @@
1
+ export * from './activity-installation-controller'
package/server/index.ts CHANGED
@@ -1,5 +1,5 @@
1
1
  import './routes'
2
2
 
3
- export * from './migrations'
3
+ export * from './controllers'
4
4
  export * from './middlewares'
5
5
  export * from './service'
@@ -29,8 +29,8 @@ registerEnumType(ActivityModelItemType, {
29
29
 
30
30
  @ObjectType({ description: 'Entity for ActivityModelItem' })
31
31
  export class ActivityModelItem {
32
- @Field()
33
- name: string
32
+ @Field({ nullable: true })
33
+ name?: string
34
34
 
35
35
  @Field({ nullable: true })
36
36
  description?: string
@@ -60,7 +60,7 @@ export class ActivityModelItem {
60
60
  unit?: string
61
61
 
62
62
  @Field(type => [Int], { nullable: true })
63
- quantifier: number[]
63
+ quantifier?: number[]
64
64
 
65
65
  @Field(type => ScalarObject, { nullable: true })
66
66
  spec?: { [key: string]: any }
@@ -5,7 +5,7 @@ import { Attachment } from '@things-factory/attachment-base'
5
5
  import { Role, User } from '@things-factory/auth-base'
6
6
  import { Domain, getQueryBuilderFromListParams, getRepository, ListParam } from '@things-factory/shell'
7
7
 
8
- import { Activity } from './activity'
8
+ import { Activity, ActivityStatus } from './activity'
9
9
  import { ActivityList } from './activity-type'
10
10
 
11
11
  @Resolver(Activity)
@@ -64,6 +64,7 @@ export class ActivityQuery {
64
64
  searchables: ['name', 'description']
65
65
  })
66
66
  .andWhere(`activity.startable = :startable`, { startable: true })
67
+ .andWhere(`activity.state = :state`, { state: ActivityStatus.Released })
67
68
  .andWhere(
68
69
  roles.length > 0
69
70
  ? new Brackets(qb => {
@@ -173,6 +173,13 @@ export class Activity {
173
173
  @Field({ nullable: true })
174
174
  updatedAt?: Date
175
175
 
176
+ @ManyToOne(type => User, { nullable: true })
177
+ @Field(type => User, { nullable: true, description: 'User assigned to the client application' })
178
+ client?: User
179
+
180
+ @RelationId((activity: Activity) => activity.creator)
181
+ clientId?: string
182
+
176
183
  @ManyToOne(type => User, { nullable: true })
177
184
  @Field(type => User, { nullable: true })
178
185
  creator?: User
@@ -1,8 +1,9 @@
1
1
  import { EventSubscriber, EntitySubscriberInterface, InsertEvent, UpdateEvent } from 'typeorm'
2
2
 
3
- import { pubsub } from '@things-factory/shell'
3
+ import { Domain, pubsub } from '@things-factory/shell'
4
4
 
5
5
  import { ActivityApproval } from './activity-approval'
6
+ import { callWebhook } from '../../controllers/call-webhook'
6
7
 
7
8
  @EventSubscriber()
8
9
  export class ActivityApprovalSubscriber implements EntitySubscriberInterface<ActivityApproval> {
@@ -10,19 +11,35 @@ export class ActivityApprovalSubscriber implements EntitySubscriberInterface<Act
10
11
  return ActivityApproval
11
12
  }
12
13
 
13
- afterInsert(event: InsertEvent<ActivityApproval>): Promise<any> | void {
14
- const activityApproval = event.entity
14
+ async afterInsert(event: InsertEvent<ActivityApproval>): Promise<any | void> {
15
+ const { manager: tx, entity } = event
16
+ const activityApproval = await tx.getRepository(ActivityApproval).findOne({
17
+ where: { id: entity.id },
18
+ relations: ['domain', 'activityThread']
19
+ })
15
20
 
16
21
  pubsub.publish('activity-approval', {
17
22
  activityApproval
18
23
  })
24
+
25
+ try {
26
+ callWebhook(activityApproval.domain, 'activity-approval-created', activityApproval, tx)
27
+ } catch (err) {}
19
28
  }
20
29
 
21
- afterUpdate(event: UpdateEvent<ActivityApproval>): Promise<any> | void {
22
- const activityApproval = event.entity
30
+ async afterUpdate(event: UpdateEvent<ActivityApproval>): Promise<any | void> {
31
+ const { manager: tx, entity } = event
32
+ const activityApproval = await tx.getRepository(ActivityApproval).findOne({
33
+ where: { id: entity.id },
34
+ relations: ['domain', 'activityThread']
35
+ })
23
36
 
24
37
  pubsub.publish('activity-approval', {
25
38
  activityApproval
26
39
  })
40
+
41
+ try {
42
+ callWebhook(activityApproval.domain, 'activity-approval-updated', activityApproval, tx)
43
+ } catch (err) {}
27
44
  }
28
45
  }
@@ -6,7 +6,7 @@ import { Domain, getQueryBuilderFromListParams, getRepository, ListParam } from
6
6
 
7
7
  import { ActivityThread } from '../activity-thread/activity-thread'
8
8
  import { Activity } from '../activity/activity'
9
- import { ActivityInstance, ActivityInstanceStatus } from './activity-instance'
9
+ import { ActivityInstance, ActivityInstanceStatus, AssigneeItem } from './activity-instance'
10
10
  import { ActivityInstanceList } from './activity-instance-type'
11
11
 
12
12
  @Resolver(ActivityInstance)
@@ -150,6 +150,49 @@ export class ActivityInstanceQuery {
150
150
  )
151
151
  }
152
152
 
153
+ @FieldResolver(type => [AssigneeItem])
154
+ async assignees(
155
+ @Root() activityInstance: ActivityInstance,
156
+ @Ctx() context: ResolverContext
157
+ ): Promise<AssigneeItem[]> {
158
+ const { domain, user } = context.state
159
+ const { assignees } = activityInstance
160
+
161
+ if (!assignees || !(assignees instanceof Array)) {
162
+ return null
163
+ }
164
+
165
+ var assigneeItemList = []
166
+
167
+ for (let item of assignees) {
168
+ var { type, value: id } = item
169
+ var assignee
170
+
171
+ switch (type) {
172
+ case 'Employee':
173
+ assignee = await getRepository('Employee').findOneBy({ domain: { id: domain.id }, id })
174
+ break
175
+ case 'Department':
176
+ assignee = await getRepository('Department').findOneBy({ domain: { id: domain.id }, id })
177
+ break
178
+ case 'Role':
179
+ assignee = await getRepository('Role').findOneBy({ domain: { id: domain.id }, id })
180
+ break
181
+ case 'Myself':
182
+ assignee = user
183
+ break
184
+ case 'MyDepartment':
185
+ case 'MySupervisor':
186
+ break
187
+ default:
188
+ }
189
+
190
+ assignee && assigneeItemList.push({ type, value: id, assignee })
191
+ }
192
+
193
+ return assigneeItemList
194
+ }
195
+
153
196
  @FieldResolver(type => Role)
154
197
  async supervisoryRole(@Root() activityInstance: ActivityInstance): Promise<Role> {
155
198
  return (
@@ -5,8 +5,7 @@ import { ObjectRef, ScalarDate, ScalarObject } from '@things-factory/shell'
5
5
  import { ApprovalLineItem } from '@things-factory/organization'
6
6
 
7
7
  import { ActivityType, ActivityUIType } from '../activity/activity'
8
- import { ActivityInstance, ActivityInstanceStatus } from './activity-instance'
9
-
8
+ import { AssigneeItem, ActivityInstance, ActivityInstanceStatus } from './activity-instance'
10
9
  @InputType()
11
10
  export class NewActivityInstance {
12
11
  @Field()
@@ -57,6 +56,9 @@ export class NewActivityInstance {
57
56
  @Field(type => ObjectRef, { nullable: true })
58
57
  assigneeRole?: Role
59
58
 
59
+ @Field(type => ScalarObject, { nullable: true })
60
+ assignees?: AssigneeItem[]
61
+
60
62
  @Field(type => ScalarObject, { nullable: true })
61
63
  approvalLine?: ApprovalLineItem[]
62
64
  }
@@ -114,8 +116,8 @@ export class ActivityInstancePost {
114
116
  @Field(type => ObjectRef, { nullable: true })
115
117
  assigneeRole?: Role
116
118
 
117
- @Field(type => [String], { nullable: true, description: 'Email of assignee users' })
118
- assignees?: string[]
119
+ @Field(type => ScalarObject, { nullable: true })
120
+ assignees?: AssigneeItem[]
119
121
 
120
122
  @Field(type => ScalarObject, { nullable: true })
121
123
  approvalLine?: ApprovalLineItem[]
@@ -126,6 +128,9 @@ export class ActivityInstanceSave {
126
128
  @Field(type => ScalarObject, { nullable: true })
127
129
  output?: { [key: string]: any }
128
130
 
131
+ @Field(type => ScalarObject, { nullable: true })
132
+ assignees?: AssigneeItem[]
133
+
129
134
  @Field(type => ScalarObject, { nullable: true })
130
135
  approvalLine?: ApprovalLineItem[]
131
136
  }
@@ -159,6 +164,9 @@ export class ActivityInstancePatch {
159
164
  @Field(type => ScalarObject, { nullable: true })
160
165
  input?: { [key: string]: any }
161
166
 
167
+ @Field(type => ScalarObject, { nullable: true })
168
+ assignees?: AssigneeItem[]
169
+
162
170
  @Field(type => ScalarObject, { nullable: true })
163
171
  approvalLine?: ApprovalLineItem[]
164
172
 
@@ -14,7 +14,7 @@ import {
14
14
 
15
15
  import { Role, User } from '@things-factory/auth-base'
16
16
  import { Domain, ScalarObject } from '@things-factory/shell'
17
- import { ApprovalLineItem } from '@things-factory/organization'
17
+ import { OrgMemberTargetType, OrgMemberTarget, ApprovalLineItem } from '@things-factory/organization'
18
18
 
19
19
  import { ActivityThread } from '../activity-thread/activity-thread'
20
20
  import { Activity, ActivityType, ActivityUIType } from '../activity/activity'
@@ -35,6 +35,18 @@ registerEnumType(ActivityInstanceStatus, {
35
35
  description: 'state enumeration of a activityInstance'
36
36
  })
37
37
 
38
+ @ObjectType()
39
+ export class AssigneeItem {
40
+ @Field(type => OrgMemberTargetType, { nullable: true })
41
+ type?: OrgMemberTargetType
42
+
43
+ @Field({ nullable: true })
44
+ value?: string
45
+
46
+ @Field(type => OrgMemberTarget, { nullable: true })
47
+ assignee?: OrgMemberTarget
48
+ }
49
+
38
50
  @Entity()
39
51
  @Index(
40
52
  'ix_activity_instance_0',
@@ -152,6 +164,10 @@ export class ActivityInstance {
152
164
  @Field({ nullable: true })
153
165
  transaction?: string
154
166
 
167
+ @Column('simple-json', { nullable: true })
168
+ @Field(type => [AssigneeItem], { nullable: true })
169
+ assignees?: AssigneeItem[]
170
+
155
171
  @Column('simple-json', { nullable: true })
156
172
  @Field(type => [ApprovalLineItem], { nullable: true })
157
173
  approvalLine?: ApprovalLineItem[]
@@ -4,6 +4,7 @@ export * from './activity-thread/activity-thread'
4
4
  export * from './activity-template/activity-template'
5
5
  export * from './activity-instance/activity-instance'
6
6
  export * from './activity/activity'
7
+ export * from './installable-activity/installable-activity'
7
8
  export * from './activity-summary/activity-summary'
8
9
 
9
10
  /* IMPORT ENTITIES AND RESOLVERS */
@@ -28,6 +29,10 @@ import {
28
29
  resolvers as ActivityThreadResolvers,
29
30
  subscribers as ActivityThreadSubscribers
30
31
  } from './activity-thread'
32
+ import {
33
+ entities as InstallableActivityEntities,
34
+ resolvers as InstallableActivityResolvers
35
+ } from './installable-activity'
31
36
  import { entities as ActivitySummaryEntities, resolvers as ActivitySummaryResolvers } from './activity-summary'
32
37
 
33
38
  export const entities = [
@@ -37,6 +42,7 @@ export const entities = [
37
42
  ...ActivityInstanceEntities,
38
43
  ...ActivityTemplateEntities,
39
44
  ...ActivityThreadEntities,
45
+ ...InstallableActivityEntities,
40
46
  ...ActivitySummaryEntities
41
47
  ]
42
48
 
@@ -56,6 +62,7 @@ export const schema = {
56
62
  ...ActivityInstanceResolvers,
57
63
  ...ActivityTemplateResolvers,
58
64
  ...ActivityThreadResolvers,
65
+ ...InstallableActivityResolvers,
59
66
  ...ActivitySummaryResolvers
60
67
  ]
61
68
  }
@@ -0,0 +1,7 @@
1
+ import { InstallableActivity } from './installable-activity'
2
+ import { InstallableActivityQuery } from './installable-activity-query'
3
+ import { InstallableActivityMutation } from './installable-activity-mutation'
4
+
5
+ export const entities = [InstallableActivity]
6
+ export const resolvers = [InstallableActivityQuery, InstallableActivityMutation]
7
+ export const subscribers = []
@@ -0,0 +1,61 @@
1
+ import { Arg, Ctx, Directive, Mutation, Resolver } from 'type-graphql'
2
+
3
+ import { ActivityInstallations } from '../../controllers/activity-installation-controller'
4
+ import { Activity, ActivityStatus } from '../activity/activity'
5
+ import { InstallableActivity } from './installable-activity'
6
+
7
+ @Resolver(InstallableActivity)
8
+ export class InstallableActivityMutation {
9
+ @Directive('@transaction')
10
+ @Mutation(returns => Activity, { description: 'To activate installable activity to Activity on given domain' })
11
+ async activateInstallableActivity(@Arg('name') name: string, @Ctx() context: ResolverContext): Promise<Activity> {
12
+ const { domain, user, tx } = context.state
13
+ const installableActivity = ActivityInstallations.get(name)
14
+ const repository = tx.getRepository(Activity)
15
+
16
+ const activity = await repository.findOneBy({
17
+ domain: { id: domain.id },
18
+ name
19
+ })
20
+
21
+ if (!activity) {
22
+ return await repository.save({
23
+ ...(installableActivity as any),
24
+ state: ActivityStatus.Released,
25
+ domain,
26
+ creator: user,
27
+ updater: user
28
+ })
29
+ } else {
30
+ return await repository.save({
31
+ ...activity,
32
+ ...(installableActivity as any),
33
+ state: ActivityStatus.Released,
34
+ domain,
35
+ updater: user
36
+ })
37
+ }
38
+ }
39
+
40
+ @Directive('@transaction')
41
+ @Mutation(returns => Activity, { description: 'To deactivate installable activity to Activity on given domain' })
42
+ async deactivateInstallableActivity(@Arg('name') name: string, @Ctx() context: ResolverContext): Promise<Activity> {
43
+ const { domain, user, tx } = context.state
44
+ const repository = tx.getRepository(Activity)
45
+
46
+ const activity = await repository.findOneBy({
47
+ domain: { id: domain.id },
48
+ name
49
+ })
50
+
51
+ if (!activity) {
52
+ return
53
+ }
54
+
55
+ return await repository.save({
56
+ ...activity,
57
+ state: ActivityStatus.Deprecated,
58
+ updater: user
59
+ })
60
+ }
61
+ }
@@ -0,0 +1,36 @@
1
+ import { Arg, Args, Ctx, Query, Resolver, FieldResolver, Root } from 'type-graphql'
2
+ import { Domain, getRepository, ListParam } from '@things-factory/shell'
3
+
4
+ import { ActivityInstallations } from '../../controllers/activity-installation-controller'
5
+ import { Activity } from '../activity/activity'
6
+ import { InstallableActivity } from './installable-activity'
7
+ import { InstallableActivityList } from './installable-activity-type'
8
+
9
+ @Resolver(InstallableActivity)
10
+ export class InstallableActivityQuery {
11
+ @Query(returns => InstallableActivity!, { nullable: true, description: 'To fetch a InstallableActivity' })
12
+ async installableActivity(@Arg('name') name: string, @Ctx() context: ResolverContext): Promise<InstallableActivity> {
13
+ return await ActivityInstallations.get(name)
14
+ }
15
+
16
+ @Query(returns => InstallableActivityList, { description: 'To fetch multiple InstallableActivitys' })
17
+ async installableActivities(
18
+ @Args() params: ListParam,
19
+ @Ctx() context: ResolverContext
20
+ ): Promise<InstallableActivityList> {
21
+ const { domain } = context.state
22
+
23
+ const items = ActivityInstallations.list()
24
+
25
+ for (var item of items) {
26
+ item.activity = await getRepository(Activity).findOneBy({
27
+ domain: { id: domain.id },
28
+ name: item.name
29
+ })
30
+ }
31
+
32
+ const total = items.length
33
+
34
+ return { items, total }
35
+ }
36
+ }
@@ -0,0 +1,12 @@
1
+ import { Field, Int, ObjectType } from 'type-graphql'
2
+
3
+ import { InstallableActivity } from './installable-activity'
4
+
5
+ @ObjectType()
6
+ export class InstallableActivityList {
7
+ @Field(type => [InstallableActivity])
8
+ items: InstallableActivity[]
9
+
10
+ @Field(type => Int)
11
+ total: number
12
+ }