97 lines
2.7 KiB
JavaScript
97 lines
2.7 KiB
JavaScript
// common.js — petits utilitaires partagés entre app.js (page globale)
|
|
// et tenant.js (page détail tenant).
|
|
|
|
const eurFormatter = new Intl.NumberFormat("fr-FR", {
|
|
style: "currency",
|
|
currency: "EUR",
|
|
maximumFractionDigits: 2,
|
|
});
|
|
|
|
function formatEUR(amount) {
|
|
if (amount === null || amount === undefined) return "—";
|
|
return eurFormatter.format(amount);
|
|
}
|
|
|
|
function formatPct(value) {
|
|
if (value === null || value === undefined) return null;
|
|
const sign = value > 0 ? "+" : "";
|
|
return `${sign}${value.toFixed(1)} %`;
|
|
}
|
|
|
|
function deltaClass(value) {
|
|
if (value === null || value === undefined) return "flat";
|
|
if (value > 0.5) return "up";
|
|
if (value < -0.5) return "down";
|
|
return "flat";
|
|
}
|
|
|
|
function deltaArrow(value) {
|
|
if (value === null || value === undefined) return "";
|
|
if (value > 0.5) return "↑";
|
|
if (value < -0.5) return "↓";
|
|
return "→";
|
|
}
|
|
|
|
function monthLabel(monthKey) {
|
|
const [y, m] = monthKey.split("-").map(Number);
|
|
const d = new Date(Date.UTC(y, m - 1, 1));
|
|
return new Intl.DateTimeFormat("fr-FR", { month: "short", year: "2-digit", timeZone: "UTC" }).format(d);
|
|
}
|
|
|
|
function dayLabel(isoDate) {
|
|
const d = new Date(`${isoDate}T00:00:00Z`);
|
|
return new Intl.DateTimeFormat("fr-FR", { day: "2-digit", month: "short", timeZone: "UTC" }).format(d);
|
|
}
|
|
|
|
function providerLabel(provider) {
|
|
return provider === "aws" ? "AWS" : provider === "azure" ? "Azure" : provider;
|
|
}
|
|
|
|
function escapeHtml(str) {
|
|
return String(str)
|
|
.replace(/&/g, "&")
|
|
.replace(/</g, "<")
|
|
.replace(/>/g, ">")
|
|
.replace(/"/g, """);
|
|
}
|
|
|
|
function cssVar(name) {
|
|
return getComputedStyle(document.documentElement).getPropertyValue(name).trim();
|
|
}
|
|
|
|
// Config partagée des axes/grilles Chart.js (gridlines discrètes, pas de
|
|
// deuxième axe, tooltip alignée sur le design system).
|
|
function chartBaseOptions() {
|
|
return {
|
|
responsive: true,
|
|
maintainAspectRatio: false,
|
|
interaction: { mode: "index", intersect: false },
|
|
plugins: {
|
|
legend: { display: false },
|
|
tooltip: {
|
|
backgroundColor: cssVar("--surface-1"),
|
|
titleColor: cssVar("--text-primary"),
|
|
bodyColor: cssVar("--text-secondary"),
|
|
borderColor: cssVar("--border"),
|
|
borderWidth: 1,
|
|
padding: 10,
|
|
displayColors: true,
|
|
boxPadding: 4,
|
|
},
|
|
},
|
|
scales: {
|
|
x: {
|
|
grid: { display: false },
|
|
border: { color: cssVar("--axis") },
|
|
ticks: { color: cssVar("--text-muted"), font: { size: 11 } },
|
|
},
|
|
y: {
|
|
beginAtZero: true,
|
|
grid: { color: cssVar("--gridline") },
|
|
border: { display: false },
|
|
ticks: { color: cssVar("--text-muted"), font: { size: 11 } },
|
|
},
|
|
},
|
|
};
|
|
}
|