@things-factory/kpi 9.1.19 → 10.0.0-beta.2

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 (140) hide show
  1. package/client/pages/kpi/kpi-list-page.ts +339 -525
  2. package/client/pages/kpi/kpi-tree-page.ts +135 -207
  3. package/client/pages/kpi-metric/kpi-metric-list-page.ts +146 -226
  4. package/client/pages/kpi-metric-value/kpi-metric-value-editor-page.ts +187 -295
  5. package/client/pages/kpi-metric-value/kpi-metric-value-list-page.ts +123 -194
  6. package/client/pages/kpi-metric-value/kpi-metric-value-manual-entry-page.ts +57 -91
  7. package/client/pages/kpi-statistic/kpi-statistic-editor-page.ts +180 -278
  8. package/client/pages/kpi-statistic/kpi-statistic-list-page.ts +186 -286
  9. package/client/pages/kpi-value/kpi-value-editor-page.ts +189 -292
  10. package/client/pages/kpi-value/kpi-value-list-page.ts +170 -264
  11. package/dist-client/pages/kpi/kpi-list-page.d.ts +0 -6
  12. package/dist-client/pages/kpi/kpi-list-page.js +150 -282
  13. package/dist-client/pages/kpi/kpi-list-page.js.map +1 -1
  14. package/dist-client/pages/kpi/kpi-tree-page.d.ts +1 -7
  15. package/dist-client/pages/kpi/kpi-tree-page.js +76 -127
  16. package/dist-client/pages/kpi/kpi-tree-page.js.map +1 -1
  17. package/dist-client/pages/kpi-metric/kpi-metric-list-page.d.ts +0 -6
  18. package/dist-client/pages/kpi-metric/kpi-metric-list-page.js +62 -116
  19. package/dist-client/pages/kpi-metric/kpi-metric-list-page.js.map +1 -1
  20. package/dist-client/pages/kpi-metric-value/kpi-metric-value-editor-page.d.ts +1 -7
  21. package/dist-client/pages/kpi-metric-value/kpi-metric-value-editor-page.js +82 -140
  22. package/dist-client/pages/kpi-metric-value/kpi-metric-value-editor-page.js.map +1 -1
  23. package/dist-client/pages/kpi-metric-value/kpi-metric-value-list-page.d.ts +0 -6
  24. package/dist-client/pages/kpi-metric-value/kpi-metric-value-list-page.js +54 -98
  25. package/dist-client/pages/kpi-metric-value/kpi-metric-value-list-page.js.map +1 -1
  26. package/dist-client/pages/kpi-metric-value/kpi-metric-value-manual-entry-page.d.ts +1 -7
  27. package/dist-client/pages/kpi-metric-value/kpi-metric-value-manual-entry-page.js +30 -57
  28. package/dist-client/pages/kpi-metric-value/kpi-metric-value-manual-entry-page.js.map +1 -1
  29. package/dist-client/pages/kpi-statistic/kpi-statistic-editor-page.d.ts +1 -7
  30. package/dist-client/pages/kpi-statistic/kpi-statistic-editor-page.js +91 -153
  31. package/dist-client/pages/kpi-statistic/kpi-statistic-editor-page.js.map +1 -1
  32. package/dist-client/pages/kpi-statistic/kpi-statistic-list-page.d.ts +0 -6
  33. package/dist-client/pages/kpi-statistic/kpi-statistic-list-page.js +81 -155
  34. package/dist-client/pages/kpi-statistic/kpi-statistic-list-page.js.map +1 -1
  35. package/dist-client/pages/kpi-value/kpi-value-editor-page.d.ts +1 -7
  36. package/dist-client/pages/kpi-value/kpi-value-editor-page.js +80 -136
  37. package/dist-client/pages/kpi-value/kpi-value-editor-page.js.map +1 -1
  38. package/dist-client/pages/kpi-value/kpi-value-list-page.d.ts +0 -6
  39. package/dist-client/pages/kpi-value/kpi-value-list-page.js +73 -134
  40. package/dist-client/pages/kpi-value/kpi-value-list-page.js.map +1 -1
  41. package/dist-client/tsconfig.tsbuildinfo +1 -1
  42. package/dist-server/service/index.d.ts +1 -1
  43. package/dist-server/tsconfig.tsbuildinfo +1 -1
  44. package/package.json +18 -18
  45. package/client/tsconfig.json +0 -11
  46. package/dist-server/tsconfig.json +0 -10
  47. package/server/@types/index.d.ts +0 -11
  48. package/server/calculator/evaluator.ts +0 -45
  49. package/server/calculator/functions.ts +0 -67
  50. package/server/calculator/index.ts +0 -4
  51. package/server/calculator/parser.ts +0 -137
  52. package/server/calculator/provider.ts +0 -10
  53. package/server/controllers/index.ts +0 -2
  54. package/server/controllers/kpi-metric-value-provider.ts +0 -79
  55. package/server/controllers/kpi-value-provider.ts +0 -51
  56. package/server/index.ts +0 -6
  57. package/server/migrations/1752190849680-seed-kpi-metrics.ts +0 -124
  58. package/server/migrations/1752190849681-seed-kpi.ts +0 -356
  59. package/server/migrations/1752192090123-add-grades-to-kpi.ts +0 -67
  60. package/server/migrations/1752192090124-add-kpi-statistics.ts +0 -719
  61. package/server/migrations/1752192090128-seed-kpi-org-scope.ts +0 -132
  62. package/server/migrations/1752192090129-seed-kpi-values.ts +0 -207
  63. package/server/migrations/grade-data/x11-performance-table.json +0 -962
  64. package/server/migrations/grade-data/x12-performance-table.json +0 -611
  65. package/server/migrations/grade-data/x14-performance-table.json +0 -42
  66. package/server/migrations/grade-data/x21-performance-table.json +0 -889
  67. package/server/migrations/grade-data/x22-performance-table.json +0 -1064
  68. package/server/migrations/grade-data/x23-performance-table.json +0 -42
  69. package/server/migrations/grade-data/x31-performance-table.json +0 -644
  70. package/server/migrations/grade-data/x32-performance-table.json +0 -993
  71. package/server/migrations/grade-data/x33-performance-table.json +0 -195
  72. package/server/migrations/grade-data/x34-performance-table.json +0 -12
  73. package/server/migrations/grade-data/x35-performance-table.json +0 -42
  74. package/server/migrations/grade-data/x41-performance-table.json +0 -825
  75. package/server/migrations/grade-data/x42-performance-table.json +0 -786
  76. package/server/migrations/grade-data/x43-performance-table.json +0 -12
  77. package/server/migrations/grade-data/x44-performance-table.json +0 -42
  78. package/server/migrations/grade-data/x51-performance-table.json +0 -924
  79. package/server/migrations/grade-data/x52-performance-table.json +0 -42
  80. package/server/migrations/grade-data/x61-performance-table.json +0 -261
  81. package/server/migrations/grade-data/x62-performance-table.json +0 -42
  82. package/server/migrations/index.ts +0 -9
  83. package/server/migrations/seed-data/kpi-metrics-seed.json +0 -454
  84. package/server/migrations/seed-data/kpi-org-scope-seed.json +0 -1676
  85. package/server/migrations/seed-data/kpi-scopes-seed.json +0 -121
  86. package/server/migrations/seed-data/kpi-values-seed.json +0 -402
  87. package/server/migrations/seed-data/kpis-seed.json +0 -488
  88. package/server/migrations/seed-data/scope-definitions-seed.json +0 -90
  89. package/server/routes.ts +0 -81
  90. package/server/service/index.ts +0 -51
  91. package/server/service/kpi/aggregate-kpi.ts +0 -103
  92. package/server/service/kpi/event-subscriber.ts +0 -29
  93. package/server/service/kpi/index.ts +0 -9
  94. package/server/service/kpi/kpi-formula.service.ts +0 -164
  95. package/server/service/kpi/kpi-grade.types.ts +0 -28
  96. package/server/service/kpi/kpi-history.ts +0 -126
  97. package/server/service/kpi/kpi-mutation.ts +0 -553
  98. package/server/service/kpi/kpi-query.ts +0 -224
  99. package/server/service/kpi/kpi-type.ts +0 -151
  100. package/server/service/kpi/kpi.ts +0 -254
  101. package/server/service/kpi-alert/index.ts +0 -3
  102. package/server/service/kpi-alert/kpi-alert-query.ts +0 -59
  103. package/server/service/kpi-alert/kpi-alert-type.ts +0 -20
  104. package/server/service/kpi-metric/aggregate-kpi-metric.ts +0 -132
  105. package/server/service/kpi-metric/index.ts +0 -7
  106. package/server/service/kpi-metric/kpi-metric-mutation.ts +0 -309
  107. package/server/service/kpi-metric/kpi-metric-query.ts +0 -70
  108. package/server/service/kpi-metric/kpi-metric-type.ts +0 -111
  109. package/server/service/kpi-metric/kpi-metric.ts +0 -134
  110. package/server/service/kpi-metric-value/index.ts +0 -7
  111. package/server/service/kpi-metric-value/kpi-metric-value-mutation.ts +0 -270
  112. package/server/service/kpi-metric-value/kpi-metric-value-query.ts +0 -62
  113. package/server/service/kpi-metric-value/kpi-metric-value-type.ts +0 -82
  114. package/server/service/kpi-metric-value/kpi-metric-value.ts +0 -93
  115. package/server/service/kpi-org-scope/index.ts +0 -6
  116. package/server/service/kpi-org-scope/kpi-org-scope-mutation.ts +0 -173
  117. package/server/service/kpi-org-scope/kpi-org-scope-query.ts +0 -127
  118. package/server/service/kpi-org-scope/kpi-org-scope-type.ts +0 -68
  119. package/server/service/kpi-org-scope/kpi-org-scope.ts +0 -123
  120. package/server/service/kpi-scope/index.ts +0 -11
  121. package/server/service/kpi-scope/kpi-scope-mutation.ts +0 -129
  122. package/server/service/kpi-scope/kpi-scope-query.ts +0 -63
  123. package/server/service/kpi-scope/kpi-scope-type.ts +0 -96
  124. package/server/service/kpi-scope/kpi-scope.ts +0 -143
  125. package/server/service/kpi-statistic/index.ts +0 -7
  126. package/server/service/kpi-statistic/kpi-statistic-batch.service.ts +0 -231
  127. package/server/service/kpi-statistic/kpi-statistic-calculation.service.ts +0 -410
  128. package/server/service/kpi-statistic/kpi-statistic-mutation.ts +0 -291
  129. package/server/service/kpi-statistic/kpi-statistic-query.ts +0 -146
  130. package/server/service/kpi-statistic/kpi-statistic-type.ts +0 -152
  131. package/server/service/kpi-statistic/kpi-statistic.ts +0 -199
  132. package/server/service/kpi-value/index.ts +0 -7
  133. package/server/service/kpi-value/kpi-value-mutation.ts +0 -432
  134. package/server/service/kpi-value/kpi-value-query.ts +0 -61
  135. package/server/service/kpi-value/kpi-value-score.service.ts +0 -106
  136. package/server/service/kpi-value/kpi-value-type.ts +0 -122
  137. package/server/service/kpi-value/kpi-value.ts +0 -160
  138. package/server/service/utils/value-date-util.ts +0 -119
  139. package/server/tsconfig.json +0 -10
  140. package/server/types/global.d.ts +0 -8
