@atlashub/smartstack-cli 4.41.0 → 4.43.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/.documentation/apex.html +2 -2
- package/.documentation/business-analyse.html +26 -27
- package/.documentation/commands.html +6 -6
- package/dist/index.js +24 -13
- package/dist/index.js.map +1 -1
- package/package.json +2 -2
- package/templates/agents/ba-reader.md +2 -2
- package/templates/agents/ba-writer.md +44 -9
- package/templates/hooks/stop-hook.sh +6 -6
- package/templates/ralph/README.md +1 -1
- package/templates/scripts/setup-ralph-loop.sh +2 -2
- package/templates/skills/_resources/context-digest-template.md +1 -1
- package/templates/skills/_shared.md +13 -13
- package/templates/skills/apex/SKILL.md +14 -7
- package/templates/skills/apex/_shared.md +1 -1
- package/templates/skills/apex/references/challenge-questions.md +46 -13
- package/templates/skills/apex/references/core-seed-data.md +4 -4
- package/templates/skills/apex/references/error-classification.md +3 -3
- package/templates/skills/apex/references/smartstack-api.md +1 -1
- package/templates/skills/apex/references/smartstack-layers.md +1 -1
- package/templates/skills/apex/steps/step-00-init.md +46 -8
- package/templates/skills/apex/steps/step-01-analyze.md +1 -1
- package/templates/skills/apex/steps/step-02-plan.md +1 -1
- package/templates/skills/apex/steps/step-03-execute.md +1 -1
- package/templates/skills/business-analyse/SKILL.md +83 -22
- package/templates/skills/business-analyse/_shared.md +12 -9
- package/templates/skills/business-analyse/questionnaire/02-stakeholders-scope.md +24 -9
- package/templates/skills/business-analyse/questionnaire/03-data-ui.md +33 -0
- package/templates/skills/business-analyse/questionnaire/04-risks-metrics.md +1 -1
- package/templates/skills/business-analyse/react/components.md +1 -22
- package/templates/skills/business-analyse/react/schema.md +1 -1
- package/templates/skills/business-analyse/references/acceptance-criteria.md +3 -3
- package/templates/skills/business-analyse/references/consolidation-structural-checks.md +1 -1
- package/templates/skills/business-analyse/references/detection-strategies.md +2 -2
- package/templates/skills/business-analyse/references/entity-architecture-decision.md +1 -1
- package/templates/skills/business-analyse/references/naming-conventions.md +6 -6
- package/templates/skills/business-analyse/references/robustness-checks.md +4 -4
- package/templates/skills/business-analyse/references/spec-auto-inference.md +2 -2
- package/templates/skills/business-analyse/references/validation-checklist.md +3 -3
- package/templates/skills/business-analyse/schemas/feature-schema.json +1 -1
- package/templates/skills/business-analyse/schemas/sections/handoff-schema.json +2 -2
- package/templates/skills/business-analyse/schemas/sections/specification-schema.json +3 -2
- package/templates/skills/business-analyse/steps/step-00-init.md +15 -5
- package/templates/skills/business-analyse/steps/step-01-cadrage.md +15 -6
- package/templates/skills/business-analyse/steps/step-02-structure.md +17 -1
- package/templates/skills/business-analyse/steps/step-03-specify.md +136 -26
- package/templates/skills/business-analyse/steps/step-04-consolidate.md +44 -8
- package/templates/skills/business-analyse/templates/tpl-handoff.md +5 -5
- package/templates/skills/business-analyse/templates/tpl-launch-displays.md +4 -4
- package/templates/skills/business-analyse/templates-frd.md +4 -4
- package/templates/skills/{ba-design-ui → business-analyse-design}/SKILL.md +9 -9
- package/templates/skills/{ba-design-ui → business-analyse-design}/steps/step-01-screens.md +9 -0
- package/templates/skills/{ba-design-ui → business-analyse-design}/steps/step-03-navigation.md +9 -2
- package/templates/skills/business-analyse-develop/SKILL.md +248 -0
- package/templates/skills/{ralph-loop → business-analyse-develop}/references/category-completeness.md +1 -1
- package/templates/skills/{ralph-loop → business-analyse-develop}/references/init-resume-recovery.md +8 -8
- package/templates/skills/{ralph-loop → business-analyse-develop}/references/multi-module-queue.md +1 -1
- package/templates/skills/business-analyse-develop/references/quality-gates.md +70 -0
- package/templates/skills/{ralph-loop → business-analyse-develop}/references/task-transform-legacy.md +1 -1
- package/templates/skills/{ralph-loop → business-analyse-develop}/steps/step-00-init.md +20 -4
- package/templates/skills/{ralph-loop → business-analyse-develop}/steps/step-01-task.md +3 -2
- package/templates/skills/business-analyse-develop/steps/step-01-v4-execute.md +131 -0
- package/templates/skills/business-analyse-develop/steps/step-02-v4-verify.md +156 -0
- package/templates/skills/{ralph-loop → business-analyse-develop}/steps/step-04-check.md +1 -1
- package/templates/skills/{ralph-loop → business-analyse-develop}/steps/step-05-report.md +1 -1
- package/templates/skills/{derive-prd → business-analyse-handoff}/SKILL.md +7 -7
- package/templates/skills/{derive-prd → business-analyse-handoff}/references/acceptance-criteria.md +5 -5
- package/templates/skills/{derive-prd → business-analyse-handoff}/references/handoff-file-templates.md +1 -1
- package/templates/skills/{derive-prd → business-analyse-handoff}/references/handoff-mappings.md +1 -1
- package/templates/skills/{derive-prd → business-analyse-handoff}/references/handoff-seeddata-generation.md +2 -2
- package/templates/skills/{derive-prd → business-analyse-handoff}/references/prd-generation.md +14 -14
- package/templates/skills/{derive-prd → business-analyse-handoff}/schemas/handoff-schema.json +2 -2
- package/templates/skills/{derive-prd → business-analyse-handoff}/steps/step-00-validate.md +7 -7
- package/templates/skills/{derive-prd → business-analyse-handoff}/steps/step-01-transform.md +50 -11
- package/templates/skills/{derive-prd → business-analyse-handoff}/steps/step-02-export.md +36 -16
- package/templates/skills/{ba-generate-html → business-analyse-html}/SKILL.md +4 -4
- package/templates/skills/{ba-generate-html → business-analyse-html}/html/ba-interactive.html +714 -286
- package/templates/skills/{ba-generate-html → business-analyse-html}/html/build-html.js +25 -3
- package/templates/skills/{ba-generate-html → business-analyse-html}/html/src/scripts/01-data-init.js +54 -0
- package/templates/skills/{ba-generate-html → business-analyse-html}/html/src/scripts/02-navigation.js +102 -12
- package/templates/skills/{ba-generate-html → business-analyse-html}/html/src/scripts/03-render-cadrage.js +8 -7
- package/templates/skills/{ba-generate-html → business-analyse-html}/html/src/scripts/04-render-modules.js +7 -7
- package/templates/skills/{ba-generate-html → business-analyse-html}/html/src/scripts/05-render-specs.js +188 -85
- package/templates/skills/{ba-generate-html → business-analyse-html}/html/src/scripts/06-render-consolidation.js +15 -14
- package/templates/skills/{ba-generate-html → business-analyse-html}/html/src/scripts/06-render-mockups.js +19 -19
- package/templates/skills/{ba-generate-html → business-analyse-html}/html/src/scripts/07-render-handoff.js +24 -4
- package/templates/skills/{ba-generate-html → business-analyse-html}/html/src/scripts/08-editing.js +6 -2
- package/templates/skills/{ba-generate-html → business-analyse-html}/html/src/scripts/09-export.js +27 -57
- package/templates/skills/{ba-generate-html → business-analyse-html}/html/src/scripts/10-comments.js +67 -45
- package/templates/skills/{ba-generate-html → business-analyse-html}/html/src/scripts/11-review-panel.js +15 -13
- package/templates/skills/business-analyse-html/html/src/styles/02-layout.css +216 -0
- package/templates/skills/{ba-generate-html → business-analyse-html}/html/src/styles/05-modules.css +36 -0
- package/templates/skills/{ba-generate-html → business-analyse-html}/html/src/template.html +22 -12
- package/templates/skills/{ba-generate-html → business-analyse-html}/references/data-build.md +1 -1
- package/templates/skills/{ba-generate-html → business-analyse-html}/references/data-mapping.md +5 -1
- package/templates/skills/{ba-generate-html → business-analyse-html}/references/output-modes.md +7 -7
- package/templates/skills/{ba-generate-html → business-analyse-html}/steps/step-01-collect.md +25 -1
- package/templates/skills/{ba-generate-html → business-analyse-html}/steps/step-02-build-data.md +33 -5
- package/templates/skills/{ba-generate-html → business-analyse-html}/steps/step-03-render.md +2 -2
- package/templates/skills/{ba-generate-html → business-analyse-html}/steps/step-04-verify.md +2 -2
- package/templates/skills/{ba-review → business-analyse-review}/SKILL.md +11 -10
- package/templates/skills/{ba-review → business-analyse-review}/references/review-data-mapping.md +2 -2
- package/templates/skills/business-analyse-review/steps/step-00-init.md +107 -0
- package/templates/skills/{ba-review → business-analyse-review}/steps/step-01-apply.md +19 -11
- package/templates/skills/business-analyse-status/SKILL.md +118 -0
- package/templates/skills/documentation/SKILL.md +2 -2
- package/templates/skills/sketch/SKILL.md +172 -0
- package/templates/skills/sketch/references/domain-heuristics.md +116 -0
- package/templates/skills/ba-generate-html/html/src/styles/02-layout.css +0 -101
- package/templates/skills/ralph-loop/SKILL.md +0 -240
- /package/templates/skills/{ba-design-ui → business-analyse-design}/steps/step-02-wireframes.md +0 -0
- /package/templates/skills/{ralph-loop → business-analyse-develop}/references/category-rules.md +0 -0
- /package/templates/skills/{ralph-loop → business-analyse-develop}/references/compact-loop.md +0 -0
- /package/templates/skills/{ralph-loop → business-analyse-develop}/references/module-transition.md +0 -0
- /package/templates/skills/{ralph-loop → business-analyse-develop}/references/parallel-execution.md +0 -0
- /package/templates/skills/{ralph-loop → business-analyse-develop}/references/section-splitting.md +0 -0
- /package/templates/skills/{ralph-loop → business-analyse-develop}/references/team-orchestration.md +0 -0
- /package/templates/skills/{ralph-loop → business-analyse-develop}/steps/step-02-execute.md +0 -0
- /package/templates/skills/{ralph-loop → business-analyse-develop}/steps/step-03-commit.md +0 -0
- /package/templates/skills/{derive-prd → business-analyse-handoff}/references/entity-domain-mapping.md +0 -0
- /package/templates/skills/{derive-prd → business-analyse-handoff}/references/readiness-scoring.md +0 -0
- /package/templates/skills/{derive-prd → business-analyse-handoff}/templates/tpl-progress.md +0 -0
- /package/templates/skills/{ba-generate-html → business-analyse-html}/html/src/partials/cadrage-context.html +0 -0
- /package/templates/skills/{ba-generate-html → business-analyse-html}/html/src/partials/cadrage-scope.html +0 -0
- /package/templates/skills/{ba-generate-html → business-analyse-html}/html/src/partials/cadrage-stakeholders.html +0 -0
- /package/templates/skills/{ba-generate-html → business-analyse-html}/html/src/partials/cadrage-success.html +0 -0
- /package/templates/skills/{ba-generate-html → business-analyse-html}/html/src/partials/consol-datamodel.html +0 -0
- /package/templates/skills/{ba-generate-html → business-analyse-html}/html/src/partials/consol-flows.html +0 -0
- /package/templates/skills/{ba-generate-html → business-analyse-html}/html/src/partials/consol-interactions.html +0 -0
- /package/templates/skills/{ba-generate-html → business-analyse-html}/html/src/partials/consol-permissions.html +0 -0
- /package/templates/skills/{ba-generate-html → business-analyse-html}/html/src/partials/decomp-dependencies.html +0 -0
- /package/templates/skills/{ba-generate-html → business-analyse-html}/html/src/partials/decomp-modules.html +0 -0
- /package/templates/skills/{ba-generate-html → business-analyse-html}/html/src/partials/handoff-summary.html +0 -0
- /package/templates/skills/{ba-generate-html → business-analyse-html}/html/src/partials/module-spec-container.html +0 -0
- /package/templates/skills/{ba-generate-html → business-analyse-html}/html/src/styles/01-variables.css +0 -0
- /package/templates/skills/{ba-generate-html → business-analyse-html}/html/src/styles/03-navigation.css +0 -0
- /package/templates/skills/{ba-generate-html → business-analyse-html}/html/src/styles/04-cards.css +0 -0
- /package/templates/skills/{ba-generate-html → business-analyse-html}/html/src/styles/06-wireframes.css +0 -0
- /package/templates/skills/{ba-generate-html → business-analyse-html}/html/src/styles/07-comments.css +0 -0
- /package/templates/skills/{ba-generate-html → business-analyse-html}/html/src/styles/08-review-panel.css +0 -0
- /package/templates/skills/{ba-generate-html → business-analyse-html}/html/src/styles/09-mockups-html.css +0 -0
- /package/templates/skills/{ba-generate-html → business-analyse-html}/references/wireframe-svg-style-guide.md +0 -0
|
@@ -60,8 +60,28 @@ function resolvePartials(template) {
|
|
|
60
60
|
return resolved;
|
|
61
61
|
}
|
|
62
62
|
|
|
63
|
+
function minifyCss(css) {
|
|
64
|
+
return css
|
|
65
|
+
.replace(/\/\*[\s\S]*?\*\//g, '') // remove comments
|
|
66
|
+
.replace(/\s*([{}:;,>~+])\s*/g, '$1') // remove whitespace around symbols
|
|
67
|
+
.replace(/\s+/g, ' ') // collapse whitespace
|
|
68
|
+
.replace(/;\s*}/g, '}') // remove trailing semicolons
|
|
69
|
+
.trim();
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
function minifyJs(js) {
|
|
73
|
+
// Light minification — remove comments and collapse whitespace (no AST transform)
|
|
74
|
+
return js
|
|
75
|
+
.replace(/\/\*[\s\S]*?\*\//g, '') // remove block comments
|
|
76
|
+
.replace(/\/\/.*$/gm, '') // remove line comments
|
|
77
|
+
.replace(/^\s*\n/gm, '') // remove empty lines
|
|
78
|
+
.replace(/\n\s+/g, '\n') // reduce leading whitespace
|
|
79
|
+
.trim();
|
|
80
|
+
}
|
|
81
|
+
|
|
63
82
|
function build() {
|
|
64
|
-
|
|
83
|
+
const doMinify = process.argv.includes('--minify');
|
|
84
|
+
console.log('[build-html] Starting build...' + (doMinify ? ' (minified)' : ''));
|
|
65
85
|
|
|
66
86
|
// Read template
|
|
67
87
|
if (!fs.existsSync(TEMPLATE_FILE)) {
|
|
@@ -80,12 +100,14 @@ function build() {
|
|
|
80
100
|
// Read and concatenate CSS files
|
|
81
101
|
const cssFiles = readSortedFiles(STYLES_DIR, '.css');
|
|
82
102
|
console.log(`[build-html] CSS files: ${cssFiles.map(f => f.name).join(', ')}`);
|
|
83
|
-
|
|
103
|
+
let css = cssFiles.map(f => `/* --- ${f.name} --- */\n${f.content}`).join('\n\n');
|
|
104
|
+
if (doMinify) css = minifyCss(css);
|
|
84
105
|
|
|
85
106
|
// Read and concatenate JS files
|
|
86
107
|
const jsFiles = readSortedFiles(SCRIPTS_DIR, '.js');
|
|
87
108
|
console.log(`[build-html] JS files: ${jsFiles.map(f => f.name).join(', ')}`);
|
|
88
|
-
|
|
109
|
+
let js = jsFiles.map(f => `/* --- ${f.name} --- */\n${f.content}`).join('\n\n');
|
|
110
|
+
if (doMinify) js = minifyJs(js);
|
|
89
111
|
|
|
90
112
|
// Inject into template
|
|
91
113
|
template = template.replace('<!-- CSS_PLACEHOLDER -->', css);
|
package/templates/skills/{ba-generate-html → business-analyse-html}/html/src/scripts/01-data-init.js
RENAMED
|
@@ -73,8 +73,23 @@ data.moduleSpecs = data.moduleSpecs || {};
|
|
|
73
73
|
if (!data.moduleSpecs[m.code].screens) {
|
|
74
74
|
data.moduleSpecs[m.code].screens = [];
|
|
75
75
|
}
|
|
76
|
+
// Ensure sections have initialized arrays for hierarchical data
|
|
77
|
+
m.anticipatedSections.forEach(function(section) {
|
|
78
|
+
section.useCases = section.useCases || [];
|
|
79
|
+
section.businessRules = section.businessRules || [];
|
|
80
|
+
section.resources = section.resources || [];
|
|
81
|
+
section.permission = section.permission || '';
|
|
82
|
+
section.route = section.route || '';
|
|
83
|
+
});
|
|
76
84
|
});
|
|
77
85
|
|
|
86
|
+
// Detect if modules use section-level specs (hierarchical mode)
|
|
87
|
+
function hasHierarchicalSpecs(mod) {
|
|
88
|
+
return (mod.anticipatedSections || []).some(function(s) {
|
|
89
|
+
return (s.useCases && s.useCases.length > 0) || (s.businessRules && s.businessRules.length > 0);
|
|
90
|
+
});
|
|
91
|
+
}
|
|
92
|
+
|
|
78
93
|
// Defensive: normalize stakeholder tasks (string → array)
|
|
79
94
|
(data.cadrage.stakeholders || []).forEach(function(s) {
|
|
80
95
|
if (typeof s.tasks === 'string') {
|
|
@@ -146,6 +161,45 @@ function formatModuleType(t) {
|
|
|
146
161
|
return { 'data-centric': 'Données', 'workflow': 'Processus', 'reporting': 'Rapports', 'integration': 'Intégration', 'full-module': 'Complet' }[t] || t;
|
|
147
162
|
}
|
|
148
163
|
|
|
164
|
+
function escapeHtml(s) {
|
|
165
|
+
if (s == null) return '';
|
|
166
|
+
var d = document.createElement('div');
|
|
167
|
+
d.textContent = String(s);
|
|
168
|
+
return d.innerHTML;
|
|
169
|
+
}
|
|
170
|
+
|
|
171
|
+
function computeProgress() {
|
|
172
|
+
var totalModules = data.modules.length;
|
|
173
|
+
var modulesWithUC = 0, modulesWithBR = 0, modulesWithEntities = 0, modulesWithWireframes = 0;
|
|
174
|
+
var totalUCs = 0, totalBRs = 0, totalEntities = 0;
|
|
175
|
+
|
|
176
|
+
data.modules.forEach(function(m) {
|
|
177
|
+
var spec = data.moduleSpecs[m.code] || {};
|
|
178
|
+
var ucs = (spec.useCases || []).length;
|
|
179
|
+
var brs = (spec.businessRules || []).length;
|
|
180
|
+
var ents = (spec.entities || []).length;
|
|
181
|
+
var wfs = (EMBEDDED_ARTIFACTS?.wireframes?.[m.code] || []).length + (spec.screens || []).length;
|
|
182
|
+
totalUCs += ucs; totalBRs += brs; totalEntities += ents;
|
|
183
|
+
if (ucs > 0) modulesWithUC++;
|
|
184
|
+
if (brs > 0) modulesWithBR++;
|
|
185
|
+
if (ents > 0) modulesWithEntities++;
|
|
186
|
+
if (wfs > 0) modulesWithWireframes++;
|
|
187
|
+
});
|
|
188
|
+
|
|
189
|
+
var checks = [];
|
|
190
|
+
if (totalModules > 0) checks.push({ done: true, label: 'Modules définis (' + totalModules + ')' });
|
|
191
|
+
checks.push({ done: modulesWithUC === totalModules && totalModules > 0, label: 'Cas d\'utilisation (' + modulesWithUC + '/' + totalModules + ' modules)' });
|
|
192
|
+
checks.push({ done: modulesWithBR === totalModules && totalModules > 0, label: 'Règles métier (' + modulesWithBR + '/' + totalModules + ' modules)' });
|
|
193
|
+
checks.push({ done: modulesWithEntities === totalModules && totalModules > 0, label: 'Données (' + modulesWithEntities + '/' + totalModules + ' modules)' });
|
|
194
|
+
checks.push({ done: modulesWithWireframes === totalModules && totalModules > 0, label: 'Maquettes (' + modulesWithWireframes + '/' + totalModules + ' modules)' });
|
|
195
|
+
checks.push({ done: data.cadrage.stakeholders.length > 0, label: 'Parties prenantes (' + data.cadrage.stakeholders.length + ')' });
|
|
196
|
+
checks.push({ done: (data.cadrage.scope.inscope || []).length > 0, label: 'Périmètre défini' });
|
|
197
|
+
|
|
198
|
+
var doneCount = checks.filter(function(c) { return c.done; }).length;
|
|
199
|
+
var pct = checks.length > 0 ? Math.round(doneCount / checks.length * 100) : 0;
|
|
200
|
+
return { checks: checks, doneCount: doneCount, total: checks.length, pct: pct, totalUCs: totalUCs, totalBRs: totalBRs, totalEntities: totalEntities };
|
|
201
|
+
}
|
|
202
|
+
|
|
149
203
|
/* ============================================
|
|
150
204
|
INITIALIZATION
|
|
151
205
|
============================================ */
|
|
@@ -156,35 +156,34 @@ function renderModuleNavItem(mod) {
|
|
|
156
156
|
var html = '<div class="nav-module" data-group-id="' + groupId + '">';
|
|
157
157
|
|
|
158
158
|
// Module header (clickable to expand + navigate to module spec)
|
|
159
|
+
var totalItems = ucCount + brCount + entCount;
|
|
159
160
|
html += '<a class="nav-item nav-module-header" onclick="toggleNavGroup(\'' + groupId + '\');showSection(\'module-spec-' + code + '\')" data-section="module-spec-' + code + '">';
|
|
160
161
|
html += '<span class="nav-chevron ' + (collapsed ? '' : 'expanded') + '">▸</span> ';
|
|
161
162
|
html += (mod.name || mod.code);
|
|
163
|
+
if (totalItems > 0) html += ' <span class="nav-badge">' + totalItems + '</span>';
|
|
162
164
|
html += '</a>';
|
|
163
165
|
|
|
164
|
-
// Children:
|
|
166
|
+
// Children: sections/resources (navigable sub-tree)
|
|
167
|
+
// Tab-level items (UC, BR, Données, etc.) are NOT shown here — they are accessed
|
|
168
|
+
// via the tab bar in the module content area to avoid redundancy.
|
|
165
169
|
html += '<div class="nav-children"' + (collapsed ? ' style="display:none;"' : '') + '>';
|
|
166
|
-
html += renderModuleTabNavItem(code, 'uc', 'Cas d\'utilisation', ucCount);
|
|
167
|
-
html += renderModuleTabNavItem(code, 'br', 'Règles métier', brCount);
|
|
168
|
-
html += renderModuleTabNavItem(code, 'ent', 'Données', entCount);
|
|
169
|
-
html += renderModuleTabNavItem(code, 'perm', 'Droits d\'accès');
|
|
170
|
-
html += renderModuleTabNavItem(code, 'mock', 'Maquettes');
|
|
171
|
-
html += renderModuleTabNavItem(code, 'struct', 'Structure', sections.length);
|
|
172
|
-
|
|
173
|
-
// Children: sections/resources (deeper tree)
|
|
174
170
|
if (sections.length > 0) {
|
|
175
171
|
sections.forEach(function(section) {
|
|
176
172
|
var resources = section.resources || [];
|
|
173
|
+
var sectionUCs = (section.useCases || []).length;
|
|
174
|
+
var sectionBRs = (section.businessRules || []).length;
|
|
175
|
+
var contentCount = sectionUCs + sectionBRs + resources.length;
|
|
177
176
|
html += '<div class="nav-section-item">';
|
|
178
177
|
html += '<a class="nav-item nav-section-link" onclick="showSection(\'module-spec-' + code + '\');switchTab(\'' + code + '\',\'struct\')" data-section="module-struct-' + code + '-' + section.code + '">';
|
|
179
|
-
html += '<span class="nav-icon nav-icon-section">▷</span> ' + section.code;
|
|
180
|
-
if (
|
|
178
|
+
html += '<span class="nav-icon nav-icon-section">▷</span> ' + escapeHtml(section.code || section.name || '');
|
|
179
|
+
if (contentCount > 0) html += ' <span class="nav-badge">' + contentCount + '</span>';
|
|
181
180
|
html += '</a>';
|
|
182
181
|
if (resources.length > 0) {
|
|
183
182
|
html += '<div class="nav-children nav-resources">';
|
|
184
183
|
resources.forEach(function(res) {
|
|
185
184
|
var resName = typeof res === 'string' ? res : (res.code || res.name || '');
|
|
186
185
|
html += '<a class="nav-item nav-resource-link">';
|
|
187
|
-
html += '<span class="nav-icon nav-icon-resource">•</span> ' + resName;
|
|
186
|
+
html += '<span class="nav-icon nav-icon-resource">•</span> ' + escapeHtml(resName);
|
|
188
187
|
html += '</a>';
|
|
189
188
|
});
|
|
190
189
|
html += '</div>';
|
|
@@ -250,3 +249,94 @@ function highlightActiveNavItem() {
|
|
|
250
249
|
var navItem = document.querySelector('#sidebarNav [data-section="' + currentSectionId + '"]');
|
|
251
250
|
if (navItem) navItem.classList.add('active');
|
|
252
251
|
}
|
|
252
|
+
|
|
253
|
+
/* ---------- Mobile Sidebar ---------- */
|
|
254
|
+
|
|
255
|
+
function toggleMobileSidebar() {
|
|
256
|
+
var sidebar = document.getElementById('sidebarAside');
|
|
257
|
+
var overlay = document.getElementById('sidebarOverlay');
|
|
258
|
+
if (!sidebar) return;
|
|
259
|
+
var isOpen = sidebar.classList.contains('mobile-open');
|
|
260
|
+
sidebar.classList.toggle('mobile-open', !isOpen);
|
|
261
|
+
if (overlay) overlay.classList.toggle('visible', !isOpen);
|
|
262
|
+
}
|
|
263
|
+
|
|
264
|
+
/* ---------- Search / Filter ---------- */
|
|
265
|
+
|
|
266
|
+
var _searchTimer;
|
|
267
|
+
function filterNavItems(query) {
|
|
268
|
+
clearTimeout(_searchTimer);
|
|
269
|
+
_searchTimer = setTimeout(function() { doFilterNavItems(query); }, 200);
|
|
270
|
+
}
|
|
271
|
+
|
|
272
|
+
function doFilterNavItems(query) {
|
|
273
|
+
var q = (query || '').toLowerCase().trim();
|
|
274
|
+
var nav = document.getElementById('sidebarNav');
|
|
275
|
+
if (!nav) return;
|
|
276
|
+
|
|
277
|
+
// Clear previous highlights
|
|
278
|
+
nav.querySelectorAll('.search-highlight').forEach(function(el) {
|
|
279
|
+
el.outerHTML = el.textContent;
|
|
280
|
+
});
|
|
281
|
+
|
|
282
|
+
if (!q) {
|
|
283
|
+
// Show all items
|
|
284
|
+
nav.querySelectorAll('.nav-item, .nav-group, .nav-module, .nav-section-item').forEach(function(el) {
|
|
285
|
+
el.classList.remove('search-hidden');
|
|
286
|
+
});
|
|
287
|
+
return;
|
|
288
|
+
}
|
|
289
|
+
|
|
290
|
+
// Filter nav items
|
|
291
|
+
var allItems = nav.querySelectorAll('.nav-item');
|
|
292
|
+
var visibleSections = new Set();
|
|
293
|
+
|
|
294
|
+
allItems.forEach(function(item) {
|
|
295
|
+
var text = item.textContent.toLowerCase();
|
|
296
|
+
if (text.includes(q)) {
|
|
297
|
+
item.classList.remove('search-hidden');
|
|
298
|
+
// Show parent groups
|
|
299
|
+
var parent = item.parentElement;
|
|
300
|
+
while (parent && parent.id !== 'sidebarNav') {
|
|
301
|
+
parent.classList.remove('search-hidden');
|
|
302
|
+
if (parent.querySelector(':scope > .nav-children')) {
|
|
303
|
+
var children = parent.querySelector(':scope > .nav-children');
|
|
304
|
+
if (children) children.style.display = '';
|
|
305
|
+
}
|
|
306
|
+
parent = parent.parentElement;
|
|
307
|
+
}
|
|
308
|
+
// Track section for content search
|
|
309
|
+
var sectionId = item.dataset.section;
|
|
310
|
+
if (sectionId) visibleSections.add(sectionId);
|
|
311
|
+
} else {
|
|
312
|
+
item.classList.add('search-hidden');
|
|
313
|
+
}
|
|
314
|
+
});
|
|
315
|
+
|
|
316
|
+
// Hide groups that have no visible children
|
|
317
|
+
nav.querySelectorAll('.nav-group, .nav-module').forEach(function(group) {
|
|
318
|
+
var visibleChildren = group.querySelectorAll('.nav-item:not(.search-hidden)');
|
|
319
|
+
if (visibleChildren.length === 0) {
|
|
320
|
+
group.classList.add('search-hidden');
|
|
321
|
+
} else {
|
|
322
|
+
group.classList.remove('search-hidden');
|
|
323
|
+
}
|
|
324
|
+
});
|
|
325
|
+
|
|
326
|
+
// Also search in section content and show matching sections
|
|
327
|
+
document.querySelectorAll('.section').forEach(function(section) {
|
|
328
|
+
var text = section.textContent.toLowerCase();
|
|
329
|
+
if (text.includes(q) && !visibleSections.has(section.id)) {
|
|
330
|
+
// Unhide corresponding nav item
|
|
331
|
+
var navItem = nav.querySelector('[data-section="' + section.id + '"]');
|
|
332
|
+
if (navItem) {
|
|
333
|
+
navItem.classList.remove('search-hidden');
|
|
334
|
+
var parent = navItem.parentElement;
|
|
335
|
+
while (parent && parent.id !== 'sidebarNav') {
|
|
336
|
+
parent.classList.remove('search-hidden');
|
|
337
|
+
parent = parent.parentElement;
|
|
338
|
+
}
|
|
339
|
+
}
|
|
340
|
+
}
|
|
341
|
+
});
|
|
342
|
+
}
|
|
@@ -42,23 +42,24 @@ function renderStakeholders() {
|
|
|
42
42
|
grid.innerHTML = data.cadrage.stakeholders.map((s, i) => `
|
|
43
43
|
<div class="stakeholder-card">
|
|
44
44
|
<div style="display:flex;justify-content:space-between;align-items:start;">
|
|
45
|
-
<div class="stakeholder-role">${s.role}</div>
|
|
45
|
+
<div class="stakeholder-role">${escapeHtml(s.role)}</div>
|
|
46
46
|
<button class="btn btn-sm" onclick="removeStakeholder(${i})" style="opacity:0.5;font-size:0.7rem;">Supprimer</button>
|
|
47
47
|
</div>
|
|
48
|
-
<div class="stakeholder-function">${s.function || ''}</div>
|
|
48
|
+
<div class="stakeholder-function">${escapeHtml(s.function || '')}</div>
|
|
49
49
|
<ul class="stakeholder-tasks">
|
|
50
|
-
${(Array.isArray(s.tasks) ? s.tasks : typeof s.tasks === 'string' ? s.tasks.split(',').map(t => t.trim()).filter(Boolean) : []).map(t => '<li>' + t + '</li>').join('')}
|
|
50
|
+
${(Array.isArray(s.tasks) ? s.tasks : typeof s.tasks === 'string' ? s.tasks.split(',').map(t => t.trim()).filter(Boolean) : []).map(t => '<li>' + escapeHtml(t) + '</li>').join('')}
|
|
51
51
|
</ul>
|
|
52
52
|
<div class="stakeholder-meta">
|
|
53
53
|
<span>${formatFrequency(s.frequency)}</span>
|
|
54
54
|
<span>${formatAccess(s.access)}</span>
|
|
55
55
|
</div>
|
|
56
|
-
${s.frustrations ? '<div style="font-size:0.8rem;color:var(--warning);margin-top:0.5rem;font-style:italic;">' + s.frustrations + '</div>' : ''}
|
|
56
|
+
${s.frustrations ? '<div style="font-size:0.8rem;color:var(--warning);margin-top:0.5rem;font-style:italic;">' + escapeHtml(s.frustrations) + '</div>' : ''}
|
|
57
57
|
</div>
|
|
58
58
|
`).join('');
|
|
59
59
|
}
|
|
60
60
|
|
|
61
61
|
function removeStakeholder(index) {
|
|
62
|
+
if (!confirm('Supprimer ce profil utilisateur ?')) return;
|
|
62
63
|
data.cadrage.stakeholders.splice(index, 1);
|
|
63
64
|
renderStakeholders();
|
|
64
65
|
updateCounts();
|
|
@@ -89,12 +90,12 @@ function renderScope() {
|
|
|
89
90
|
<div class="uc-item">
|
|
90
91
|
<div class="uc-header">
|
|
91
92
|
<span class="priority priority-${p}">${formatPriority(p)}</span>
|
|
92
|
-
<span class="uc-title">${item.name}</span>
|
|
93
|
+
<span class="uc-title">${escapeHtml(item.name)}</span>
|
|
93
94
|
<div class="uc-actions">
|
|
94
95
|
<button class="btn btn-sm" onclick="removeScopeItem('${p}',${i})">Supprimer</button>
|
|
95
96
|
</div>
|
|
96
97
|
</div>
|
|
97
|
-
${item.description ? '<div class="uc-detail">' + item.description + '</div>' : ''}
|
|
98
|
+
${item.description ? '<div class="uc-detail">' + escapeHtml(item.description) + '</div>' : ''}
|
|
98
99
|
</div>
|
|
99
100
|
`).join('');
|
|
100
101
|
});
|
|
@@ -139,7 +140,7 @@ function renderCriteria() {
|
|
|
139
140
|
container.innerHTML = criteria.map((c, i) => `
|
|
140
141
|
<div class="uc-item" style="display:flex;align-items:center;gap:0.75rem;">
|
|
141
142
|
<input type="checkbox" ${c.validated ? 'checked' : ''} onchange="toggleCriterion(${i})" style="cursor:pointer;width:18px;height:18px;flex-shrink:0;">
|
|
142
|
-
<span style="flex:1;${c.validated ? 'text-decoration:line-through;color:var(--text-muted);' : ''}">${c.text}</span>
|
|
143
|
+
<span style="flex:1;${c.validated ? 'text-decoration:line-through;color:var(--text-muted);' : ''}">${escapeHtml(c.text)}</span>
|
|
143
144
|
<button class="btn btn-sm" onclick="removeCriterion(${i})" style="opacity:0.5;flex-shrink:0;">✕</button>
|
|
144
145
|
</div>
|
|
145
146
|
`).join('');
|
|
@@ -55,10 +55,10 @@ function renderModules() {
|
|
|
55
55
|
<div class="module-card" onclick="showSection('module-spec-${m.code}')">
|
|
56
56
|
<button class="module-card-remove" onclick="event.stopPropagation();removeModule(${i})">✕</button>
|
|
57
57
|
<div class="module-card-header">
|
|
58
|
-
<span class="module-card-code">${m.name}</span>
|
|
58
|
+
<span class="module-card-code">${escapeHtml(m.name)}</span>
|
|
59
59
|
<span class="module-card-type">${formatModuleType(m.featureType)}</span>
|
|
60
60
|
</div>
|
|
61
|
-
<div class="module-card-desc">${m.description || ''}</div>
|
|
61
|
+
<div class="module-card-desc">${escapeHtml(m.description || '')}</div>
|
|
62
62
|
<div class="module-card-meta">
|
|
63
63
|
<span>${(m.entities || []).length} données</span>
|
|
64
64
|
<span>${(data.moduleSpecs[m.code]?.useCases || []).length} cas d'utilisation</span>
|
|
@@ -115,10 +115,10 @@ function renderDependencies() {
|
|
|
115
115
|
const toName = data.modules.find(m => m.code === d.to)?.name || d.to;
|
|
116
116
|
return `
|
|
117
117
|
<div class="interaction-item">
|
|
118
|
-
<span style="font-weight:600;color:var(--text-bright);">${fromName}</span>
|
|
118
|
+
<span style="font-weight:600;color:var(--text-bright);">${escapeHtml(fromName)}</span>
|
|
119
119
|
<span class="interaction-arrow">→</span>
|
|
120
|
-
<span style="font-weight:600;color:var(--text-bright);">${toName}</span>
|
|
121
|
-
<span style="flex:1;font-size:0.8rem;color:var(--text-muted);">${d.description || ''}</span>
|
|
120
|
+
<span style="font-weight:600;color:var(--text-bright);">${escapeHtml(toName)}</span>
|
|
121
|
+
<span style="flex:1;font-size:0.8rem;color:var(--text-muted);">${escapeHtml(d.description || '')}</span>
|
|
122
122
|
<button class="btn btn-sm" onclick="removeDependency(${i})" style="opacity:0.5;">Supprimer</button>
|
|
123
123
|
</div>
|
|
124
124
|
`;
|
|
@@ -147,7 +147,7 @@ function renderDepGraph() {
|
|
|
147
147
|
<div class="dep-layer-modules">
|
|
148
148
|
${layer.map(code => {
|
|
149
149
|
const m = data.modules.find(mod => mod.code === code);
|
|
150
|
-
return `<div class="dep-module">${m ? (m.name || m.code) : code}</div>`;
|
|
150
|
+
return `<div class="dep-module">${escapeHtml(m ? (m.name || m.code) : code)}</div>`;
|
|
151
151
|
}).join('')}
|
|
152
152
|
</div>
|
|
153
153
|
</div>
|
|
@@ -195,7 +195,7 @@ function renderProcessingOrder() {
|
|
|
195
195
|
return `
|
|
196
196
|
<div class="process-step">
|
|
197
197
|
<div class="process-step-number">Étape ${i + 1}</div>
|
|
198
|
-
<div class="process-step-label">${m ? (m.name || m.code) : code}</div>
|
|
198
|
+
<div class="process-step-label">${escapeHtml(m ? (m.name || m.code) : code)}</div>
|
|
199
199
|
</div>
|
|
200
200
|
${i < order.length - 1 ? '<div class="process-arrow">→</div>' : ''}
|
|
201
201
|
`;
|