Lot 4 modernisation JS (SonarLint) + restauration CI sonarqube non-bloquante
Build and deploy / test-python (push) Successful in 11m18s
Build and deploy / test-js (push) Successful in 1m16s
Build and deploy / lint-python (push) Successful in 4m24s
Build and deploy / lint-js (push) Successful in 2m51s
Build and deploy / build-and-push (push) Skipped
Build and deploy / deploy (push) Skipped
Build and deploy / sonarqube (push) Successful in 5m30s
Build and deploy / test-python (push) Successful in 11m18s
Build and deploy / test-js (push) Successful in 1m16s
Build and deploy / lint-python (push) Successful in 4m24s
Build and deploy / lint-js (push) Successful in 2m51s
Build and deploy / build-and-push (push) Skipped
Build and deploy / deploy (push) Skipped
Build and deploy / sonarqube (push) Successful in 5m30s
Corrige les findings SonarQube (via SonarLint IDE, fichier par fichier) sur ~24 fichiers static/js/ : parseFloat/parseInt -> Number.*, .replace(/x/g,y) -> .replaceAll, .indexOf() -> .includes()/.startsWith(), getAttribute/setAttribute -> .dataset, tableaux -> Set, x && x.y -> x?.y (verifie site par site), extraction de template litteraux imbriques, ternaires imbriquees, refactors de complexite cognitive (S3776) via tables de dispatch, Object.hasOwn, .at(), et deduplication de fonctions identiques (S4144). Deux exceptions S2486 documentees/corrigees (filter-repeater-rows.js) et un cas S2703 de partage inter-scripts complete (_collisionWizard, trigger-editor.js <-> collision-rules-editor.js). Details complets dans CODE_QUALITY.md section 5. Restaure aussi le job CI "sonarqube" (non-bloquant) dans .gitea/workflows/deploy.yml maintenant que l'instance prod est operationnelle. Suites vertes : 276/276 JS (node --test), 591/591 Python (pytest). SKIP=djlint sur ce commit : hook djlint bloquant sur le backlog H021 (styles inline, 49 occurrences/6 templates) deja documente comme dette assumee non traitee dans CODE_QUALITY.md section 6, aucun rapport avec ce commit (aucun template touche ici) - valide explicitement avec l'utilisateur avant de contourner ce hook. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
This commit is contained in:
co-authored by
Claude Sonnet 5
parent
66d8eaeae8
commit
ccf836f2c5
@@ -11,10 +11,10 @@ function initBuilderPanel() {
|
||||
if (!xEl || !wEl) return;
|
||||
function apply() {
|
||||
const canvasEl = document.getElementById(`el-${CURRENT_SELECTED_ID}`);
|
||||
const x = parseFloat(xEl.value) || 0; const
|
||||
y = parseFloat(yEl.value) || 0;
|
||||
const w = parseFloat(wEl.value) || 1; const
|
||||
h = parseFloat(hEl.value) || 1;
|
||||
const x = Number.parseFloat(xEl.value) || 0; const
|
||||
y = Number.parseFloat(yEl.value) || 0;
|
||||
const w = Number.parseFloat(wEl.value) || 1; const
|
||||
h = Number.parseFloat(hEl.value) || 1;
|
||||
if (canvasEl) {
|
||||
canvasEl.style.left = `${x}%`; canvasEl.style.top = `${y}%`;
|
||||
canvasEl.style.width = `${w}%`; canvasEl.style.height = `${h}%`;
|
||||
@@ -109,7 +109,7 @@ function bindJaugeDefinitionSelect() {
|
||||
const champNomSel = document.getElementById('field-champ_nom');
|
||||
if (!defSel || !rowSel || !champSel || !champNomSel) return; // pas la Jauge
|
||||
defSel.addEventListener('change', () => {
|
||||
const info = (DEFINITIONS_DATA || {})[defSel.value] || { rows: [], fields: [] };
|
||||
const info = DEFINITIONS_DATA?.[defSel.value] || { rows: [], fields: [] };
|
||||
rowSel.innerHTML = info.rows.length
|
||||
? info.rows.map((r) => `<option value="${r.id}">${r.label}</option>`).join('')
|
||||
: '<option value="">Aucune donnée dans cet objet</option>';
|
||||
@@ -149,9 +149,9 @@ function bindDefinitionFieldSelects(defSelId, fieldSelIds) {
|
||||
const fieldSels = fieldSelIds.map((id) => document.getElementById(id)).filter(Boolean);
|
||||
if (!fieldSels.length) return;
|
||||
defSel.addEventListener('change', () => {
|
||||
const info = (DEFINITIONS_DATA || {})[defSel.value] || { fields: [] };
|
||||
const opts = `<option value="">(sélectionner un objet d'abord)</option>${
|
||||
info.fields.map((f) => `<option value="${f.name}">${fieldOptionLabel(f)}</option>`).join('')}`;
|
||||
const info = DEFINITIONS_DATA?.[defSel.value] || { fields: [] };
|
||||
const fieldOptionsHtml = info.fields.map((f) => `<option value="${f.name}">${fieldOptionLabel(f)}</option>`).join('');
|
||||
const opts = `<option value="">(sélectionner un objet d'abord)</option>${fieldOptionsHtml}`;
|
||||
fieldSels.forEach((sel) => { sel.innerHTML = opts; });
|
||||
});
|
||||
}
|
||||
@@ -200,7 +200,7 @@ function addClauseRow(key) {
|
||||
// bloquée sur "(sélectionner un objet d'abord)" même si un objet est
|
||||
// déjà réglé plus haut dans le panneau).
|
||||
const defSel = document.getElementById('field-data_definition_id');
|
||||
if (defSel && defSel.value) defSel.dispatchEvent(new Event('change'));
|
||||
if (defSel?.value) defSel.dispatchEvent(new Event('change'));
|
||||
// Initialise le sélecteur de valeur (fixe/dynamique/variable) de cette
|
||||
// nouvelle ligne — sans effet sur les lignes déjà initialisées.
|
||||
initFilterValuePickers();
|
||||
@@ -227,9 +227,9 @@ function bindClauseListDefinitionSelect(defSelId) {
|
||||
const defSel = document.getElementById(defSelId);
|
||||
if (!defSel) return;
|
||||
defSel.addEventListener('change', () => {
|
||||
const info = (DEFINITIONS_DATA || {})[defSel.value] || { fields: [] };
|
||||
const opts = `<option value="">(sélectionner un objet d'abord)</option>${
|
||||
info.fields.map((f) => `<option value="${f.name}">${fieldOptionLabel(f)}</option>`).join('')}`;
|
||||
const info = DEFINITIONS_DATA?.[defSel.value] || { fields: [] };
|
||||
const fieldOptionsHtml = info.fields.map((f) => `<option value="${f.name}">${fieldOptionLabel(f)}</option>`).join('');
|
||||
const opts = `<option value="">(sélectionner un objet d'abord)</option>${fieldOptionsHtml}`;
|
||||
document.querySelectorAll('.clauseChampSelect').forEach((sel) => {
|
||||
const current = sel.value;
|
||||
sel.innerHTML = opts;
|
||||
@@ -266,8 +266,9 @@ function _filterValueDefinitionId(objName) {
|
||||
}
|
||||
|
||||
function populateFilterValueFields(fieldSel, defId, selectedName) {
|
||||
const info = (DEFINITIONS_DATA || {})[defId] || { fields: [] };
|
||||
fieldSel.innerHTML = `<option value="">— champ —</option>${info.fields.map((f) => `<option value="${f.name}"${f.name === selectedName ? ' selected' : ''}>${fieldOptionLabel(f)}</option>`).join('')}`;
|
||||
const info = DEFINITIONS_DATA?.[defId] || { fields: [] };
|
||||
const fieldOptionsHtml = info.fields.map((f) => `<option value="${f.name}"${f.name === selectedName ? ' selected' : ''}>${fieldOptionLabel(f)}</option>`).join('');
|
||||
fieldSel.innerHTML = `<option value="">— champ —</option>${fieldOptionsHtml}`;
|
||||
}
|
||||
|
||||
function updateFilterValueFromDynamic(wrap) {
|
||||
|
||||
@@ -9,7 +9,7 @@
|
||||
|
||||
function _personnageElementId() {
|
||||
const body = document.getElementById('personnagePanelBody');
|
||||
return body ? parseInt(body.dataset.elementId, 10) : null;
|
||||
return body ? Number.parseInt(body.dataset.elementId, 10) : null;
|
||||
}
|
||||
|
||||
function _savePersonnageData(data) {
|
||||
|
||||
@@ -16,7 +16,7 @@ function _stopPersonnageIdlePreview(elementId) {
|
||||
|
||||
function _startPersonnageIdlePreview(targetEl, elementId, frames, fps) {
|
||||
_stopPersonnageIdlePreview(elementId);
|
||||
if (!frames || !frames.length) return;
|
||||
if (!frames?.length) return;
|
||||
targetEl.src = frames[0];
|
||||
if (frames.length === 1) return;
|
||||
let frameIndex = 0;
|
||||
@@ -42,7 +42,7 @@ function restartPersonnageIdlePreview(elementId, animations) {
|
||||
|
||||
function startAllPersonnagePreviews() {
|
||||
document.querySelectorAll('#canvas [data-personnage="1"]').forEach((targetEl) => {
|
||||
const elementId = parseInt(targetEl.dataset.elementId, 10);
|
||||
const elementId = Number.parseInt(targetEl.dataset.elementId, 10);
|
||||
const animations = ELEMENT_ANIMATIONS_MAP[elementId];
|
||||
const frames = (animations && (animations.idle || Object.values(animations)[0])) || null;
|
||||
// Pas d'entrée dans ELEMENT_ANIMATIONS_MAP (personnage vidé/sprite
|
||||
|
||||
@@ -123,7 +123,7 @@ if (!window.__forgeFloatPanelDragBound) {
|
||||
function onUp() {
|
||||
document.removeEventListener('mousemove', onMove);
|
||||
document.removeEventListener('mouseup', onUp);
|
||||
saveFloatPanelState(key, { left: parseFloat(panel.style.left), top: parseFloat(panel.style.top) });
|
||||
saveFloatPanelState(key, { left: Number.parseFloat(panel.style.left), top: Number.parseFloat(panel.style.top) });
|
||||
}
|
||||
document.addEventListener('mousemove', onMove);
|
||||
document.addEventListener('mouseup', onUp);
|
||||
@@ -144,7 +144,7 @@ function addIconElement(iconClass) {
|
||||
form.method = 'post';
|
||||
form.action = ELEMENT_ADD_URL;
|
||||
form.innerHTML = '<input type="hidden" name="widget" value="icone">'
|
||||
+ `<input type="hidden" name="icon_class" value="${iconClass.replace(/"/g, '"')}">`;
|
||||
+ `<input type="hidden" name="icon_class" value="${iconClass.replaceAll('"', '"')}">`;
|
||||
document.body.appendChild(form);
|
||||
form.requestSubmit();
|
||||
}
|
||||
@@ -314,7 +314,10 @@ if (!window.__forgeTreeDragBound) {
|
||||
e.preventDefault();
|
||||
e.dataTransfer.dropEffect = 'move';
|
||||
clearTreeDropIndicators();
|
||||
row.classList.add(zone === 'before' ? 'dropBefore' : zone === 'after' ? 'dropAfter' : 'dropInside');
|
||||
let zoneClass = 'dropInside';
|
||||
if (zone === 'before') zoneClass = 'dropBefore';
|
||||
else if (zone === 'after') zoneClass = 'dropAfter';
|
||||
row.classList.add(zoneClass);
|
||||
});
|
||||
|
||||
document.addEventListener('drop', (e) => {
|
||||
@@ -456,10 +459,10 @@ function onElementMouseDown(e, id) {
|
||||
const rect = canvas.getBoundingClientRect();
|
||||
const startX = e.clientX; const
|
||||
startY = e.clientY;
|
||||
const startLeft = parseFloat(el.style.left); const
|
||||
startTop = parseFloat(el.style.top);
|
||||
const width = parseFloat(el.style.width); const
|
||||
height = parseFloat(el.style.height);
|
||||
const startLeft = Number.parseFloat(el.style.left); const
|
||||
startTop = Number.parseFloat(el.style.top);
|
||||
const width = Number.parseFloat(el.style.width); const
|
||||
height = Number.parseFloat(el.style.height);
|
||||
let moved = false;
|
||||
// Un clic (sans glisser) sélectionne l'élément précis qu'on a touché —
|
||||
// même s'il est physiquement imbriqué dans ce conteneur — pour éviter de
|
||||
@@ -481,8 +484,8 @@ function onElementMouseDown(e, id) {
|
||||
document.removeEventListener('mousemove', onMove);
|
||||
document.removeEventListener('mouseup', onUp);
|
||||
if (moved) {
|
||||
const newLeft = parseFloat(el.style.left); const
|
||||
newTop = parseFloat(el.style.top);
|
||||
const newLeft = Number.parseFloat(el.style.left); const
|
||||
newTop = Number.parseFloat(el.style.top);
|
||||
updatePosFields(newLeft, newTop, width, height);
|
||||
saveGeometry(id, newLeft, newTop, width, height);
|
||||
} else if (String(clickedId) !== String(CURRENT_SELECTED_ID)) {
|
||||
@@ -501,10 +504,10 @@ function onResizeMouseDown(e, id) {
|
||||
const rect = canvas.getBoundingClientRect();
|
||||
const startX = e.clientX; const
|
||||
startY = e.clientY;
|
||||
const startWidth = parseFloat(el.style.width); const
|
||||
startHeight = parseFloat(el.style.height);
|
||||
const left = parseFloat(el.style.left); const
|
||||
top = parseFloat(el.style.top);
|
||||
const startWidth = Number.parseFloat(el.style.width); const
|
||||
startHeight = Number.parseFloat(el.style.height);
|
||||
const left = Number.parseFloat(el.style.left); const
|
||||
top = Number.parseFloat(el.style.top);
|
||||
|
||||
function onMove(ev) {
|
||||
const dx = ev.clientX - startX; const
|
||||
@@ -517,8 +520,8 @@ function onResizeMouseDown(e, id) {
|
||||
function onUp() {
|
||||
document.removeEventListener('mousemove', onMove);
|
||||
document.removeEventListener('mouseup', onUp);
|
||||
const newWidth = parseFloat(el.style.width); const
|
||||
newHeight = parseFloat(el.style.height);
|
||||
const newWidth = Number.parseFloat(el.style.width); const
|
||||
newHeight = Number.parseFloat(el.style.height);
|
||||
updatePosFields(left, top, newWidth, newHeight);
|
||||
saveGeometry(id, left, top, newWidth, newHeight);
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user