// Import common js
-import { loadModals, showToast, sortTable, initSortableTable, resetSorting, filterData, clearSearch } from './common.js';
+import { loadModals, showToast, sortTable, initSortableTable, resetSorting, filterTable, clearSearch } from './common.js';
import { reloadDNS, reloadDHCP } from './services.js';
import { apiMap, fetchData } from './api.js';
// -----------------------------
// State variables
// -----------------------------
-let aliasesList = [];
+let allAliases = [];
+let viewAliases = [];
let editingAliasId = null;
const sortState = { sortDirection: {}, lastSort: null };
// -----------------------------
async function fetchAliases () {
const loader = document.getElementById("loader");
- const container = document.getElementById("devices-container");
const dataTable = document.getElementById("dataTable");
// hide table during loading to avoid flickering and show loader
loader.style.display = "block";
// Fetch aliases
- aliasesList = await fetchData(apiMap.aliases);
+ allAliases = await fetchData(apiMap.aliases);
+ viewAliases = [...allAliases];
} catch (err) {
- console.error(err?.message || "Error loading aliases");
- showToast(err?.message || "Error loading aliase", false);
- aliasesList = [];
- // hide loader and show table
- loader.style.display = "none";
- dataTable.classList.remove("d-none");
+ console.error(err?.message || "Error loading aliases");
+ showToast(err?.message || "Error loading aliase", false);
+ allAliases = [];
+ viewAliases = [];
+ // hide loader and show table
+ loader.style.display = "none";
+ dataTable.classList.remove("d-none");
}
}
// -----------------------------
-// Update table with current hosts
+// Update table with current aliases
// -----------------------------
function updateTable () {
+ const loader = document.getElementById("loader");
+ const dataTable = document.getElementById("dataTable");
// DOM Reference
const tbody = document.querySelector("#dataTable tbody");
tbody.innerHTML = "";
// if no aliases, show an empty row
- if (!aliasesList.length) {
+ if (!viewAliases.length) {
const trEmpty = document.createElement("tr");
const tdEmpty = document.createElement("td");
tdEmpty.colSpan = 7;
// fragment per performance
const frag = document.createDocumentFragment();
- aliasesList.forEach(h => {
+ viewAliases.forEach(h => {
const id = Number(h.id);
const tr = document.createElement("tr");
tbody.appendChild(frag);
// apply last sorting
- if (typeof lastSort === "object" && lastSort && Array.isArray(sortDirection)) {
- if (Number.isInteger(lastSort.colIndex)) {
- sortDirection[lastSort.colIndex] = !lastSort.ascending;
- sortTable(lastSort.colIndex, sortState);
- }
+ const { lastSort, sortDirection } = sortState;
+
+ if (lastSort && Number.isInteger(lastSort.colIndex)) {
+ sortDirection[lastSort.colIndex] = !lastSort.ascending;
+ sortTable(lastSort.colIndex, sortState);
}
// hide loader and show table
loader.style.display = "none";
dataTable.classList.remove("d-none");
+
+ // apply current search filter
+ const searchInput = document.getElementById("searchInput");
+ if (searchInput) {
+ const term = searchInput.value.trim().toLowerCase();
+ if (term) {
+ filterTable(term);
+ }
+ }
}
// -----------------------------
// close modal and reload aliases
closeAddAliasModal();
await loadAliases();
+ updateTable();
return true
}
// clean input on load
input.value = "";
// live filter for each keystroke
- input.addEventListener("input", filterData);
- // Escape management when focus is in the input
- input.addEventListener("keydown", (e) => {
- if (e.key === "Escape") {
- e.preventDefault(); // evita side-effect (es. chiusure di modali del browser)
- e.stopPropagation(); // evita che arrivi al listener globale
- resetSorting(sortState);
- clearSearch(); // svuota input e ricarica tabella (come definito nella tua funzione)
- updateTable(); // aggiorna tabella
- filterData(''); // ripristina tabella
- }
+ input.addEventListener("input", (e) => {
+ const term = e.target.value.trim().toLowerCase();
+ filterTable(term);
});
}
// KEYBOARD (ESC + accessibility)
// -----------------------------
function handleKeyboard(e) {
- // Ignore if focus is in a typing field
- const tag = (e.target.tagName || "").toLowerCase();
- const isTypingField =
- tag === "input" || tag === "textarea" || tag === "select" || e.target.isContentEditable;
-
- // global ESC key listener to clear search and reset sorting
- if (e.key === "Escape" && !isTypingField) {
- // Prevent default form submission
- e.preventDefault(); // evita side-effect (es. chiusure di modali del browser)
- resetSorting(sortState);
- clearSearch(); // svuota input e ricarica tabella (come definito nella tua funzione)
- updateTable(); // aggiorna tabella
- filterData(''); // ripristina tabella
- }
- // Button event delegation (Enter, Space)
+ // Button event delegation (Escape, Enter, Space)
+ const isEscape = e.key === 'Escape';
const isEnter = e.key === 'Enter';
const isSpace = e.key === ' ';
- if (!isEnter && !isSpace) return;
+ if (!isEscape && !isEnter && !isSpace) return;
+
+ // ESC delegation: clear search and reset sorting
+ if (isEscape) {
+ // Ignore if focus is in a typing field
+ const tag = (e.target.tagName || "").toLowerCase();
+ const isTypingField =
+ tag === "input" || tag === "textarea" || tag === "select" || e.target.isContentEditable;
+ const isSearchInput = e.target.id === "searchInput";
+
+ // ESC should clear search and reset sorting only if not focused on a typing field, or if focused on the search input (to allow quick clearing of search)
+ if (!isTypingField || isSearchInput) {
+ // Prevent default form submission
+ e.preventDefault(); // evita side-effect (es. chiusure di modali del browser)
+ resetSorting(sortState);
+ clearSearch(); // svuota input e ricarica tabella (come definito nella tua funzione)
+ viewAliases = [...allAliases];
+ updateTable(); // aggiorna tabella
+ }
+ return;
+ }
+
+ // Enter / Space delegation
const el = e.target.closest('[data-action]');
if (!el) return;
/**
* Live filter: mostra solo le righe che contengono il testo di ricerca (case-insensitive)
*/
-export function filterData() {
- const query = document.getElementById("searchInput").value.toLowerCase();
+export function filterTable(term) {
const rows = document.querySelectorAll("#dataTable tbody tr");
rows.forEach(row => {
const text = row.textContent.toLowerCase();
- row.style.display = text.includes(query) ? "" : "none";
+ row.style.display = text.includes(term) ? "" : "none";
});
}
// Import common js
-import { loadModals, isValidIPv4, isValidIPv6, isValidMAC, showToast, sortTable, initSortableTable, resetSorting, filterData, clearSearch } from './common.js';
+import { loadModals, isValidIPv4, isValidIPv6, isValidMAC, showToast, sortTable, initSortableTable, resetSorting, filterTable, clearSearch } from './common.js';
import { reloadDNS, reloadDHCP } from './services.js';
import { apiMap, fetchData } from './api.js';
// -----------------------------
// State variables
// -----------------------------
-let devicesList = [];
+let allDevices = [];
+let viewDevices = [];
let editingHostId = null;
const sortState = { sortDirection: {}, lastSort: null };
// -----------------------------
async function fetchDevices () {
const loader = document.getElementById("loader");
- const container = document.getElementById("devices-container");
const dataTable = document.getElementById("dataTable");
// hide table during loading to avoid flickering and show loader
loader.style.display = "block";
// Fetch devices
- devicesList = await fetchData(apiMap.devices);
+ allDevices = await fetchData(apiMap.devices);
+ viewDevices = [...allDevices];
} catch (err) {
console.error(err?.message || "Error loading devices");
showToast(err?.message || "Error loading devices", false);
- devicesList = [];
+ allDevices = [];
+ viewDevices = [];
// hide loader and show table
loader.style.display = "none";
dataTable.classList.remove("d-none");
// Update table with current devices
// -----------------------------
function updateTable () {
+ const loader = document.getElementById("loader");
+ const dataTable = document.getElementById("dataTable");
// DOM Reference
const tbody = document.querySelector("#dataTable tbody");
tbody.innerHTML = "";
// if no devices, show an empty row
- if (!devicesList.length) {
+ if (!viewDevices.length) {
const trEmpty = document.createElement("tr");
const tdEmpty = document.createElement("td");
tdEmpty.colSpan = 7;
// fragment per performance
const frag = document.createDocumentFragment();
- devicesList.forEach(d => {
+ viewDevices.forEach(d => {
const id = d.id;
let type = 0;
delSpan.appendChild(i);
}
- if(type == 1) {
+ if (type === 1) {
td.appendChild(editSpan);
- } else if (type == 2) {
+ } else if (type === 2) {
td.appendChild(addSpan);
} else {
}
tbody.appendChild(frag);
// apply last sorting
- if (typeof lastSort === "object" && lastSort && Array.isArray(sortDirection)) {
- if (Number.isInteger(lastSort.colIndex)) {
- sortDirection[lastSort.colIndex] = !lastSort.ascending;
- sortTable(lastSort.colIndex, sortState);
- }
+ const { lastSort, sortDirection } = sortState;
+
+ if (lastSort && Number.isInteger(lastSort.colIndex)) {
+ sortDirection[lastSort.colIndex] = !lastSort.ascending;
+ sortTable(lastSort.colIndex, sortState);
}
// hide loader and show table
loader.style.display = "none";
dataTable.classList.remove("d-none");
+
+ // apply current search filter
+ const searchInput = document.getElementById("searchInput");
+ if (searchInput) {
+ const term = searchInput.value.trim().toLowerCase();
+ if (term) {
+ filterTable(term);
+ }
+ }
}
// -----------------------------
// close modal and reload hosts
closeAddHostModal();
await loadDevices();
+ updateTable();
return true
}
// clean input on load
input.value = "";
// live filter for each keystroke
- input.addEventListener("input", filterData);
- // Escape management when focus is in the input
- input.addEventListener("keydown", (e) => {
- if (e.key === "Escape") {
- e.preventDefault(); // evita side-effect (es. chiusure di modali del browser)
- e.stopPropagation(); // evita che arrivi al listener globale
- resetSorting(sortState);
- clearSearch(); // svuota input e ricarica tabella (come definito nella tua funzione)
- updateTable(); // aggiorna tabella
- filterData(''); // ripristina tabella
- }
+ input.addEventListener("input", (e) => {
+ const term = e.target.value.trim().toLowerCase();
+ filterTable(term);
});
}
// KEYBOARD (ESC + accessibility)
// -----------------------------
function handleKeyboard(e) {
- // Ignore if focus is in a typing field
- const tag = (e.target.tagName || "").toLowerCase();
- const isTypingField =
- tag === "input" || tag === "textarea" || tag === "select" || e.target.isContentEditable;
-
- // global ESC key listener to clear search and reset sorting
- if (e.key === "Escape" && !isTypingField) {
- // Prevent default form submission
- e.preventDefault(); // evita side-effect (es. chiusure di modali del browser)
- resetSorting(sortState);
- clearSearch(); // svuota input e ricarica tabella (come definito nella tua funzione)
- updateTable(); // aggiorna tabella
- filterData(''); // ripristina tabella
- }
- // Button event delegation (Enter, Space)
+ // Button event delegation (Escape, Enter, Space)
+ const isEscape = e.key === 'Escape';
const isEnter = e.key === 'Enter';
const isSpace = e.key === ' ';
- if (!isEnter && !isSpace) return;
+ if (!isEscape && !isEnter && !isSpace) return;
+
+ // ESC delegation: clear search and reset sorting
+ if (isEscape) {
+ // Ignore if focus is in a typing field
+ const tag = (e.target.tagName || "").toLowerCase();
+ const isTypingField =
+ tag === "input" || tag === "textarea" || tag === "select" || e.target.isContentEditable;
+ const isSearchInput = e.target.id === "searchInput";
+
+ // ESC should clear search and reset sorting only if not focused on a typing field, or if focused on the search input (to allow quick clearing of search)
+ if (!isTypingField || isSearchInput) {
+ // Prevent default form submission
+ e.preventDefault(); // evita side-effect (es. chiusure di modali del browser)
+ resetSorting(sortState);
+ clearSearch(); // svuota input e ricarica tabella (come definito nella tua funzione)
+ viewDevices = [...allDevices];
+ updateTable(); // aggiorna tabella
+ }
+ return;
+ }
+
+ // Enter / Space delegation
const el = e.target.closest('[data-action]');
if (!el) return;
// Import common js
-import { loadModals, isValidIPv4, isValidIPv6, isValidMAC, showToast, sortTable, initSortableTable, resetSorting, filterData, clearSearch } from './common.js';
+import { loadModals, isValidIPv4, isValidIPv6, isValidMAC, showToast, sortTable, initSortableTable, resetSorting, filterTable, clearSearch } from './common.js';
import { reloadDNS, reloadDHCP } from './services.js';
import { apiMap, fetchData } from './api.js';
// -----------------------------
// State variables
// -----------------------------
-let hostsList = [];
+let allHosts = [];
+let viewHosts = [];
let editingHostId = null;
const sortState = { sortDirection: {}, lastSort: null };
// -----------------------------
async function fetchHosts () {
const loader = document.getElementById("loader");
- const container = document.getElementById("devices-container");
const dataTable = document.getElementById("dataTable");
// hide table during loading to avoid flickering and show loader
loader.style.display = "block";
// Fetch hosts
- hostsList = await fetchData(apiMap.hosts);
+ allHosts = await fetchData(apiMap.hosts);
+ viewHosts = [...allHosts];
} catch (err) {
console.error(err?.message || "Error loading hosts");
showToast(err?.message || "Error loading hosts", false);
- hostsList = [];
+ allHosts = [];
+ viewHosts = [];
// hide loader and show table
loader.style.display = "none";
dataTable.classList.remove("d-none");
// Update table with current hosts
// -----------------------------
function updateTable () {
+ const loader = document.getElementById("loader");
+ const dataTable = document.getElementById("dataTable");
// DOM Reference
const tbody = document.querySelector("#dataTable tbody");
tbody.innerHTML = "";
// if no hosts, show an empty row
- if (!hostsList.length) {
+ if (!viewHosts.length) {
const trEmpty = document.createElement("tr");
const tdEmpty = document.createElement("td");
tdEmpty.colSpan = 7;
// fragment per performance
const frag = document.createDocumentFragment();
- hostsList.forEach(h => {
+ viewHosts.forEach(h => {
const id = Number(h.id);
const tr = document.createElement("tr");
tbody.appendChild(frag);
// apply last sorting
- if (typeof lastSort === "object" && lastSort && Array.isArray(sortDirection)) {
- if (Number.isInteger(lastSort.colIndex)) {
- sortDirection[lastSort.colIndex] = !lastSort.ascending;
- sortTable(lastSort.colIndex, sortState);
- }
+ const { lastSort, sortDirection } = sortState;
+
+ if (lastSort && Number.isInteger(lastSort.colIndex)) {
+ sortDirection[lastSort.colIndex] = !lastSort.ascending;
+ sortTable(lastSort.colIndex, sortState);
}
// hide loader and show table
loader.style.display = "none";
dataTable.classList.remove("d-none");
+
+ // apply current search filter
+ const searchInput = document.getElementById("searchInput");
+ if (searchInput) {
+ const term = searchInput.value.trim().toLowerCase();
+ if (term) {
+ filterTable(term);
+ }
+ }
}
// -----------------------------
// clean input on load
input.value = "";
// live filter for each keystroke
- input.addEventListener("input", filterData);
- // Escape management when focus is in the input
- input.addEventListener("keydown", (e) => {
- if (e.key === "Escape") {
- e.preventDefault(); // evita side-effect (es. chiusure di modali del browser)
- e.stopPropagation(); // evita che arrivi al listener globale
- resetSorting(sortState);
- clearSearch(); // svuota input e ricarica tabella (come definito nella tua funzione)
- updateTable(); // aggiorna tabella
- filterData(''); // ripristina tabella
- }
+ input.addEventListener("input", (e) => {
+ const term = e.target.value.trim().toLowerCase();
+ filterTable(term);
});
}
// KEYBOARD (ESC + accessibility)
// -----------------------------
function handleKeyboard(e) {
- // Ignore if focus is in a typing field
- const tag = (e.target.tagName || "").toLowerCase();
- const isTypingField =
- tag === "input" || tag === "textarea" || tag === "select" || e.target.isContentEditable;
-
- // global ESC key listener to clear search and reset sorting
- if (e.key === "Escape" && !isTypingField) {
- // Prevent default form submission
- e.preventDefault(); // evita side-effect (es. chiusure di modali del browser)
- resetSorting(sortState);
- clearSearch(); // svuota input e ricarica tabella (come definito nella tua funzione)
- updateTable(); // aggiorna tabella
- filterData(''); // ripristina tabella
- }
- // Button event delegation (Enter, Space)
+ // Button event delegation (Escape, Enter, Space)
+ const isEscape = e.key === 'Escape';
const isEnter = e.key === 'Enter';
const isSpace = e.key === ' ';
- if (!isEnter && !isSpace) return;
+ if (!isEscape && !isEnter && !isSpace) return;
+
+ // ESC delegation: clear search and reset sorting
+ if (isEscape) {
+ // Ignore if focus is in a typing field
+ const tag = (e.target.tagName || "").toLowerCase();
+ const isTypingField =
+ tag === "input" || tag === "textarea" || tag === "select" || e.target.isContentEditable;
+ const isSearchInput = e.target.id === "searchInput";
+
+ // ESC should clear search and reset sorting only if not focused on a typing field, or if focused on the search input (to allow quick clearing of search)
+ if (!isTypingField || isSearchInput) {
+ // Prevent default form submission
+ e.preventDefault(); // evita side-effect (es. chiusure di modali del browser)
+ resetSorting(sortState);
+ clearSearch(); // svuota input e ricarica tabella (come definito nella tua funzione)
+ viewHosts = [...allHosts];
+ updateTable(); // aggiorna tabella
+ }
+ return;
+ }
+
+ // Enter / Space delegation
const el = e.target.closest('[data-action]');
if (!el) return;
// Import common js
-import { loadModals, isValidIPv4, isValidIPv6, isValidMAC, showToast, sortTable, initSortableTable, resetSorting, filterData, clearSearch } from './common.js';
+import { loadModals, isValidIPv4, isValidIPv6, isValidMAC, showToast, sortTable, initSortableTable, resetSorting, filterTable, clearSearch } from './common.js';
import { reloadDNS, reloadDHCP } from './services.js';
import { apiMap, fetchData } from './api.js';
// -----------------------------
// State variables
// -----------------------------
-let leasesList = [];
+let allLeases = [];
+let viewLeases = [];
const sortState = { sortDirection: {}, lastSort: null };
// -----------------------------
// -----------------------------
async function fetchLeases () {
const loader = document.getElementById("loader");
- const container = document.getElementById("devices-container");
const dataTable = document.getElementById("dataTable");
// hide table during loading to avoid flickering and show loader
loader.style.display = "block";
// Fetch leases
- leasesList = await fetchData(apiMap.leases);
+ allLeases = await fetchData(apiMap.leases);
+ viewLeases = [...allLeases];
} catch (err) {
console.error(err?.message || "Error loading leases");
showToast(err?.message || "Error loading leases", false);
- leasesList = [];
+ allLeases = [];
+ viewLeases = [];
// hide loader and show table
loader.style.display = "none";
dataTable.classList.remove("d-none");
// Update table with current hosts
// -----------------------------
function updateTable () {
+ const loader = document.getElementById("loader");
+ const dataTable = document.getElementById("dataTable");
// DOM Reference
const tbody = document.querySelector("#dataTable tbody");
tbody.innerHTML = "";
// if no leases, show an empty row
- if (!leasesList.length) {
+ if (!viewLeases.length) {
const trEmpty = document.createElement("tr");
const tdEmpty = document.createElement("td");
tdEmpty.colSpan = 7;
// fragment per performance
const frag = document.createDocumentFragment();
- leasesList.forEach(l => {
+ viewLeases.forEach(l => {
const id = Number(l.id);
const tr = document.createElement("tr");
tbody.appendChild(frag);
// apply last sorting
- if (typeof lastSort === "object" && lastSort && Array.isArray(sortDirection)) {
- if (Number.isInteger(lastSort.colIndex)) {
- sortDirection[lastSort.colIndex] = !lastSort.ascending;
- sortTable(lastSort.colIndex, sortState);
- }
+ const { lastSort, sortDirection } = sortState;
+
+ if (lastSort && Number.isInteger(lastSort.colIndex)) {
+ sortDirection[lastSort.colIndex] = !lastSort.ascending;
+ sortTable(lastSort.colIndex, sortState);
}
// hide loader and show table
loader.style.display = "none";
dataTable.classList.remove("d-none");
+
+ // apply current search filter
+ const searchInput = document.getElementById("searchInput");
+ if (searchInput) {
+ const term = searchInput.value.trim().toLowerCase();
+ if (term) {
+ filterTable(term);
+ }
+ }
}
// -----------------------------
// clean input on load
input.value = "";
// live filter for each keystroke
- input.addEventListener("input", filterData);
- // Escape management when focus is in the input
- input.addEventListener("keydown", (e) => {
- if (e.key === "Escape") {
- e.preventDefault(); // evita side-effect (es. chiusure di modali del browser)
- e.stopPropagation(); // evita che arrivi al listener globale
- resetSorting(sortState);
- clearSearch(); // svuota input e ricarica tabella (come definito nella tua funzione)
- updateTable(); // aggiorna tabella
- filterData(''); // ripristina tabella
- }
+ input.addEventListener("input", (e) => {
+ const term = e.target.value.trim().toLowerCase();
+ filterTable(term);
});
}
// KEYBOARD (ESC + accessibility)
// -----------------------------
function handleKeyboard(e) {
- // Ignore if focus is in a typing field
- const tag = (e.target.tagName || "").toLowerCase();
- const isTypingField =
- tag === "input" || tag === "textarea" || tag === "select" || e.target.isContentEditable;
-
- // global ESC key listener to clear search and reset sorting
- if (e.key === "Escape" && !isTypingField) {
- // Prevent default form submission
- e.preventDefault(); // evita side-effect (es. chiusure di modali del browser)
- resetSorting(sortState);
- clearSearch(); // svuota input e ricarica tabella (come definito nella tua funzione)
- updateTable(); // aggiorna tabella
- filterData(''); // ripristina tabella
- }
- // Button event delegation (Enter, Space)
+ // Button event delegation (Escape, Enter, Space)
+ const isEscape = e.key === 'Escape';
const isEnter = e.key === 'Enter';
const isSpace = e.key === ' ';
- if (!isEnter && !isSpace) return;
+ if (!isEscape && !isEnter && !isSpace) return;
+
+ // ESC delegation: clear search and reset sorting
+ if (isEscape) {
+ // Ignore if focus is in a typing field
+ const tag = (e.target.tagName || "").toLowerCase();
+ const isTypingField =
+ tag === "input" || tag === "textarea" || tag === "select" || e.target.isContentEditable;
+ const isSearchInput = e.target.id === "searchInput";
+
+ // ESC should clear search and reset sorting only if not focused on a typing field, or if focused on the search input (to allow quick clearing of search)
+ if (!isTypingField || isSearchInput) {
+ // Prevent default form submission
+ e.preventDefault(); // evita side-effect (es. chiusure di modali del browser)
+ resetSorting(sortState);
+ clearSearch(); // svuota input e ricarica tabella (come definito nella tua funzione)
+ viewLeases = [...allLeases];
+ updateTable(); // aggiorna tabella
+ }
+ return;
+ }
+
+ // Enter / Space delegation
const el = e.target.closest('[data-action]');
if (!el) return;