@silvestv/migration-planificator 3.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +96 -0
- package/README.fr.md +359 -0
- package/README.md +360 -0
- package/SECURITY.md +187 -0
- package/dist/client.bundle.js +357 -0
- package/dist/src/core/app-analyzer.js +134 -0
- package/dist/src/core/ast/matchers/html/html-attribute-matcher.js +86 -0
- package/dist/src/core/ast/matchers/html/html-component-matcher.js +40 -0
- package/dist/src/core/ast/matchers/html/html-element-matcher.js +54 -0
- package/dist/src/core/ast/matchers/html/html-parser.js +58 -0
- package/dist/src/core/ast/matchers/html/html-pipe-matcher.js +95 -0
- package/dist/src/core/ast/matchers/html/html-text-matcher.js +53 -0
- package/dist/src/core/ast/matchers/html/index.js +118 -0
- package/dist/src/core/ast/matchers/index.js +377 -0
- package/dist/src/core/ast/matchers/ts/collection-matcher.js +51 -0
- package/dist/src/core/ast/matchers/ts/context-matcher.js +275 -0
- package/dist/src/core/ast/matchers/ts/decorator-matcher.js +465 -0
- package/dist/src/core/ast/matchers/ts/expression-matcher.js +237 -0
- package/dist/src/core/ast/matchers/ts/file-matcher.js +97 -0
- package/dist/src/core/ast/matchers/ts/hierarchy-matcher.js +172 -0
- package/dist/src/core/ast/matchers/ts/import-matcher.js +39 -0
- package/dist/src/core/ast/matchers/ts/index.js +53 -0
- package/dist/src/core/ast/matchers/ts/node-matcher.js +156 -0
- package/dist/src/core/ast/matchers/ts/symbol-matcher.js +281 -0
- package/dist/src/core/ast/matchers/ts/type-matcher.js +207 -0
- package/dist/src/core/ast/matchers/utils/matcher-helpers.js +37 -0
- package/dist/src/core/ast/scanner-ast.js +444 -0
- package/dist/src/core/project-detector.js +196 -0
- package/dist/src/core/project-strategy/index.js +9 -0
- package/dist/src/core/project-strategy/nx-strategy.js +130 -0
- package/dist/src/core/project-strategy/project-strategy.interface.js +2 -0
- package/dist/src/core/project-strategy/standalone-strategy.js +74 -0
- package/dist/src/core/project-strategy/strategy-factory.js +15 -0
- package/dist/src/core/rules-loader.js +89 -0
- package/dist/src/core/scan-reporter.js +316 -0
- package/dist/src/core/scanner-delta.js +339 -0
- package/dist/src/core/scanner-orchestrator.js +266 -0
- package/dist/src/core/scanner-regex.js +298 -0
- package/dist/src/core/workload/calculator.js +82 -0
- package/dist/src/core/workload/constants.js +15 -0
- package/dist/src/core/workload/grouping.js +18 -0
- package/dist/src/core/workload/hierarchy-calculator.js +127 -0
- package/dist/src/core/workload/index.js +11 -0
- package/dist/src/core/workload/metadata.js +20 -0
- package/dist/src/core/workload/special-workload.js +101 -0
- package/dist/src/core/workload/target-resolver.js +34 -0
- package/dist/src/data/angular-migration-rules.json +2337 -0
- package/dist/src/data/markdown/angular-migration-17-18.md +408 -0
- package/dist/src/data/markdown/angular-migration-18-19.md +600 -0
- package/dist/src/data/markdown/angular-migration-19-20.md +521 -0
- package/dist/src/data/rules/rearchitecture/rearchitecture-rules.json +66 -0
- package/dist/src/data/rules/to18/rules-18-obligatoire.json +374 -0
- package/dist/src/data/rules/to18/rules-18-optionnelle.json +188 -0
- package/dist/src/data/rules/to18/rules-18-recommande.json +218 -0
- package/dist/src/data/rules/to19/rules-19-obligatoire.json +348 -0
- package/dist/src/data/rules/to19/rules-19-optionnelle.json +223 -0
- package/dist/src/data/rules/to19/rules-19-recommande.json +200 -0
- package/dist/src/data/rules/to20/rules-20-obligatoire.json +556 -0
- package/dist/src/data/rules/to20/rules-20-optionnelle.json +190 -0
- package/dist/src/data/rules/to20/rules-20-recommande.json +151 -0
- package/dist/src/index.js +161 -0
- package/dist/src/models/chip-config.js +45 -0
- package/dist/src/models/interfaces/app-details.interface.js +2 -0
- package/dist/src/models/interfaces/ast-interfaces.js +5 -0
- package/dist/src/models/interfaces/ast-pattern.interface.js +2 -0
- package/dist/src/models/interfaces/client-interfaces.js +6 -0
- package/dist/src/models/interfaces/detection-stats.interface.js +2 -0
- package/dist/src/models/interfaces/html-match.interface.js +2 -0
- package/dist/src/models/interfaces/html-report-data.interface.js +2 -0
- package/dist/src/models/interfaces/lib-details.interface.js +2 -0
- package/dist/src/models/interfaces/migration-rules.interface.js +2 -0
- package/dist/src/models/interfaces/parsed-args.interface.js +2 -0
- package/dist/src/models/interfaces/project-info.interface.js +2 -0
- package/dist/src/models/interfaces/project-overview-data.interface.js +2 -0
- package/dist/src/models/interfaces/rule-match.interface.js +2 -0
- package/dist/src/models/interfaces/rule.interface.js +2 -0
- package/dist/src/models/interfaces/rules-by-priority.interface.js +2 -0
- package/dist/src/models/interfaces/scanner-comparison.interface.js +2 -0
- package/dist/src/models/interfaces/special-workload.interface.js +2 -0
- package/dist/src/models/interfaces/workload-report.interface.js +2 -0
- package/dist/src/models/types/build-block-blob.type.js +2 -0
- package/dist/src/models/types/migration-version.type.js +2 -0
- package/dist/src/models/types/project-type.type.js +2 -0
- package/dist/src/models/types/risk-level.type.js +2 -0
- package/dist/src/models/types/rule-category.type.js +2 -0
- package/dist/src/models/types/rule-priority.type.js +2 -0
- package/dist/src/models/types/rule-workload-type.type.js +2 -0
- package/dist/src/templates/landing/applications-analyzed.template.js +18 -0
- package/dist/src/templates/landing/card-app-info.template.js +63 -0
- package/dist/src/templates/landing/card-lib-info.template.js +67 -0
- package/dist/src/templates/landing/libs-analyzed.template.js +22 -0
- package/dist/src/templates/landing/nx-summary.template.js +115 -0
- package/dist/src/templates/landing/project-overview.template.js +27 -0
- package/dist/src/templates/page/index-page.template.js +95 -0
- package/dist/src/templates/page/main.template.js +83 -0
- package/dist/src/templates/page/migration-guide.template.js +175 -0
- package/dist/src/templates/page/workload-report.template.js +53 -0
- package/dist/src/templates/workload/dashboard.template.js +184 -0
- package/dist/src/templates/workload/filters-panel.template.js +215 -0
- package/dist/src/templates/workload/guide-rule-card.template.js +107 -0
- package/dist/src/templates/workload/hierarchy-nx.template.js +104 -0
- package/dist/src/templates/workload/hierarchy-shared.js +163 -0
- package/dist/src/templates/workload/hierarchy-standalone.template.js +36 -0
- package/dist/src/templates/workload/hierarchy.template.js +35 -0
- package/dist/src/templates/workload/rule-modal.template.js +280 -0
- package/dist/src/utils/core/args-parser.js +123 -0
- package/dist/src/utils/core/array-helpers.js +18 -0
- package/dist/src/utils/core/ast-helpers.js +99 -0
- package/dist/src/utils/core/file-helpers.js +109 -0
- package/dist/src/utils/core/html-helpers.js +36 -0
- package/dist/src/utils/core/index.js +28 -0
- package/dist/src/utils/core/logger.js +38 -0
- package/dist/src/utils/core/rule-helpers.js +15 -0
- package/dist/src/utils/core/workload-formatter.js +6 -0
- package/dist/src/utils/shared/array-helpers.js +25 -0
- package/dist/src/utils/shared/date-helpers.js +109 -0
- package/dist/src/utils/shared/html-helpers.js +37 -0
- package/dist/src/utils/shared/index.js +25 -0
- package/dist/src/utils/shared/rule-helpers.js +20 -0
- package/dist/src/utils/shared/time-formatters.js +76 -0
- package/dist/styles.css +2 -0
- package/package.json +107 -0
|
@@ -0,0 +1,107 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
/**
|
|
3
|
+
* Template pour cards de règles dans le Migration Guide
|
|
4
|
+
* Réutilise les sections de rule-modal.template.ts (principe DRY)
|
|
5
|
+
*/
|
|
6
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
7
|
+
exports.renderGuideRuleCard = renderGuideRuleCard;
|
|
8
|
+
exports.renderGuideRuleCards = renderGuideRuleCards;
|
|
9
|
+
const shared_1 = require("../../utils/shared");
|
|
10
|
+
const rule_modal_template_1 = require("./rule-modal.template");
|
|
11
|
+
/**
|
|
12
|
+
* Retourne la couleur du badge selon le niveau de risque
|
|
13
|
+
*/
|
|
14
|
+
function getRiskColor(riskLevel) {
|
|
15
|
+
const colorMap = {
|
|
16
|
+
critical: 'red',
|
|
17
|
+
high: 'orange',
|
|
18
|
+
medium: 'yellow',
|
|
19
|
+
low: 'green'
|
|
20
|
+
};
|
|
21
|
+
return colorMap[riskLevel] || 'gray';
|
|
22
|
+
}
|
|
23
|
+
/**
|
|
24
|
+
* Génère une card de règle pour le guide
|
|
25
|
+
*/
|
|
26
|
+
function renderGuideRuleCard(rule, matches) {
|
|
27
|
+
const cardId = `guide-card-${rule.key}`;
|
|
28
|
+
const riskColor = getRiskColor(rule.risk_level);
|
|
29
|
+
return `
|
|
30
|
+
<div id="${cardId}"
|
|
31
|
+
class="bg-white border-2 border-gray-200 rounded-xl shadow-lg mb-6 overflow-hidden"
|
|
32
|
+
data-rule-card
|
|
33
|
+
data-rule-key="${rule.key}"
|
|
34
|
+
data-migration="${getMigrationFromRuleKey(rule.key)}">
|
|
35
|
+
|
|
36
|
+
<!-- Header avec checkbox et badges -->
|
|
37
|
+
<div class="bg-gradient-to-r from-${riskColor}-50 to-${riskColor}-100 p-4 border-b border-gray-200">
|
|
38
|
+
<div class="flex items-start justify-between">
|
|
39
|
+
<div class="flex items-start space-x-3 flex-1">
|
|
40
|
+
<!-- Checkbox completion -->
|
|
41
|
+
<input
|
|
42
|
+
type="checkbox"
|
|
43
|
+
data-rule-checkbox="${rule.key}"
|
|
44
|
+
class="mt-1 w-5 h-5 text-green-600 rounded focus:ring-2 focus:ring-green-500 cursor-pointer"
|
|
45
|
+
title="Marquer comme complété"
|
|
46
|
+
/>
|
|
47
|
+
|
|
48
|
+
<div class="flex-1">
|
|
49
|
+
<h3 class="text-xl font-bold text-gray-800 mb-2">${(0, shared_1.escapeHtml)(rule.summary)}</h3>
|
|
50
|
+
<div class="flex items-center flex-wrap gap-2">
|
|
51
|
+
${(0, shared_1.renderBadge)(rule.risk_level.toUpperCase(), riskColor)}
|
|
52
|
+
${(0, shared_1.renderBadge)(rule.category, 'blue')}
|
|
53
|
+
${rule.auto_fixable ? (0, shared_1.renderBadge)('Auto-fixable', 'green') : ''}
|
|
54
|
+
</div>
|
|
55
|
+
</div>
|
|
56
|
+
</div>
|
|
57
|
+
|
|
58
|
+
<!-- Bouton collapse -->
|
|
59
|
+
<button
|
|
60
|
+
data-collapse-trigger="${cardId}"
|
|
61
|
+
class="ml-4 text-2xl font-bold text-gray-600 hover:text-gray-800 transition-colors"
|
|
62
|
+
title="Réduire/Développer"
|
|
63
|
+
>
|
|
64
|
+
<span data-collapse-icon>▶</span>
|
|
65
|
+
</button>
|
|
66
|
+
</div>
|
|
67
|
+
</div>
|
|
68
|
+
|
|
69
|
+
<!-- Contenu de la card (collapsible) - REPLIÉ PAR DÉFAUT -->
|
|
70
|
+
<div data-collapse-content class="hidden p-6 space-y-6">
|
|
71
|
+
${(0, rule_modal_template_1.renderDescriptionSection)(rule)}
|
|
72
|
+
${(0, rule_modal_template_1.renderCodeExamplesSection)(rule)}
|
|
73
|
+
${(0, rule_modal_template_1.renderMigrationCommandSection)(rule)}
|
|
74
|
+
${(0, rule_modal_template_1.renderDocumentationSection)(rule)}
|
|
75
|
+
${(0, rule_modal_template_1.renderAffectedFilesSection)(matches)}
|
|
76
|
+
${(0, rule_modal_template_1.renderMetadataSection)(rule)}
|
|
77
|
+
</div>
|
|
78
|
+
</div>
|
|
79
|
+
`;
|
|
80
|
+
}
|
|
81
|
+
/**
|
|
82
|
+
* Extrait la migration (to18, to19, to20) depuis la clé de règle
|
|
83
|
+
* Ex: "angular_18_environment" -> "to18"
|
|
84
|
+
*/
|
|
85
|
+
function getMigrationFromRuleKey(ruleKey) {
|
|
86
|
+
if (ruleKey.includes('_18_'))
|
|
87
|
+
return 'to18';
|
|
88
|
+
if (ruleKey.includes('_19_'))
|
|
89
|
+
return 'to19';
|
|
90
|
+
if (ruleKey.includes('_20_'))
|
|
91
|
+
return 'to20';
|
|
92
|
+
return 'unknown';
|
|
93
|
+
}
|
|
94
|
+
/**
|
|
95
|
+
* Génère toutes les cards pour un ensemble de règles
|
|
96
|
+
*/
|
|
97
|
+
function renderGuideRuleCards(rules, matches) {
|
|
98
|
+
// Grouper matches par ruleKey
|
|
99
|
+
const matchesByRule = new Map();
|
|
100
|
+
matches.forEach(match => {
|
|
101
|
+
if (!matchesByRule.has(match.ruleKey)) {
|
|
102
|
+
matchesByRule.set(match.ruleKey, []);
|
|
103
|
+
}
|
|
104
|
+
matchesByRule.get(match.ruleKey).push(match);
|
|
105
|
+
});
|
|
106
|
+
return rules.map(rule => renderGuideRuleCard(rule, matchesByRule.get(rule.key) || [])).join('');
|
|
107
|
+
}
|
|
@@ -0,0 +1,104 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
/**
|
|
3
|
+
* Template spécifique pour vue hiérarchique Nx Monorepo
|
|
4
|
+
* Structure: Monorepo > (Routines | Apps | Libs) > Migrations > Priorities > Rules
|
|
5
|
+
*/
|
|
6
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
7
|
+
exports.renderNxMonorepoView = renderNxMonorepoView;
|
|
8
|
+
const core_1 = require("../../utils/core");
|
|
9
|
+
const hierarchy_shared_1 = require("./hierarchy-shared");
|
|
10
|
+
/**
|
|
11
|
+
* Vue pour Monorepo Nx : Affiche Monorepo > (Routines | Apps | Libs)
|
|
12
|
+
*/
|
|
13
|
+
function renderNxMonorepoView(workload) {
|
|
14
|
+
// Séparer monorepo (routines) et apps/libs
|
|
15
|
+
const monorepoTarget = workload.targets.find(t => t.targetType === 'monorepo');
|
|
16
|
+
const apps = workload.targets.filter(t => t.targetType === 'app');
|
|
17
|
+
const libs = workload.targets.filter(t => t.targetType === 'lib');
|
|
18
|
+
// Calculer le temps total global (monorepo + apps + libs)
|
|
19
|
+
const globalTotalTime = (0, core_1.calculateTotalTime)(workload.targets);
|
|
20
|
+
const monorepoName = workload.projectInfo.name;
|
|
21
|
+
const sectionId = `monorepo-${monorepoName.replace(/[^a-z0-9]/gi, '-')}`;
|
|
22
|
+
return `
|
|
23
|
+
<div id="${sectionId}" class="mb-6 border-l-4 border-purple-500 pl-4">
|
|
24
|
+
<div class="flex items-center justify-between bg-purple-50 p-4 rounded-lg cursor-pointer" data-collapse-trigger="${sectionId}">
|
|
25
|
+
<div class="flex items-center space-x-3">
|
|
26
|
+
<span data-collapse-icon class="text-xl">▼</span>
|
|
27
|
+
<h3 class="text-xl font-bold text-purple-900">🏗️ ${(0, core_1.escapeHtml)(monorepoName)}</h3>
|
|
28
|
+
${(0, core_1.renderBadge)('monorepo', 'purple')}
|
|
29
|
+
</div>
|
|
30
|
+
<span class="text-lg font-semibold text-purple-600" data-monorepo-total-time="${monorepoName}">${globalTotalTime}</span>
|
|
31
|
+
</div>
|
|
32
|
+
<div data-collapse-content class="mt-4 space-y-6">
|
|
33
|
+
${monorepoTarget ? renderRoutinesSection(monorepoTarget, monorepoName) : ''}
|
|
34
|
+
${apps.length > 0 ? renderTargetGroupSection('Applications', apps, 'blue', '📱', monorepoName) : ''}
|
|
35
|
+
${libs.length > 0 ? renderTargetGroupSection('Librairies', libs, 'green', '📚', monorepoName) : ''}
|
|
36
|
+
</div>
|
|
37
|
+
</div>
|
|
38
|
+
`;
|
|
39
|
+
}
|
|
40
|
+
/**
|
|
41
|
+
* Section Routines Globales (monorepo)
|
|
42
|
+
*/
|
|
43
|
+
function renderRoutinesSection(monorepoTarget, monorepoName) {
|
|
44
|
+
const sectionId = `routines-section`;
|
|
45
|
+
return `
|
|
46
|
+
<div id="${sectionId}" class="ml-6 border-l-4 border-teal-400 pl-4">
|
|
47
|
+
<div class="flex items-center justify-between bg-teal-50 p-3 rounded-lg cursor-pointer" data-collapse-trigger="${sectionId}">
|
|
48
|
+
<div class="flex items-center space-x-2">
|
|
49
|
+
<span data-collapse-icon class="text-lg">▼</span>
|
|
50
|
+
<h4 class="text-lg font-bold text-teal-800">🔧 Routines Globales</h4>
|
|
51
|
+
</div>
|
|
52
|
+
<span class="font-semibold text-teal-600" data-target-time="${monorepoTarget.targetName}">${(0, core_1.formatTime)(monorepoTarget.totalTime.minutes, monorepoTarget.totalTime.hours, monorepoTarget.totalTime.days)}</span>
|
|
53
|
+
</div>
|
|
54
|
+
<div data-collapse-content class="mt-3 space-y-3">
|
|
55
|
+
${monorepoTarget.migrations.map(migration => (0, hierarchy_shared_1.renderMigration)(monorepoTarget.targetName, migration)).join('')}
|
|
56
|
+
</div>
|
|
57
|
+
</div>
|
|
58
|
+
`;
|
|
59
|
+
}
|
|
60
|
+
/**
|
|
61
|
+
* Section générique pour Apps ou Libs (DRY)
|
|
62
|
+
*/
|
|
63
|
+
function renderTargetGroupSection(title, targets, color, icon, monorepoName) {
|
|
64
|
+
const sectionId = `${title.toLowerCase()}-section`;
|
|
65
|
+
const totalTime = (0, core_1.calculateTotalTime)(targets);
|
|
66
|
+
const groupId = `${monorepoName}-${title.toLowerCase()}`;
|
|
67
|
+
return `
|
|
68
|
+
<div id="${sectionId}" class="ml-6 border-l-4 border-${color}-400 pl-4">
|
|
69
|
+
<div class="flex items-center justify-between bg-${color}-50 p-3 rounded-lg cursor-pointer" data-collapse-trigger="${sectionId}">
|
|
70
|
+
<div class="flex items-center space-x-2">
|
|
71
|
+
<span data-collapse-icon class="text-lg">▼</span>
|
|
72
|
+
<h4 class="text-lg font-bold text-${color}-800">${icon} ${title}</h4>
|
|
73
|
+
<span class="text-sm text-gray-600">(${targets.length})</span>
|
|
74
|
+
</div>
|
|
75
|
+
<span class="font-semibold text-${color}-600" data-group-time="${groupId}">${totalTime}</span>
|
|
76
|
+
</div>
|
|
77
|
+
<div data-collapse-content class="mt-3 space-y-4">
|
|
78
|
+
${targets.map(target => renderSubTarget(target)).join('')}
|
|
79
|
+
</div>
|
|
80
|
+
</div>
|
|
81
|
+
`;
|
|
82
|
+
}
|
|
83
|
+
/**
|
|
84
|
+
* Render Sub-Target (app ou lib dans monorepo)
|
|
85
|
+
*/
|
|
86
|
+
function renderSubTarget(target) {
|
|
87
|
+
const sectionId = `subtarget-${target.targetName.replace(/[^a-z0-9]/gi, '-')}`;
|
|
88
|
+
const color = target.targetType === 'app' ? 'blue' : 'green';
|
|
89
|
+
return `
|
|
90
|
+
<div id="${sectionId}" class="ml-6 border-l-2 border-gray-300 pl-4">
|
|
91
|
+
<div class="flex items-center justify-between bg-gray-50 p-3 rounded-lg cursor-pointer" data-collapse-trigger="${sectionId}">
|
|
92
|
+
<div class="flex items-center space-x-2">
|
|
93
|
+
<span data-collapse-icon class="text-base">▼</span>
|
|
94
|
+
<h5 class="text-base font-semibold text-gray-800">${(0, core_1.escapeHtml)(target.targetName)}</h5>
|
|
95
|
+
${(0, core_1.renderBadge)(target.targetType, color)}
|
|
96
|
+
</div>
|
|
97
|
+
<span class="font-semibold text-gray-600" data-target-time="${target.targetName}">${(0, core_1.formatTime)(target.totalTime.minutes, target.totalTime.hours, target.totalTime.days)}</span>
|
|
98
|
+
</div>
|
|
99
|
+
<div data-collapse-content class="mt-3 space-y-3">
|
|
100
|
+
${target.migrations.map(migration => (0, hierarchy_shared_1.renderMigration)(target.targetName, migration)).join('')}
|
|
101
|
+
</div>
|
|
102
|
+
</div>
|
|
103
|
+
`;
|
|
104
|
+
}
|
|
@@ -0,0 +1,163 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
/**
|
|
3
|
+
* Composants partagés pour templates hiérarchiques (Nx & Standalone)
|
|
4
|
+
* Contient les renderers pour: Migration, Priority, Rule
|
|
5
|
+
*/
|
|
6
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
7
|
+
exports.renderMigration = renderMigration;
|
|
8
|
+
exports.renderPriority = renderPriority;
|
|
9
|
+
exports.renderRule = renderRule;
|
|
10
|
+
const core_1 = require("../../utils/core");
|
|
11
|
+
/**
|
|
12
|
+
* Render Migration (niveau 2 : to18, to19, to20)
|
|
13
|
+
*/
|
|
14
|
+
function renderMigration(targetName, migration) {
|
|
15
|
+
const migrationId = `${targetName}-${migration.migration}`;
|
|
16
|
+
const sectionId = `section-${migrationId}`;
|
|
17
|
+
const colorMap = { to18: 'blue', to19: 'indigo', to20: 'purple' };
|
|
18
|
+
const color = colorMap[migration.migration] || 'gray';
|
|
19
|
+
return `
|
|
20
|
+
<div id="${sectionId}" class="ml-8 border-l-4 border-${color}-400 pl-4" data-migration="${migration.migration}">
|
|
21
|
+
<div class="flex items-center justify-between bg-${color}-50 p-3 rounded-lg cursor-pointer" data-collapse-trigger="${sectionId}">
|
|
22
|
+
<div class="flex items-center space-x-2">
|
|
23
|
+
<span data-collapse-icon class="text-lg">▼</span>
|
|
24
|
+
<span class="font-bold text-${color}-800">${migration.migration.toUpperCase()}</span>
|
|
25
|
+
</div>
|
|
26
|
+
<span class="font-semibold text-${color}-600" data-migration-time="${migrationId}">${(0, core_1.formatTime)(migration.totalTime.minutes, migration.totalTime.hours, migration.totalTime.days)}</span>
|
|
27
|
+
</div>
|
|
28
|
+
<div data-collapse-content class="mt-3 space-y-3">
|
|
29
|
+
${migration.priorities.map(priority => renderPriority(migrationId, priority)).join('')}
|
|
30
|
+
</div>
|
|
31
|
+
</div>
|
|
32
|
+
`;
|
|
33
|
+
}
|
|
34
|
+
/**
|
|
35
|
+
* Render Priority (niveau 3 : obligatoire, recommandé, optionnel)
|
|
36
|
+
*/
|
|
37
|
+
function renderPriority(migrationId, priority) {
|
|
38
|
+
const priorityId = `${migrationId}-${priority.priority}`;
|
|
39
|
+
const sectionId = `section-${priorityId}`;
|
|
40
|
+
const colorMap = { obligatoire: 'red', recommande: 'yellow', optionnelle: 'green' };
|
|
41
|
+
const color = colorMap[priority.priority] || 'gray';
|
|
42
|
+
return `
|
|
43
|
+
<div id="${sectionId}" class="ml-8 border-l-4 border-${color}-400 pl-4">
|
|
44
|
+
<div class="flex items-center justify-between bg-${color}-50 p-3 rounded-lg cursor-pointer" data-collapse-trigger="${sectionId}">
|
|
45
|
+
<div class="flex items-center space-x-2">
|
|
46
|
+
<span data-collapse-icon class="text-lg">▼</span>
|
|
47
|
+
${(0, core_1.renderBadge)(priority.priority.charAt(0).toUpperCase() + priority.priority.slice(1), color)}
|
|
48
|
+
<span class="text-sm text-gray-600">(${priority.rules.length} règles)</span>
|
|
49
|
+
</div>
|
|
50
|
+
<span class="font-semibold text-${color}-600" data-priority-time="${priorityId}">${(0, core_1.formatTime)(priority.totalTime.minutes, priority.totalTime.hours, priority.totalTime.days)}</span>
|
|
51
|
+
</div>
|
|
52
|
+
<div data-collapse-content class="mt-3 space-y-2">
|
|
53
|
+
${priority.rules.map(rule => renderRule(rule)).join('')}
|
|
54
|
+
</div>
|
|
55
|
+
</div>
|
|
56
|
+
`;
|
|
57
|
+
}
|
|
58
|
+
/**
|
|
59
|
+
* Render Rule (niveau 4 : règle individuelle avec édition temps)
|
|
60
|
+
* Note: Les attributs data-risk-level, data-category, data-rule-type seront injectés dynamiquement
|
|
61
|
+
* côté client car RuleWorkload ne contient pas ces métadonnées (uniquement Rule les a)
|
|
62
|
+
*/
|
|
63
|
+
function renderRule(rule) {
|
|
64
|
+
const typeColor = rule.type === 'routine' ? 'teal' : rule.type === 'special' ? 'pink' : rule.type === 'combined' ? 'purple' : 'blue';
|
|
65
|
+
const hasSpecialWorkload = rule.type === 'special' || rule.type === 'combined';
|
|
66
|
+
// Calcul des temps
|
|
67
|
+
const baseOccurrences = rule.baseOccurrences ?? rule.occurrences;
|
|
68
|
+
const baseMinutes = rule.minutesPerOccurrence * baseOccurrences;
|
|
69
|
+
const specialMinutes = hasSpecialWorkload && rule.specialWorkloadFiles && rule.specialTimePerFile
|
|
70
|
+
? rule.specialWorkloadFiles * rule.specialTimePerFile
|
|
71
|
+
: 0;
|
|
72
|
+
return `
|
|
73
|
+
<div
|
|
74
|
+
class="ml-8 bg-white border border-gray-200 rounded-lg p-4 hover:shadow-md transition-shadow"
|
|
75
|
+
data-rule-card
|
|
76
|
+
data-rule-key="${rule.ruleKey}"
|
|
77
|
+
data-title="${(0, core_1.escapeHtml)(rule.ruleSummary)}"
|
|
78
|
+
data-rule-type="${rule.type || 'standard'}"
|
|
79
|
+
>
|
|
80
|
+
<div class="flex justify-between items-start">
|
|
81
|
+
<div class="flex-1">
|
|
82
|
+
<!-- Chips container (rempli dynamiquement côté client) -->
|
|
83
|
+
<div class="flex items-center gap-2 mb-2" data-chips-container="${rule.ruleKey}"></div>
|
|
84
|
+
|
|
85
|
+
<h5 class="font-semibold text-gray-800 mb-2">${(0, core_1.escapeHtml)(rule.ruleSummary)}</h5>
|
|
86
|
+
<div class="flex items-center space-x-2 text-sm mb-2">
|
|
87
|
+
${(0, core_1.renderBadge)(rule.type || 'standard', typeColor)}
|
|
88
|
+
</div>
|
|
89
|
+
<div class="text-sm text-gray-700">
|
|
90
|
+
${rule.type === 'combined' ? `
|
|
91
|
+
<span data-calc-display="${rule.ruleKey}">
|
|
92
|
+
${baseOccurrences} occ ×
|
|
93
|
+
<input
|
|
94
|
+
type="number"
|
|
95
|
+
data-time-input="${rule.ruleKey}"
|
|
96
|
+
data-original-time="${rule.minutesPerOccurrence}"
|
|
97
|
+
value="${rule.minutesPerOccurrence}"
|
|
98
|
+
min="1"
|
|
99
|
+
class="w-14 px-2 py-1 mx-1 border border-gray-300 rounded text-center"
|
|
100
|
+
/>min +
|
|
101
|
+
${rule.specialWorkloadFiles} fichiers ×
|
|
102
|
+
<input
|
|
103
|
+
type="number"
|
|
104
|
+
data-special-time-input="${rule.ruleKey}"
|
|
105
|
+
data-original-special-time="${rule.specialTimePerFile}"
|
|
106
|
+
value="${rule.specialTimePerFile}"
|
|
107
|
+
min="1"
|
|
108
|
+
class="w-14 px-2 py-1 mx-1 border border-gray-300 rounded text-center"
|
|
109
|
+
/>min =
|
|
110
|
+
<span class="font-semibold text-gray-900" data-rule-time="${rule.ruleKey}">${(0, core_1.formatTime)(rule.totalTime.minutes, rule.totalTime.hours, rule.totalTime.days)}</span>
|
|
111
|
+
</span>
|
|
112
|
+
` : rule.type === 'special' ? `
|
|
113
|
+
<span data-calc-display="${rule.ruleKey}">
|
|
114
|
+
${rule.specialWorkloadFiles} fichiers ×
|
|
115
|
+
<input
|
|
116
|
+
type="number"
|
|
117
|
+
data-special-time-input="${rule.ruleKey}"
|
|
118
|
+
data-original-special-time="${rule.specialTimePerFile}"
|
|
119
|
+
value="${rule.specialTimePerFile}"
|
|
120
|
+
min="1"
|
|
121
|
+
class="w-14 px-2 py-1 mx-1 border border-gray-300 rounded text-center"
|
|
122
|
+
/>min =
|
|
123
|
+
<span class="font-semibold text-gray-900" data-rule-time="${rule.ruleKey}">${(0, core_1.formatTime)(rule.totalTime.minutes, rule.totalTime.hours, rule.totalTime.days)}</span>
|
|
124
|
+
</span>
|
|
125
|
+
` : rule.type === 'routine' ? `
|
|
126
|
+
<span data-calc-display="${rule.ruleKey}">
|
|
127
|
+
${rule.occurrences} ×
|
|
128
|
+
<input
|
|
129
|
+
type="number"
|
|
130
|
+
data-time-input="${rule.ruleKey}"
|
|
131
|
+
data-original-time="${rule.minutesPerOccurrence}"
|
|
132
|
+
value="${rule.minutesPerOccurrence}"
|
|
133
|
+
min="1"
|
|
134
|
+
class="w-14 px-2 py-1 mx-1 border border-gray-300 rounded text-center"
|
|
135
|
+
/>min =
|
|
136
|
+
<span class="font-semibold text-gray-900" data-rule-time="${rule.ruleKey}">${(0, core_1.formatTime)(rule.totalTime.minutes, rule.totalTime.hours, rule.totalTime.days)}</span>
|
|
137
|
+
</span>
|
|
138
|
+
` : `
|
|
139
|
+
<span data-calc-display="${rule.ruleKey}">
|
|
140
|
+
${rule.occurrences} occ ×
|
|
141
|
+
<input
|
|
142
|
+
type="number"
|
|
143
|
+
data-time-input="${rule.ruleKey}"
|
|
144
|
+
data-original-time="${rule.minutesPerOccurrence}"
|
|
145
|
+
value="${rule.minutesPerOccurrence}"
|
|
146
|
+
min="1"
|
|
147
|
+
class="w-14 px-2 py-1 mx-1 border border-gray-300 rounded text-center"
|
|
148
|
+
/>min =
|
|
149
|
+
<span class="font-semibold text-gray-900" data-rule-time="${rule.ruleKey}">${(0, core_1.formatTime)(rule.totalTime.minutes, rule.totalTime.hours, rule.totalTime.days)}</span>
|
|
150
|
+
</span>
|
|
151
|
+
`}
|
|
152
|
+
</div>
|
|
153
|
+
</div>
|
|
154
|
+
<button
|
|
155
|
+
class="px-3 py-1 text-sm bg-blue-500 text-white rounded hover:bg-blue-600"
|
|
156
|
+
data-modal-trigger="modal-${rule.ruleKey}"
|
|
157
|
+
>
|
|
158
|
+
Détails
|
|
159
|
+
</button>
|
|
160
|
+
</div>
|
|
161
|
+
</div>
|
|
162
|
+
`;
|
|
163
|
+
}
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
/**
|
|
3
|
+
* Template spécifique pour vue hiérarchique Angular Standalone
|
|
4
|
+
* Structure: Target > Migrations > Priorities > Rules
|
|
5
|
+
*/
|
|
6
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
7
|
+
exports.renderStandaloneView = renderStandaloneView;
|
|
8
|
+
const core_1 = require("../../utils/core");
|
|
9
|
+
const hierarchy_shared_1 = require("./hierarchy-shared");
|
|
10
|
+
/**
|
|
11
|
+
* Vue pour projet Standalone : Affiche directement les migrations
|
|
12
|
+
*/
|
|
13
|
+
function renderStandaloneView(workload) {
|
|
14
|
+
return workload.targets.map(target => renderStandaloneTarget(target)).join('');
|
|
15
|
+
}
|
|
16
|
+
/**
|
|
17
|
+
* Render Target pour Standalone (structure simple)
|
|
18
|
+
*/
|
|
19
|
+
function renderStandaloneTarget(target) {
|
|
20
|
+
const sectionId = `target-${target.targetName.replace(/[^a-z0-9]/gi, '-')}`;
|
|
21
|
+
return `
|
|
22
|
+
<div id="${sectionId}" class="mb-6 border-l-4 border-blue-500 pl-4">
|
|
23
|
+
<div class="flex items-center justify-between bg-blue-50 p-4 rounded-lg cursor-pointer" data-collapse-trigger="${sectionId}">
|
|
24
|
+
<div class="flex items-center space-x-3">
|
|
25
|
+
<span data-collapse-icon class="text-xl">▼</span>
|
|
26
|
+
<h3 class="text-xl font-bold text-blue-900">${(0, core_1.escapeHtml)(target.targetName)}</h3>
|
|
27
|
+
${(0, core_1.renderBadge)(target.targetType, 'blue')}
|
|
28
|
+
</div>
|
|
29
|
+
<span class="text-lg font-semibold text-blue-600" data-target-time="${target.targetName}">${(0, core_1.formatTime)(target.totalTime.minutes, target.totalTime.hours, target.totalTime.days)}</span>
|
|
30
|
+
</div>
|
|
31
|
+
<div data-collapse-content class="mt-4 space-y-4">
|
|
32
|
+
${target.migrations.map(migration => (0, hierarchy_shared_1.renderMigration)(target.targetName, migration)).join('')}
|
|
33
|
+
</div>
|
|
34
|
+
</div>
|
|
35
|
+
`;
|
|
36
|
+
}
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
/**
|
|
3
|
+
* Template vue hiérarchique (Entry Point)
|
|
4
|
+
* Délègue vers Nx ou Standalone selon le type de projet
|
|
5
|
+
*/
|
|
6
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
7
|
+
exports.renderHierarchy = renderHierarchy;
|
|
8
|
+
const project_strategy_1 = require("../../core/project-strategy");
|
|
9
|
+
const hierarchy_nx_template_1 = require("./hierarchy-nx.template");
|
|
10
|
+
const hierarchy_standalone_template_1 = require("./hierarchy-standalone.template");
|
|
11
|
+
/**
|
|
12
|
+
* Point d'entrée : Render hiérarchie complète
|
|
13
|
+
* Détecte automatiquement le type de projet et délègue
|
|
14
|
+
*/
|
|
15
|
+
function renderHierarchy(workload) {
|
|
16
|
+
const strategy = (0, project_strategy_1.createProjectStrategy)(workload.projectInfo);
|
|
17
|
+
const isMultiTarget = strategy.isMultiTarget(workload.projectInfo);
|
|
18
|
+
return `
|
|
19
|
+
<div class="bg-white rounded-2xl shadow-xl p-8">
|
|
20
|
+
<div class="flex justify-between items-center mb-6">
|
|
21
|
+
<h2 class="text-3xl font-bold text-gray-800">🗂️ Vue Hiérarchique</h2>
|
|
22
|
+
<div class="space-x-2">
|
|
23
|
+
<button onclick="expandAll()" class="px-4 py-2 bg-blue-500 text-white rounded-lg hover:bg-blue-600">
|
|
24
|
+
Tout Déplier
|
|
25
|
+
</button>
|
|
26
|
+
<button onclick="collapseAll()" class="px-4 py-2 bg-gray-500 text-white rounded-lg hover:bg-gray-600">
|
|
27
|
+
Tout Replier
|
|
28
|
+
</button>
|
|
29
|
+
</div>
|
|
30
|
+
</div>
|
|
31
|
+
|
|
32
|
+
${isMultiTarget ? (0, hierarchy_nx_template_1.renderNxMonorepoView)(workload) : (0, hierarchy_standalone_template_1.renderStandaloneView)(workload)}
|
|
33
|
+
</div>
|
|
34
|
+
`;
|
|
35
|
+
}
|