]> git.giorgioravera.it Git - network-manager.git/commitdiff
restored filter based on html field
authorGiorgio Ravera <giorgio.ravera@gmail.com>
Tue, 26 May 2026 21:34:33 +0000 (23:34 +0200)
committerGiorgio Ravera <giorgio.ravera@gmail.com>
Tue, 26 May 2026 21:34:33 +0000 (23:34 +0200)
frontend/js/aliases.js
frontend/js/common.js
frontend/js/devices.js
frontend/js/hosts.js
frontend/js/leases.js

index a01dca6fd4f3f1c9086d4d411c4771e7fc355202..2488b2beefe9976352a3cda0facc63e7c618c80d 100644 (file)
@@ -1,12 +1,13 @@
 // 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 };
 
@@ -15,7 +16,6 @@ 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
@@ -26,22 +26,26 @@ async function fetchAliases () {
         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");
@@ -54,7 +58,7 @@ function updateTable () {
     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;
@@ -71,7 +75,7 @@ function updateTable () {
     // fragment per performance
     const frag = document.createDocumentFragment();
 
-    aliasesList.forEach(h => {
+    viewAliases.forEach(h => {
 
         const id = Number(h.id);
         const tr = document.createElement("tr");
@@ -215,16 +219,25 @@ function updateTable () {
     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);
+        }
+    }
 }
 
 // -----------------------------
@@ -428,6 +441,7 @@ async function handleAddAliasSubmit(e) {
             // close modal and reload aliases
             closeAddAliasModal();
             await loadAliases();
+            updateTable();
             return true
         }
 
@@ -595,17 +609,9 @@ function initSearch() {
     // 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);
     });
 }
 
@@ -700,26 +706,35 @@ async function handleActionClick(e) {
 // 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;
 
index ae2f0bf9d58425981296028af2261b9298f7bdaf..63b4758c03696510a0370bf2a37863ce1c214c2a 100644 (file)
@@ -332,13 +332,12 @@ export function initSortableTable() {
 /**
   * 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";
     });
 }
 
index fbde4ac6c57a43d2ec6995504a1aa40051103e0c..edf65f0cf9f0063f7277c907d1b62730ce0d9458 100644 (file)
@@ -1,12 +1,13 @@
 // 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 };
 
@@ -15,7 +16,6 @@ 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
@@ -26,12 +26,14 @@ async function fetchDevices () {
         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");
@@ -42,6 +44,8 @@ async function fetchDevices () {
 // 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");
@@ -54,7 +58,7 @@ function updateTable () {
     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;
@@ -71,7 +75,7 @@ function updateTable () {
     // fragment per performance
     const frag = document.createDocumentFragment();
 
-    devicesList.forEach(d => {
+    viewDevices.forEach(d => {
 
         const id = d.id;
         let type = 0;
@@ -259,9 +263,9 @@ function updateTable () {
                 delSpan.appendChild(i);
             }
 
-            if(type == 1) {
+            if (type === 1) {
               td.appendChild(editSpan);
-            } else if (type == 2) {
+            } else if (type === 2) {
               td.appendChild(addSpan);
             } else {
             }
@@ -276,16 +280,25 @@ function updateTable () {
     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);
+        }
+    }
 }
 
 // -----------------------------
@@ -527,6 +540,7 @@ async function handleAddHostSubmit(e) {
             // close modal and reload hosts
             closeAddHostModal();
             await loadDevices();
+            updateTable();
             return true
         }
 
@@ -710,17 +724,9 @@ function initSearch() {
     // 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);
     });
 }
 
@@ -815,26 +821,35 @@ async function handleActionClick(e) {
 // 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;
 
index acb2d46c4a05512155d128a7fc971867c0361734..364590efaf04733491d68133ad0f4c927343ee7b 100644 (file)
@@ -1,12 +1,13 @@
 // 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 };
 
@@ -15,7 +16,6 @@ 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
@@ -26,12 +26,14 @@ async function fetchHosts () {
         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");
@@ -42,6 +44,8 @@ async function fetchHosts () {
 // 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");
@@ -54,7 +58,7 @@ function updateTable () {
     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;
@@ -71,7 +75,7 @@ function updateTable () {
     // fragment per performance
     const frag = document.createDocumentFragment();
 
-    hostsList.forEach(h => {
+    viewHosts.forEach(h => {
 
         const id = Number(h.id);
         const tr = document.createElement("tr");
@@ -225,16 +229,25 @@ function updateTable () {
     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);
+        }
+    }
 }
 
 // -----------------------------
@@ -620,17 +633,9 @@ function initSearch() {
     // 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);
     });
 }
 
@@ -725,26 +730,35 @@ async function handleActionClick(e) {
 // 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;
 
index c4d28e4817f3b59865b30fdaad675959beda74f3..51ed645537de88c482e6f081ea709da3c8acf0fe 100644 (file)
@@ -1,12 +1,13 @@
 // 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 };
 
 // -----------------------------
@@ -14,7 +15,6 @@ 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
@@ -25,12 +25,14 @@ async function fetchLeases () {
         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");
@@ -41,6 +43,8 @@ async function fetchLeases () {
 // 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");
@@ -53,7 +57,7 @@ function updateTable () {
     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;
@@ -70,7 +74,7 @@ function updateTable () {
     // fragment per performance
     const frag = document.createDocumentFragment();
 
-    leasesList.forEach(l => {
+    viewLeases.forEach(l => {
 
         const id = Number(l.id);
         const tr = document.createElement("tr");
@@ -240,16 +244,25 @@ function updateTable () {
     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);
+        }
+    }
 }
 
 // -----------------------------
@@ -584,17 +597,9 @@ function initSearch() {
     // 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);
     });
 }
 
@@ -681,26 +686,35 @@ async function handleActionClick(e) {
 // 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;