@dssp/dkpi 1.0.0-alpha.82 → 1.0.0-alpha.84
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.
- package/dist-client/components/kpi-lookup-chart.js +45 -12
- package/dist-client/components/kpi-lookup-chart.js.map +1 -1
- package/dist-client/entries/auth/checkin.js +7 -2
- package/dist-client/entries/auth/checkin.js.map +1 -1
- package/dist-client/pages/kpi-dashboard/kpi-dashboard-map.js +1 -1
- package/dist-client/pages/kpi-dashboard/kpi-dashboard-map.js.map +1 -1
- package/dist-client/pages/project-complete-tabs/pc-tab1-plan.js +20 -24
- package/dist-client/pages/project-complete-tabs/pc-tab1-plan.js.map +1 -1
- package/dist-client/pages/sv-project-update.d.ts +5 -0
- package/dist-client/pages/sv-project-update.js +36 -6
- package/dist-client/pages/sv-project-update.js.map +1 -1
- package/dist-client/route.d.ts +1 -1
- package/dist-client/shared/complete-api.js +1 -0
- package/dist-client/shared/complete-api.js.map +1 -1
- package/dist-client/shared/geo-group-mapping.d.ts +25 -0
- package/dist-client/shared/geo-group-mapping.js +189 -0
- package/dist-client/shared/geo-group-mapping.js.map +1 -0
- package/dist-client/tsconfig.tsbuildinfo +1 -1
- package/dist-client/viewparts/menu-tools.js +1 -1
- package/dist-client/viewparts/menu-tools.js.map +1 -1
- package/dist-server/service/kpi-metric-value/kpi-metric-value-mutation.js +22 -11
- package/dist-server/service/kpi-metric-value/kpi-metric-value-mutation.js.map +1 -1
- package/dist-server/service/kpi-metric-value/kpi-metric-value-query.d.ts +5 -0
- package/dist-server/service/kpi-metric-value/kpi-metric-value-query.js +7 -10
- package/dist-server/service/kpi-metric-value/kpi-metric-value-query.js.map +1 -1
- package/dist-server/service/kpi-value/kpi-value-query.js +16 -3
- package/dist-server/service/kpi-value/kpi-value-query.js.map +1 -1
- package/dist-server/tsconfig.tsbuildinfo +1 -1
- package/package.json +5 -5
|
@@ -5,23 +5,20 @@ const tslib_1 = require("tslib");
|
|
|
5
5
|
const type_graphql_1 = require("type-graphql");
|
|
6
6
|
const shell_1 = require("@things-factory/shell");
|
|
7
7
|
const kpi_1 = require("@things-factory/kpi");
|
|
8
|
-
const domain_inheritance_js_1 = require("@things-factory/kpi/dist-server/service/utils/domain-inheritance.js");
|
|
9
8
|
const project_1 = require("@dssp/project");
|
|
10
9
|
let KpiMetricValueQuery = class KpiMetricValueQuery {
|
|
10
|
+
/**
|
|
11
|
+
* KPI 메트릭 값 목록 페이지 전용 — 도메인 필터 없이 모든 도메인의 KpiMetricValue
|
|
12
|
+
* 를 반환. 접근 권한은 @privilege 가 superUser/domainOwner 만 허용해 보호.
|
|
13
|
+
* 자식 도메인 (프로젝트 테넌트) 의 값까지 admin 화면에서 한꺼번에 확인 가능.
|
|
14
|
+
*/
|
|
11
15
|
async kpiMetricValues(params, context) {
|
|
12
|
-
const { domain } = context.state;
|
|
13
|
-
// multi-level 부모 도메인까지 포함. things-factory 의 KpiMetricValueQuery 와 동일 패턴.
|
|
14
|
-
// SYSTEM → 프로젝트 테넌트 계층에서 정의가 부모에 있고 값이 자식에 있어도 합쳐 보임.
|
|
15
|
-
const domainIds = await (0, domain_inheritance_js_1.getDomainIdsWithAncestors)(domain);
|
|
16
16
|
const queryBuilder = (0, shell_1.getQueryBuilderFromListParams)({
|
|
17
|
-
domain: undefined, // 도메인
|
|
17
|
+
domain: undefined, // 도메인 필터 미적용 — admin 운영자가 모든 도메인 데이터 조회
|
|
18
18
|
params,
|
|
19
19
|
repository: await (0, shell_1.getRepository)(kpi_1.KpiMetricValue),
|
|
20
20
|
searchables: ['metricId', 'group', 'valueDate', 'org']
|
|
21
21
|
});
|
|
22
|
-
queryBuilder.andWhere(`${queryBuilder.alias}.domain IN (:...ancestorDomainIds)`, {
|
|
23
|
-
ancestorDomainIds: domainIds
|
|
24
|
-
});
|
|
25
22
|
const [items, total] = await queryBuilder.getManyAndCount();
|
|
26
23
|
return { items, total };
|
|
27
24
|
}
|
|
@@ -39,7 +36,7 @@ let KpiMetricValueQuery = class KpiMetricValueQuery {
|
|
|
39
36
|
exports.KpiMetricValueQuery = KpiMetricValueQuery;
|
|
40
37
|
tslib_1.__decorate([
|
|
41
38
|
(0, type_graphql_1.Directive)('@privilege(category: "kpi", privilege: "read", domainOwnerGranted: true, superUserGranted: true)'),
|
|
42
|
-
(0, type_graphql_1.Query)(returns => kpi_1.KpiMetricValueList, { description: 'To fetch multiple KpiMetricValues' }),
|
|
39
|
+
(0, type_graphql_1.Query)(returns => kpi_1.KpiMetricValueList, { description: 'To fetch multiple KpiMetricValues (cross-domain admin view)' }),
|
|
43
40
|
tslib_1.__param(0, (0, type_graphql_1.Args)(type => shell_1.ListParam)),
|
|
44
41
|
tslib_1.__param(1, (0, type_graphql_1.Ctx)()),
|
|
45
42
|
tslib_1.__metadata("design:type", Function),
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"kpi-metric-value-query.js","sourceRoot":"","sources":["../../../server/service/kpi-metric-value/kpi-metric-value-query.ts"],"names":[],"mappings":";;;;AAAA,+CAA8F;AAC9F,iDAAuG;AAEvG,6CAAwE;AACxE
|
|
1
|
+
{"version":3,"file":"kpi-metric-value-query.js","sourceRoot":"","sources":["../../../server/service/kpi-metric-value/kpi-metric-value-query.ts"],"names":[],"mappings":";;;;AAAA,+CAA8F;AAC9F,iDAAuG;AAEvG,6CAAwE;AACxE,2CAAuC;AAGhC,IAAM,mBAAmB,GAAzB,MAAM,mBAAmB;IAC9B;;;;OAIG;IAGG,AAAN,KAAK,CAAC,eAAe,CACM,MAAiB,EACnC,OAAwB;QAE/B,MAAM,YAAY,GAAG,IAAA,qCAA6B,EAAC;YACjD,MAAM,EAAE,SAAS,EAAE,wCAAwC;YAC3D,MAAM;YACN,UAAU,EAAE,MAAM,IAAA,qBAAa,EAAC,oBAAc,CAAC;YAC/C,WAAW,EAAE,CAAC,UAAU,EAAE,OAAO,EAAE,WAAW,EAAE,KAAK,CAAC;SACvD,CAAC,CAAA;QAEF,MAAM,CAAC,KAAK,EAAE,KAAK,CAAC,GAAG,MAAM,YAAY,CAAC,eAAe,EAAE,CAAA;QAE3D,OAAO,EAAE,KAAK,EAAE,KAAK,EAAE,CAAA;IACzB,CAAC;IAGK,AAAN,KAAK,CAAC,OAAO,CAAS,cAA8B;QAClD,IAAI,CAAC,cAAc,CAAC,GAAG;YAAE,OAAO,IAAI,CAAA;QACpC,IAAI,CAAC;YACH,OAAO,MAAM,IAAA,qBAAa,EAAC,iBAAO,CAAC,CAAC,SAAS,CAAC,EAAE,EAAE,EAAE,cAAc,CAAC,GAAG,EAAE,CAAC,CAAA;QAC3E,CAAC;QAAC,WAAM,CAAC;YACP,OAAO,IAAI,CAAA;QACb,CAAC;IACH,CAAC;CACF,CAAA;AAjCY,kDAAmB;AAQxB;IAFL,IAAA,wBAAS,EAAC,kGAAkG,CAAC;IAC7G,IAAA,oBAAK,EAAC,OAAO,CAAC,EAAE,CAAC,wBAAkB,EAAE,EAAE,WAAW,EAAE,6DAA6D,EAAE,CAAC;IAElH,mBAAA,IAAA,mBAAI,EAAC,IAAI,CAAC,EAAE,CAAC,iBAAS,CAAC,CAAA;IACvB,mBAAA,IAAA,kBAAG,GAAE,CAAA;;6CAD2B,iBAAS;;0DAa3C;AAGK;IADL,IAAA,4BAAa,EAAC,IAAI,CAAC,EAAE,CAAC,iBAAO,EAAE,EAAE,QAAQ,EAAE,IAAI,EAAE,CAAC;IACpC,mBAAA,IAAA,mBAAI,GAAE,CAAA;;6CAAiB,oBAAc;;kDAOnD;8BAhCU,mBAAmB;IAD/B,IAAA,uBAAQ,EAAC,oBAAc,CAAC;GACZ,mBAAmB,CAiC/B","sourcesContent":["import { Directive, Resolver, Query, Args, Arg, Ctx, FieldResolver, Root } from 'type-graphql'\nimport { Domain, getQueryBuilderFromListParams, getRepository, ListParam } from '@things-factory/shell'\nimport { User } from '@things-factory/auth-base'\nimport { KpiMetricValue, KpiMetricValueList } from '@things-factory/kpi'\nimport { Project } from '@dssp/project'\n\n@Resolver(KpiMetricValue)\nexport class KpiMetricValueQuery {\n /**\n * KPI 메트릭 값 목록 페이지 전용 — 도메인 필터 없이 모든 도메인의 KpiMetricValue\n * 를 반환. 접근 권한은 @privilege 가 superUser/domainOwner 만 허용해 보호.\n * 자식 도메인 (프로젝트 테넌트) 의 값까지 admin 화면에서 한꺼번에 확인 가능.\n */\n @Directive('@privilege(category: \"kpi\", privilege: \"read\", domainOwnerGranted: true, superUserGranted: true)')\n @Query(returns => KpiMetricValueList, { description: 'To fetch multiple KpiMetricValues (cross-domain admin view)' })\n async kpiMetricValues(\n @Args(type => ListParam) params: ListParam,\n @Ctx() context: ResolverContext\n ): Promise<KpiMetricValueList> {\n const queryBuilder = getQueryBuilderFromListParams({\n domain: undefined, // 도메인 필터 미적용 — admin 운영자가 모든 도메인 데이터 조회\n params,\n repository: await getRepository(KpiMetricValue),\n searchables: ['metricId', 'group', 'valueDate', 'org']\n })\n\n const [items, total] = await queryBuilder.getManyAndCount()\n\n return { items, total }\n }\n\n @FieldResolver(type => Project, { nullable: true })\n async project(@Root() kpiMetricValue: KpiMetricValue): Promise<Project | null> {\n if (!kpiMetricValue.org) return null\n try {\n return await getRepository(Project).findOneBy({ id: kpiMetricValue.org })\n } catch {\n return null\n }\n }\n}\n"]}
|
|
@@ -17,15 +17,28 @@ let KpiValueQueryForProject = class KpiValueQueryForProject {
|
|
|
17
17
|
return { items, total };
|
|
18
18
|
}
|
|
19
19
|
async projectXKpiValues(projectId) {
|
|
20
|
+
var _a, _b, _c;
|
|
20
21
|
const repository = await (0, shell_1.getRepository)(kpi_1.KpiValue);
|
|
21
|
-
|
|
22
|
+
// history 포함 전체 fetch — 한 프로젝트의 X KPI 들이라 row 수가 적어 JS group-by 가
|
|
23
|
+
// SQL DISTINCT ON 보다 단순. 같은 (kpiId, valueDate, kpiOrgScope) 좌표는 version 이
|
|
24
|
+
// 큰 것만 통과.
|
|
25
|
+
const allKpiValues = await repository
|
|
22
26
|
.createQueryBuilder('kpiValue')
|
|
23
27
|
.leftJoinAndSelect('kpiValue.kpi', 'kpi')
|
|
24
28
|
.where('kpiValue.group = :projectId', { projectId })
|
|
25
29
|
.andWhere('kpi.name LIKE :namePrefix', { namePrefix: 'X%' })
|
|
26
30
|
.orderBy('kpi.name', 'ASC')
|
|
27
31
|
.getMany();
|
|
28
|
-
|
|
32
|
+
// 좌표별 latest version 만 선택
|
|
33
|
+
const latestByKey = new Map();
|
|
34
|
+
for (const kv of allKpiValues) {
|
|
35
|
+
const key = `${kv.kpiId || ((_a = kv.kpi) === null || _a === void 0 ? void 0 : _a.id)}:${kv.valueDate}:${kv.kpiOrgScopeId || ''}`;
|
|
36
|
+
const existing = latestByKey.get(key);
|
|
37
|
+
if (!existing || ((_b = kv.version) !== null && _b !== void 0 ? _b : 0) > ((_c = existing.version) !== null && _c !== void 0 ? _c : 0)) {
|
|
38
|
+
latestByKey.set(key, kv);
|
|
39
|
+
}
|
|
40
|
+
}
|
|
41
|
+
return Array.from(latestByKey.values()).sort((a, b) => { var _a, _b; return (((_a = a.kpi) === null || _a === void 0 ? void 0 : _a.name) || '').localeCompare(((_b = b.kpi) === null || _b === void 0 ? void 0 : _b.name) || ''); });
|
|
29
42
|
}
|
|
30
43
|
async project(kpiValue) {
|
|
31
44
|
if (!kpiValue.group)
|
|
@@ -44,7 +57,7 @@ tslib_1.__decorate([
|
|
|
44
57
|
], KpiValueQueryForProject.prototype, "kpiValues", null);
|
|
45
58
|
tslib_1.__decorate([
|
|
46
59
|
(0, type_graphql_1.Directive)('@privilege(category: "kpi", privilege: "read", domainOwnerGranted: true, superUserGranted: true)'),
|
|
47
|
-
(0, type_graphql_1.Query)(returns => [kpi_1.KpiValue], { description: 'To fetch KpiValues by project group with X prefix kpi names' }),
|
|
60
|
+
(0, type_graphql_1.Query)(returns => [kpi_1.KpiValue], { description: 'To fetch KpiValues by project group with X prefix kpi names (latest version only)' }),
|
|
48
61
|
tslib_1.__param(0, (0, type_graphql_1.Arg)('projectId', type => String)),
|
|
49
62
|
tslib_1.__metadata("design:type", Function),
|
|
50
63
|
tslib_1.__metadata("design:paramtypes", [String]),
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"kpi-value-query.js","sourceRoot":"","sources":["../../../server/service/kpi-value/kpi-value-query.ts"],"names":[],"mappings":";;;;AAAA,+CAAqG;AACrG,iDAAuG;AAEvG,6CAAiE;AACjE,+EAA2E;AAGpE,IAAM,uBAAuB,GAA7B,MAAM,uBAAuB;IAG5B,AAAN,KAAK,CAAC,SAAS,CAA0B,MAAiB;QACxD,MAAM,YAAY,GAAG,IAAA,qCAA6B,EAAC;YACjD,MAAM;YACN,UAAU,EAAE,MAAM,IAAA,qBAAa,EAAC,cAAQ,CAAC;YACzC,WAAW,EAAE,CAAC,KAAK,EAAE,OAAO,EAAE,WAAW,CAAC;SAC3C,CAAC,CAAA;QAEF,MAAM,CAAC,KAAK,EAAE,KAAK,CAAC,GAAG,MAAM,YAAY,CAAC,eAAe,EAAE,CAAA;QAE3D,OAAO,EAAE,KAAK,EAAE,KAAK,EAAE,CAAA;IACzB,CAAC;IAIK,AAAN,KAAK,CAAC,iBAAiB,CAAmC,SAAiB
|
|
1
|
+
{"version":3,"file":"kpi-value-query.js","sourceRoot":"","sources":["../../../server/service/kpi-value/kpi-value-query.ts"],"names":[],"mappings":";;;;AAAA,+CAAqG;AACrG,iDAAuG;AAEvG,6CAAiE;AACjE,+EAA2E;AAGpE,IAAM,uBAAuB,GAA7B,MAAM,uBAAuB;IAG5B,AAAN,KAAK,CAAC,SAAS,CAA0B,MAAiB;QACxD,MAAM,YAAY,GAAG,IAAA,qCAA6B,EAAC;YACjD,MAAM;YACN,UAAU,EAAE,MAAM,IAAA,qBAAa,EAAC,cAAQ,CAAC;YACzC,WAAW,EAAE,CAAC,KAAK,EAAE,OAAO,EAAE,WAAW,CAAC;SAC3C,CAAC,CAAA;QAEF,MAAM,CAAC,KAAK,EAAE,KAAK,CAAC,GAAG,MAAM,YAAY,CAAC,eAAe,EAAE,CAAA;QAE3D,OAAO,EAAE,KAAK,EAAE,KAAK,EAAE,CAAA;IACzB,CAAC;IAIK,AAAN,KAAK,CAAC,iBAAiB,CAAmC,SAAiB;;QACzE,MAAM,UAAU,GAAG,MAAM,IAAA,qBAAa,EAAC,cAAQ,CAAC,CAAA;QAEhD,kEAAkE;QAClE,0EAA0E;QAC1E,WAAW;QACX,MAAM,YAAY,GAAG,MAAM,UAAU;aAClC,kBAAkB,CAAC,UAAU,CAAC;aAC9B,iBAAiB,CAAC,cAAc,EAAE,KAAK,CAAC;aACxC,KAAK,CAAC,6BAA6B,EAAE,EAAE,SAAS,EAAE,CAAC;aACnD,QAAQ,CAAC,2BAA2B,EAAE,EAAE,UAAU,EAAE,IAAI,EAAE,CAAC;aAC3D,OAAO,CAAC,UAAU,EAAE,KAAK,CAAC;aAC1B,OAAO,EAAE,CAAA;QAEZ,0BAA0B;QAC1B,MAAM,WAAW,GAAG,IAAI,GAAG,EAAoB,CAAA;QAC/C,KAAK,MAAM,EAAE,IAAI,YAAY,EAAE,CAAC;YAC9B,MAAM,GAAG,GAAG,GAAI,EAAU,CAAC,KAAK,KAAI,MAAA,EAAE,CAAC,GAAG,0CAAE,EAAE,CAAA,IAAI,EAAE,CAAC,SAAS,IAAK,EAAU,CAAC,aAAa,IAAI,EAAE,EAAE,CAAA;YACnG,MAAM,QAAQ,GAAG,WAAW,CAAC,GAAG,CAAC,GAAG,CAAC,CAAA;YACrC,IAAI,CAAC,QAAQ,IAAI,CAAC,MAAA,EAAE,CAAC,OAAO,mCAAI,CAAC,CAAC,GAAG,CAAC,MAAA,QAAQ,CAAC,OAAO,mCAAI,CAAC,CAAC,EAAE,CAAC;gBAC7D,WAAW,CAAC,GAAG,CAAC,GAAG,EAAE,EAAE,CAAC,CAAA;YAC1B,CAAC;QACH,CAAC;QACD,OAAO,KAAK,CAAC,IAAI,CAAC,WAAW,CAAC,MAAM,EAAE,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,CAAC,EAAE,EAAE,eAAC,OAAA,CAAC,CAAA,MAAA,CAAC,CAAC,GAAG,0CAAE,IAAI,KAAI,EAAE,CAAC,CAAC,aAAa,CAAC,CAAA,MAAA,CAAC,CAAC,GAAG,0CAAE,IAAI,KAAI,EAAE,CAAC,CAAA,EAAA,CAAC,CAAA;IAC9G,CAAC;IAGK,AAAN,KAAK,CAAC,OAAO,CAAS,QAAkB;QACtC,IAAI,CAAC,QAAQ,CAAC,KAAK;YAAE,OAAO,IAAI,CAAA;QAChC,OAAO,MAAM,IAAA,qBAAa,EAAC,iBAAO,CAAC,CAAC,SAAS,CAAC,EAAE,EAAE,EAAE,QAAQ,CAAC,KAAK,EAAE,CAAC,CAAA;IACvE,CAAC;CACF,CAAA;AAhDY,0DAAuB;AAG5B;IAFL,IAAA,wBAAS,EAAC,kGAAkG,CAAC;IAC7G,IAAA,oBAAK,EAAC,OAAO,CAAC,EAAE,CAAC,kBAAY,EAAE,EAAE,WAAW,EAAE,6BAA6B,EAAE,CAAC;IAC9D,mBAAA,IAAA,mBAAI,EAAC,IAAI,CAAC,EAAE,CAAC,iBAAS,CAAC,CAAA;;6CAAS,iBAAS;;wDAUzD;AAIK;IAFL,IAAA,wBAAS,EAAC,kGAAkG,CAAC;IAC7G,IAAA,oBAAK,EAAC,OAAO,CAAC,EAAE,CAAC,CAAC,cAAQ,CAAC,EAAE,EAAE,WAAW,EAAE,mFAAmF,EAAE,CAAC;IAC1G,mBAAA,IAAA,kBAAG,EAAC,WAAW,EAAE,IAAI,CAAC,EAAE,CAAC,MAAM,CAAC,CAAA;;;;gEAwBxD;AAGK;IADL,IAAA,4BAAa,EAAC,IAAI,CAAC,EAAE,CAAC,iBAAO,CAAC;IAChB,mBAAA,IAAA,mBAAI,GAAE,CAAA;;6CAAW,cAAQ;;sDAGvC;kCA/CU,uBAAuB;IADnC,IAAA,uBAAQ,EAAC,cAAQ,CAAC;GACN,uBAAuB,CAgDnC","sourcesContent":["import { Resolver, Query, FieldResolver, Root, Args, Arg, Ctx, Directive, Float } from 'type-graphql'\nimport { Domain, getQueryBuilderFromListParams, getRepository, ListParam } from '@things-factory/shell'\nimport { User } from '@things-factory/auth-base'\nimport { Kpi, KpiValue, KpiValueList } from '@things-factory/kpi'\nimport { Project } from '@dssp/project/dist-server/service/project/project'\n\n@Resolver(KpiValue)\nexport class KpiValueQueryForProject {\n @Directive('@privilege(category: \"kpi\", privilege: \"read\", domainOwnerGranted: true, superUserGranted: true)')\n @Query(returns => KpiValueList, { description: 'To fetch multiple KpiValues' })\n async kpiValues(@Args(type => ListParam) params: ListParam): Promise<KpiValueList> {\n const queryBuilder = getQueryBuilderFromListParams({\n params,\n repository: await getRepository(KpiValue),\n searchables: ['kpi', 'group', 'valueDate']\n })\n\n const [items, total] = await queryBuilder.getManyAndCount()\n\n return { items, total }\n }\n\n @Directive('@privilege(category: \"kpi\", privilege: \"read\", domainOwnerGranted: true, superUserGranted: true)')\n @Query(returns => [KpiValue], { description: 'To fetch KpiValues by project group with X prefix kpi names (latest version only)' })\n async projectXKpiValues(@Arg('projectId', type => String) projectId: string): Promise<KpiValue[]> {\n const repository = await getRepository(KpiValue)\n\n // history 포함 전체 fetch — 한 프로젝트의 X KPI 들이라 row 수가 적어 JS group-by 가\n // SQL DISTINCT ON 보다 단순. 같은 (kpiId, valueDate, kpiOrgScope) 좌표는 version 이\n // 큰 것만 통과.\n const allKpiValues = await repository\n .createQueryBuilder('kpiValue')\n .leftJoinAndSelect('kpiValue.kpi', 'kpi')\n .where('kpiValue.group = :projectId', { projectId })\n .andWhere('kpi.name LIKE :namePrefix', { namePrefix: 'X%' })\n .orderBy('kpi.name', 'ASC')\n .getMany()\n\n // 좌표별 latest version 만 선택\n const latestByKey = new Map<string, KpiValue>()\n for (const kv of allKpiValues) {\n const key = `${(kv as any).kpiId || kv.kpi?.id}:${kv.valueDate}:${(kv as any).kpiOrgScopeId || ''}`\n const existing = latestByKey.get(key)\n if (!existing || (kv.version ?? 0) > (existing.version ?? 0)) {\n latestByKey.set(key, kv)\n }\n }\n return Array.from(latestByKey.values()).sort((a, b) => (a.kpi?.name || '').localeCompare(b.kpi?.name || ''))\n }\n\n @FieldResolver(type => Project)\n async project(@Root() kpiValue: KpiValue): Promise<Project | null> {\n if (!kpiValue.group) return null\n return await getRepository(Project).findOneBy({ id: kpiValue.group })\n }\n}\n"]}
|