@things-factory/process 8.0.0-beta.9 → 8.0.0

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 (62) hide show
  1. package/client/actions/main.ts +1 -0
  2. package/client/bootstrap.ts +8 -0
  3. package/client/index.ts +1 -0
  4. package/client/pages/event/event-importer.ts +86 -0
  5. package/client/pages/event/event-list-page.ts +324 -0
  6. package/client/pages/gateway/gateway-importer.ts +87 -0
  7. package/client/pages/gateway/gateway-list-page.ts +323 -0
  8. package/client/pages/main.ts +25 -0
  9. package/client/pages/process/process-importer.ts +87 -0
  10. package/client/pages/process/process-list-page.ts +324 -0
  11. package/client/pages/process-instance/process-instance-importer.ts +87 -0
  12. package/client/pages/process-instance/process-instance-list-page.ts +323 -0
  13. package/client/pages/process-thread/process-thread-importer.ts +87 -0
  14. package/client/pages/process-thread/process-thread-list-page.ts +323 -0
  15. package/client/reducers/main.ts +17 -0
  16. package/client/route.ts +27 -0
  17. package/client/tsconfig.json +13 -0
  18. package/dist-client/tsconfig.tsbuildinfo +1 -1
  19. package/dist-server/tsconfig.tsbuildinfo +1 -1
  20. package/package.json +14 -14
  21. package/server/controllers/common.ts +90 -0
  22. package/server/controllers/index.ts +0 -0
  23. package/server/controllers/process-instance/abort.ts +75 -0
  24. package/server/controllers/process-instance/end.ts +74 -0
  25. package/server/controllers/process-instance/index.ts +2 -0
  26. package/server/controllers/process-thread/_abort.ts +20 -0
  27. package/server/controllers/process-thread/abort.ts +48 -0
  28. package/server/controllers/process-thread/end.ts +54 -0
  29. package/server/controllers/process-thread/index.ts +3 -0
  30. package/server/controllers/process-thread/start.ts +49 -0
  31. package/server/index.ts +4 -0
  32. package/server/middlewares/index.ts +3 -0
  33. package/server/migrations/index.ts +9 -0
  34. package/server/routes.ts +80 -0
  35. package/server/service/index.ts +44 -0
  36. package/server/service/process/event-subscriber.ts +17 -0
  37. package/server/service/process/index.ts +9 -0
  38. package/server/service/process/process-history.ts +108 -0
  39. package/server/service/process/process-mutation.ts +210 -0
  40. package/server/service/process/process-query.ts +120 -0
  41. package/server/service/process/process-search-key-item-type.ts +16 -0
  42. package/server/service/process/process-type.ts +65 -0
  43. package/server/service/process/process.ts +97 -0
  44. package/server/service/process-instance/event-subscriber.ts +44 -0
  45. package/server/service/process-instance/index.ts +10 -0
  46. package/server/service/process-instance/process-instance-history.ts +154 -0
  47. package/server/service/process-instance/process-instance-mutation.ts +33 -0
  48. package/server/service/process-instance/process-instance-query.ts +141 -0
  49. package/server/service/process-instance/process-instance-subscription.ts +46 -0
  50. package/server/service/process-instance/process-instance-type.ts +71 -0
  51. package/server/service/process-instance/process-instance.ts +147 -0
  52. package/server/service/process-stats/index.ts +3 -0
  53. package/server/service/process-stats/process-stats-query.ts +57 -0
  54. package/server/service/process-stats/process-stats-type.ts +31 -0
  55. package/server/service/process-thread/event-subscriber.ts +31 -0
  56. package/server/service/process-thread/index.ts +9 -0
  57. package/server/service/process-thread/process-thread-mutation.ts +34 -0
  58. package/server/service/process-thread/process-thread-query.ts +61 -0
  59. package/server/service/process-thread/process-thread-subscription.ts +42 -0
  60. package/server/service/process-thread/process-thread-type.ts +15 -0
  61. package/server/service/process-thread/process-thread.ts +90 -0
  62. package/server/tsconfig.json +10 -0
