@dssp/dkpi 1.0.0-alpha.6 ā 1.0.0-alpha.61
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/KPI-STATISTICS-SERVICE.md +233 -0
- package/assets/favicon.ico +0 -0
- package/assets/images/project-image.png +0 -0
- package/assets/manifest/apple-1024.png +0 -0
- package/assets/manifest/apple-120.png +0 -0
- package/assets/manifest/apple-152.png +0 -0
- package/assets/manifest/apple-167.png +0 -0
- package/assets/manifest/apple-180.png +0 -0
- package/assets/manifest/apple-touch-icon.png +0 -0
- package/assets/manifest/badge-128x128.png +0 -0
- package/assets/manifest/chrome-splashscreen-icon-384x384.png +0 -0
- package/assets/manifest/chrome-touch-icon-192x192.png +0 -0
- package/assets/manifest/icon-128x128.png +0 -0
- package/assets/manifest/icon-192x192.png +0 -0
- package/assets/manifest/icon-512x512.png +0 -0
- package/assets/manifest/icon-72x72.png +0 -0
- package/assets/manifest/icon-96x96.png +0 -0
- package/assets/manifest/image-metaog.png +0 -0
- package/assets/manifest/maskable_icon.png +0 -0
- package/assets/manifest/ms-icon-144x144.png +0 -0
- package/assets/manifest/ms-touch-icon-144x144-precomposed.png +0 -0
- package/assets/videos/intro.mp4 +0 -0
- package/dist-client/bootstrap.js +64 -4
- package/dist-client/bootstrap.js.map +1 -1
- package/dist-client/components/kpi-boxplot-chart.d.ts +24 -0
- package/dist-client/components/kpi-boxplot-chart.js +264 -0
- package/dist-client/components/kpi-boxplot-chart.js.map +1 -0
- package/dist-client/components/kpi-lookup-chart.d.ts +29 -0
- package/dist-client/components/kpi-lookup-chart.js +434 -0
- package/dist-client/components/kpi-lookup-chart.js.map +1 -0
- package/dist-client/components/kpi-mini-trend-chart.d.ts +14 -0
- package/dist-client/components/kpi-mini-trend-chart.js +148 -0
- package/dist-client/components/kpi-mini-trend-chart.js.map +1 -0
- package/dist-client/components/kpi-radar-chart.d.ts +17 -0
- package/dist-client/components/kpi-radar-chart.js +235 -0
- package/dist-client/components/kpi-radar-chart.js.map +1 -0
- package/dist-client/components/kpi-single-boxplot-chart.d.ts +24 -0
- package/dist-client/components/kpi-single-boxplot-chart.js +333 -0
- package/dist-client/components/kpi-single-boxplot-chart.js.map +1 -0
- package/dist-client/components/kpi-trend-chart.d.ts +25 -0
- package/dist-client/components/kpi-trend-chart.js +220 -0
- package/dist-client/components/kpi-trend-chart.js.map +1 -0
- package/dist-client/components/sv-pagenation-control.d.ts +18 -0
- package/dist-client/components/sv-pagenation-control.js +142 -0
- package/dist-client/components/sv-pagenation-control.js.map +1 -0
- package/dist-client/google-map/common-google-map.d.ts +35 -0
- package/dist-client/google-map/common-google-map.js +343 -0
- package/dist-client/google-map/common-google-map.js.map +1 -0
- package/dist-client/google-map/google-map-loader.d.ts +6 -0
- package/dist-client/google-map/google-map-loader.js +23 -0
- package/dist-client/google-map/google-map-loader.js.map +1 -0
- package/dist-client/icons/menu-icons.d.ts +6 -0
- package/dist-client/icons/menu-icons.js +42 -0
- package/dist-client/icons/menu-icons.js.map +1 -1
- package/dist-client/menu.d.ts +23 -1
- package/dist-client/menu.js +57 -2
- package/dist-client/menu.js.map +1 -1
- package/dist-client/pages/kpi-dashboard/cards/kpi-level1-card.d.ts +17 -0
- package/dist-client/pages/kpi-dashboard/cards/kpi-level1-card.js +280 -0
- package/dist-client/pages/kpi-dashboard/cards/kpi-level1-card.js.map +1 -0
- package/dist-client/pages/kpi-dashboard/cards/kpi-level2-comparison.d.ts +21 -0
- package/dist-client/pages/kpi-dashboard/cards/kpi-level2-comparison.js +389 -0
- package/dist-client/pages/kpi-dashboard/cards/kpi-level2-comparison.js.map +1 -0
- package/dist-client/pages/kpi-dashboard/cards/kpi-level3-comparison.d.ts +25 -0
- package/dist-client/pages/kpi-dashboard/cards/kpi-level3-comparison.js +469 -0
- package/dist-client/pages/kpi-dashboard/cards/kpi-level3-comparison.js.map +1 -0
- package/dist-client/pages/kpi-dashboard/components/kpi-chart-toggle.d.ts +8 -0
- package/dist-client/pages/kpi-dashboard/components/kpi-chart-toggle.js +78 -0
- package/dist-client/pages/kpi-dashboard/components/kpi-chart-toggle.js.map +1 -0
- package/dist-client/pages/kpi-dashboard/components/kpi-left-panel.d.ts +34 -0
- package/dist-client/pages/kpi-dashboard/components/kpi-left-panel.js +642 -0
- package/dist-client/pages/kpi-dashboard/components/kpi-left-panel.js.map +1 -0
- package/dist-client/pages/kpi-dashboard/components/kpi-map-panel.d.ts +38 -0
- package/dist-client/pages/kpi-dashboard/components/kpi-map-panel.js +501 -0
- package/dist-client/pages/kpi-dashboard/components/kpi-map-panel.js.map +1 -0
- package/dist-client/pages/kpi-dashboard/components/kpi-region-popup.d.ts +26 -0
- package/dist-client/pages/kpi-dashboard/components/kpi-region-popup.js +439 -0
- package/dist-client/pages/kpi-dashboard/components/kpi-region-popup.js.map +1 -0
- package/dist-client/pages/kpi-dashboard/kpi-alert-panel.d.ts +18 -0
- package/dist-client/pages/kpi-dashboard/kpi-alert-panel.js +131 -0
- package/dist-client/pages/kpi-dashboard/kpi-alert-panel.js.map +1 -0
- package/dist-client/pages/kpi-dashboard/kpi-dashboard-map.d.ts +36 -0
- package/dist-client/pages/kpi-dashboard/kpi-dashboard-map.js +572 -0
- package/dist-client/pages/kpi-dashboard/kpi-dashboard-map.js.map +1 -0
- package/dist-client/pages/kpi-dashboard/kpi-dashboard.d.ts +59 -0
- package/dist-client/pages/kpi-dashboard/kpi-dashboard.js +1027 -0
- package/dist-client/pages/kpi-dashboard/kpi-dashboard.js.map +1 -0
- package/dist-client/pages/kpi-dashboard/kpi-grade-visualization.d.ts +12 -0
- package/dist-client/pages/kpi-dashboard/kpi-grade-visualization.js +82 -0
- package/dist-client/pages/kpi-dashboard/kpi-grade-visualization.js.map +1 -0
- package/dist-client/pages/kpi-dashboard/kpi-history-viewer.d.ts +11 -0
- package/dist-client/pages/kpi-dashboard/kpi-history-viewer.js +65 -0
- package/dist-client/pages/kpi-dashboard/kpi-history-viewer.js.map +1 -0
- package/dist-client/pages/kpi-dashboard/kpi-list-summary.d.ts +13 -0
- package/dist-client/pages/kpi-dashboard/kpi-list-summary.js +115 -0
- package/dist-client/pages/kpi-dashboard/kpi-list-summary.js.map +1 -0
- package/dist-client/pages/kpi-dashboard/kpi-performance-summary.d.ts +15 -0
- package/dist-client/pages/kpi-dashboard/kpi-performance-summary.js +147 -0
- package/dist-client/pages/kpi-dashboard/kpi-performance-summary.js.map +1 -0
- package/dist-client/pages/kpi-dashboard/kpi-value-entry.d.ts +7 -0
- package/dist-client/pages/kpi-dashboard/kpi-value-entry.js +86 -0
- package/dist-client/pages/kpi-dashboard/kpi-value-entry.js.map +1 -0
- package/dist-client/pages/kpi-metric-value/kpi-metric-value-editor-page.d.ts +58 -0
- package/dist-client/pages/kpi-metric-value/kpi-metric-value-editor-page.js +731 -0
- package/dist-client/pages/kpi-metric-value/kpi-metric-value-editor-page.js.map +1 -0
- package/dist-client/pages/kpi-metric-value/kpi-metric-value-importer.d.ts +23 -0
- package/dist-client/pages/kpi-metric-value/kpi-metric-value-importer.js +76 -0
- package/dist-client/pages/kpi-metric-value/kpi-metric-value-importer.js.map +1 -0
- package/dist-client/pages/kpi-metric-value/kpi-metric-value-list-page.d.ts +69 -0
- package/dist-client/pages/kpi-metric-value/kpi-metric-value-list-page.js +385 -0
- package/dist-client/pages/kpi-metric-value/kpi-metric-value-list-page.js.map +1 -0
- package/dist-client/pages/kpi-metric-value/kpi-metric-value-manual-entry-form.d.ts +12 -0
- package/dist-client/pages/kpi-metric-value/kpi-metric-value-manual-entry-form.js +174 -0
- package/dist-client/pages/kpi-metric-value/kpi-metric-value-manual-entry-form.js.map +1 -0
- package/dist-client/pages/kpi-metric-value/kpi-metric-value-manual-entry-page.d.ts +41 -0
- package/dist-client/pages/kpi-metric-value/kpi-metric-value-manual-entry-page.js +191 -0
- package/dist-client/pages/kpi-metric-value/kpi-metric-value-manual-entry-page.js.map +1 -0
- package/dist-client/pages/kpi-value/kpi-value-importer.d.ts +23 -0
- package/dist-client/pages/kpi-value/kpi-value-importer.js +93 -0
- package/dist-client/pages/kpi-value/kpi-value-importer.js.map +1 -0
- package/dist-client/pages/kpi-value/kpi-value-list-page.d.ts +72 -0
- package/dist-client/pages/kpi-value/kpi-value-list-page.js +465 -0
- package/dist-client/pages/kpi-value/kpi-value-list-page.js.map +1 -0
- package/dist-client/pages/project-complete-tabs/pc-tab1-plan.d.ts +14 -0
- package/dist-client/pages/project-complete-tabs/pc-tab1-plan.js +319 -0
- package/dist-client/pages/project-complete-tabs/pc-tab1-plan.js.map +1 -0
- package/dist-client/pages/project-complete-tabs/pc-tab2-rating.d.ts +14 -0
- package/dist-client/pages/project-complete-tabs/pc-tab2-rating.js +275 -0
- package/dist-client/pages/project-complete-tabs/pc-tab2-rating.js.map +1 -0
- package/dist-client/pages/project-complete-tabs/pc-tab3-upload.d.ts +18 -0
- package/dist-client/pages/project-complete-tabs/pc-tab3-upload.js +307 -0
- package/dist-client/pages/project-complete-tabs/pc-tab3-upload.js.map +1 -0
- package/dist-client/pages/sv-project-complete.d.ts +20 -0
- package/dist-client/pages/sv-project-complete.js +209 -0
- package/dist-client/pages/sv-project-complete.js.map +1 -0
- package/dist-client/pages/sv-project-completed-list.d.ts +27 -0
- package/dist-client/pages/sv-project-completed-list.js +416 -0
- package/dist-client/pages/sv-project-completed-list.js.map +1 -0
- package/dist-client/pages/sv-project-detail.d.ts +34 -0
- package/dist-client/pages/sv-project-detail.js +1081 -0
- package/dist-client/pages/sv-project-detail.js.map +1 -0
- package/dist-client/pages/sv-project-list.d.ts +165 -0
- package/dist-client/pages/sv-project-list.js +489 -0
- package/dist-client/pages/sv-project-list.js.map +1 -0
- package/dist-client/route.d.ts +1 -1
- package/dist-client/route.js +25 -1
- package/dist-client/route.js.map +1 -1
- package/dist-client/shared/complete-api.d.ts +8 -0
- package/dist-client/shared/complete-api.js +177 -0
- package/dist-client/shared/complete-api.js.map +1 -0
- package/dist-client/shared/func.d.ts +2 -0
- package/dist-client/shared/func.js +22 -0
- package/dist-client/shared/func.js.map +1 -0
- package/dist-client/themes/dark.css +24 -24
- package/dist-client/themes/light.css +23 -23
- package/dist-client/tsconfig.tsbuildinfo +1 -1
- package/dist-client/viewparts/menu-tools.d.ts +46 -1
- package/dist-client/viewparts/menu-tools.js +377 -15
- package/dist-client/viewparts/menu-tools.js.map +1 -1
- package/dist-server/index.d.ts +2 -0
- package/dist-server/index.js +5 -0
- package/dist-server/index.js.map +1 -1
- package/dist-server/migrations/index.d.ts +1 -0
- package/dist-server/migrations/index.js +12 -0
- package/dist-server/migrations/index.js.map +1 -0
- package/dist-server/scripts/calculate-kpi-scores.d.ts +10 -0
- package/dist-server/scripts/calculate-kpi-scores.js +271 -0
- package/dist-server/scripts/calculate-kpi-scores.js.map +1 -0
- package/dist-server/scripts/load-grade-data-migration.d.ts +10 -0
- package/dist-server/scripts/load-grade-data-migration.js +194 -0
- package/dist-server/scripts/load-grade-data-migration.js.map +1 -0
- package/dist-server/scripts/propagate-parent-kpi-values.d.ts +10 -0
- package/dist-server/scripts/propagate-parent-kpi-values.js +440 -0
- package/dist-server/scripts/propagate-parent-kpi-values.js.map +1 -0
- package/dist-server/service/index.d.ts +4 -0
- package/dist-server/service/index.js +20 -0
- package/dist-server/service/index.js.map +1 -0
- package/dist-server/service/kpi-metric-value/index.d.ts +4 -0
- package/dist-server/service/kpi-metric-value/index.js +8 -0
- package/dist-server/service/kpi-metric-value/index.js.map +1 -0
- package/dist-server/service/kpi-metric-value/kpi-metric-value-mutation.d.ts +62 -0
- package/dist-server/service/kpi-metric-value/kpi-metric-value-mutation.js +572 -0
- package/dist-server/service/kpi-metric-value/kpi-metric-value-mutation.js.map +1 -0
- package/dist-server/service/kpi-metric-value/kpi-metric-value-query.d.ts +7 -0
- package/dist-server/service/kpi-metric-value/kpi-metric-value-query.js +47 -0
- package/dist-server/service/kpi-metric-value/kpi-metric-value-query.js.map +1 -0
- package/dist-server/service/kpi-stat/index.d.ts +4 -0
- package/dist-server/service/kpi-stat/index.js +8 -0
- package/dist-server/service/kpi-stat/index.js.map +1 -0
- package/dist-server/service/kpi-stat/kpi-stat-query.d.ts +9 -0
- package/dist-server/service/kpi-stat/kpi-stat-query.js +443 -0
- package/dist-server/service/kpi-stat/kpi-stat-query.js.map +1 -0
- package/dist-server/service/kpi-stat/kpi-stat-types.d.ts +19 -0
- package/dist-server/service/kpi-stat/kpi-stat-types.js +130 -0
- package/dist-server/service/kpi-stat/kpi-stat-types.js.map +1 -0
- package/dist-server/service/kpi-value/index.d.ts +3 -0
- package/dist-server/service/kpi-value/index.js +7 -0
- package/dist-server/service/kpi-value/index.js.map +1 -0
- package/dist-server/service/kpi-value/kpi-value-query.d.ts +8 -0
- package/dist-server/service/kpi-value/kpi-value-query.js +69 -0
- package/dist-server/service/kpi-value/kpi-value-query.js.map +1 -0
- package/dist-server/tsconfig.tsbuildinfo +1 -1
- package/kpi-module-service-tests.md +1286 -0
- package/kpi-module-test-report.md +676 -0
- package/kpi-module-unit-test-detailed-report.md +925 -0
- package/kpi-module-unit-tests-detailed.md +1452 -0
- package/package.json +62 -51
- package/schema.graphql +11559 -3215
- package/things-factory.config.js +7 -1
|
@@ -0,0 +1,271 @@
|
|
|
1
|
+
#!/usr/bin/env ts-node
|
|
2
|
+
"use strict";
|
|
3
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
4
|
+
exports.calculateKpiScores = calculateKpiScores;
|
|
5
|
+
exports.listKpisWithLookupTables = listKpisWithLookupTables;
|
|
6
|
+
const typeorm_1 = require("typeorm");
|
|
7
|
+
/**
|
|
8
|
+
* Calculate KPI scores based on lookup tables (grades)
|
|
9
|
+
* Processes kpi-values and updates scores based on KPI grades
|
|
10
|
+
*/
|
|
11
|
+
async function calculateKpiScores(specificKpiName, forceRecalculate = false) {
|
|
12
|
+
// Set NODE_ENV if not set
|
|
13
|
+
if (!process.env.NODE_ENV) {
|
|
14
|
+
process.env.NODE_ENV = 'development';
|
|
15
|
+
}
|
|
16
|
+
// Initialize Things-Factory environment
|
|
17
|
+
const { config } = require('@things-factory/env');
|
|
18
|
+
const ormconfig = require('@things-factory/shell/dist-server/initializers/ormconfig.js');
|
|
19
|
+
const connectionConfig = config.get('ormconfig');
|
|
20
|
+
let connection;
|
|
21
|
+
console.log('š Starting KPI Score Calculation...');
|
|
22
|
+
try {
|
|
23
|
+
// Create database connection using Things-Factory pattern
|
|
24
|
+
console.log('š Connecting to database...');
|
|
25
|
+
connection = await (0, typeorm_1.createConnection)(Object.assign(Object.assign(Object.assign({}, ormconfig), connectionConfig), { logging: false }));
|
|
26
|
+
// Register the connection with Things-Factory shell
|
|
27
|
+
const { addDataSource } = require('@things-factory/shell');
|
|
28
|
+
addDataSource('default', connection);
|
|
29
|
+
console.log('ā
Database connected');
|
|
30
|
+
// Now we can use getRepository with the registered connection
|
|
31
|
+
const { getRepository } = require('@things-factory/shell');
|
|
32
|
+
const { Kpi } = require('@things-factory/kpi');
|
|
33
|
+
const kpiRepository = getRepository(Kpi);
|
|
34
|
+
// Get KPI-Value repository (assuming it exists)
|
|
35
|
+
let kpiValueRepository;
|
|
36
|
+
try {
|
|
37
|
+
const { KpiValue } = require('@things-factory/kpi');
|
|
38
|
+
kpiValueRepository = getRepository(KpiValue);
|
|
39
|
+
}
|
|
40
|
+
catch (error) {
|
|
41
|
+
console.error('ā KpiValue entity not found. Please ensure it exists in @things-factory/kpi');
|
|
42
|
+
return;
|
|
43
|
+
}
|
|
44
|
+
// Get KPIs with grades (lookup tables)
|
|
45
|
+
let kpisQuery = kpiRepository
|
|
46
|
+
.createQueryBuilder('kpi')
|
|
47
|
+
.leftJoinAndSelect('kpi.domain', 'domain')
|
|
48
|
+
.where('kpi.grades IS NOT NULL')
|
|
49
|
+
.andWhere('domain.name = :domainName', { domainName: 'SYSTEM' });
|
|
50
|
+
if (specificKpiName) {
|
|
51
|
+
kpisQuery = kpisQuery.andWhere('kpi.name = :name', { name: specificKpiName });
|
|
52
|
+
console.log(`šÆ Processing specific KPI: ${specificKpiName}`);
|
|
53
|
+
}
|
|
54
|
+
else {
|
|
55
|
+
console.log('šÆ Processing all KPIs with lookup tables');
|
|
56
|
+
}
|
|
57
|
+
const kpis = await kpisQuery.getMany();
|
|
58
|
+
if (kpis.length === 0) {
|
|
59
|
+
console.log('ā ļø No KPIs found with lookup tables (grades)');
|
|
60
|
+
return;
|
|
61
|
+
}
|
|
62
|
+
console.log(`š Found ${kpis.length} KPIs with lookup tables`);
|
|
63
|
+
let totalProcessed = 0;
|
|
64
|
+
let totalUpdated = 0;
|
|
65
|
+
let errorCount = 0;
|
|
66
|
+
for (const kpi of kpis) {
|
|
67
|
+
try {
|
|
68
|
+
console.log(`\nš Processing KPI: ${kpi.name}`);
|
|
69
|
+
if (!kpi.grades || !Array.isArray(kpi.grades) || kpi.grades.length === 0) {
|
|
70
|
+
console.log(` ā ļø No grades found, skipping`);
|
|
71
|
+
continue;
|
|
72
|
+
}
|
|
73
|
+
console.log(` š Lookup table: ${kpi.grades.length} grades`);
|
|
74
|
+
// Get KPI values for this KPI
|
|
75
|
+
let kpiValuesQuery = kpiValueRepository
|
|
76
|
+
.createQueryBuilder('kpiValue')
|
|
77
|
+
.leftJoinAndSelect('kpiValue.kpi', 'kpi')
|
|
78
|
+
.where('kpi.id = :kpiId', { kpiId: kpi.id })
|
|
79
|
+
.andWhere('kpiValue.value IS NOT NULL');
|
|
80
|
+
if (!forceRecalculate) {
|
|
81
|
+
// Only process null or 0 scores by default
|
|
82
|
+
kpiValuesQuery = kpiValuesQuery.andWhere('(kpiValue.score IS NULL OR kpiValue.score = 0)');
|
|
83
|
+
}
|
|
84
|
+
const kpiValues = await kpiValuesQuery.getMany();
|
|
85
|
+
if (kpiValues.length === 0) {
|
|
86
|
+
console.log(` ā
No null/zero scores found (all values already calculated)`);
|
|
87
|
+
continue;
|
|
88
|
+
}
|
|
89
|
+
console.log(` š¢ Processing ${kpiValues.length} null/zero scores`);
|
|
90
|
+
let updatedCount = 0;
|
|
91
|
+
for (const kpiValue of kpiValues) {
|
|
92
|
+
const value = kpiValue.value;
|
|
93
|
+
const calculatedScore = calculateScoreFromGrades(value, kpi.grades);
|
|
94
|
+
if (calculatedScore !== null) {
|
|
95
|
+
// Only update if the score is actually different
|
|
96
|
+
if (kpiValue.score !== calculatedScore) {
|
|
97
|
+
const oldScore = kpiValue.score;
|
|
98
|
+
kpiValue.score = calculatedScore;
|
|
99
|
+
await kpiValueRepository.save(kpiValue);
|
|
100
|
+
updatedCount++;
|
|
101
|
+
console.log(` š Value ${value} ā Score ${calculatedScore} (was ${oldScore || 'null'})`);
|
|
102
|
+
}
|
|
103
|
+
}
|
|
104
|
+
else {
|
|
105
|
+
console.log(` ā ļø Value ${value} is below all ranges in lookup table`);
|
|
106
|
+
}
|
|
107
|
+
totalProcessed++;
|
|
108
|
+
}
|
|
109
|
+
console.log(` ā
Updated ${updatedCount}/${kpiValues.length} values`);
|
|
110
|
+
totalUpdated += updatedCount;
|
|
111
|
+
}
|
|
112
|
+
catch (kpiError) {
|
|
113
|
+
console.log(` ā Error processing KPI ${kpi.name}: ${kpiError.message}`);
|
|
114
|
+
errorCount++;
|
|
115
|
+
}
|
|
116
|
+
}
|
|
117
|
+
console.log(`\nš KPI Score Calculation Complete!`);
|
|
118
|
+
console.log(` š KPIs processed: ${kpis.length}`);
|
|
119
|
+
console.log(` š¢ Total values processed: ${totalProcessed}`);
|
|
120
|
+
console.log(` ā
Scores updated: ${totalUpdated}`);
|
|
121
|
+
console.log(` ā Errors: ${errorCount}`);
|
|
122
|
+
if (errorCount > 0) {
|
|
123
|
+
console.log(`\nā ļø Some KPIs had errors. Check the logs above for details.`);
|
|
124
|
+
}
|
|
125
|
+
}
|
|
126
|
+
catch (error) {
|
|
127
|
+
console.error(`ā Fatal error during score calculation:`, error);
|
|
128
|
+
throw error;
|
|
129
|
+
}
|
|
130
|
+
finally {
|
|
131
|
+
if (connection) {
|
|
132
|
+
await connection.close();
|
|
133
|
+
console.log('š Database connection closed');
|
|
134
|
+
}
|
|
135
|
+
}
|
|
136
|
+
}
|
|
137
|
+
/**
|
|
138
|
+
* Calculate score from grades lookup table
|
|
139
|
+
* If exact range not found, use the score of the largest minValue that is <= value
|
|
140
|
+
*/
|
|
141
|
+
function calculateScoreFromGrades(value, grades) {
|
|
142
|
+
// First try to find exact range match
|
|
143
|
+
for (const grade of grades) {
|
|
144
|
+
if (value >= grade.minValue && value <= grade.maxValue) {
|
|
145
|
+
return grade.score || 0;
|
|
146
|
+
}
|
|
147
|
+
}
|
|
148
|
+
// If no exact match, find the grade with largest minValue that is <= value
|
|
149
|
+
let bestGrade = null;
|
|
150
|
+
let bestMinValue = -Infinity;
|
|
151
|
+
for (const grade of grades) {
|
|
152
|
+
if (grade.minValue <= value && grade.minValue > bestMinValue) {
|
|
153
|
+
bestGrade = grade;
|
|
154
|
+
bestMinValue = grade.minValue;
|
|
155
|
+
}
|
|
156
|
+
}
|
|
157
|
+
if (bestGrade) {
|
|
158
|
+
return bestGrade.score || 0;
|
|
159
|
+
}
|
|
160
|
+
return null; // Value is smaller than all minValues in lookup table
|
|
161
|
+
}
|
|
162
|
+
/**
|
|
163
|
+
* List KPIs that have lookup tables (grades)
|
|
164
|
+
*/
|
|
165
|
+
async function listKpisWithLookupTables() {
|
|
166
|
+
// Set NODE_ENV if not set
|
|
167
|
+
if (!process.env.NODE_ENV) {
|
|
168
|
+
process.env.NODE_ENV = 'development';
|
|
169
|
+
}
|
|
170
|
+
// Initialize Things-Factory environment
|
|
171
|
+
const { config } = require('@things-factory/env');
|
|
172
|
+
const ormconfig = require('@things-factory/shell/dist-server/initializers/ormconfig.js');
|
|
173
|
+
const connectionConfig = config.get('ormconfig');
|
|
174
|
+
let connection;
|
|
175
|
+
try {
|
|
176
|
+
console.log('š Connecting to database...');
|
|
177
|
+
connection = await (0, typeorm_1.createConnection)(Object.assign(Object.assign(Object.assign({}, ormconfig), connectionConfig), { logging: false }));
|
|
178
|
+
const { addDataSource } = require('@things-factory/shell');
|
|
179
|
+
addDataSource('default', connection);
|
|
180
|
+
const { getRepository } = require('@things-factory/shell');
|
|
181
|
+
const { Kpi } = require('@things-factory/kpi');
|
|
182
|
+
const kpiRepository = getRepository(Kpi);
|
|
183
|
+
// Get KPIs with grades
|
|
184
|
+
const kpis = await kpiRepository
|
|
185
|
+
.createQueryBuilder('kpi')
|
|
186
|
+
.leftJoinAndSelect('kpi.domain', 'domain')
|
|
187
|
+
.where('kpi.grades IS NOT NULL')
|
|
188
|
+
.andWhere('domain.name = :domainName', { domainName: 'SYSTEM' })
|
|
189
|
+
.getMany();
|
|
190
|
+
console.log(`š KPIs with lookup tables (${kpis.length}):\n`);
|
|
191
|
+
if (kpis.length === 0) {
|
|
192
|
+
console.log(' No KPIs found with lookup tables.');
|
|
193
|
+
return;
|
|
194
|
+
}
|
|
195
|
+
kpis.forEach((kpi, index) => {
|
|
196
|
+
const gradeCount = kpi.grades ? kpi.grades.length : 0;
|
|
197
|
+
console.log(` ${(index + 1).toString().padStart(2)}: ${kpi.name} (${gradeCount} grades)`);
|
|
198
|
+
});
|
|
199
|
+
console.log(`\nš Total: ${kpis.length} KPIs with lookup tables`);
|
|
200
|
+
}
|
|
201
|
+
catch (error) {
|
|
202
|
+
console.error('ā Error listing KPIs:', error);
|
|
203
|
+
}
|
|
204
|
+
finally {
|
|
205
|
+
if (connection) {
|
|
206
|
+
await connection.close();
|
|
207
|
+
}
|
|
208
|
+
}
|
|
209
|
+
}
|
|
210
|
+
/**
|
|
211
|
+
* CLI execution when called directly
|
|
212
|
+
*/
|
|
213
|
+
async function main() {
|
|
214
|
+
const args = process.argv.slice(2);
|
|
215
|
+
try {
|
|
216
|
+
if (args.includes('--help') || args.includes('-h')) {
|
|
217
|
+
console.log(`
|
|
218
|
+
šÆ KPI Score Calculator
|
|
219
|
+
|
|
220
|
+
Usage:
|
|
221
|
+
ts-node server/scripts/calculate-kpi-scores.ts [options] [kpiName]
|
|
222
|
+
|
|
223
|
+
Options:
|
|
224
|
+
--list, -l List KPIs that have lookup tables
|
|
225
|
+
--force, -f Force recalculate all scores (not just null/zero ones)
|
|
226
|
+
--help, -h Show this help
|
|
227
|
+
|
|
228
|
+
Examples:
|
|
229
|
+
ts-node server/scripts/calculate-kpi-scores.ts # Calculate scores for null/zero values only
|
|
230
|
+
ts-node server/scripts/calculate-kpi-scores.ts --force # Recalculate ALL scores
|
|
231
|
+
ts-node server/scripts/calculate-kpi-scores.ts "X11. ģ°ė©“ģ ėė¹ ź³µģ¬źø°ź°" # Calculate for specific KPI
|
|
232
|
+
ts-node server/scripts/calculate-kpi-scores.ts --list # List KPIs with lookup tables
|
|
233
|
+
|
|
234
|
+
Note: By default, only processes kpi-values with null or zero scores.
|
|
235
|
+
Use --force to recalculate all scores.
|
|
236
|
+
`);
|
|
237
|
+
return;
|
|
238
|
+
}
|
|
239
|
+
if (args.includes('--list') || args.includes('-l')) {
|
|
240
|
+
await listKpisWithLookupTables();
|
|
241
|
+
return;
|
|
242
|
+
}
|
|
243
|
+
const forceRecalculate = args.includes('--force') || args.includes('-f');
|
|
244
|
+
const specificKpiName = args.find(arg => !arg.startsWith('--'));
|
|
245
|
+
if (specificKpiName) {
|
|
246
|
+
console.log(`šÆ Calculating scores for specific KPI: ${specificKpiName}`);
|
|
247
|
+
console.log(` Mode: ${forceRecalculate ? 'Force recalculate ALL' : 'Only null/zero scores'}`);
|
|
248
|
+
await calculateKpiScores(specificKpiName, forceRecalculate);
|
|
249
|
+
}
|
|
250
|
+
else {
|
|
251
|
+
console.log(`šÆ Calculating scores for all KPIs with lookup tables`);
|
|
252
|
+
console.log(` Mode: ${forceRecalculate ? 'Force recalculate ALL' : 'Only null/zero scores'}`);
|
|
253
|
+
await calculateKpiScores(undefined, forceRecalculate);
|
|
254
|
+
}
|
|
255
|
+
console.log('\n⨠Done!');
|
|
256
|
+
}
|
|
257
|
+
catch (error) {
|
|
258
|
+
console.error('\nā Script failed:', error.message);
|
|
259
|
+
process.exit(1);
|
|
260
|
+
}
|
|
261
|
+
}
|
|
262
|
+
// Handle uncaught errors
|
|
263
|
+
process.on('unhandledRejection', (error) => {
|
|
264
|
+
console.error('ā Unhandled error:', error.message || error);
|
|
265
|
+
process.exit(1);
|
|
266
|
+
});
|
|
267
|
+
// Run if called directly
|
|
268
|
+
if (require.main === module) {
|
|
269
|
+
main();
|
|
270
|
+
}
|
|
271
|
+
//# sourceMappingURL=calculate-kpi-scores.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"calculate-kpi-scores.js","sourceRoot":"","sources":["../../server/scripts/calculate-kpi-scores.ts"],"names":[],"mappings":";;;AAgCA,gDA2JC;AAmCD,4DAyDC;AArRD,qCAA0C;AA0B1C;;;GAGG;AACI,KAAK,UAAU,kBAAkB,CAAC,eAAwB,EAAE,gBAAgB,GAAG,KAAK;IACzF,0BAA0B;IAC1B,IAAI,CAAC,OAAO,CAAC,GAAG,CAAC,QAAQ,EAAE,CAAC;QAC1B,OAAO,CAAC,GAAG,CAAC,QAAQ,GAAG,aAAa,CAAA;IACtC,CAAC;IAED,wCAAwC;IACxC,MAAM,EAAE,MAAM,EAAE,GAAG,OAAO,CAAC,qBAAqB,CAAC,CAAA;IACjD,MAAM,SAAS,GAAG,OAAO,CAAC,6DAA6D,CAAC,CAAA;IACxF,MAAM,gBAAgB,GAAG,MAAM,CAAC,GAAG,CAAC,WAAW,CAAC,CAAA;IAEhD,IAAI,UAAU,CAAA;IAEd,OAAO,CAAC,GAAG,CAAC,sCAAsC,CAAC,CAAA;IAEnD,IAAI,CAAC;QACH,0DAA0D;QAC1D,OAAO,CAAC,GAAG,CAAC,8BAA8B,CAAC,CAAA;QAC3C,UAAU,GAAG,MAAM,IAAA,0BAAgB,gDAC9B,SAAS,GACT,gBAAgB,KACnB,OAAO,EAAE,KAAK,IACd,CAAA;QAEF,oDAAoD;QACpD,MAAM,EAAE,aAAa,EAAE,GAAG,OAAO,CAAC,uBAAuB,CAAC,CAAA;QAC1D,aAAa,CAAC,SAAS,EAAE,UAAU,CAAC,CAAA;QAEpC,OAAO,CAAC,GAAG,CAAC,sBAAsB,CAAC,CAAA;QAEnC,8DAA8D;QAC9D,MAAM,EAAE,aAAa,EAAE,GAAG,OAAO,CAAC,uBAAuB,CAAC,CAAA;QAC1D,MAAM,EAAE,GAAG,EAAE,GAAG,OAAO,CAAC,qBAAqB,CAAC,CAAA;QAC9C,MAAM,aAAa,GAAG,aAAa,CAAC,GAAG,CAAC,CAAA;QAExC,gDAAgD;QAChD,IAAI,kBAAkB,CAAA;QACtB,IAAI,CAAC;YACH,MAAM,EAAE,QAAQ,EAAE,GAAG,OAAO,CAAC,qBAAqB,CAAC,CAAA;YACnD,kBAAkB,GAAG,aAAa,CAAC,QAAQ,CAAC,CAAA;QAC9C,CAAC;QAAC,OAAO,KAAK,EAAE,CAAC;YACf,OAAO,CAAC,KAAK,CAAC,6EAA6E,CAAC,CAAA;YAC5F,OAAM;QACR,CAAC;QAED,uCAAuC;QACvC,IAAI,SAAS,GAAG,aAAa;aAC1B,kBAAkB,CAAC,KAAK,CAAC;aACzB,iBAAiB,CAAC,YAAY,EAAE,QAAQ,CAAC;aACzC,KAAK,CAAC,wBAAwB,CAAC;aAC/B,QAAQ,CAAC,2BAA2B,EAAE,EAAE,UAAU,EAAE,QAAQ,EAAE,CAAC,CAAA;QAElE,IAAI,eAAe,EAAE,CAAC;YACpB,SAAS,GAAG,SAAS,CAAC,QAAQ,CAAC,kBAAkB,EAAE,EAAE,IAAI,EAAE,eAAe,EAAE,CAAC,CAAA;YAC7E,OAAO,CAAC,GAAG,CAAC,+BAA+B,eAAe,EAAE,CAAC,CAAA;QAC/D,CAAC;aAAM,CAAC;YACN,OAAO,CAAC,GAAG,CAAC,2CAA2C,CAAC,CAAA;QAC1D,CAAC;QAED,MAAM,IAAI,GAAG,MAAM,SAAS,CAAC,OAAO,EAAE,CAAA;QAEtC,IAAI,IAAI,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;YACtB,OAAO,CAAC,GAAG,CAAC,+CAA+C,CAAC,CAAA;YAC5D,OAAM;QACR,CAAC;QAED,OAAO,CAAC,GAAG,CAAC,YAAY,IAAI,CAAC,MAAM,0BAA0B,CAAC,CAAA;QAE9D,IAAI,cAAc,GAAG,CAAC,CAAA;QACtB,IAAI,YAAY,GAAG,CAAC,CAAA;QACpB,IAAI,UAAU,GAAG,CAAC,CAAA;QAElB,KAAK,MAAM,GAAG,IAAI,IAAI,EAAE,CAAC;YACvB,IAAI,CAAC;gBACH,OAAO,CAAC,GAAG,CAAC,wBAAwB,GAAG,CAAC,IAAI,EAAE,CAAC,CAAA;gBAE/C,IAAI,CAAC,GAAG,CAAC,MAAM,IAAI,CAAC,KAAK,CAAC,OAAO,CAAC,GAAG,CAAC,MAAM,CAAC,IAAI,GAAG,CAAC,MAAM,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;oBACzE,OAAO,CAAC,GAAG,CAAC,kCAAkC,CAAC,CAAA;oBAC/C,SAAQ;gBACV,CAAC;gBAED,OAAO,CAAC,GAAG,CAAC,uBAAuB,GAAG,CAAC,MAAM,CAAC,MAAM,SAAS,CAAC,CAAA;gBAE9D,8BAA8B;gBAC9B,IAAI,cAAc,GAAG,kBAAkB;qBACpC,kBAAkB,CAAC,UAAU,CAAC;qBAC9B,iBAAiB,CAAC,cAAc,EAAE,KAAK,CAAC;qBACxC,KAAK,CAAC,iBAAiB,EAAE,EAAE,KAAK,EAAE,GAAG,CAAC,EAAE,EAAE,CAAC;qBAC3C,QAAQ,CAAC,4BAA4B,CAAC,CAAA;gBAEzC,IAAI,CAAC,gBAAgB,EAAE,CAAC;oBACtB,2CAA2C;oBAC3C,cAAc,GAAG,cAAc,CAAC,QAAQ,CAAC,gDAAgD,CAAC,CAAA;gBAC5F,CAAC;gBAED,MAAM,SAAS,GAAG,MAAM,cAAc,CAAC,OAAO,EAAE,CAAA;gBAEhD,IAAI,SAAS,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;oBAC3B,OAAO,CAAC,GAAG,CAAC,gEAAgE,CAAC,CAAA;oBAC7E,SAAQ;gBACV,CAAC;gBAED,OAAO,CAAC,GAAG,CAAC,oBAAoB,SAAS,CAAC,MAAM,mBAAmB,CAAC,CAAA;gBAEpE,IAAI,YAAY,GAAG,CAAC,CAAA;gBAEpB,KAAK,MAAM,QAAQ,IAAI,SAAS,EAAE,CAAC;oBACjC,MAAM,KAAK,GAAG,QAAQ,CAAC,KAAK,CAAA;oBAC5B,MAAM,eAAe,GAAG,wBAAwB,CAAC,KAAK,EAAE,GAAG,CAAC,MAAM,CAAC,CAAA;oBAEnE,IAAI,eAAe,KAAK,IAAI,EAAE,CAAC;wBAC7B,iDAAiD;wBACjD,IAAI,QAAQ,CAAC,KAAK,KAAK,eAAe,EAAE,CAAC;4BACvC,MAAM,QAAQ,GAAG,QAAQ,CAAC,KAAK,CAAA;4BAC/B,QAAQ,CAAC,KAAK,GAAG,eAAe,CAAA;4BAChC,MAAM,kBAAkB,CAAC,IAAI,CAAC,QAAQ,CAAC,CAAA;4BACvC,YAAY,EAAE,CAAA;4BAEd,OAAO,CAAC,GAAG,CAAC,iBAAiB,KAAK,YAAY,eAAe,SAAS,QAAQ,IAAI,MAAM,GAAG,CAAC,CAAA;wBAC9F,CAAC;oBACH,CAAC;yBAAM,CAAC;wBACN,OAAO,CAAC,GAAG,CAAC,kBAAkB,KAAK,sCAAsC,CAAC,CAAA;oBAC5E,CAAC;oBAED,cAAc,EAAE,CAAA;gBAClB,CAAC;gBAED,OAAO,CAAC,GAAG,CAAC,gBAAgB,YAAY,IAAI,SAAS,CAAC,MAAM,SAAS,CAAC,CAAA;gBACtE,YAAY,IAAI,YAAY,CAAA;YAE9B,CAAC;YAAC,OAAO,QAAQ,EAAE,CAAC;gBAClB,OAAO,CAAC,GAAG,CAAC,6BAA6B,GAAG,CAAC,IAAI,KAAK,QAAQ,CAAC,OAAO,EAAE,CAAC,CAAA;gBACzE,UAAU,EAAE,CAAA;YACd,CAAC;QACH,CAAC;QAED,OAAO,CAAC,GAAG,CAAC,sCAAsC,CAAC,CAAA;QACnD,OAAO,CAAC,GAAG,CAAC,yBAAyB,IAAI,CAAC,MAAM,EAAE,CAAC,CAAA;QACnD,OAAO,CAAC,GAAG,CAAC,iCAAiC,cAAc,EAAE,CAAC,CAAA;QAC9D,OAAO,CAAC,GAAG,CAAC,wBAAwB,YAAY,EAAE,CAAC,CAAA;QACnD,OAAO,CAAC,GAAG,CAAC,gBAAgB,UAAU,EAAE,CAAC,CAAA;QAEzC,IAAI,UAAU,GAAG,CAAC,EAAE,CAAC;YACnB,OAAO,CAAC,GAAG,CAAC,+DAA+D,CAAC,CAAA;QAC9E,CAAC;IAEH,CAAC;IAAC,OAAO,KAAK,EAAE,CAAC;QACf,OAAO,CAAC,KAAK,CAAC,yCAAyC,EAAE,KAAK,CAAC,CAAA;QAC/D,MAAM,KAAK,CAAA;IACb,CAAC;YAAS,CAAC;QACT,IAAI,UAAU,EAAE,CAAC;YACf,MAAM,UAAU,CAAC,KAAK,EAAE,CAAA;YACxB,OAAO,CAAC,GAAG,CAAC,+BAA+B,CAAC,CAAA;QAC9C,CAAC;IACH,CAAC;AACH,CAAC;AAED;;;GAGG;AACH,SAAS,wBAAwB,CAAC,KAAa,EAAE,MAAkB;IACjE,sCAAsC;IACtC,KAAK,MAAM,KAAK,IAAI,MAAM,EAAE,CAAC;QAC3B,IAAI,KAAK,IAAI,KAAK,CAAC,QAAQ,IAAI,KAAK,IAAI,KAAK,CAAC,QAAQ,EAAE,CAAC;YACvD,OAAO,KAAK,CAAC,KAAK,IAAI,CAAC,CAAA;QACzB,CAAC;IACH,CAAC;IAED,2EAA2E;IAC3E,IAAI,SAAS,GAAoB,IAAI,CAAA;IACrC,IAAI,YAAY,GAAG,CAAC,QAAQ,CAAA;IAE5B,KAAK,MAAM,KAAK,IAAI,MAAM,EAAE,CAAC;QAC3B,IAAI,KAAK,CAAC,QAAQ,IAAI,KAAK,IAAI,KAAK,CAAC,QAAQ,GAAG,YAAY,EAAE,CAAC;YAC7D,SAAS,GAAG,KAAK,CAAA;YACjB,YAAY,GAAG,KAAK,CAAC,QAAQ,CAAA;QAC/B,CAAC;IACH,CAAC;IAED,IAAI,SAAS,EAAE,CAAC;QACd,OAAO,SAAS,CAAC,KAAK,IAAI,CAAC,CAAA;IAC7B,CAAC;IAED,OAAO,IAAI,CAAA,CAAC,sDAAsD;AACpE,CAAC;AAED;;GAEG;AACI,KAAK,UAAU,wBAAwB;IAC5C,0BAA0B;IAC1B,IAAI,CAAC,OAAO,CAAC,GAAG,CAAC,QAAQ,EAAE,CAAC;QAC1B,OAAO,CAAC,GAAG,CAAC,QAAQ,GAAG,aAAa,CAAA;IACtC,CAAC;IAED,wCAAwC;IACxC,MAAM,EAAE,MAAM,EAAE,GAAG,OAAO,CAAC,qBAAqB,CAAC,CAAA;IACjD,MAAM,SAAS,GAAG,OAAO,CAAC,6DAA6D,CAAC,CAAA;IACxF,MAAM,gBAAgB,GAAG,MAAM,CAAC,GAAG,CAAC,WAAW,CAAC,CAAA;IAEhD,IAAI,UAAU,CAAA;IAEd,IAAI,CAAC;QACH,OAAO,CAAC,GAAG,CAAC,8BAA8B,CAAC,CAAA;QAC3C,UAAU,GAAG,MAAM,IAAA,0BAAgB,gDAC9B,SAAS,GACT,gBAAgB,KACnB,OAAO,EAAE,KAAK,IACd,CAAA;QAEF,MAAM,EAAE,aAAa,EAAE,GAAG,OAAO,CAAC,uBAAuB,CAAC,CAAA;QAC1D,aAAa,CAAC,SAAS,EAAE,UAAU,CAAC,CAAA;QAEpC,MAAM,EAAE,aAAa,EAAE,GAAG,OAAO,CAAC,uBAAuB,CAAC,CAAA;QAC1D,MAAM,EAAE,GAAG,EAAE,GAAG,OAAO,CAAC,qBAAqB,CAAC,CAAA;QAC9C,MAAM,aAAa,GAAG,aAAa,CAAC,GAAG,CAAC,CAAA;QAExC,uBAAuB;QACvB,MAAM,IAAI,GAAG,MAAM,aAAa;aAC7B,kBAAkB,CAAC,KAAK,CAAC;aACzB,iBAAiB,CAAC,YAAY,EAAE,QAAQ,CAAC;aACzC,KAAK,CAAC,wBAAwB,CAAC;aAC/B,QAAQ,CAAC,2BAA2B,EAAE,EAAE,UAAU,EAAE,QAAQ,EAAE,CAAC;aAC/D,OAAO,EAAE,CAAA;QAEZ,OAAO,CAAC,GAAG,CAAC,+BAA+B,IAAI,CAAC,MAAM,MAAM,CAAC,CAAA;QAE7D,IAAI,IAAI,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;YACtB,OAAO,CAAC,GAAG,CAAC,sCAAsC,CAAC,CAAA;YACnD,OAAM;QACR,CAAC;QAED,IAAI,CAAC,OAAO,CAAC,CAAC,GAAG,EAAE,KAAK,EAAE,EAAE;YAC1B,MAAM,UAAU,GAAG,GAAG,CAAC,MAAM,CAAC,CAAC,CAAC,GAAG,CAAC,MAAM,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC,CAAA;YACrD,OAAO,CAAC,GAAG,CAAC,MAAM,CAAC,KAAK,GAAG,CAAC,CAAC,CAAC,QAAQ,EAAE,CAAC,QAAQ,CAAC,CAAC,CAAC,KAAK,GAAG,CAAC,IAAI,KAAK,UAAU,UAAU,CAAC,CAAA;QAC7F,CAAC,CAAC,CAAA;QAEF,OAAO,CAAC,GAAG,CAAC,eAAe,IAAI,CAAC,MAAM,0BAA0B,CAAC,CAAA;IAEnE,CAAC;IAAC,OAAO,KAAK,EAAE,CAAC;QACf,OAAO,CAAC,KAAK,CAAC,uBAAuB,EAAE,KAAK,CAAC,CAAA;IAC/C,CAAC;YAAS,CAAC;QACT,IAAI,UAAU,EAAE,CAAC;YACf,MAAM,UAAU,CAAC,KAAK,EAAE,CAAA;QAC1B,CAAC;IACH,CAAC;AACH,CAAC;AAED;;GAEG;AACH,KAAK,UAAU,IAAI;IACjB,MAAM,IAAI,GAAG,OAAO,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC,CAAC,CAAA;IAElC,IAAI,CAAC;QACH,IAAI,IAAI,CAAC,QAAQ,CAAC,QAAQ,CAAC,IAAI,IAAI,CAAC,QAAQ,CAAC,IAAI,CAAC,EAAE,CAAC;YACnD,OAAO,CAAC,GAAG,CAAC;;;;;;;;;;;;;;;;;;;OAmBX,CAAC,CAAA;YACF,OAAM;QACR,CAAC;QAED,IAAI,IAAI,CAAC,QAAQ,CAAC,QAAQ,CAAC,IAAI,IAAI,CAAC,QAAQ,CAAC,IAAI,CAAC,EAAE,CAAC;YACnD,MAAM,wBAAwB,EAAE,CAAA;YAChC,OAAM;QACR,CAAC;QAED,MAAM,gBAAgB,GAAG,IAAI,CAAC,QAAQ,CAAC,SAAS,CAAC,IAAI,IAAI,CAAC,QAAQ,CAAC,IAAI,CAAC,CAAA;QACxE,MAAM,eAAe,GAAG,IAAI,CAAC,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,CAAC,GAAG,CAAC,UAAU,CAAC,IAAI,CAAC,CAAC,CAAA;QAE/D,IAAI,eAAe,EAAE,CAAC;YACpB,OAAO,CAAC,GAAG,CAAC,2CAA2C,eAAe,EAAE,CAAC,CAAA;YACzE,OAAO,CAAC,GAAG,CAAC,YAAY,gBAAgB,CAAC,CAAC,CAAC,uBAAuB,CAAC,CAAC,CAAC,uBAAuB,EAAE,CAAC,CAAA;YAC/F,MAAM,kBAAkB,CAAC,eAAe,EAAE,gBAAgB,CAAC,CAAA;QAC7D,CAAC;aAAM,CAAC;YACN,OAAO,CAAC,GAAG,CAAC,uDAAuD,CAAC,CAAA;YACpE,OAAO,CAAC,GAAG,CAAC,YAAY,gBAAgB,CAAC,CAAC,CAAC,uBAAuB,CAAC,CAAC,CAAC,uBAAuB,EAAE,CAAC,CAAA;YAC/F,MAAM,kBAAkB,CAAC,SAAS,EAAE,gBAAgB,CAAC,CAAA;QACvD,CAAC;QAED,OAAO,CAAC,GAAG,CAAC,WAAW,CAAC,CAAA;IAE1B,CAAC;IAAC,OAAO,KAAK,EAAE,CAAC;QACf,OAAO,CAAC,KAAK,CAAC,oBAAoB,EAAE,KAAK,CAAC,OAAO,CAAC,CAAA;QAClD,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAA;IACjB,CAAC;AACH,CAAC;AAED,yBAAyB;AACzB,OAAO,CAAC,EAAE,CAAC,oBAAoB,EAAE,CAAC,KAAU,EAAE,EAAE;IAC9C,OAAO,CAAC,KAAK,CAAC,oBAAoB,EAAE,KAAK,CAAC,OAAO,IAAI,KAAK,CAAC,CAAA;IAC3D,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAA;AACjB,CAAC,CAAC,CAAA;AAEF,yBAAyB;AACzB,IAAI,OAAO,CAAC,IAAI,KAAK,MAAM,EAAE,CAAC;IAC5B,IAAI,EAAE,CAAA;AACR,CAAC","sourcesContent":["#!/usr/bin/env ts-node\n\nimport { createConnection } from 'typeorm'\nimport * as fs from 'fs'\nimport * as path from 'path'\n\ninterface KpiGrade {\n name: string\n minValue: number\n maxValue: number\n score?: number\n color?: string\n description?: string\n}\n\ninterface KpiRecord {\n id: string\n name: string\n grades: KpiGrade[]\n}\n\ninterface KpiValueRecord {\n id: string\n value: number\n score?: number\n kpi: KpiRecord\n}\n\n/**\n * Calculate KPI scores based on lookup tables (grades)\n * Processes kpi-values and updates scores based on KPI grades\n */\nexport async function calculateKpiScores(specificKpiName?: string, forceRecalculate = false): Promise<void> {\n // Set NODE_ENV if not set\n if (!process.env.NODE_ENV) {\n process.env.NODE_ENV = 'development'\n }\n\n // Initialize Things-Factory environment\n const { config } = require('@things-factory/env')\n const ormconfig = require('@things-factory/shell/dist-server/initializers/ormconfig.js')\n const connectionConfig = config.get('ormconfig')\n\n let connection\n\n console.log('š Starting KPI Score Calculation...')\n\n try {\n // Create database connection using Things-Factory pattern\n console.log('š Connecting to database...')\n connection = await createConnection({\n ...ormconfig,\n ...connectionConfig,\n logging: false\n })\n\n // Register the connection with Things-Factory shell\n const { addDataSource } = require('@things-factory/shell')\n addDataSource('default', connection)\n\n console.log('ā
Database connected')\n\n // Now we can use getRepository with the registered connection\n const { getRepository } = require('@things-factory/shell')\n const { Kpi } = require('@things-factory/kpi')\n const kpiRepository = getRepository(Kpi)\n\n // Get KPI-Value repository (assuming it exists)\n let kpiValueRepository\n try {\n const { KpiValue } = require('@things-factory/kpi')\n kpiValueRepository = getRepository(KpiValue)\n } catch (error) {\n console.error('ā KpiValue entity not found. Please ensure it exists in @things-factory/kpi')\n return\n }\n\n // Get KPIs with grades (lookup tables)\n let kpisQuery = kpiRepository\n .createQueryBuilder('kpi')\n .leftJoinAndSelect('kpi.domain', 'domain')\n .where('kpi.grades IS NOT NULL')\n .andWhere('domain.name = :domainName', { domainName: 'SYSTEM' })\n\n if (specificKpiName) {\n kpisQuery = kpisQuery.andWhere('kpi.name = :name', { name: specificKpiName })\n console.log(`šÆ Processing specific KPI: ${specificKpiName}`)\n } else {\n console.log('šÆ Processing all KPIs with lookup tables')\n }\n\n const kpis = await kpisQuery.getMany()\n\n if (kpis.length === 0) {\n console.log('ā ļø No KPIs found with lookup tables (grades)')\n return\n }\n\n console.log(`š Found ${kpis.length} KPIs with lookup tables`)\n\n let totalProcessed = 0\n let totalUpdated = 0\n let errorCount = 0\n\n for (const kpi of kpis) {\n try {\n console.log(`\\nš Processing KPI: ${kpi.name}`)\n \n if (!kpi.grades || !Array.isArray(kpi.grades) || kpi.grades.length === 0) {\n console.log(` ā ļø No grades found, skipping`)\n continue\n }\n\n console.log(` š Lookup table: ${kpi.grades.length} grades`)\n\n // Get KPI values for this KPI\n let kpiValuesQuery = kpiValueRepository\n .createQueryBuilder('kpiValue')\n .leftJoinAndSelect('kpiValue.kpi', 'kpi')\n .where('kpi.id = :kpiId', { kpiId: kpi.id })\n .andWhere('kpiValue.value IS NOT NULL')\n\n if (!forceRecalculate) {\n // Only process null or 0 scores by default\n kpiValuesQuery = kpiValuesQuery.andWhere('(kpiValue.score IS NULL OR kpiValue.score = 0)')\n }\n\n const kpiValues = await kpiValuesQuery.getMany()\n\n if (kpiValues.length === 0) {\n console.log(` ā
No null/zero scores found (all values already calculated)`)\n continue\n }\n\n console.log(` š¢ Processing ${kpiValues.length} null/zero scores`)\n\n let updatedCount = 0\n\n for (const kpiValue of kpiValues) {\n const value = kpiValue.value\n const calculatedScore = calculateScoreFromGrades(value, kpi.grades)\n\n if (calculatedScore !== null) {\n // Only update if the score is actually different\n if (kpiValue.score !== calculatedScore) {\n const oldScore = kpiValue.score\n kpiValue.score = calculatedScore\n await kpiValueRepository.save(kpiValue)\n updatedCount++\n \n console.log(` š Value ${value} ā Score ${calculatedScore} (was ${oldScore || 'null'})`)\n }\n } else {\n console.log(` ā ļø Value ${value} is below all ranges in lookup table`)\n }\n\n totalProcessed++\n }\n\n console.log(` ā
Updated ${updatedCount}/${kpiValues.length} values`)\n totalUpdated += updatedCount\n\n } catch (kpiError) {\n console.log(` ā Error processing KPI ${kpi.name}: ${kpiError.message}`)\n errorCount++\n }\n }\n\n console.log(`\\nš KPI Score Calculation Complete!`)\n console.log(` š KPIs processed: ${kpis.length}`)\n console.log(` š¢ Total values processed: ${totalProcessed}`)\n console.log(` ā
Scores updated: ${totalUpdated}`)\n console.log(` ā Errors: ${errorCount}`)\n\n if (errorCount > 0) {\n console.log(`\\nā ļø Some KPIs had errors. Check the logs above for details.`)\n }\n\n } catch (error) {\n console.error(`ā Fatal error during score calculation:`, error)\n throw error\n } finally {\n if (connection) {\n await connection.close()\n console.log('š Database connection closed')\n }\n }\n}\n\n/**\n * Calculate score from grades lookup table\n * If exact range not found, use the score of the largest minValue that is <= value\n */\nfunction calculateScoreFromGrades(value: number, grades: KpiGrade[]): number | null {\n // First try to find exact range match\n for (const grade of grades) {\n if (value >= grade.minValue && value <= grade.maxValue) {\n return grade.score || 0\n }\n }\n \n // If no exact match, find the grade with largest minValue that is <= value\n let bestGrade: KpiGrade | null = null\n let bestMinValue = -Infinity\n \n for (const grade of grades) {\n if (grade.minValue <= value && grade.minValue > bestMinValue) {\n bestGrade = grade\n bestMinValue = grade.minValue\n }\n }\n \n if (bestGrade) {\n return bestGrade.score || 0\n }\n \n return null // Value is smaller than all minValues in lookup table\n}\n\n/**\n * List KPIs that have lookup tables (grades)\n */\nexport async function listKpisWithLookupTables(): Promise<void> {\n // Set NODE_ENV if not set\n if (!process.env.NODE_ENV) {\n process.env.NODE_ENV = 'development'\n }\n\n // Initialize Things-Factory environment\n const { config } = require('@things-factory/env')\n const ormconfig = require('@things-factory/shell/dist-server/initializers/ormconfig.js')\n const connectionConfig = config.get('ormconfig')\n\n let connection\n\n try {\n console.log('š Connecting to database...')\n connection = await createConnection({\n ...ormconfig,\n ...connectionConfig,\n logging: false\n })\n\n const { addDataSource } = require('@things-factory/shell')\n addDataSource('default', connection)\n\n const { getRepository } = require('@things-factory/shell')\n const { Kpi } = require('@things-factory/kpi')\n const kpiRepository = getRepository(Kpi)\n\n // Get KPIs with grades\n const kpis = await kpiRepository\n .createQueryBuilder('kpi')\n .leftJoinAndSelect('kpi.domain', 'domain')\n .where('kpi.grades IS NOT NULL')\n .andWhere('domain.name = :domainName', { domainName: 'SYSTEM' })\n .getMany()\n\n console.log(`š KPIs with lookup tables (${kpis.length}):\\n`)\n\n if (kpis.length === 0) {\n console.log(' No KPIs found with lookup tables.')\n return\n }\n\n kpis.forEach((kpi, index) => {\n const gradeCount = kpi.grades ? kpi.grades.length : 0\n console.log(` ${(index + 1).toString().padStart(2)}: ${kpi.name} (${gradeCount} grades)`)\n })\n\n console.log(`\\nš Total: ${kpis.length} KPIs with lookup tables`)\n\n } catch (error) {\n console.error('ā Error listing KPIs:', error)\n } finally {\n if (connection) {\n await connection.close()\n }\n }\n}\n\n/**\n * CLI execution when called directly\n */\nasync function main() {\n const args = process.argv.slice(2)\n\n try {\n if (args.includes('--help') || args.includes('-h')) {\n console.log(`\nšÆ KPI Score Calculator\n\nUsage:\n ts-node server/scripts/calculate-kpi-scores.ts [options] [kpiName]\n\nOptions:\n --list, -l List KPIs that have lookup tables\n --force, -f Force recalculate all scores (not just null/zero ones)\n --help, -h Show this help\n\nExamples:\n ts-node server/scripts/calculate-kpi-scores.ts # Calculate scores for null/zero values only\n ts-node server/scripts/calculate-kpi-scores.ts --force # Recalculate ALL scores\n ts-node server/scripts/calculate-kpi-scores.ts \"X11. ģ°ė©“ģ ėė¹ ź³µģ¬źø°ź°\" # Calculate for specific KPI\n ts-node server/scripts/calculate-kpi-scores.ts --list # List KPIs with lookup tables\n\nNote: By default, only processes kpi-values with null or zero scores.\n Use --force to recalculate all scores.\n `)\n return\n }\n\n if (args.includes('--list') || args.includes('-l')) {\n await listKpisWithLookupTables()\n return\n }\n\n const forceRecalculate = args.includes('--force') || args.includes('-f')\n const specificKpiName = args.find(arg => !arg.startsWith('--'))\n \n if (specificKpiName) {\n console.log(`šÆ Calculating scores for specific KPI: ${specificKpiName}`)\n console.log(` Mode: ${forceRecalculate ? 'Force recalculate ALL' : 'Only null/zero scores'}`)\n await calculateKpiScores(specificKpiName, forceRecalculate)\n } else {\n console.log(`šÆ Calculating scores for all KPIs with lookup tables`)\n console.log(` Mode: ${forceRecalculate ? 'Force recalculate ALL' : 'Only null/zero scores'}`)\n await calculateKpiScores(undefined, forceRecalculate)\n }\n\n console.log('\\n⨠Done!')\n \n } catch (error) {\n console.error('\\nā Script failed:', error.message)\n process.exit(1)\n }\n}\n\n// Handle uncaught errors\nprocess.on('unhandledRejection', (error: any) => {\n console.error('ā Unhandled error:', error.message || error)\n process.exit(1)\n})\n\n// Run if called directly\nif (require.main === module) {\n main()\n}"]}
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
#!/usr/bin/env ts-node
|
|
2
|
+
/**
|
|
3
|
+
* Load KPI grade data from JSON files - Migration Style
|
|
4
|
+
* This can be called directly from migrations or other server-side scripts
|
|
5
|
+
*/
|
|
6
|
+
export declare function loadKpiGradeData(specificFile?: string): Promise<void>;
|
|
7
|
+
/**
|
|
8
|
+
* List available grade data files
|
|
9
|
+
*/
|
|
10
|
+
export declare function listGradeDataFiles(): string[];
|
|
@@ -0,0 +1,194 @@
|
|
|
1
|
+
#!/usr/bin/env ts-node
|
|
2
|
+
"use strict";
|
|
3
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
4
|
+
exports.loadKpiGradeData = loadKpiGradeData;
|
|
5
|
+
exports.listGradeDataFiles = listGradeDataFiles;
|
|
6
|
+
const tslib_1 = require("tslib");
|
|
7
|
+
const typeorm_1 = require("typeorm");
|
|
8
|
+
const fs = tslib_1.__importStar(require("fs"));
|
|
9
|
+
const path = tslib_1.__importStar(require("path"));
|
|
10
|
+
/**
|
|
11
|
+
* Load KPI grade data from JSON files - Migration Style
|
|
12
|
+
* This can be called directly from migrations or other server-side scripts
|
|
13
|
+
*/
|
|
14
|
+
async function loadKpiGradeData(specificFile) {
|
|
15
|
+
const gradeDataPath = path.join(__dirname, 'grade-data');
|
|
16
|
+
// Set NODE_ENV if not set
|
|
17
|
+
if (!process.env.NODE_ENV) {
|
|
18
|
+
process.env.NODE_ENV = 'development';
|
|
19
|
+
}
|
|
20
|
+
// Initialize Things-Factory environment
|
|
21
|
+
const { config } = require('@things-factory/env');
|
|
22
|
+
const ormconfig = require('@things-factory/shell/dist-server/initializers/ormconfig.js');
|
|
23
|
+
const connectionConfig = config.get('ormconfig');
|
|
24
|
+
let connection;
|
|
25
|
+
console.log('š Loading KPI Grade Data...');
|
|
26
|
+
console.log(`š Source directory: ${gradeDataPath}`);
|
|
27
|
+
try {
|
|
28
|
+
// Create database connection using Things-Factory pattern
|
|
29
|
+
console.log('š Connecting to database...');
|
|
30
|
+
connection = await (0, typeorm_1.createConnection)(Object.assign(Object.assign(Object.assign({}, ormconfig), connectionConfig), { logging: false }));
|
|
31
|
+
// Register the connection with Things-Factory shell
|
|
32
|
+
const { addDataSource } = require('@things-factory/shell');
|
|
33
|
+
addDataSource('default', connection);
|
|
34
|
+
console.log('ā
Database connected');
|
|
35
|
+
// Check if grade-data directory exists
|
|
36
|
+
if (!fs.existsSync(gradeDataPath)) {
|
|
37
|
+
console.error(`ā Grade data directory not found: ${gradeDataPath}`);
|
|
38
|
+
throw new Error('Grade data directory not found');
|
|
39
|
+
}
|
|
40
|
+
// Get files to process
|
|
41
|
+
let files;
|
|
42
|
+
if (specificFile) {
|
|
43
|
+
if (!fs.existsSync(path.join(gradeDataPath, specificFile))) {
|
|
44
|
+
throw new Error(`File not found: ${specificFile}`);
|
|
45
|
+
}
|
|
46
|
+
files = [specificFile];
|
|
47
|
+
console.log(`š Processing single file: ${specificFile}`);
|
|
48
|
+
}
|
|
49
|
+
else {
|
|
50
|
+
files = fs.readdirSync(gradeDataPath).filter(file => file.endsWith('.json'));
|
|
51
|
+
console.log(`š Found ${files.length} grade data files`);
|
|
52
|
+
}
|
|
53
|
+
if (files.length === 0) {
|
|
54
|
+
console.log('ā ļø No JSON files found to process');
|
|
55
|
+
return;
|
|
56
|
+
}
|
|
57
|
+
let successCount = 0;
|
|
58
|
+
let errorCount = 0;
|
|
59
|
+
// Now we can use getRepository with the registered connection
|
|
60
|
+
const { getRepository } = require('@things-factory/shell');
|
|
61
|
+
const { Kpi } = require('@things-factory/kpi');
|
|
62
|
+
const kpiRepository = getRepository(Kpi);
|
|
63
|
+
for (const file of files) {
|
|
64
|
+
try {
|
|
65
|
+
console.log(`\nš Processing: ${file}`);
|
|
66
|
+
const filePath = path.join(gradeDataPath, file);
|
|
67
|
+
const fileContent = fs.readFileSync(filePath, 'utf8');
|
|
68
|
+
const gradeData = JSON.parse(fileContent);
|
|
69
|
+
// Validate grade data structure
|
|
70
|
+
if (!gradeData.kpiName || !gradeData.grades || !Array.isArray(gradeData.grades)) {
|
|
71
|
+
console.log(` ā Invalid structure - missing kpiName or grades`);
|
|
72
|
+
errorCount++;
|
|
73
|
+
continue;
|
|
74
|
+
}
|
|
75
|
+
console.log(` š KPI Name: ${gradeData.kpiName}`);
|
|
76
|
+
console.log(` š Grades: ${gradeData.grades.length} entries`);
|
|
77
|
+
// Find KPI by name in SYSTEM domain
|
|
78
|
+
const kpi = await kpiRepository.findOne({
|
|
79
|
+
where: { name: gradeData.kpiName, domain: { name: 'SYSTEM' } },
|
|
80
|
+
relations: ['domain']
|
|
81
|
+
});
|
|
82
|
+
if (kpi) {
|
|
83
|
+
// Update grades data
|
|
84
|
+
const originalGradesCount = kpi.grades ? kpi.grades.length : 0;
|
|
85
|
+
kpi.grades = gradeData.grades;
|
|
86
|
+
await kpiRepository.save(kpi);
|
|
87
|
+
console.log(` ā
Updated successfully`);
|
|
88
|
+
console.log(` š Grades: ${originalGradesCount} ā ${gradeData.grades.length}`);
|
|
89
|
+
successCount++;
|
|
90
|
+
}
|
|
91
|
+
else {
|
|
92
|
+
console.log(` ā ļø KPI not found in SYSTEM domain: ${gradeData.kpiName}`);
|
|
93
|
+
errorCount++;
|
|
94
|
+
}
|
|
95
|
+
}
|
|
96
|
+
catch (fileError) {
|
|
97
|
+
console.log(` ā File processing error: ${fileError.message}`);
|
|
98
|
+
errorCount++;
|
|
99
|
+
}
|
|
100
|
+
}
|
|
101
|
+
console.log(`\nš KPI Grade Data Loading Complete!`);
|
|
102
|
+
console.log(` š Total files: ${files.length}`);
|
|
103
|
+
console.log(` ā
Successful: ${successCount}`);
|
|
104
|
+
console.log(` ā Errors: ${errorCount}`);
|
|
105
|
+
if (errorCount > 0) {
|
|
106
|
+
console.log(`\nā ļø Some files had errors. Check the logs above for details.`);
|
|
107
|
+
}
|
|
108
|
+
}
|
|
109
|
+
catch (error) {
|
|
110
|
+
console.error(`ā Fatal error during grade data loading:`, error);
|
|
111
|
+
throw error;
|
|
112
|
+
}
|
|
113
|
+
finally {
|
|
114
|
+
if (connection) {
|
|
115
|
+
await connection.close();
|
|
116
|
+
console.log('š Database connection closed');
|
|
117
|
+
}
|
|
118
|
+
}
|
|
119
|
+
}
|
|
120
|
+
/**
|
|
121
|
+
* List available grade data files
|
|
122
|
+
*/
|
|
123
|
+
function listGradeDataFiles() {
|
|
124
|
+
const gradeDataPath = path.join(__dirname, 'grade-data');
|
|
125
|
+
try {
|
|
126
|
+
if (!fs.existsSync(gradeDataPath)) {
|
|
127
|
+
console.log('š Grade data directory not found');
|
|
128
|
+
return [];
|
|
129
|
+
}
|
|
130
|
+
const files = fs.readdirSync(gradeDataPath).filter(file => file.endsWith('.json'));
|
|
131
|
+
console.log(`š Available grade data files in ${gradeDataPath}:\n`);
|
|
132
|
+
files.forEach((file, index) => {
|
|
133
|
+
console.log(` ${(index + 1).toString().padStart(2)}: ${file}`);
|
|
134
|
+
});
|
|
135
|
+
console.log(`\nš Total: ${files.length} files`);
|
|
136
|
+
return files;
|
|
137
|
+
}
|
|
138
|
+
catch (error) {
|
|
139
|
+
console.error('ā Error reading grade data directory:', error);
|
|
140
|
+
return [];
|
|
141
|
+
}
|
|
142
|
+
}
|
|
143
|
+
/**
|
|
144
|
+
* CLI execution when called directly
|
|
145
|
+
*/
|
|
146
|
+
async function main() {
|
|
147
|
+
const args = process.argv.slice(2);
|
|
148
|
+
try {
|
|
149
|
+
if (args.includes('--help') || args.includes('-h')) {
|
|
150
|
+
console.log(`
|
|
151
|
+
šÆ KPI Grade Data Loader (Migration Style)
|
|
152
|
+
|
|
153
|
+
Usage:
|
|
154
|
+
ts-node server/scripts/load-grade-data-migration.ts [options] [fileName]
|
|
155
|
+
|
|
156
|
+
Options:
|
|
157
|
+
--list, -l List available grade data files
|
|
158
|
+
--help, -h Show this help
|
|
159
|
+
|
|
160
|
+
Examples:
|
|
161
|
+
ts-node server/scripts/load-grade-data-migration.ts # Load all files
|
|
162
|
+
ts-node server/scripts/load-grade-data-migration.ts x11-performance-table.json # Load specific file
|
|
163
|
+
ts-node server/scripts/load-grade-data-migration.ts --list # List files
|
|
164
|
+
|
|
165
|
+
Note: This script connects to the database using the current Things-Factory configuration.
|
|
166
|
+
Make sure the application is properly configured before running.
|
|
167
|
+
`);
|
|
168
|
+
return;
|
|
169
|
+
}
|
|
170
|
+
if (args.includes('--list') || args.includes('-l')) {
|
|
171
|
+
listGradeDataFiles();
|
|
172
|
+
return;
|
|
173
|
+
}
|
|
174
|
+
const specificFile = args.find(arg => !arg.startsWith('--'));
|
|
175
|
+
if (specificFile) {
|
|
176
|
+
console.log(`šÆ Loading specific file: ${specificFile}`);
|
|
177
|
+
await loadKpiGradeData(specificFile);
|
|
178
|
+
}
|
|
179
|
+
else {
|
|
180
|
+
console.log(`šÆ Loading all grade data files`);
|
|
181
|
+
await loadKpiGradeData();
|
|
182
|
+
}
|
|
183
|
+
console.log('\n⨠Done!');
|
|
184
|
+
}
|
|
185
|
+
catch (error) {
|
|
186
|
+
console.error('\nā Script failed:', error.message);
|
|
187
|
+
process.exit(1);
|
|
188
|
+
}
|
|
189
|
+
}
|
|
190
|
+
// Run if called directly
|
|
191
|
+
if (require.main === module) {
|
|
192
|
+
main();
|
|
193
|
+
}
|
|
194
|
+
//# sourceMappingURL=load-grade-data-migration.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"load-grade-data-migration.js","sourceRoot":"","sources":["../../server/scripts/load-grade-data-migration.ts"],"names":[],"mappings":"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","sourcesContent":["#!/usr/bin/env ts-node\n\nimport { createConnection } from 'typeorm'\nimport * as fs from 'fs'\nimport * as path from 'path'\n\ninterface GradeData {\n kpiName: string\n version: number\n description: string\n grades: Array<{\n name: string\n minValue: number\n maxValue: number\n score?: number\n color?: string\n description?: string\n }>\n}\n\n/**\n * Load KPI grade data from JSON files - Migration Style\n * This can be called directly from migrations or other server-side scripts\n */\nexport async function loadKpiGradeData(specificFile?: string): Promise<void> {\n const gradeDataPath = path.join(__dirname, 'grade-data')\n \n // Set NODE_ENV if not set\n if (!process.env.NODE_ENV) {\n process.env.NODE_ENV = 'development'\n }\n\n // Initialize Things-Factory environment\n const { config } = require('@things-factory/env')\n const ormconfig = require('@things-factory/shell/dist-server/initializers/ormconfig.js')\n const connectionConfig = config.get('ormconfig')\n\n let connection\n\n console.log('š Loading KPI Grade Data...')\n console.log(`š Source directory: ${gradeDataPath}`)\n\n try {\n // Create database connection using Things-Factory pattern\n console.log('š Connecting to database...')\n connection = await createConnection({\n ...ormconfig,\n ...connectionConfig,\n logging: false\n })\n\n // Register the connection with Things-Factory shell\n const { addDataSource } = require('@things-factory/shell')\n addDataSource('default', connection)\n\n console.log('ā
Database connected')\n\n // Check if grade-data directory exists\n if (!fs.existsSync(gradeDataPath)) {\n console.error(`ā Grade data directory not found: ${gradeDataPath}`)\n throw new Error('Grade data directory not found')\n }\n\n // Get files to process\n let files: string[]\n if (specificFile) {\n if (!fs.existsSync(path.join(gradeDataPath, specificFile))) {\n throw new Error(`File not found: ${specificFile}`)\n }\n files = [specificFile]\n console.log(`š Processing single file: ${specificFile}`)\n } else {\n files = fs.readdirSync(gradeDataPath).filter(file => file.endsWith('.json'))\n console.log(`š Found ${files.length} grade data files`)\n }\n\n if (files.length === 0) {\n console.log('ā ļø No JSON files found to process')\n return\n }\n\n let successCount = 0\n let errorCount = 0\n\n // Now we can use getRepository with the registered connection\n const { getRepository } = require('@things-factory/shell')\n const { Kpi } = require('@things-factory/kpi')\n const kpiRepository = getRepository(Kpi)\n\n for (const file of files) {\n try {\n console.log(`\\nš Processing: ${file}`)\n \n const filePath = path.join(gradeDataPath, file)\n const fileContent = fs.readFileSync(filePath, 'utf8')\n const gradeData: GradeData = JSON.parse(fileContent)\n\n // Validate grade data structure\n if (!gradeData.kpiName || !gradeData.grades || !Array.isArray(gradeData.grades)) {\n console.log(` ā Invalid structure - missing kpiName or grades`)\n errorCount++\n continue\n }\n\n console.log(` š KPI Name: ${gradeData.kpiName}`)\n console.log(` š Grades: ${gradeData.grades.length} entries`)\n\n // Find KPI by name in SYSTEM domain\n const kpi = await kpiRepository.findOne({\n where: { name: gradeData.kpiName, domain: { name: 'SYSTEM' } },\n relations: ['domain']\n })\n\n if (kpi) {\n // Update grades data\n const originalGradesCount = kpi.grades ? kpi.grades.length : 0\n kpi.grades = gradeData.grades\n await kpiRepository.save(kpi)\n \n console.log(` ā
Updated successfully`)\n console.log(` š Grades: ${originalGradesCount} ā ${gradeData.grades.length}`)\n successCount++\n } else {\n console.log(` ā ļø KPI not found in SYSTEM domain: ${gradeData.kpiName}`)\n errorCount++\n }\n \n } catch (fileError) {\n console.log(` ā File processing error: ${fileError.message}`)\n errorCount++\n }\n }\n\n console.log(`\\nš KPI Grade Data Loading Complete!`)\n console.log(` š Total files: ${files.length}`)\n console.log(` ā
Successful: ${successCount}`)\n console.log(` ā Errors: ${errorCount}`)\n\n if (errorCount > 0) {\n console.log(`\\nā ļø Some files had errors. Check the logs above for details.`)\n }\n\n } catch (error) {\n console.error(`ā Fatal error during grade data loading:`, error)\n throw error\n } finally {\n if (connection) {\n await connection.close()\n console.log('š Database connection closed')\n }\n }\n}\n\n/**\n * List available grade data files\n */\nexport function listGradeDataFiles(): string[] {\n const gradeDataPath = path.join(__dirname, 'grade-data')\n \n try {\n if (!fs.existsSync(gradeDataPath)) {\n console.log('š Grade data directory not found')\n return []\n }\n \n const files = fs.readdirSync(gradeDataPath).filter(file => file.endsWith('.json'))\n \n console.log(`š Available grade data files in ${gradeDataPath}:\\n`)\n files.forEach((file, index) => {\n console.log(` ${(index + 1).toString().padStart(2)}: ${file}`)\n })\n console.log(`\\nš Total: ${files.length} files`)\n \n return files\n } catch (error) {\n console.error('ā Error reading grade data directory:', error)\n return []\n }\n}\n\n/**\n * CLI execution when called directly\n */\nasync function main() {\n const args = process.argv.slice(2)\n\n try {\n if (args.includes('--help') || args.includes('-h')) {\n console.log(`\nšÆ KPI Grade Data Loader (Migration Style)\n\nUsage:\n ts-node server/scripts/load-grade-data-migration.ts [options] [fileName]\n\nOptions:\n --list, -l List available grade data files\n --help, -h Show this help\n\nExamples:\n ts-node server/scripts/load-grade-data-migration.ts # Load all files\n ts-node server/scripts/load-grade-data-migration.ts x11-performance-table.json # Load specific file\n ts-node server/scripts/load-grade-data-migration.ts --list # List files\n\nNote: This script connects to the database using the current Things-Factory configuration.\n Make sure the application is properly configured before running.\n `)\n return\n }\n\n if (args.includes('--list') || args.includes('-l')) {\n listGradeDataFiles()\n return\n }\n\n const specificFile = args.find(arg => !arg.startsWith('--'))\n \n if (specificFile) {\n console.log(`šÆ Loading specific file: ${specificFile}`)\n await loadKpiGradeData(specificFile)\n } else {\n console.log(`šÆ Loading all grade data files`)\n await loadKpiGradeData()\n }\n\n console.log('\\n⨠Done!')\n \n } catch (error) {\n console.error('\\nā Script failed:', error.message)\n process.exit(1)\n }\n}\n\n// Run if called directly\nif (require.main === module) {\n main()\n}"]}
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
#!/usr/bin/env ts-node
|
|
2
|
+
/**
|
|
3
|
+
* Propagate parent KPI values based on child KPI scores and weights
|
|
4
|
+
* Processes hierarchy from leaf to root, calculating weighted averages
|
|
5
|
+
*/
|
|
6
|
+
export declare function propagateParentKpiValues(specificKpiName?: string, forceRecalculate?: boolean, targetDate?: string, orgScope?: string, version?: number): Promise<void>;
|
|
7
|
+
/**
|
|
8
|
+
* List parent KPIs and their hierarchy
|
|
9
|
+
*/
|
|
10
|
+
export declare function listParentKpiHierarchy(): Promise<void>;
|