feat(patching/import): filtre intervenant en dropdown, retire filtre asset texte, ajoute tri asc/desc/none au clic sur entete Asset
This commit is contained in:
parent
488b5a980b
commit
8b6057aef2
@ -108,8 +108,9 @@
|
||||
<div id="sheet-table-wrap" class="overflow-x-auto" style="display:none;">
|
||||
{# Filtres client-side #}
|
||||
<div class="flex gap-2 items-center mb-2 flex-wrap">
|
||||
<input type="text" id="filter-asset" placeholder="Filtre asset…" class="text-xs px-2 py-1" style="width:160px">
|
||||
<input type="text" id="filter-intervenant" placeholder="Filtre intervenant…" class="text-xs px-2 py-1" style="width:160px">
|
||||
<select id="filter-intervenant" class="text-xs px-2 py-1">
|
||||
<option value="">— Tous intervenants —</option>
|
||||
</select>
|
||||
<select id="filter-env" class="text-xs px-2 py-1">
|
||||
<option value="">— Tous environnements —</option>
|
||||
</select>
|
||||
@ -133,7 +134,9 @@
|
||||
<thead class="text-cyber-accent border-b border-cyber-border">
|
||||
<tr>
|
||||
<th class="text-left p-1 w-6"><input type="checkbox" id="select-all-head"></th>
|
||||
<th class="text-left p-1">Asset</th>
|
||||
<th class="text-left p-1 cursor-pointer select-none hover:text-cyber-accent" id="th-asset" title="Cliquer pour trier">
|
||||
Asset <span id="th-asset-arrow" class="text-[10px] opacity-50">↕</span>
|
||||
</th>
|
||||
<th class="text-left p-1">Env</th>
|
||||
<th class="text-left p-1">Domaine</th>
|
||||
<th class="text-left p-1">OS</th>
|
||||
@ -172,13 +175,15 @@
|
||||
const selCount = document.getElementById('selection-count');
|
||||
const btnPre = document.getElementById('btn-prepatch');
|
||||
const btnPatch = document.getElementById('btn-patch');
|
||||
const fAsset = document.getElementById('filter-asset');
|
||||
const fInter = document.getElementById('filter-intervenant');
|
||||
const fEnv = document.getElementById('filter-env');
|
||||
const fReset = document.getElementById('filter-reset');
|
||||
const fCount = document.getElementById('filter-count');
|
||||
const thAsset = document.getElementById('th-asset');
|
||||
const thAssetArrow = document.getElementById('th-asset-arrow');
|
||||
|
||||
let currentRows = [];
|
||||
let sortAsset = 0; // 0 = ordre fichier, 1 = asc, -1 = desc
|
||||
|
||||
function escapeHTML(s){
|
||||
if (s === null || s === undefined) return '';
|
||||
@ -199,17 +204,13 @@
|
||||
}
|
||||
|
||||
function applyFilters(){
|
||||
const fa = (fAsset.value || '').toLowerCase().trim();
|
||||
const fi = (fInter.value || '').toLowerCase().trim();
|
||||
const fi = (fInter.value || '').trim();
|
||||
const fe = (fEnv.value || '').trim();
|
||||
let visibleCount = 0;
|
||||
tbody.querySelectorAll('tr').forEach(tr => {
|
||||
const a = (tr.dataset.asset || '').toLowerCase();
|
||||
const i = (tr.dataset.intervenant || '').toLowerCase();
|
||||
const i = tr.dataset.intervenant || '';
|
||||
const e = tr.dataset.env || '';
|
||||
const ok = (!fa || a.includes(fa))
|
||||
&& (!fi || i.includes(fi))
|
||||
&& (!fe || e === fe);
|
||||
const ok = (!fi || i === fi) && (!fe || e === fe);
|
||||
if (ok) { tr.classList.remove('row-hidden'); tr.style.display=''; visibleCount++; }
|
||||
else { tr.classList.add('row-hidden'); tr.style.display='none'; }
|
||||
});
|
||||
@ -217,11 +218,16 @@
|
||||
refreshSelection();
|
||||
}
|
||||
|
||||
function rebuildEnvOptions(rows){
|
||||
const envs = Array.from(new Set(rows.map(r => r.environnement).filter(x => x))).sort();
|
||||
const cur = fEnv.value;
|
||||
fEnv.innerHTML = '<option value="">— Tous environnements —</option>'
|
||||
+ envs.map(e => '<option value="' + escapeHTML(e) + '"' + (cur === e ? ' selected' : '') + '>' + escapeHTML(e) + '</option>').join('');
|
||||
function rebuildSelectOptions(sel, values, placeholder){
|
||||
const cur = sel.value;
|
||||
const opts = Array.from(new Set(values.filter(x => x))).sort((a,b) => a.localeCompare(b, 'fr', {sensitivity:'base'}));
|
||||
sel.innerHTML = '<option value="">' + placeholder + '</option>'
|
||||
+ opts.map(v => '<option value="' + escapeHTML(v) + '"' + (cur === v ? ' selected' : '') + '>' + escapeHTML(v) + '</option>').join('');
|
||||
}
|
||||
|
||||
function updateSortArrow(){
|
||||
thAssetArrow.textContent = sortAsset === 1 ? '▲' : (sortAsset === -1 ? '▼' : '↕');
|
||||
thAssetArrow.classList.toggle('opacity-50', sortAsset === 0);
|
||||
}
|
||||
|
||||
async function loadSheet(name){
|
||||
@ -237,8 +243,25 @@
|
||||
empty.style.display='none'; wrap.style.display='';
|
||||
summary.textContent = j.count + ' lignes';
|
||||
currentRows = j.rows;
|
||||
rebuildEnvOptions(currentRows);
|
||||
tbody.innerHTML = j.rows.map(r => {
|
||||
rebuildSelectOptions(fInter, currentRows.map(r => r.intervenant), '— Tous intervenants —');
|
||||
rebuildSelectOptions(fEnv, currentRows.map(r => r.environnement), '— Tous environnements —');
|
||||
sortAsset = 0;
|
||||
updateSortArrow();
|
||||
renderTable();
|
||||
}
|
||||
|
||||
function renderTable(){
|
||||
let rows = currentRows.slice();
|
||||
if (sortAsset !== 0) {
|
||||
rows.sort((a, b) => {
|
||||
const av = (a.asset_name || '').toLowerCase();
|
||||
const bv = (b.asset_name || '').toLowerCase();
|
||||
if (av < bv) return -sortAsset;
|
||||
if (av > bv) return sortAsset;
|
||||
return 0;
|
||||
});
|
||||
}
|
||||
tbody.innerHTML = rows.map(r => {
|
||||
const linkSrv = r.server_id
|
||||
? '<a href="/qualys/search?field=hostname&q=' + encodeURIComponent(r.resolved_hostname || r.asset_name) + '" class="text-cyber-blue hover:underline">' + escapeHTML(r.resolved_hostname || r.asset_name) + '</a>'
|
||||
: '<span class="text-cyber-yellow" title="Pas matché en base PatchCenter">' + escapeHTML(r.asset_name || '') + ' ⚠</span>';
|
||||
@ -280,11 +303,17 @@
|
||||
selAll.addEventListener('change', () => toggleAll(selAll.checked));
|
||||
selAllHead.addEventListener('change', () => toggleAll(selAllHead.checked));
|
||||
|
||||
[fAsset, fInter, fEnv].forEach(el => el.addEventListener('input', applyFilters));
|
||||
fEnv.addEventListener('change', applyFilters);
|
||||
[fInter, fEnv].forEach(el => el.addEventListener('change', applyFilters));
|
||||
fReset.addEventListener('click', () => {
|
||||
fAsset.value = ''; fInter.value = ''; fEnv.value = '';
|
||||
applyFilters();
|
||||
fInter.value = ''; fEnv.value = '';
|
||||
sortAsset = 0;
|
||||
updateSortArrow();
|
||||
renderTable();
|
||||
});
|
||||
thAsset.addEventListener('click', () => {
|
||||
sortAsset = sortAsset === 1 ? -1 : (sortAsset === -1 ? 0 : 1);
|
||||
updateSortArrow();
|
||||
renderTable();
|
||||
});
|
||||
|
||||
btnPre.addEventListener('click', () => {
|
||||
|
||||
Loading…
Reference in New Issue
Block a user