@@ -1,173 +0,0 @@
1
- import { Resolver, Mutation, Arg, Ctx, Directive } from 'type-graphql'
2
- import { In } from 'typeorm'
3
- import { getRepository } from '@things-factory/shell'
4
-
5
- import { KpiOrgScope } from './kpi-org-scope'
6
- import { NewKpiOrgScope, KpiOrgScopePatch } from './kpi-org-scope-type'
7
-
8
- @Resolver(KpiOrgScope)
9
- export class KpiOrgScopeMutation {
10
- @Directive('@privilege(category: "kpi", privilege: "mutation", domainOwnerGranted: true, superUserGranted: true)')
11
- @Directive('@transaction')
12
- @Mutation(returns => KpiOrgScope, { description: 'Create a new KPI org-scope mapping with the provided details.' })
13
- async createKpiOrgScope(
14
- @Arg('kpiOrgScope', { description: 'Input object containing details for the new org-scope mapping.' })
15
- kpiOrgScope: NewKpiOrgScope,
16
- @Ctx() context: ResolverContext
17
- ): Promise<KpiOrgScope> {
18
- const { domain, user, tx } = context.state
19
-
20
- // Check if org already exists for this domain
21
- const existingOrgScope = await getRepository(KpiOrgScope, tx).findOne({
22
- where: { domain: { id: domain.id }, org: kpiOrgScope.org }
23
- })
24
-
25
- if (existingOrgScope) {
26
- throw new Error(`Organization '${kpiOrgScope.org}' already has a scope mapping in this domain`)
27
- }
28
-
29
- const entity: Partial<KpiOrgScope> = {
30
- ...kpiOrgScope,
31
- domain,
32
- creator: user,
33
- updater: user
34
- }
35
-
36
- return await getRepository(KpiOrgScope, tx).save(entity)
37
- }
38
-
39
- @Directive('@privilege(category: "kpi", privilege: "mutation", domainOwnerGranted: true, superUserGranted: true)')
40
- @Directive('@transaction')
41
- @Mutation(returns => [KpiOrgScope], {
42
- description: 'Update multiple KPI org-scope mappings with the provided patches.'
43
- })
44
- async updateMultipleKpiOrgScope(
45
- @Arg('patches', type => [KpiOrgScopePatch], {
46
- description: 'Array of patch objects for updating org-scope mappings.'
47
- })
48
- patches: KpiOrgScopePatch[],
49
- @Ctx() context: ResolverContext
50
- ): Promise<KpiOrgScope[]> {
51
- const { domain, user, tx } = context.state
52
-
53
- const ids = patches.map(patch => patch.id)
54
- const existingOrgScopes = await getRepository(KpiOrgScope, tx).find({
55
- where: {
56
- domain: { id: domain.id },
57
- id: In(ids)
58
- }
59
- })
60
-
61
- if (existingOrgScopes.length !== patches.length) {
62
- throw new Error('Some org-scope mappings not found or not accessible')
63
- }
64
-
65
- const updatedOrgScopes: KpiOrgScope[] = []
66
-
67
- for (const patch of patches) {
68
- const existingOrgScope = existingOrgScopes.find(os => os.id === patch.id)
69
- if (!existingOrgScope) continue
70
-
71
- // Check if org is being changed and if new org already exists
72
- if (patch.org && patch.org !== existingOrgScope.org) {
73
- const duplicateOrgScope = await getRepository(KpiOrgScope, tx).findOne({
74
- where: {
75
- domain: { id: domain.id },
76
- org: patch.org,
77
- id: In(ids.filter(id => id !== patch.id))
78
- }
79
- })
80
- if (duplicateOrgScope) {
81
- throw new Error(`Organization '${patch.org}' already has a scope mapping in this domain`)
82
- }
83
- }
84
-
85
- const updatedEntity: Partial<KpiOrgScope> = {
86
- ...existingOrgScope,
87
- ...patch,
88
- updater: user,
89
- updatedAt: new Date()
90
- }
91
-
92
- const savedOrgScope = await getRepository(KpiOrgScope, tx).save(updatedEntity)
93
- updatedOrgScopes.push(savedOrgScope)
94
- }
95
-
96
- return updatedOrgScopes
97
- }
98
-
99
- @Directive('@privilege(category: "kpi", privilege: "mutation", domainOwnerGranted: true, superUserGranted: true)')
100
- @Directive('@transaction')
101
- @Mutation(returns => Boolean, { description: 'Delete KPI org-scope mappings by their IDs.' })
102
- async deleteKpiOrgScopes(
103
- @Arg('ids', type => [String], { description: 'Array of org-scope mapping IDs to delete.' }) ids: string[],
104
- @Ctx() context: ResolverContext
105
- ): Promise<boolean> {
106
- const { domain, tx } = context.state
107
-
108
- const existingOrgScopes = await getRepository(KpiOrgScope, tx).find({
109
- where: {
110
- domain: { id: domain.id },
111
- id: In(ids)
112
- }
113
- })
114
-
115
- if (existingOrgScopes.length === 0) {
116
- throw new Error('No org-scope mappings found to delete')
117
- }
118
-
119
- // Soft delete
120
- await getRepository(KpiOrgScope, tx).softDelete(existingOrgScopes.map(os => os.id))
121
-
122
- return true
123
- }
124
-
125
- @Directive('@privilege(category: "kpi", privilege: "mutation", domainOwnerGranted: true, superUserGranted: true)')
126
- @Directive('@transaction')
127
- @Mutation(returns => [KpiOrgScope], { description: 'Bulk create or update KPI org-scope mappings.' })
128
- async bulkUpsertKpiOrgScopes(
129
- @Arg('orgScopes', type => [NewKpiOrgScope], { description: 'Array of org-scope mapping data for bulk upsert.' })
130
- orgScopes: NewKpiOrgScope[],
131
- @Ctx() context: ResolverContext
132
- ): Promise<KpiOrgScope[]> {
133
- const { domain, user, tx } = context.state
134
-
135
- const orgs = orgScopes.map(os => os.org)
136
- const existingOrgScopes = await getRepository(KpiOrgScope, tx).find({
137
- where: {
138
- domain: { id: domain.id },
139
- org: In(orgs)
140
- }
141
- })
142
-
143
- const results: KpiOrgScope[] = []
144
-
145
- for (const orgScopeData of orgScopes) {
146
- const existing = existingOrgScopes.find(os => os.org === orgScopeData.org)
147
-
148
- if (existing) {
149
- // Update existing
150
- const updatedEntity: Partial<KpiOrgScope> = {
151
- ...existing,
152
- ...orgScopeData,
153
- updater: user,
154
- updatedAt: new Date()
155
- }
156
- const updated = await getRepository(KpiOrgScope, tx).save(updatedEntity)
157
- results.push(updated)
158
- } else {
159
- // Create new
160
- const newEntity: Partial<KpiOrgScope> = {
161
- ...orgScopeData,
162
- domain,
163
- creator: user,
164
- updater: user
165
- }
166
- const saved = await getRepository(KpiOrgScope, tx).save(newEntity)
167
- results.push(saved)
168
- }
169
- }
170
-
171
- return results
172
- }
173
- }
@@ -1,127 +0,0 @@
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
-
5
- import { KpiOrgScope } from './kpi-org-scope'
6
- import { KpiOrgScopeList } from './kpi-org-scope-type'
7
-
8
- @Resolver(KpiOrgScope)
9
- export class KpiOrgScopeQuery {
10
- @Directive('@privilege(category: "kpi", privilege: "query", domainOwnerGranted: true, superUserGranted: true)')
11
- @Query(returns => KpiOrgScope!, {
12
- nullable: true,
13
- description: 'Fetch a single KPI org-scope mapping by its unique identifier.'
14
- })
15
- async kpiOrgScope(
16
- @Arg('id', { description: 'Unique identifier of the org-scope mapping to fetch.' }) id: string,
17
- @Ctx() context: ResolverContext
18
- ): Promise<KpiOrgScope> {
19
- const { domain } = context.state
20
-
21
- return await getRepository(KpiOrgScope).findOne({
22
- where: { domain: { id: domain.id }, id }
23
- })
24
- }
25
-
26
- @Directive('@privilege(category: "kpi", privilege: "query", domainOwnerGranted: true, superUserGranted: true)')
27
- @Query(returns => KpiOrgScopeList, {
28
- description: 'Fetch multiple KPI org-scope mappings with filters and pagination'
29
- })
30
- async kpiOrgScopes(
31
- @Args(type => ListParam) params: ListParam,
32
- @Ctx() context: ResolverContext
33
- ): Promise<KpiOrgScopeList> {
34
- const { domain } = context.state
35
-
36
- const queryBuilder = getQueryBuilderFromListParams({
37
- domain,
38
- params,
39
- repository: await getRepository(KpiOrgScope),
40
- searchables: ['org', 'scope01', 'scope02', 'scope03', 'scope04', 'scope05']
41
- })
42
-
43
- const [items, total] = await queryBuilder.getManyAndCount()
44
-
45
- return { items, total }
46
- }
47
-
48
- @Directive('@privilege(category: "kpi", privilege: "query", domainOwnerGranted: true, superUserGranted: true)')
49
- @Query(returns => [String], { description: 'Get distinct values for a specific scope field' })
50
- async kpiOrgScopeValues(
51
- @Arg('scopeField', { description: 'Scope field to get distinct values from' })
52
- scopeField: 'scope01' | 'scope02' | 'scope03' | 'scope04' | 'scope05',
53
- @Ctx() context: ResolverContext,
54
- @Arg('searchTerm', { nullable: true, description: 'Optional search term to filter values' }) searchTerm?: string
55
- ): Promise<string[]> {
56
- const { domain } = context.state
57
-
58
- const queryBuilder = getRepository(KpiOrgScope)
59
- .createQueryBuilder('orgScope')
60
- .select(`DISTINCT orgScope.${scopeField}`, 'value')
61
- .where('orgScope.domain_id = :domainId', { domainId: domain.id })
62
- .andWhere(`orgScope.${scopeField} IS NOT NULL`)
63
- .andWhere(`orgScope.${scopeField} != ''`)
64
- .andWhere('orgScope.active = true')
65
-
66
- if (searchTerm) {
67
- queryBuilder.andWhere(`orgScope.${scopeField} ILIKE :searchTerm`, {
68
- searchTerm: `%${searchTerm}%`
69
- })
70
- }
71
-
72
- const results = await queryBuilder.getRawMany()
73
- return results.map(r => r.value).filter(v => v)
74
- }
75
-
76
- @Directive('@privilege(category: "kpi", privilege: "query", domainOwnerGranted: true, superUserGranted: true)')
77
- @Query(returns => [String], { description: 'Get distinct org values' })
78
- async kpiOrgValues(
79
- @Ctx() context: ResolverContext,
80
- @Arg('searchTerm', { nullable: true, description: 'Optional search term to filter org values' }) searchTerm?: string
81
- ): Promise<string[]> {
82
- const { domain } = context.state
83
-
84
- const queryBuilder = getRepository(KpiOrgScope)
85
- .createQueryBuilder('orgScope')
86
- .select('DISTINCT orgScope.org', 'value')
87
- .where('orgScope.domain_id = :domainId', { domainId: domain.id })
88
- .andWhere('orgScope.active = true')
89
-
90
- if (searchTerm) {
91
- queryBuilder.andWhere('orgScope.org ILIKE :searchTerm', {
92
- searchTerm: `%${searchTerm}%`
93
- })
94
- }
95
-
96
- const results = await queryBuilder.getRawMany()
97
- return results.map(r => r.value)
98
- }
99
-
100
- @Directive('@privilege(category: "kpi", privilege: "query", domainOwnerGranted: true, superUserGranted: true)')
101
- @Query(returns => KpiOrgScope, { nullable: true, description: 'Find org-scope mapping by org identifier' })
102
- async kpiOrgScopeByOrg(
103
- @Arg('org', { description: 'Organization identifier to search for' }) org: string,
104
- @Ctx() context: ResolverContext
105
- ): Promise<KpiOrgScope | undefined> {
106
- const { domain } = context.state
107
-
108
- return await getRepository(KpiOrgScope).findOne({
109
- where: { domain: { id: domain.id }, org }
110
- })
111
- }
112
-
113
- @FieldResolver(type => Domain)
114
- async domain(@Root() kpiOrgScope: KpiOrgScope): Promise<Domain> {
115
- return kpiOrgScope.domainId && (await getRepository(Domain).findOneBy({ id: kpiOrgScope.domainId }))
116
- }
117
-
118
- @FieldResolver(type => User)
119
- async creator(@Root() kpiOrgScope: KpiOrgScope): Promise<User> {
120
- return kpiOrgScope.creatorId && (await getRepository(User).findOneBy({ id: kpiOrgScope.creatorId }))
121
- }
122
-
123
- @FieldResolver(type => User)
124
- async updater(@Root() kpiOrgScope: KpiOrgScope): Promise<User> {
125
- return kpiOrgScope.updaterId && (await getRepository(User).findOneBy({ id: kpiOrgScope.updaterId }))
126
- }
127
- }
@@ -1,68 +0,0 @@
1
- import { InputType, Field, ID, ObjectType, Int } from 'type-graphql'
2
- import { KpiOrgScope } from './kpi-org-scope'
3
-
4
- @InputType({ description: 'Input type for creating a new KPI org-scope mapping' })
5
- export class NewKpiOrgScope {
6
- @Field({ description: 'Organizational unit identifier' })
7
- org: string
8
-
9
- @Field({ nullable: true, description: 'First scope dimension' })
10
- scope01?: string
11
-
12
- @Field({ nullable: true, description: 'Second scope dimension' })
13
- scope02?: string
14
-
15
- @Field({ nullable: true, description: 'Third scope dimension' })
16
- scope03?: string
17
-
18
- @Field({ nullable: true, description: 'Fourth scope dimension' })
19
- scope04?: string
20
-
21
- @Field({ nullable: true, description: 'Fifth scope dimension' })
22
- scope05?: string
23
-
24
- @Field({ nullable: true, description: 'Human-readable name or description' })
25
- displayName?: string
26
-
27
- @Field({ nullable: true, description: 'Active status' })
28
- active?: boolean
29
- }
30
-
31
- @InputType({ description: 'Input type for updating an existing KPI org-scope mapping' })
32
- export class KpiOrgScopePatch {
33
- @Field(type => ID, { description: 'ID of the org-scope mapping to update' })
34
- id: string
35
-
36
- @Field({ nullable: true, description: 'Organizational unit identifier' })
37
- org?: string
38
-
39
- @Field({ nullable: true, description: 'First scope dimension' })
40
- scope01?: string
41
-
42
- @Field({ nullable: true, description: 'Second scope dimension' })
43
- scope02?: string
44
-
45
- @Field({ nullable: true, description: 'Third scope dimension' })
46
- scope03?: string
47
-
48
- @Field({ nullable: true, description: 'Fourth scope dimension' })
49
- scope04?: string
50
-
51
- @Field({ nullable: true, description: 'Fifth scope dimension' })
52
- scope05?: string
53
-
54
- @Field({ nullable: true, description: 'Human-readable name or description' })
55
- displayName?: string
56
-
57
- @Field({ nullable: true, description: 'Active status' })
58
- active?: boolean
59
- }
60
-
61
- @ObjectType({ description: 'List of KPI org-scope mappings with pagination' })
62
- export class KpiOrgScopeList {
63
- @Field(type => [KpiOrgScope], { description: 'Array of KPI org-scope mappings' })
64
- items: KpiOrgScope[]
65
-
66
- @Field(type => Int, { description: 'Total count of items' })
67
- total: number
68
- }
@@ -1,123 +0,0 @@
1
- import {
2
- CreateDateColumn,
3
- UpdateDateColumn,
4
- DeleteDateColumn,
5
- Entity,
6
- Index,
7
- Column,
8
- RelationId,
9
- ManyToOne,
10
- PrimaryGeneratedColumn,
11
- EntityManager
12
- } from 'typeorm'
13
- import { ObjectType, Field, ID } from 'type-graphql'
14
-
15
- import { Domain } from '@things-factory/shell'
16
- import { User } from '@things-factory/auth-base'
17
-
18
- @Entity()
19
- @Index('ix_kpi_org_scope_0', (orgScope: KpiOrgScope) => [orgScope.domain, orgScope.entityType, orgScope.entityId], {
20
- unique: true
21
- })
22
- @ObjectType({
23
- description:
24
- 'KPI organization scope mapping entity. Maps business entities to various scope dimensions for KPI analysis using generic reference pattern.'
25
- })
26
- export class KpiOrgScope {
27
- @PrimaryGeneratedColumn('uuid')
28
- @Field(type => ID, { description: 'Unique identifier for this org-scope mapping.' })
29
- readonly id: string
30
-
31
- @ManyToOne(type => Domain)
32
- @Field({ nullable: true, description: 'Domain (tenant) to which this org-scope mapping belongs.' })
33
- domain?: Domain
34
-
35
- @RelationId((orgScope: KpiOrgScope) => orgScope.domain)
36
- @Field({ nullable: true, description: 'ID of the domain (tenant) for this org-scope mapping.' })
37
- domainId?: string
38
-
39
- @Column()
40
- @Field({ description: 'Type of the referenced business entity (e.g., Project, Department, Company, Employee)' })
41
- entityType: string
42
-
43
- @Column()
44
- @Field({ description: 'ID of the referenced business entity' })
45
- entityId: string
46
-
47
- @Column()
48
- @Field({ description: 'Name of the referenced business entity (denormalized for performance and convenience)' })
49
- entityName: string
50
-
51
- @Column({ nullable: true })
52
- @Field({ nullable: true, description: 'Legacy org field for backward compatibility' })
53
- org?: string
54
-
55
- @Column({ nullable: true })
56
- @Field({ nullable: true, description: 'First scope dimension (e.g., geographical region, business unit)' })
57
- scope01?: string
58
-
59
- @Column({ nullable: true })
60
- @Field({ nullable: true, description: 'Second scope dimension (e.g., product line, customer segment)' })
61
- scope02?: string
62
-
63
- @Column({ nullable: true })
64
- @Field({ nullable: true, description: 'Third scope dimension (e.g., process type, technology stack)' })
65
- scope03?: string
66
-
67
- @Column({ nullable: true })
68
- @Field({ nullable: true, description: 'Fourth scope dimension (e.g., cost center, profit center)' })
69
- scope04?: string
70
-
71
- @Column({ nullable: true })
72
- @Field({ nullable: true, description: 'Fifth scope dimension (e.g., risk level, priority tier)' })
73
- scope05?: string
74
-
75
- @CreateDateColumn()
76
- @Field({ nullable: true, description: 'Timestamp when this org-scope mapping was created.' })
77
- createdAt?: Date
78
-
79
- @UpdateDateColumn()
80
- @Field({ nullable: true, description: 'Timestamp when this org-scope mapping was last updated.' })
81
- updatedAt?: Date
82
-
83
- @ManyToOne(type => User, { nullable: true })
84
- @Field(type => User, { nullable: true, description: 'User who created this org-scope mapping.' })
85
- creator?: User
86
-
87
- @RelationId((orgScope: KpiOrgScope) => orgScope.creator)
88
- @Field({ nullable: true, description: 'ID of the user who created this org-scope mapping.' })
89
- creatorId?: string
90
-
91
- @ManyToOne(type => User, { nullable: true })
92
- @Field(type => User, { nullable: true, description: 'User who last updated this org-scope mapping.' })
93
- updater?: User
94
-
95
- @RelationId((orgScope: KpiOrgScope) => orgScope.updater)
96
- @Field({ nullable: true, description: 'ID of the user who last updated this org-scope mapping.' })
97
- updaterId?: string
98
-
99
- // Helper methods for Generic Reference Pattern
100
- async getReferencedEntity(entityManager: EntityManager): Promise<any> {
101
- try {
102
- const repository = entityManager.getRepository(this.entityType)
103
- return await repository.findOne({ where: { id: this.entityId } })
104
- } catch (error) {
105
- console.warn(`Failed to get referenced entity ${this.entityType}:${this.entityId}`, error)
106
- return null
107
- }
108
- }
109
-
110
- async validateEntityReference(entityManager: EntityManager): Promise<boolean> {
111
- try {
112
- const entity = await this.getReferencedEntity(entityManager)
113
- return !!entity
114
- } catch {
115
- return false
116
- }
117
- }
118
-
119
- // Convenience getter for display purposes
120
- get displayName(): string {
121
- return this.entityName || `${this.entityType}:${this.entityId}` || this.org || 'Unknown'
122
- }
123
- }
@@ -1,11 +0,0 @@
1
- import { KpiScope } from './kpi-scope'
2
- import { KpiScopeQuery } from './kpi-scope-query'
3
- import { KpiScopeMutation } from './kpi-scope-mutation'
4
-
5
- export const entities = [KpiScope]
6
- export const resolvers = [KpiScopeQuery, KpiScopeMutation]
7
-
8
- export * from './kpi-scope'
9
- export * from './kpi-scope-query'
10
- export * from './kpi-scope-mutation'
11
- export * from './kpi-scope-type'
@@ -1,129 +0,0 @@
1
- import { Resolver, Mutation, Arg, Ctx, Directive } from 'type-graphql'
2
- import { In } from 'typeorm'
3
- import { getRepository } from '@things-factory/shell'
4
- import type ResolverContext from '@things-factory/auth-base'
5
-
6
- import { KpiScope } from './kpi-scope'
7
- import { NewKpiScope, KpiScopePatch } from './kpi-scope-type'
8
-
9
- @Resolver(KpiScope)
10
- export class KpiScopeMutation {
11
- @Directive('@transaction')
12
- @Directive('@privilege(category: "kpi", privilege: "mutation", domainOwnerGranted: true, superUserGranted: true)')
13
- @Mutation(returns => KpiScope, { description: 'Create a new scope dimension definition' })
14
- async createKpiScope(
15
- @Arg('kpiScope') kpiScope: NewKpiScope,
16
- @Ctx() context: ResolverContext
17
- ): Promise<KpiScope> {
18
- const { domain, user, tx } = context.state
19
-
20
- const result = await getRepository(KpiScope, tx).save({
21
- ...kpiScope,
22
- domain,
23
- creator: user,
24
- updater: user
25
- })
26
-
27
- return result
28
- }
29
-
30
- @Directive('@transaction')
31
- @Directive('@privilege(category: "kpi", privilege: "mutation", domainOwnerGranted: true, superUserGranted: true)')
32
- @Mutation(returns => KpiScope, { description: 'Update a scope dimension definition' })
33
- async updateKpiScope(
34
- @Arg('id') id: string,
35
- @Arg('patch') patch: KpiScopePatch,
36
- @Ctx() context: ResolverContext
37
- ): Promise<KpiScope> {
38
- const { domain, user, tx } = context.state
39
-
40
- const repository = getRepository(KpiScope, tx)
41
- const kpiScope = await repository.findOne({
42
- where: { domain: { id: domain.id }, id }
43
- })
44
-
45
- const result = await repository.save({
46
- ...kpiScope,
47
- ...patch,
48
- updater: user
49
- })
50
-
51
- return result
52
- }
53
-
54
- @Directive('@transaction')
55
- @Directive('@privilege(category: "kpi", privilege: "mutation", domainOwnerGranted: true, superUserGranted: true)')
56
- @Mutation(returns => [KpiScope], { description: "Update multiple scope dimension definitions" })
57
- async updateMultipleKpiScope(
58
- @Arg('patches', type => [KpiScopePatch]) patches: KpiScopePatch[],
59
- @Ctx() context: ResolverContext
60
- ): Promise<KpiScope[]> {
61
- const { domain, user, tx } = context.state
62
-
63
- let results = []
64
- const _createRecords = patches.filter((patch: any) => patch.cuFlag.toUpperCase() === '+')
65
- const _updateRecords = patches.filter((patch: any) => patch.cuFlag.toUpperCase() === 'M')
66
- const kpiScopeRepo = getRepository(KpiScope, tx)
67
-
68
- if (_createRecords.length > 0) {
69
- for (let i = 0; i < _createRecords.length; i++) {
70
- const newRecord = _createRecords[i]
71
-
72
- const result = await kpiScopeRepo.save({
73
- ...newRecord,
74
- domain,
75
- creator: user,
76
- updater: user
77
- })
78
-
79
- results.push({ ...result, cuFlag: '+' })
80
- }
81
- }
82
-
83
- if (_updateRecords.length > 0) {
84
- for (let i = 0; i < _updateRecords.length; i++) {
85
- const updateRecord = _updateRecords[i]
86
- const kpiScope = await kpiScopeRepo.findOneBy({ id: updateRecord.id })
87
-
88
- const result = await kpiScopeRepo.save({
89
- ...kpiScope,
90
- ...updateRecord,
91
- updater: user
92
- })
93
-
94
- results.push({ ...result, cuFlag: 'M' })
95
- }
96
- }
97
-
98
- return results
99
- }
100
-
101
- @Directive('@transaction')
102
- @Directive('@privilege(category: "kpi", privilege: "mutation", domainOwnerGranted: true, superUserGranted: true)')
103
- @Mutation(returns => Boolean, { description: 'Delete a scope dimension definition' })
104
- async deleteKpiScope(@Arg('id') id: string, @Ctx() context: ResolverContext): Promise<boolean> {
105
- const { domain, tx } = context.state
106
-
107
- await getRepository(KpiScope, tx).delete({ domain: { id: domain.id }, id })
108
-
109
- return true
110
- }
111
-
112
- @Directive('@transaction')
113
- @Directive('@privilege(category: "kpi", privilege: "mutation", domainOwnerGranted: true, superUserGranted: true)')
114
- @Mutation(returns => Boolean, { description: 'Delete multiple scope dimension definitions' })
115
- async deleteKpiScopes(
116
- @Arg('ids', type => [String]) ids: string[],
117
- @Ctx() context: ResolverContext
118
- ): Promise<boolean> {
119
- const { domain, tx } = context.state
120
-
121
- await getRepository(KpiScope, tx).delete({
122
- domain: { id: domain.id },
123
- id: In(ids)
124
- })
125
-
126
- return true
127
- }
128
-
129
- }