@@ -0,0 +1,154 @@
1
+ import { Field, ID, Int, ObjectType } from 'type-graphql'
2
+ import { Column, Entity, Index, ManyToOne, PrimaryGeneratedColumn, RelationId } from 'typeorm'
3
+
4
+ import {
5
+ HistoryActionColumn,
6
+ HistoryActionType,
7
+ HistoryEntityInterface,
8
+ HistoryOriginalIdColumn
9
+ } from '@operato/typeorm-history'
10
+ import { Role, User } from '@things-factory/auth-base'
11
+ import { config } from '@things-factory/env'
12
+ import { Domain, ScalarObject } from '@things-factory/shell'
13
+
14
+ import { ProcessInstance, ProcessInstanceStatus } from './process-instance'
15
+
16
+ const ORMCONFIG = config.get('ormconfig', {})
17
+ const DATABASE_TYPE = ORMCONFIG.type
18
+
19
+ @Entity()
20
+ @Index(
21
+ 'ix_process_instance_history_0',
22
+ (processInstanceHistory: ProcessInstanceHistory) => [
23
+ processInstanceHistory.originalId,
24
+ processInstanceHistory.version
25
+ ],
26
+ { unique: true }
27
+ )
28
+ @Index(
29
+ 'ix_process_instance_history_1',
30
+ (processInstanceHistory: ProcessInstanceHistory) => [
31
+ processInstanceHistory.domain,
32
+ processInstanceHistory.originalId,
33
+ processInstanceHistory.version
34
+ ],
35
+ { unique: true }
36
+ )
37
+ @ObjectType({ description: 'History Entity of ProcessInstance' })
38
+ export class ProcessInstanceHistory implements HistoryEntityInterface<ProcessInstance> {
39
+ @PrimaryGeneratedColumn('uuid')
40
+ @Field(type => ID)
41
+ readonly id: string
42
+
43
+ @Column({
44
+ nullable: true,
45
+ default: 1
46
+ })
47
+ @Field({ nullable: true })
48
+ version?: number = 1
49
+
50
+ @ManyToOne(type => Domain)
51
+ @Field(type => Domain)
52
+ domain?: Domain
53
+
54
+ @RelationId((processInstance: ProcessInstance) => processInstance.domain)
55
+ domainId?: string
56
+
57
+ @Column()
58
+ @Field({ nullable: true })
59
+ name?: string
60
+
61
+ @Column({ nullable: true })
62
+ @Field({ nullable: true })
63
+ description?: string
64
+
65
+ @Column({ nullable: true, default: '' })
66
+ @Field({ nullable: true })
67
+ key01?: string = ''
68
+
69
+ @Column({ nullable: true, default: '' })
70
+ @Field({ nullable: true })
71
+ key02?: string = ''
72
+
73
+ @Column({ nullable: true, default: '' })
74
+ @Field({ nullable: true })
75
+ key03?: string = ''
76
+
77
+ @Column({ nullable: true, default: '' })
78
+ @Field({ nullable: true })
79
+ key04?: string = ''
80
+
81
+ @Column({ nullable: true, default: '' })
82
+ @Field({ nullable: true })
83
+ key05?: string = ''
84
+
85
+ @Column({ nullable: true })
86
+ @Field({ nullable: true })
87
+ state?: ProcessInstanceStatus
88
+
89
+ @Column({ nullable: true })
90
+ @Field({ nullable: true })
91
+ reason?: string
92
+
93
+ @Column({ nullable: true })
94
+ @Field({ nullable: true })
95
+ refBy?: string
96
+
97
+ @ManyToOne(type => Role, { nullable: true })
98
+ @Field(type => Role, { nullable: true })
99
+ supervisoryRole?: Role
100
+
101
+ @RelationId((processInstance: ProcessInstance) => processInstance.supervisoryRole)
102
+ supervisoryRoleId?: string
103
+
104
+ @Column({ nullable: true })
105
+ @Field({ nullable: true })
106
+ dueAt?: Date
107
+
108
+ @Column()
109
+ @Field({ nullable: true })
110
+ createdAt?: Date
111
+
112
+ @Column()
113
+ @Field({ nullable: true })
114
+ updatedAt?: Date
115
+
116
+ @Column({ nullable: true })
117
+ @Field({ nullable: true })
118
+ terminatedAt?: Date
119
+
120
+ @ManyToOne(type => User, { nullable: true })
121
+ @Field(type => User, { nullable: true })
122
+ creator?: User
123
+
124
+ @RelationId((processInstance: ProcessInstance) => processInstance.creator)
125
+ creatorId?: string
126
+
127
+ @ManyToOne(type => User, { nullable: true })
128
+ @Field(type => User, { nullable: true })
129
+ updater?: User
130
+
131
+ @RelationId((processInstance: ProcessInstance) => processInstance.updater)
132
+ updaterId?: string
133
+
134
+ @HistoryOriginalIdColumn()
135
+ public originalId!: string
136
+
137
+ @HistoryActionColumn({
138
+ nullable: false,
139
+ type:
140
+ DATABASE_TYPE == 'postgres' || DATABASE_TYPE == 'mysql' || DATABASE_TYPE == 'mariadb'
141
+ ? 'enum'
142
+ : DATABASE_TYPE == 'oracle'
143
+ ? 'varchar2'
144
+ : DATABASE_TYPE == 'mssql'
145
+ ? 'nvarchar'
146
+ : 'varchar',
147
+ enum:
148
+ DATABASE_TYPE == 'postgres' || DATABASE_TYPE == 'mysql' || DATABASE_TYPE == 'mariadb'
149
+ ? HistoryActionType
150
+ : undefined,
151
+ length: DATABASE_TYPE == 'postgres' || DATABASE_TYPE == 'mysql' || DATABASE_TYPE == 'mariadb' ? undefined : 10
152
+ })
153
+ public action!: HistoryActionType
154
+ }
@@ -0,0 +1,33 @@
1
+ import { Arg, Ctx, Directive, Mutation, Resolver } from 'type-graphql'
2
+
3
+ import { ScalarObject } from '@things-factory/shell'
4
+
5
+ import { abort, end } from '../../controllers/process-instance'
6
+ import { ProcessInstance } from './process-instance'
7
+ import { ProcessInstanceIssue, ProcessInstanceDraft } from './process-instance-type'
8
+
9
+ @Resolver(ProcessInstance)
10
+ export class ProcessInstanceMutation {
11
+ @Directive('@transaction')
12
+ @Directive('@privilege(category: "process", privilege: "mutation", domainOwnerGranted: true)')
13
+ @Mutation(returns => ProcessInstance, { description: 'To end a ProcessInstance' })
14
+ async endProcessInstance(
15
+ @Arg('id') id: string,
16
+ @Arg('output', type => ScalarObject, { nullable: true }) output: { [key: string]: any },
17
+ @Arg('reason', { nullable: true }) reason: string,
18
+ @Ctx() context: ResolverContext
19
+ ): Promise<ProcessInstance> {
20
+ return await end({ id, output, reason }, context)
21
+ }
22
+
23
+ @Directive('@transaction')
24
+ @Directive('@privilege(category: "process", privilege: "mutation", domainOwnerGranted: true)')
25
+ @Mutation(returns => ProcessInstance, { description: 'To abort a ProcessInstance' })
26
+ async abortProcessInstance(
27
+ @Arg('id') id: string,
28
+ @Arg('reason', { nullable: true }) reason: string,
29
+ @Ctx() context: ResolverContext
30
+ ): Promise<ProcessInstance> {
31
+ return await abort({ id, reason }, context)
32
+ }
33
+ }
@@ -0,0 +1,141 @@
1
+ import { Arg, Args, Ctx, Directive, FieldResolver, Query, Resolver, Root } from 'type-graphql'
2
+
3
+ import { Attachment } from '@things-factory/attachment-base'
4
+ import { Role, User } from '@things-factory/auth-base'
5
+ import { Domain, getQueryBuilderFromListParams, getRepository, ListParam } from '@things-factory/shell'
6
+
7
+ import { ProcessThread } from '../process-thread/process-thread'
8
+ import { Process } from '../process/process'
9
+ import { ProcessInstance, ProcessInstanceStatus } from './process-instance'
10
+ import { ProcessInstanceList } from './process-instance-type'
11
+
12
+ @Resolver(ProcessInstance)
13
+ export class ProcessInstanceQuery {
14
+ @Directive('@privilege(category: "process-instance", privilege: "query", domainOwnerGranted: true)')
15
+ @Query(returns => ProcessInstance!, { nullable: true, description: 'To fetch a ProcessInstance' })
16
+ async processInstance(@Arg('id') id: string, @Ctx() context: ResolverContext): Promise<ProcessInstance> {
17
+ const { domain } = context.state
18
+
19
+ return await getRepository(ProcessInstance).findOne({
20
+ where: { domain: { id: domain.id }, id }
21
+ })
22
+ }
23
+
24
+ @Directive('@privilege(category: "process-instance", privilege: "query", domainOwnerGranted: true)')
25
+ @Query(returns => ProcessInstanceList, { description: 'To fetch multiple ProcessInstances' })
26
+ async processInstances(
27
+ @Args(type => ListParam) params: ListParam,
28
+ @Ctx() context: ResolverContext
29
+ ): Promise<ProcessInstanceList> {
30
+ const { domain } = context.state
31
+
32
+ const [items, total] = await getQueryBuilderFromListParams({
33
+ domain,
34
+ params,
35
+ repository: getRepository(ProcessInstance),
36
+ searchables: ['name', 'description']
37
+ }).getManyAndCount()
38
+
39
+ return { items, total }
40
+ }
41
+
42
+ @Directive('@privilege(category: "process-instance", privilege: "query", domainOwnerGranted: true)')
43
+ @Query(returns => ProcessInstanceList, { description: 'To fetch multiple process instances by process' })
44
+ async processInstancesByProcess(
45
+ @Arg('processId') processId: string,
46
+ @Args(type => ListParam) params: ListParam,
47
+ @Ctx() context: ResolverContext
48
+ ): Promise<ProcessInstanceList> {
49
+ const { domain } = context.state
50
+
51
+ const process = await getRepository(Process).findOneBy({ id: processId })
52
+ const searchables = process?.searchKeys?.map((item, index) => `key0${index + 1}`) || []
53
+
54
+ const queryBuilder = getQueryBuilderFromListParams({
55
+ repository: getRepository(ProcessInstance),
56
+ params,
57
+ domain,
58
+ alias: 'pi',
59
+ searchables: ['name', 'description'].concat(searchables)
60
+ }).where('pi.process = :process', { process: processId })
61
+
62
+ const [items, total] = await queryBuilder.getManyAndCount()
63
+
64
+ return { items, total }
65
+ }
66
+
67
+ @FieldResolver(type => Process)
68
+ async process(@Root() processInstance: ProcessInstance): Promise<Process> {
69
+ const { processId } = processInstance
70
+
71
+ return await getRepository(Process).findOneBy({ id: processId })
72
+ }
73
+
74
+ @FieldResolver(type => [ProcessThread])
75
+ async processThreads(
76
+ @Root() processInstance: ProcessInstance,
77
+ @Ctx() context: ResolverContext
78
+ ): Promise<ProcessThread[]> {
79
+ const { user } = context.state
80
+ const { supervisoryRoleId } = processInstance
81
+
82
+ if (supervisoryRoleId) {
83
+ /* only user having supervisoryRole can get whole processThreads */
84
+ const roles = (
85
+ (await getRepository(User).findOne({
86
+ where: { id: user.id },
87
+ relations: ['roles']
88
+ })) as User
89
+ ).roles.map(role => role.id)
90
+
91
+ if (!roles.includes(supervisoryRoleId)) {
92
+ return
93
+ }
94
+ }
95
+
96
+ return await getRepository(ProcessThread).findBy({
97
+ processInstance: { id: processInstance.id }
98
+ })
99
+ }
100
+
101
+ @FieldResolver(type => Role)
102
+ async supervisoryRole(@Root() processInstance: ProcessInstance): Promise<Role> {
103
+ return (
104
+ processInstance.supervisoryRole ||
105
+ (processInstance.supervisoryRoleId &&
106
+ (await getRepository(Role).findOneBy({
107
+ id: processInstance.supervisoryRoleId
108
+ })))
109
+ )
110
+ }
111
+
112
+ @FieldResolver(type => String)
113
+ async thumbnail(@Root() processInstance: ProcessInstance): Promise<string | undefined> {
114
+ const { processId } = processInstance
115
+ const attachment: Attachment =
116
+ processId &&
117
+ (await getRepository(Attachment).findOne({
118
+ where: {
119
+ domain: { id: processInstance.domainId },
120
+ refBy: processId
121
+ }
122
+ }))
123
+
124
+ return attachment?.fullpath
125
+ }
126
+
127
+ @FieldResolver(type => Domain)
128
+ async domain(@Root() processInstance: ProcessInstance): Promise<Domain> {
129
+ return await getRepository(Domain).findOneBy({ id: processInstance.domainId })
130
+ }
131
+
132
+ @FieldResolver(type => User)
133
+ async updater(@Root() processInstance: ProcessInstance): Promise<User> {
134
+ return processInstance.updaterId && (await getRepository(User).findOneBy({ id: processInstance.updaterId }))
135
+ }
136
+
137
+ @FieldResolver(type => User)
138
+ async creator(@Root() processInstance: ProcessInstance): Promise<User> {
139
+ return processInstance.creatorId && (await getRepository(User).findOneBy({ id: processInstance.creatorId }))
140
+ }
141
+ }
@@ -0,0 +1,46 @@
1
+ import { filter, pipe } from 'graphql-yoga'
2
+ import { Resolver, Root, Subscription } from 'type-graphql'
3
+
4
+ import { pubsub } from '@things-factory/shell'
5
+ import { User } from '@things-factory/auth-base'
6
+
7
+ import { ProcessInstance } from './process-instance'
8
+
9
+ @Resolver(ProcessInstance)
10
+ export class ProcessInstanceSubscription {
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 pipe(
25
+ pubsub.subscribe('process-instance'),
26
+ filter(async (payload: { processInstance: ProcessInstance }) => {
27
+ const { processInstance } = payload
28
+ const { domainId } = processInstance
29
+
30
+ if (domainId !== domain?.id) {
31
+ return false
32
+ }
33
+
34
+ if (processInstance.creatorId === user.id) {
35
+ return true
36
+ }
37
+
38
+ return await User.hasPrivilege('query', 'process-instance', domain, user)
39
+ })
40
+ )
41
+ }
42
+ })
43
+ processInstance(@Root() payload: { processInstance: ProcessInstance }): ProcessInstance {
44
+ return payload.processInstance
45
+ }
46
+ }
@@ -0,0 +1,71 @@
1
+ import { Field, ID, InputType, Int, ObjectType } from 'type-graphql'
2
+
3
+ import { Role } from '@things-factory/auth-base'
4
+ import { ObjectRef, ScalarDate, ScalarObject } from '@things-factory/shell'
5
+ import { ProcessInstance } from './process-instance'
6
+
7
+ @InputType()
8
+ export class ProcessInstanceDraft {
9
+ @Field(type => ID, { nullable: true })
10
+ id?: string
11
+
12
+ @Field()
13
+ name: string
14
+
15
+ @Field({ nullable: true })
16
+ processId: string
17
+
18
+ @Field({ nullable: true })
19
+ description?: string
20
+
21
+ @Field({ nullable: true })
22
+ reason?: string
23
+
24
+ @Field(type => ScalarDate, { nullable: true })
25
+ dueAt?: Date
26
+
27
+ @Field({ nullable: true })
28
+ refBy?: string
29
+
30
+ @Field(type => ObjectRef, { nullable: true })
31
+ supervisoryRole?: Role
32
+ }
33
+
34
+ @InputType()
35
+ export class ProcessInstanceIssue {
36
+ @Field(type => ID, { nullable: true })
37
+ id?: string
38
+
39
+ @Field({ nullable: true })
40
+ name?: string
41
+
42
+ @Field({ nullable: true })
43
+ processId?: string
44
+
45
+ @Field({ nullable: true })
46
+ description?: string
47
+
48
+ @Field({ nullable: true })
49
+ reason?: string
50
+
51
+ @Field(type => ScalarDate, { nullable: true })
52
+ dueAt?: Date
53
+
54
+ @Field({ nullable: true })
55
+ refBy?: string
56
+
57
+ @Field({ nullable: true })
58
+ viewSource?: string
59
+
60
+ @Field(type => ObjectRef, { nullable: true })
61
+ supervisoryRole?: Role
62
+ }
63
+
64
+ @ObjectType()
65
+ export class ProcessInstanceList {
66
+ @Field(type => [ProcessInstance])
67
+ items: ProcessInstance[]
68
+
69
+ @Field(type => Int)
70
+ total: number
71
+ }
@@ -0,0 +1,147 @@
1
+ import { Field, ID, Int, ObjectType, registerEnumType } from 'type-graphql'
2
+ import {
3
+ Column,
4
+ CreateDateColumn,
5
+ Entity,
6
+ Index,
7
+ ManyToOne,
8
+ OneToMany,
9
+ PrimaryGeneratedColumn,
10
+ RelationId,
11
+ UpdateDateColumn,
12
+ VersionColumn
13
+ } from 'typeorm'
14
+
15
+ import { Role, User } from '@things-factory/auth-base'
16
+ import { Domain, ScalarObject } from '@things-factory/shell'
17
+
18
+ import { ProcessThread } from '../process-thread/process-thread'
19
+ import { Process } from '../process/process'
20
+
21
+ export enum ProcessInstanceStatus {
22
+ Started = 'started',
23
+ Pending = 'pending',
24
+ Ended = 'ended',
25
+ Aborted = 'aborted'
26
+ }
27
+
28
+ registerEnumType(ProcessInstanceStatus, {
29
+ name: 'ProcessInstanceStatus',
30
+ description: 'state enumeration of a process instance'
31
+ })
32
+
33
+ @Entity()
34
+ @Index('ix_process_instance_0', (processInstance: ProcessInstance) => [processInstance.domain, processInstance.name], {
35
+ unique: false
36
+ })
37
+ @Index('ix_process_instance_1', (processInstance: ProcessInstance) => [processInstance.domain, processInstance.state], {
38
+ unique: false
39
+ })
40
+ @ObjectType({ description: 'Entity for ProcessInstance' })
41
+ export class ProcessInstance {
42
+ @PrimaryGeneratedColumn('uuid')
43
+ @Field(type => ID)
44
+ readonly id: string
45
+
46
+ @VersionColumn()
47
+ @Field({ nullable: true })
48
+ version?: number = 1
49
+
50
+ @ManyToOne(type => Domain)
51
+ @Field(type => Domain)
52
+ domain?: Domain
53
+
54
+ @RelationId((processInstance: ProcessInstance) => processInstance.domain)
55
+ domainId?: string
56
+
57
+ @Column()
58
+ @Field({ nullable: true })
59
+ name?: string
60
+
61
+ @Column({ nullable: true })
62
+ @Field({ nullable: true })
63
+ description?: string
64
+
65
+ @Column({ nullable: true, default: '' })
66
+ @Field({ nullable: true })
67
+ key01?: string = ''
68
+
69
+ @Column({ nullable: true, default: '' })
70
+ @Field({ nullable: true })
71
+ key02?: string = ''
72
+
73
+ @Column({ nullable: true, default: '' })
74
+ @Field({ nullable: true })
75
+ key03?: string = ''
76
+
77
+ @Column({ nullable: true, default: '' })
78
+ @Field({ nullable: true })
79
+ key04?: string = ''
80
+
81
+ @Column({ nullable: true, default: '' })
82
+ @Field({ nullable: true })
83
+ key05?: string = ''
84
+
85
+ @OneToMany(type => ProcessThread, processThread => processThread.processInstance)
86
+ @Field(type => [ProcessThread])
87
+ processThreads?: ProcessThread[]
88
+
89
+ @Column({ nullable: true })
90
+ @Field({ nullable: true })
91
+ state?: ProcessInstanceStatus
92
+
93
+ @Column({ nullable: true })
94
+ @Field({ nullable: true })
95
+ reason?: string
96
+
97
+ @Column({ nullable: true })
98
+ @Field({ nullable: true })
99
+ refBy?: string
100
+
101
+ @ManyToOne(type => Process, { nullable: true })
102
+ @Field(type => Process, { nullable: true })
103
+ process?: Process
104
+
105
+ @RelationId((processInstance: ProcessInstance) => processInstance.process)
106
+ processId?: string
107
+
108
+ @ManyToOne(type => Role, { nullable: true })
109
+ @Field(type => Role, { nullable: true })
110
+ supervisoryRole?: Role
111
+
112
+ @RelationId((processInstance: ProcessInstance) => processInstance.supervisoryRole)
113
+ supervisoryRoleId?: string
114
+
115
+ @Column({ nullable: true })
116
+ @Field({ nullable: true })
117
+ dueAt?: Date
118
+
119
+ @CreateDateColumn()
120
+ @Field({ nullable: true })
121
+ createdAt?: Date
122
+
123
+ @UpdateDateColumn()
124
+ @Field({ nullable: true })
125
+ updatedAt?: Date
126
+
127
+ @Column({ nullable: true })
128
+ @Field({ nullable: true })
129
+ terminatedAt?: Date
130
+
131
+ @ManyToOne(type => User, { nullable: true })
132
+ @Field(type => User, { nullable: true })
133
+ creator?: User
134
+
135
+ @RelationId((processInstance: ProcessInstance) => processInstance.creator)
136
+ creatorId?: string
137
+
138
+ @ManyToOne(type => User, { nullable: true })
139
+ @Field(type => User, { nullable: true })
140
+ updater?: User
141
+
142
+ @RelationId((processInstance: ProcessInstance) => processInstance.updater)
143
+ updaterId?: string
144
+
145
+ @Field(type => String, { nullable: true })
146
+ thumbnail?: string
147
+ }
@@ -0,0 +1,3 @@
1
+ import { ProcessStatsQuery } from './process-stats-query'
2
+
3
+ export const resolvers = [ProcessStatsQuery]
@@ -0,0 +1,57 @@
1
+ import { Resolver, Query, FieldResolver, Root, Args, Arg, Ctx, Directive } from 'type-graphql'
2
+ import { Domain, getQueryBuilderFromListParams, getRepository, ListParam } from '@things-factory/shell'
3
+ import { User } from '@things-factory/auth-base'
4
+ import { ProcessEvent, ProcessEventStatus } from './process-stats-type'
5
+ import { ProcessThread, ProcessThreadStatus } from '../process-thread/process-thread'
6
+
7
+ @Resolver(ProcessStatsQuery)
8
+ export class ProcessStatsQuery {
9
+ @Query(returns => [ProcessEvent], { description: 'To fetch process events by period' })
10
+ async processEvents(
11
+ @Arg('from') from: string,
12
+ @Arg('to') to: string,
13
+ @Ctx() context: ResolverContext
14
+ ): Promise<ProcessEvent[]> {
15
+ const { domain, user } = context.state
16
+
17
+ if (!from) {
18
+ const beginOfToday = new Date()
19
+ beginOfToday.setHours(0, 0, 0, 0)
20
+ from = beginOfToday.toISOString().split('T').join(' ')
21
+ }
22
+
23
+ if (!to) {
24
+ const endOfToday = new Date()
25
+ endOfToday.setDate(endOfToday.getDate() + 1)
26
+ endOfToday.setHours(0, 0, 0, 0)
27
+ to = endOfToday.toISOString().split('T').join(' ')
28
+ }
29
+
30
+ const status = [ProcessThreadStatus.Ended, ProcessThreadStatus.Aborted]
31
+
32
+ var params = { filters: [{ name: 'terminatedAt', operator: 'between', value: [from, to] }] }
33
+
34
+ var doneItems = await getQueryBuilderFromListParams({
35
+ repository: getRepository(ProcessThread),
36
+ params,
37
+ domain,
38
+ alias: 'at'
39
+ })
40
+ .leftJoinAndSelect('at.processInstance', 'ai')
41
+ .andWhere('at.state IN (:...status)', { status })
42
+ .andWhere('at.assignee = :user', { user: user.id })
43
+ .getMany()
44
+
45
+ const processThreadDoneEvents = doneItems.map(({ id, processInstance, terminatedAt }) => {
46
+ return {
47
+ id,
48
+ name: processInstance.name,
49
+ date: terminatedAt,
50
+ state: ProcessEventStatus.Done,
51
+ type: 'process-thread'
52
+ }
53
+ })
54
+
55
+ return [...processThreadDoneEvents]
56
+ }
57
+ }
@@ -0,0 +1,31 @@
1
+ import { ObjectType, Field, Int, ID, registerEnumType } from 'type-graphql'
2
+
3
+ export enum ProcessEventStatus {
4
+ Done = 'done',
5
+ Pending = 'pending',
6
+ Approved = 'approved',
7
+ Rejected = 'rejected'
8
+ }
9
+
10
+ registerEnumType(ProcessEventStatus, {
11
+ name: 'ProcessEventStatus',
12
+ description: 'state enumeration of a Process Event'
13
+ })
14
+
15
+ @ObjectType()
16
+ export class ProcessEvent {
17
+ @Field({ nullable: true })
18
+ id?: string
19
+
20
+ @Field({ nullable: true })
21
+ name?: string
22
+
23
+ @Field({ nullable: true })
24
+ type?: string
25
+
26
+ @Field({ nullable: true })
27
+ state?: ProcessEventStatus
28
+
29
+ @Field({ nullable: true })
30
+ date?: Date
31
+ }