fix: corriger les vignettes du portail production
All checks were successful
Validation applicative / Tests de contrat (push) Successful in 17s
All checks were successful
Validation applicative / Tests de contrat (push) Successful in 17s
This commit is contained in:
@@ -1,8 +1,10 @@
|
|||||||
# Crédits photographiques — tuiles Infrastructure
|
# Crédits visuels — tuiles du Portail Applicatif
|
||||||
|
|
||||||
| Fichier | Tuile | Source | Licence |
|
| Fichier | Tuile | Source | Licence / usage |
|
||||||
|---|---|---|---|
|
|---|---|---|---|
|
||||||
| `portail.png` | Portail Applicatif | Photo de collaboration en environnement numérique, Unsplash | [Licence Unsplash](https://unsplash.com/license) |
|
| `portail.png` | Portail Applicatif | Photo de collaboration en environnement numérique, Unsplash | [Licence Unsplash](https://unsplash.com/license) |
|
||||||
| `dashboard.png` | Dashboard Production | Photo de réseau et de supervision technique, Unsplash | [Licence Unsplash](https://unsplash.com/license) |
|
| `dashboard.png` | Dashboard Production | Photo de réseau et de supervision technique, Unsplash | [Licence Unsplash](https://unsplash.com/license) |
|
||||||
|
| `budget-si.jpg` | Gestion budget informatique | Photo « Budgeting Pictures », Unsplash | [Licence Unsplash](https://unsplash.com/license) |
|
||||||
|
| `studio-portee.png` | Studio Portée | Visuel original généré pour le portail, inspiré du langage éditorial fourni par le client | Usage interne Santinova |
|
||||||
|
|
||||||
Les photos sont utilisées pour illustrer les deux tuiles d’infrastructure. Aucun logo, texte ni donnée métier n’est incorporé dans ces visuels.
|
Les visuels sont destinés à illustrer les tuiles applicatives. Ils ne contiennent ni donnée métier ni secret.
|
||||||
|
|||||||
BIN
images/budget-si.jpg
Normal file
BIN
images/budget-si.jpg
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 348 KiB |
Binary file not shown.
|
Before Width: | Height: | Size: 2.4 MiB After Width: | Height: | Size: 3.6 MiB |
10
index.html
10
index.html
@@ -402,6 +402,14 @@
|
|||||||
var APPS_REFRESH_MS = 300000;
|
var APPS_REFRESH_MS = 300000;
|
||||||
var hasRenderedApps = false;
|
var hasRenderedApps = false;
|
||||||
|
|
||||||
|
/* Les applications déployées restent issues du dashboard. Cette liste
|
||||||
|
* ne sert qu'aux exceptions de visibilité explicites du portail prod. */
|
||||||
|
var PORTAL_EXCLUDED_APP_IDS = new Set(['santelis-gestion']);
|
||||||
|
|
||||||
|
function isPortalVisible(app) {
|
||||||
|
return app && !PORTAL_EXCLUDED_APP_IDS.has(app.id);
|
||||||
|
}
|
||||||
|
|
||||||
function switchTab(tabName, button) {
|
function switchTab(tabName, button) {
|
||||||
document.querySelectorAll('.tab-btn').forEach(function(tab) { tab.classList.remove('active'); });
|
document.querySelectorAll('.tab-btn').forEach(function(tab) { tab.classList.remove('active'); });
|
||||||
document.querySelectorAll('.tab-panel').forEach(function(panel) { panel.classList.remove('active'); });
|
document.querySelectorAll('.tab-panel').forEach(function(panel) { panel.classList.remove('active'); });
|
||||||
@@ -449,7 +457,7 @@
|
|||||||
// Le dashboard local est la source de vérité : toutes les catégories
|
// Le dashboard local est la source de vérité : toutes les catégories
|
||||||
// déployées, y compris INFRA, restent publiées dans leur onglet dédié.
|
// déployées, y compris INFRA, restent publiées dans leur onglet dédié.
|
||||||
var deployableApps = apps.filter(function(app) {
|
var deployableApps = apps.filter(function(app) {
|
||||||
return isHttpsUrl(app.urls && app.urls[ENV]);
|
return isPortalVisible(app) && isHttpsUrl(app.urls && app.urls[ENV]);
|
||||||
});
|
});
|
||||||
var itinovaApps = deployableApps.filter(function(app) { return app.category === 'ITINOVA'; });
|
var itinovaApps = deployableApps.filter(function(app) { return app.category === 'ITINOVA'; });
|
||||||
var santinovaApps = deployableApps.filter(function(app) { return app.category === 'SANTINOVA'; });
|
var santinovaApps = deployableApps.filter(function(app) { return app.category === 'SANTINOVA'; });
|
||||||
|
|||||||
@@ -1,21 +1,91 @@
|
|||||||
/*
|
/*
|
||||||
* Contrat de non-régression du portail dynamique.
|
* Contrat de non-régression du portail de production.
|
||||||
* Il bloque les marqueurs de conflit, les doublons de configuration
|
* Il vérifie la séparation stricte des environnements, la publication
|
||||||
* et le mélange des URLs recette/production.
|
* dynamique des applications et les exceptions explicitement demandées.
|
||||||
*/
|
*/
|
||||||
const assert = require('node:assert/strict');
|
const assert = require('node:assert/strict');
|
||||||
const fs = require('node:fs');
|
const fs = require('node:fs');
|
||||||
const path = require('node:path');
|
const path = require('node:path');
|
||||||
|
const vm = require('node:vm');
|
||||||
|
|
||||||
const html = fs.readFileSync(path.join(__dirname, '..', 'index.html'), 'utf8');
|
const root = path.join(__dirname, '..');
|
||||||
|
const html = fs.readFileSync(path.join(root, 'index.html'), 'utf8');
|
||||||
|
const attributions = fs.readFileSync(path.join(root, 'images', 'ATTRIBUTIONS.md'), 'utf8');
|
||||||
|
|
||||||
assert.equal(/^(<<<<<<<|=======|>>>>>>>)/m.test(html), false, 'aucun marqueur de conflit Git ne doit être livré');
|
assert.equal(/^(<<<<<<<|=======|>>>>>>>)/m.test(html), false, 'aucun marqueur de conflit Git ne doit être livré');
|
||||||
assert.equal((html.match(/var DASHBOARD_APPS_URL/g) || []).length, 1, 'une seule URL API applications doit être déclarée');
|
assert.equal((html.match(/var DASHBOARD_APPS_URL/g) || []).length, 1, 'une seule URL API applications doit être déclarée');
|
||||||
assert.equal((html.match(/var DASHBOARD_STATUS_URL/g) || []).length, 1, 'une seule URL API statuts doit être déclarée');
|
assert.equal((html.match(/var DASHBOARD_STATUS_URL/g) || []).length, 1, 'une seule URL API statuts doit être déclarée');
|
||||||
assert.match(html, /var ENV = 'prod';/, 'la version recette doit déclarer explicitement son environnement');
|
assert.match(html, /var ENV = 'prod';/, 'la version production doit déclarer explicitement son environnement');
|
||||||
assert.match(html, /app\.urls\[ENV\]/, 'les liens doivent être sélectionnés depuis l’environnement déclaré');
|
assert.match(html, /app\.urls\[ENV\]/, 'les liens doivent être sélectionnés depuis l’environnement déclaré');
|
||||||
assert.match(html, /app\.category !== 'INFRA'/, 'les tuiles INFRA doivent être filtrées côté portail');
|
assert.match(html, /app\.category === 'INFRA'/, 'les tuiles INFRA doivent rester dans leur onglet dédié');
|
||||||
assert.match(html, /var STATUS_REFRESH_MS = 30000;/, 'le délai de grisage doit être explicite');
|
assert.match(html, /var STATUS_REFRESH_MS = 30000;/, 'le délai de grisage doit être explicite');
|
||||||
assert.match(html, /setInterval\(fetchAndApplyStatuses, STATUS_REFRESH_MS\)/, 'le grisage doit être réactualisé périodiquement');
|
assert.match(html, /setInterval\(fetchAndApplyStatuses, STATUS_REFRESH_MS\)/, 'le grisage doit être réactualisé périodiquement');
|
||||||
|
|
||||||
|
for (const imageName of ['budget-si.jpg', 'studio-portee.png']) {
|
||||||
|
const imagePath = path.join(root, 'images', imageName);
|
||||||
|
assert.equal(fs.existsSync(imagePath), true, `l’asset ${imageName} doit être publié`);
|
||||||
|
assert.ok(fs.statSync(imagePath).size > 2048, `l’asset ${imageName} ne doit pas être vide`);
|
||||||
|
assert.match(attributions, new RegExp(imageName.replace('.', '\\.')), `l’attribution de ${imageName} doit être documentée`);
|
||||||
|
}
|
||||||
|
|
||||||
|
const script = html.match(/<script>([\s\S]*?)<\/script>/)?.[1];
|
||||||
|
assert.ok(script, 'le script dynamique du portail doit être présent');
|
||||||
|
|
||||||
|
const elements = new Map();
|
||||||
|
function element(id) {
|
||||||
|
if (!elements.has(id)) {
|
||||||
|
elements.set(id, {
|
||||||
|
innerHTML: '',
|
||||||
|
textContent: '',
|
||||||
|
classList: { toggle() {} },
|
||||||
|
setAttribute() {}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
return elements.get(id);
|
||||||
|
}
|
||||||
|
|
||||||
|
const sandbox = {
|
||||||
|
AbortController,
|
||||||
|
Map,
|
||||||
|
Set,
|
||||||
|
URL,
|
||||||
|
console,
|
||||||
|
document: {
|
||||||
|
addEventListener() {},
|
||||||
|
getElementById: element,
|
||||||
|
querySelectorAll() { return []; }
|
||||||
|
},
|
||||||
|
setInterval() {},
|
||||||
|
setTimeout() { return 0; },
|
||||||
|
clearTimeout() {}
|
||||||
|
};
|
||||||
|
vm.createContext(sandbox);
|
||||||
|
vm.runInContext(script, sandbox);
|
||||||
|
|
||||||
|
sandbox.renderApps([
|
||||||
|
{
|
||||||
|
id: 'itinova-budget-si',
|
||||||
|
name: 'Gestion budget informatique',
|
||||||
|
category: 'SANTINOVA',
|
||||||
|
image: 'images/budget-si.jpg',
|
||||||
|
urls: { prod: 'https://budget-si.santinova-soft.org' },
|
||||||
|
status: 'online',
|
||||||
|
containerRunning: true
|
||||||
|
},
|
||||||
|
{
|
||||||
|
id: 'santelis-gestion',
|
||||||
|
name: 'SANTELIS Gestion',
|
||||||
|
category: 'SANTINOVA',
|
||||||
|
image: 'images/santelis-gestion.png',
|
||||||
|
urls: { prod: 'https://gestion-santelis.santinova-soft.org' },
|
||||||
|
status: 'online',
|
||||||
|
containerRunning: true
|
||||||
|
}
|
||||||
|
]);
|
||||||
|
|
||||||
|
const santinovaMarkup = element('grid-santinova').innerHTML;
|
||||||
|
assert.match(santinovaMarkup, /Gestion budget informatique/, 'Budget informatique doit être rendu dans le portail production');
|
||||||
|
assert.doesNotMatch(santinovaMarkup, /SANTELIS Gestion/, 'SANTELIS Gestion ne doit pas être rendu dans le portail production');
|
||||||
|
assert.equal(element('count-santinova').textContent, 1, 'le compteur Santinova ne doit retenir que les applications visibles');
|
||||||
|
|
||||||
console.log('OK portal-contract');
|
console.log('OK portal-contract');
|
||||||
|
|||||||
Reference in New Issue
Block a user