]> git.giorgioravera.it Git - network-manager.git/commitdiff
Refactored js services
authorGiorgio Ravera <giorgio.ravera@gmail.com>
Thu, 28 May 2026 17:02:04 +0000 (19:02 +0200)
committerGiorgio Ravera <giorgio.ravera@gmail.com>
Thu, 28 May 2026 17:02:04 +0000 (19:02 +0200)
frontend/js/aliases.js
frontend/js/api.js
frontend/js/devices.js
frontend/js/hosts.js
frontend/js/index.js
frontend/js/leases.js
frontend/js/services.js
frontend/modals.html

index 2488b2beefe9976352a3cda0facc63e7c618c80d..ed3754d6d1386ed004d979e1eb8dfc722be94da9 100644 (file)
@@ -1,7 +1,7 @@
 // Import 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';
+// Import services
+import { serviceReloadDNS, serviceReloadDHCP, serviceGetAliases, serviceGetAlias, serviceCreateAlias, serviceUpdateAlias, serviceDeleteAlias } from './services.js';
 
 // -----------------------------
 // State variables
@@ -12,7 +12,7 @@ let editingAliasId = null;
 const sortState = { sortDirection: {}, lastSort: null };
 
 // -----------------------------
-// Fetch hosts from API
+// Fetch aliases from API
 // -----------------------------
 async function fetchAliases () {
     const loader = document.getElementById("loader");
@@ -26,7 +26,7 @@ async function fetchAliases () {
         loader.style.display = "block";
 
         // Fetch aliases
-        allAliases = await fetchData(apiMap.aliases);
+        allAliases = await serviceGetAliases();
         viewAliases = [...allAliases];
 
     } catch (err) {
@@ -247,50 +247,27 @@ async function editAlias(id) {
     // Clear form first
     clearAddAliasForm();
 
-    // Fetch alias
-    const res = await fetch(`/api/aliases/${id}`, {
-        headers: { Accept: 'application/json' },
-    });
-
-    // Check content-type to avoid parsing errors
-    const contentType = res.headers.get("content-type") || "";
-    if (!contentType.includes("application/json")) {
-        const err = new Error(`Fetch failed for alias ${id}: ${res.statusText}`);
-        err.status = res.status;
-        throw err;
-    }
-
-    // Check JSON
-    let data;
     try {
-        data = await res.json();
-    } catch {
-        throw new Error(`Fetch failed for alias ${id}: Invalid JSON payload`);
-    }
-
-    // Check JSON errors
-    if (!res.ok) {
-        const serverMsg = data?.detail?.message?.trim();
-        const base = `Fetch failed for alias ${id}`;
-        const err = new Error(serverMsg ? `${base}: ${serverMsg}` : base);
-        err.status = res.status;
-        throw err;
-    }
-
-    // Store the ID of the alias being edited
-    editingAliasId = id;
-
-    // Pre-fill the form fields
-    document.getElementById("aliasName").value = data.name ?? "";
-    document.getElementById("aliasTarget").value = data.target ?? "";
-    document.getElementById("aliasDescription").value = data.description ?? "";
-    document.getElementById("aliasSSL").checked = !!data.ssl_enabled;
-    if (data.visibility == 2) {
-        document.getElementById("aliasVisibilityAlias").checked = true;
-    } else if (data.visibility == 1){
-        document.getElementById("aliasVisibilityGlobal").checked = true;
-    } else {
-        document.getElementById("aliasVisibilityLocal").checked = true;
+        const data = await serviceGetAlias(id);
+
+        // Store the ID of the alias being edited
+        editingAliasId = id;
+
+        // Pre-fill the form fields
+        document.getElementById("aliasName").value = data.name ?? "";
+        document.getElementById("aliasTarget").value = data.target ?? "";
+        document.getElementById("aliasDescription").value = data.description ?? "";
+        document.getElementById("aliasSSL").checked = !!data.ssl_enabled;
+        if (data.visibility == 2) {
+            document.getElementById("aliasVisibilityAlias").checked = true;
+        } else if (data.visibility == 1){
+            document.getElementById("aliasVisibilityGlobal").checked = true;
+        } else {
+            document.getElementById("aliasVisibilityLocal").checked = true;
+        }
+    } catch (err) {
+        console.error(err?.message || "Error loading alias");
+        showToast(err?.message || "Error loading alias", false);
     }
 }
 
@@ -309,92 +286,34 @@ async function saveAlias(aliasData) {
         return false;
     }
 
-    if (editingAliasId !== null) {
-        // Update existing alias
-        const res = await fetch(`/api/aliases/${editingAliasId}`, {
-            method: 'PUT',
-            headers: { 'Content-Type': 'application/json' },
-            body: JSON.stringify(aliasData)
-        });
-
-        // Success without JSON
-        if (res.status === 204) {
-            showToast('Alias updated successfully', true);
-            return true;
-        }
+    try {
+        let result;
 
-        // Check content-type to avoid parsing errors
-        const contentType = res.headers.get("content-type") || "";
-        if (!contentType.includes("application/json")) {
-            const err = new Error(`${res.status}: ${res.statusText}`);
-            err.status = res.status;
-            throw err;
+        if (editingAliasId !== null) {
+            // Update
+            result = await serviceUpdateAlias(editingAliasId, aliasData);
+        } else {
+            // Create
+            result = await serviceCreateAlias(aliasData);
         }
 
-        // Check JSON
-        let data;
-        try {
-            data = await res.json();
-        } catch {
-            throw new Error('Invalid JSON payload');
-        }
+        const msg = (typeof result === 'object' && result?.message)
+            ? result.message
+            : editingAliasId !== null
+                ? 'Alias updated successfully'
+                : 'Alias created successfully';
 
-        // Check JSON errors
-        if (!res.ok) {
-            const serverMsg = data?.detail?.message?.trim();
-            const base = `Error updating alias`;
-            const err = new Error(serverMsg ? `${base}: ${serverMsg}` : base);
-            err.status = res.status;
-            throw err;
-        }
+        showToast(msg, true);
 
-        // Success
-        showToast(data?.message || 'Alias updated successfully', true);
         return true;
 
-    } else {
-        // Create new alias
-        const res = await fetch(`/api/aliases`, {
-            method: 'POST',
-            headers: { 'Content-Type': 'application/json' },
-            body: JSON.stringify(aliasData)
-        });
-
-        // Success without JSON
-        if (res.status === 204) {
-            showToast('Alias created successfully', true);
-            return true;
-        }
-
-        // Check content-type to avoid parsing errors
-        const contentType = res.headers.get("content-type") || "";
-        if (!contentType.includes("application/json")) {
-            const err = new Error(`${res.status}: ${res.statusText}`);
-            err.status = res.status;
-            throw err;
-        }
-
-        // Check JSON
-        let data;
-        try {
-            data = await res.json();
-        } catch {
-            throw new Error('Invalid JSON payload');
-        }
+    } catch (err) {
+        console.error(err?.message || "Error saving alias");
+        showToast(err?.message || "Error saving alias", false);
+    }
 
-        // Check JSON errors
-        if (!res.ok) {
-            const serverMsg = data?.detail?.message?.trim();
-            const base = `Error adding alias`;
-            const err = new Error(serverMsg ? `${base}: ${serverMsg}` : base);
-            err.status = res.status;
-            throw err;
-        }
+    return false;
 
-        // Success
-        showToast(data?.message || 'Alias created successfully', true);
-        return true
-    }
 }
 
 // -----------------------------
@@ -440,7 +359,7 @@ async function handleAddAliasSubmit(e) {
         if (ok !== false) {
             // close modal and reload aliases
             closeAddAliasModal();
-            await loadAliases();
+            await fetchAliases();
             updateTable();
             return true
         }
@@ -463,50 +382,23 @@ async function handleDeleteAlias(e, el) {
     // Get alias ID
     const id = Number(el.dataset.aliasId);
     if (!Number.isFinite(id)) {
-        console.warn('Delete: alias id not valid for delete:', id);
         showToast('Alias id not valid for delete', false);
         return;
     }
 
-    // Execute delete
     try {
-        // Fetch data
-        const res = await fetch(`/api/aliases/${id}`, {
-            method: 'DELETE',
-            headers: { 'Accept': 'application/json' },
-        });
-
-        // Check content-type to avoid parsing errors
-        const contentType = res.headers.get("content-type") || "";
-        if (!contentType.includes("application/json")) {
-            const err = new Error(`${res.status}: ${res.statusText}`);
-            err.status = res.status;
-            throw err;
-        }
+        const result = await serviceDeleteAlias(id);
 
-        // Check JSON
-        let data;
-        try {
-            data = await res.json();
-        } catch {
-            throw new Error('Invalid JSON payload');
-        }
-
-        // Check JSON errors
-        if (!res.ok) {
-            const serverMsg = data?.detail?.message?.trim();
-            const base = `Error deleting alias`;
-            const err = new Error(serverMsg ? `${base}: ${serverMsg}` : base);
-            err.status = res.status;
-            throw err;
-        }
+        const msg = (typeof result === 'object' && result?.message)
+            ? result.message
+            : 'Alias deleted successfully';
 
-        // Success
-        showToast(data?.message || 'Alias deleted successfully', true);
+        showToast(msg, true);
 
         // Reload aliases
         await fetchAliases();
         updateTable();
+
         return true;
 
     } catch (err) {
@@ -532,7 +424,7 @@ const actionHandlers = {
     // Reload DNS
     reloadDns: async () => {
         try {
-            const result = await reloadDNS();
+            const result = await serviceReloadDNS();
             const msg = (typeof result === 'object' && result?.message)
                         ? result.message
                         : 'DNS reload successfully';
@@ -544,7 +436,7 @@ const actionHandlers = {
     // Reload DHCP
     reloadDhcp: async () => {
         try {
-            const result = await reloadDHCP();
+            const result = await serviceReloadDHCP();
             const msg = (typeof result === 'object' && result?.message)
                         ? result.message
                         : 'DHCP reload successfully';
@@ -631,7 +523,7 @@ function initModalLifecycle() {
     modalEl.addEventListener('show.bs.modal', async (ev) => {
         lastTriggerEl = ev.relatedTarget; // trigger (Add o Edit)
 
-        // check Add or Edit mode based on presence of data-host-id in the trigger element
+        // check Add or Edit mode based on presence of data-alias-id in the trigger element
         const id = Number(lastTriggerEl?.dataset?.aliasId);
 
         if (Number.isFinite(id)) {
index c12be8a8ef30a250960d8a48d9f4aaebd51466bc..34a1e75a523eeb50b279bc393343989154ddbff6 100644 (file)
@@ -1,61 +1,87 @@
-// -----------------------------
-// API Endpoints
-// -----------------------------
-export const apiMap = {
-    hosts: {
-        url: "/api/hosts",
-        name: "Hosts"
-    },
-    aliases: {
-        url: "/api/aliases",
-        name: "Aliases"
-    },
-    leases: {
-        url: "/api/dhcp/leases",
-        name: "Leases"
-    },
-    devices: {
-        url: "/api/devices",
-        name: "Devices"
-    }
-};
-
-// -----------------------------
-// Fetch Data functions
-// -----------------------------
-export async function fetchData(api) {
+// -------------------------------------------------------
+// API CORE - Generic request wrapper
+// -------------------------------------------------------
+export async function apiRequest(
+    url,
+    {
+        method = 'GET',
+        headers = {},
+        body = null,
+    } = {},
+    errorPrefix = 'Request error'
+) {
+    let res;
 
-    let items = [];
+    try {
+        res = await fetch(url, {
+            method,
+            headers: {
+                'Accept': 'application/json',
+                ...headers
+            },
+            body
+        });
+    } catch (err) {
+        throw new Error(
+            `${errorPrefix}: network error${err?.message ? `: ${err.message}` : ''}`,
+            { cause: err }
+        );
+    }
 
-    // Fetch data
-    const res = await fetch(api.url, {
-        headers: { Accept: 'application/json' },
-    });
+    // 204 No Content
+    if (res.status === 204) {
+        return true;
+    }
 
-    // Check content-type to avoid parsing errors
+    // Content-Type check
     const contentType = res.headers.get("content-type") || "";
     if (!contentType.includes("application/json")) {
-        const err = new Error(`${res.status}: ${res.statusText}`);
+        const err = new Error(
+            `${errorPrefix}: ${res.status} ${res.statusText || 'Unexpected response'}`
+        );
         err.status = res.status;
         throw err;
     }
 
-    // Check JSON
+    // Parse JSON
     let data;
     try {
         data = await res.json();
-        items = Array.isArray(data) ? data : (Array.isArray(data?.data) ? data.data : []);
     } catch {
-        throw new Error('Invalid JSON payload');
+        throw new Error(`${errorPrefix}: Invalid JSON payload`);
     }
 
-    // Check JSON errors
+    // Handle HTTP error
     if (!res.ok) {
-        const serverMsg = data?.detail?.message?.trim();
-        const base = `Error loading ${api.name}`;
-        const err = new Error(serverMsg ? `${base}: ${serverMsg}` : base);
+        const serverMsg =
+            data?.detail?.message?.trim()
+            || (typeof data?.detail === 'string' ? data.detail.trim() : '')
+            || data?.message?.trim()
+            || data?.error?.message?.trim()
+            || (typeof data?.error === 'string' ? data.error.trim() : '');
+
+        const err = new Error(
+            `${errorPrefix}${serverMsg ? `: ${serverMsg}` : ''}`
+        );
         err.status = res.status;
         throw err;
     }
-    return items;
+
+    return data;
+}
+
+export function apiGet(url, errorPrefix = 'Fetch error') {
+    return apiRequest(url, { method: 'GET' }, errorPrefix);
+}
+
+export function apiPost(url, payload, errorPrefix = 'Request error') {
+    return apiRequest(
+        url,
+        {
+            method: 'POST',
+            headers: { 'Content-Type': 'application/json' },
+            body: JSON.stringify(payload)
+        },
+        errorPrefix
+    );
 }
index edf65f0cf9f0063f7277c907d1b62730ce0d9458..377c2c35405f0b0c9a79ee9df37804eaaff414f3 100644 (file)
@@ -1,7 +1,7 @@
 // Import 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';
+// Import services
+import { serviceReloadDNS, serviceReloadDHCP, serviceGetDHCPLeases, serviceGetDHCPLease, serviceDeleteDHCPLease, serviceGetDevices, serviceGetHost, serviceCreateHost, serviceUpdateHost, serviceDeleteHost } from './services.js';
 
 // -----------------------------
 // State variables
@@ -26,7 +26,7 @@ async function fetchDevices () {
         loader.style.display = "block";
 
         // Fetch devices
-        allDevices  = await fetchData(apiMap.devices);
+        allDevices  = await serviceGetDevices();
         viewDevices = [...allDevices];
 
     } catch (err) {
@@ -87,8 +87,8 @@ function updateTable () {
         } else if (id.startsWith("d-")) {
             type = 2;
         } else {
-            console.error("loadDevices: unknown device type:", id);
-            showToast("loadDevices: unknown device type:", false);
+            console.error("updateTable: unknown device type:", id);
+            showToast("updateTable: unknown device type:", false);
         }
 
         const tr = document.createElement("tr");
@@ -306,21 +306,19 @@ function updateTable () {
 // -----------------------------
 async function editHost(id) {
 
-    let fetchUrl = "";
     let host = false;
 
     // Clear form first
     clearAddHostForm();
 
+    // host or lease
     if (id !== null) {
         // Static or Dynamic?
         if (id.startsWith("s-")) {
             // static
-            fetchUrl = `/api/hosts/${id.slice(2)}`;
             host = true;
         } else if (id.startsWith("d-")) {
             // dynamic
-            fetchUrl = `/api/dhcp/leases/${id.slice(2)}`;
             host = false;
         } else {
             throw new Error("Invalid Device ID format for edit");
@@ -330,54 +328,36 @@ async function editHost(id) {
         throw new Error("Invalid Device ID for edit");
     }
 
-    // Fetch host
-    const res = await fetch(fetchUrl, {
-        headers: { Accept: 'application/json' },
-    });
-
-    // Check content-type to avoid parsing errors
-    const contentType = res.headers.get("content-type") || "";
-    if (!contentType.includes("application/json")) {
-        const err = new Error(`Fetch failed for host ${id}: ${res.statusText}`);
-        err.status = res.status;
-        throw err;
-    }
-
-    // Check JSON
-    let data;
     try {
-        data = await res.json();
-    } catch {
-        throw new Error(`Fetch failed for host ${id}: Invalid JSON payload`);
-    }
+        let data;
 
-    // Check JSON errors
-    if (!res.ok) {
-        const serverMsg = data?.detail?.message?.trim();
-        const base = `Fetch failed for host ${id}`;
-        const err = new Error(serverMsg ? `${base}: ${serverMsg}` : base);
-        err.status = res.status;
-        throw err;
-    }
+        if(host){
+            data = await serviceGetHost(id);
 
-    if(host) {
-        // Store the ID of the host being edited
-        editingHostId = id;
-    }
+            // Store the ID of the host being edited
+            editingHostId = id;
+        } else {
+            data = await serviceGetDHCPLease(id);
+        }
 
-    // Pre-fill the form fields
-    document.getElementById("hostName").value = data.name ?? "";
-    document.getElementById("hostIPv4").value = data.ipv4 ?? "";
-    document.getElementById("hostIPv6").value = data.ipv6 ?? "";
-    document.getElementById("hostMAC").value = data.mac ?? "";
-    document.getElementById("hostDescription").value = data.description ?? "";
-    document.getElementById("hostSSL").checked = !!data.ssl_enabled;
-    if (data.visibility == 2) {
-        document.getElementById("hostVisibilityAlias").checked = true;
-    } else if (data.visibility == 1){
-        document.getElementById("hostVisibilityGlobal").checked = true;
-    } else {
-        document.getElementById("hostVisibilityLocal").checked = true;
+        // Pre-fill the form fields
+        document.getElementById("hostName").value = data.name ?? "";
+        document.getElementById("hostIPv4").value = data.ipv4 ?? "";
+        document.getElementById("hostIPv6").value = data.ipv6 ?? "";
+        document.getElementById("hostMAC").value = data.mac ?? "";
+        document.getElementById("hostDescription").value = data.description ?? "";
+        document.getElementById("hostSSL").checked = !!data.ssl_enabled;
+        if (data.visibility == 2) {
+            document.getElementById("hostVisibilityAlias").checked = true;
+        } else if (data.visibility == 1){
+            document.getElementById("hostVisibilityGlobal").checked = true;
+        } else {
+            document.getElementById("hostVisibilityLocal").checked = true;
+        }
+
+    } catch (err) {
+        console.error(err?.message || "Error loading device");
+        showToast(err?.message || "Error loading device", false);
     }
 }
 
@@ -406,92 +386,34 @@ async function saveHost(hostData) {
         return false;
     }
 
-    if (editingHostId !== null) {
-        // Update existing host
-        const res = await fetch(`/api/hosts/${editingHostId}`, {
-            method: 'PUT',
-            headers: { 'Content-Type': 'application/json' },
-            body: JSON.stringify(hostData)
-        });
-
-        // Success without JSON
-        if (res.status === 204) {
-            showToast('Host updated successfully', true);
-            return true;
-        }
+    try {
+        let result;
 
-        // Check content-type to avoid parsing errors
-        const contentType = res.headers.get("content-type") || "";
-        if (!contentType.includes("application/json")) {
-            const err = new Error(`${res.status}: ${res.statusText}`);
-            err.status = res.status;
-            throw err;
+        if (editingHostId !== null) {
+            // Update
+            result = await serviceUpdateHost(editingHostId, hostData);
+        } else {
+            // Create
+            result = await serviceCreateHost(hostData);
         }
 
-        // Check JSON
-        let data;
-        try {
-            data = await res.json();
-        } catch {
-            throw new Error('Invalid JSON payload');
-        }
+        const msg = (typeof result === 'object' && result?.message)
+            ? result.message
+            : editingHostId !== null
+                ? 'Host updated successfully'
+                : 'Host created successfully';
 
-        // Check JSON errors
-        if (!res.ok) {
-            const serverMsg = data?.detail?.message?.trim();
-            const base = `Error updating host`;
-            const err = new Error(serverMsg ? `${base}: ${serverMsg}` : base);
-            err.status = res.status;
-            throw err;
-        }
+        showToast(msg, true);
 
-        // Success
-        showToast(data?.message || 'Host updated successfully', true);
         return true;
 
-    } else {
-        // Create new host
-        const res = await fetch(`/api/hosts`, {
-            method: 'POST',
-            headers: { 'Content-Type': 'application/json' },
-            body: JSON.stringify(hostData)
-        });
-
-        // Success without JSON
-        if (res.status === 204) {
-            showToast('Host created successfully', true);
-            return true;
-        }
-
-        // Check content-type to avoid parsing errors
-        const contentType = res.headers.get("content-type") || "";
-        if (!contentType.includes("application/json")) {
-            const err = new Error(`${res.status}: ${res.statusText}`);
-            err.status = res.status;
-            throw err;
-        }
-
-        // Check JSON
-        let data;
-        try {
-            data = await res.json();
-        } catch {
-            throw new Error('Invalid JSON payload');
-        }
+    } catch (err) {
+        console.error(err?.message || "Error saving host");
+        showToast(err?.message || "Error saving host", false);
+    }
 
-        // Check JSON errors
-        if (!res.ok) {
-            const serverMsg = data?.detail?.message?.trim();
-            const base = `Error adding host`;
-            const err = new Error(serverMsg ? `${base}: ${serverMsg}` : base);
-            err.status = res.status;
-            throw err;
-        }
+    return false;
 
-        // Success
-        showToast(data?.message || 'Host created successfully', true);
-        return true
-    }
 }
 
 // -----------------------------
@@ -539,7 +461,7 @@ async function handleAddHostSubmit(e) {
         if (ok !== false) {
             // close modal and reload hosts
             closeAddHostModal();
-            await loadDevices();
+            await fetchDevices();
             updateTable();
             return true
         }
@@ -556,11 +478,14 @@ async function handleAddHostSubmit(e) {
 // Handle delete device action
 // -----------------------------
 async function handleDeleteDevice(e, el) {
+
+    let host = false;
+
     // Prevent default action
     e.preventDefault();
 
     // Get device ID
-    const id = el.dataset.deviceId;
+    let id = el.dataset.deviceId;
 
     if (!id) {
         console.warn('Delete: device id not valid for delete:', id);
@@ -568,60 +493,41 @@ async function handleDeleteDevice(e, el) {
         return;
     }
 
-    let deleteUrl = "";
-
-    // Static or Dynamic?
-    if (id.startsWith("s-")) {
-        // static â†’ delete su DB
-        deleteUrl = `/api/hosts/${id.slice(2)}`
-    } else if (id.startsWith("d-")) {
-        // dynamic â†’ delete su DHCP server
-        deleteUrl = `/api/dhcp/leases/${id.slice(2)}`
+    // host or lease
+    if (id !== null) {
+        // Static or Dynamic?
+        if (id.startsWith("s-")) {
+            // static
+            host = true;
+        } else if (id.startsWith("d-")) {
+            // dynamic
+            host = false;
+        } else {
+            throw new Error("Invalid Device ID format for edit");
+        }
+        id = Number(id.slice(2));
     } else {
-        console.error("Delete: unknown device type:", id);
-        showToast("Delete: unknown device type:", false);
-        return;
+        throw new Error("Invalid Device ID for edit");
     }
 
-    // Execute delete
     try {
-        // Fetch data
-        const res = await fetch(deleteUrl, {
-            method: 'DELETE',
-            headers: { 'Accept': 'application/json' },
-        });
-
-        // Check content-type to avoid parsing errors
-        const contentType = res.headers.get("content-type") || "";
-        if (!contentType.includes("application/json")) {
-            const err = new Error(`${res.status}: ${res.statusText}`);
-            err.status = res.status;
-            throw err;
-        }
+       if(host){
+            const result = await serviceDeleteHost(id);
 
-        // Check JSON
-        let data;
-        try {
-            data = await res.json();
-        } catch {
-            throw new Error('Invalid JSON payload');
+        } else {
+            const result = await serviceDeleteDHCPLease(id);
         }
 
-        // Check JSON errors
-        if (!res.ok) {
-            const serverMsg = data?.detail?.message?.trim();
-            const base = `Error deleting device`;
-            const err = new Error(serverMsg ? `${base}: ${serverMsg}` : base);
-            err.status = res.status;
-            throw err;
-        }
+        const msg = (typeof result === 'object' && result?.message)
+            ? result.message
+            : 'Host deleted successfully';
 
-        // Success
-        showToast(data?.message || 'Device deleted successfully', true);
+        showToast(msg, true);
 
         // Reload devices
         await fetchDevices();
         updateTable();
+
         return true;
 
     } catch (err) {
@@ -647,7 +553,7 @@ const actionHandlers = {
     // Reload DNS
     reloadDns: async () => {
         try {
-            const result = await reloadDNS();
+            const result = await serviceReloadDNS();
             const msg = (typeof result === 'object' && result?.message)
                         ? result.message
                         : 'DNS reload successfully';
@@ -659,7 +565,7 @@ const actionHandlers = {
     // Reload DHCP
     reloadDhcp: async () => {
         try {
-            const result = await reloadDHCP();
+            const result = await serviceReloadDHCP();
             const msg = (typeof result === 'object' && result?.message)
                         ? result.message
                         : 'DHCP reload successfully';
index 364590efaf04733491d68133ad0f4c927343ee7b..b35b2e513fa6815f5196115e9376b4444c1be1de 100644 (file)
@@ -1,7 +1,7 @@
 // Import 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';
+// Import services
+import { serviceReloadDNS, serviceReloadDHCP, serviceGetHosts, serviceGetHost, serviceCreateHost, serviceUpdateHost, serviceDeleteHost } from './services.js';
 
 // -----------------------------
 // State variables
@@ -26,7 +26,7 @@ async function fetchHosts () {
         loader.style.display = "block";
 
         // Fetch hosts
-        allHosts = await fetchData(apiMap.hosts);
+        allHosts = await serviceGetHosts();
         viewHosts = [...allHosts];
 
     } catch (err) {
@@ -257,52 +257,30 @@ async function editHost(id) {
     // Clear form first
     clearAddHostForm();
 
-    // Fetch host
-    const res = await fetch(`/api/hosts/${id}`, {
-        headers: { Accept: 'application/json' },
-    });
-
-    // Check content-type to avoid parsing errors
-    const contentType = res.headers.get("content-type") || "";
-    if (!contentType.includes("application/json")) {
-        const err = new Error(`Fetch failed for host ${id}: ${res.statusText}`);
-        err.status = res.status;
-        throw err;
-    }
-
-    // Check JSON
-    let data;
     try {
-        data = await res.json();
-    } catch {
-        throw new Error(`Fetch failed for host ${id}: Invalid JSON payload`);
-    }
-
-    // Check JSON errors
-    if (!res.ok) {
-        const serverMsg = data?.detail?.message?.trim();
-        const base = `Fetch failed for host ${id}`;
-        const err = new Error(serverMsg ? `${base}: ${serverMsg}` : base);
-        err.status = res.status;
-        throw err;
-    }
+        const data = await serviceGetHost(id);
+
+        // Store the ID of the host being edited
+        editingHostId = id;
+
+        // Pre-fill the form fields
+        document.getElementById("hostName").value = data.name ?? "";
+        document.getElementById("hostIPv4").value = data.ipv4 ?? "";
+        document.getElementById("hostIPv6").value = data.ipv6 ?? "";
+        document.getElementById("hostMAC").value = data.mac ?? "";
+        document.getElementById("hostDescription").value = data.description ?? "";
+        document.getElementById("hostSSL").checked = !!data.ssl_enabled;
+        if (data.visibility == 2) {
+            document.getElementById("hostVisibilityAlias").checked = true;
+        } else if (data.visibility == 1){
+            document.getElementById("hostVisibilityGlobal").checked = true;
+        } else {
+            document.getElementById("hostVisibilityLocal").checked = true;
+        }
 
-    // Store the ID of the host being edited
-    editingHostId = id;
-
-    // Pre-fill the form fields
-    document.getElementById("hostName").value = data.name ?? "";
-    document.getElementById("hostIPv4").value = data.ipv4 ?? "";
-    document.getElementById("hostIPv6").value = data.ipv6 ?? "";
-    document.getElementById("hostMAC").value = data.mac ?? "";
-    document.getElementById("hostDescription").value = data.description ?? "";
-    document.getElementById("hostSSL").checked = !!data.ssl_enabled;
-    if (data.visibility == 2) {
-        document.getElementById("hostVisibilityAlias").checked = true;
-    } else if (data.visibility == 1){
-        document.getElementById("hostVisibilityGlobal").checked = true;
-    } else {
-        document.getElementById("hostVisibilityLocal").checked = true;
+    } catch (err) {
+        console.error(err?.message || "Error loading host");
+        showToast(err?.message || "Error loading host", false);
     }
 }
 
@@ -331,92 +309,34 @@ async function saveHost(hostData) {
         return false;
     }
 
-    if (editingHostId !== null) {
-        // Update existing host
-        const res = await fetch(`/api/hosts/${editingHostId}`, {
-            method: 'PUT',
-            headers: { 'Content-Type': 'application/json' },
-            body: JSON.stringify(hostData)
-        });
-
-        // Success without JSON
-        if (res.status === 204) {
-            showToast('Host updated successfully', true);
-            return true;
-        }
+    try {
+        let result;
 
-        // Check content-type to avoid parsing errors
-        const contentType = res.headers.get("content-type") || "";
-        if (!contentType.includes("application/json")) {
-            const err = new Error(`${res.status}: ${res.statusText}`);
-            err.status = res.status;
-            throw err;
+        if (editingHostId !== null) {
+            // Update
+            result = await serviceUpdateHost(editingHostId, hostData);
+        } else {
+            // Create
+            result = await serviceCreateHost(hostData);
         }
 
-        // Check JSON
-        let data;
-        try {
-            data = await res.json();
-        } catch {
-            throw new Error('Invalid JSON payload');
-        }
+        const msg = (typeof result === 'object' && result?.message)
+            ? result.message
+            : editingHostId !== null
+                ? 'Host updated successfully'
+                : 'Host created successfully';
 
-        // Check JSON errors
-        if (!res.ok) {
-            const serverMsg = data?.detail?.message?.trim();
-            const base = `Error updating host`;
-            const err = new Error(serverMsg ? `${base}: ${serverMsg}` : base);
-            err.status = res.status;
-            throw err;
-        }
+        showToast(msg, true);
 
-        // Success
-        showToast(data?.message || 'Host updated successfully', true);
         return true;
 
-    } else {
-        // Create new host
-        const res = await fetch(`/api/hosts`, {
-            method: 'POST',
-            headers: { 'Content-Type': 'application/json' },
-            body: JSON.stringify(hostData)
-        });
-
-        // Success without JSON
-        if (res.status === 204) {
-            showToast('Host created successfully', true);
-            return true;
-        }
-
-        // Check content-type to avoid parsing errors
-        const contentType = res.headers.get("content-type") || "";
-        if (!contentType.includes("application/json")) {
-            const err = new Error(`${res.status}: ${res.statusText}`);
-            err.status = res.status;
-            throw err;
-        }
-
-        // Check JSON
-        let data;
-        try {
-            data = await res.json();
-        } catch {
-            throw new Error('Invalid JSON payload');
-        }
+    } catch (err) {
+        console.error(err?.message || "Error saving host");
+        showToast(err?.message || "Error saving host", false);
+    }
 
-        // Check JSON errors
-        if (!res.ok) {
-            const serverMsg = data?.detail?.message?.trim();
-            const base = `Error adding host`;
-            const err = new Error(serverMsg ? `${base}: ${serverMsg}` : base);
-            err.status = res.status;
-            throw err;
-        }
+    return false;
 
-        // Success
-        showToast(data?.message || 'Host created successfully', true);
-        return true
-    }
 }
 
 // -----------------------------
@@ -487,50 +407,23 @@ async function handleDeleteHost(e, el) {
     // Get host ID
     const id = Number(el.dataset.hostId);
     if (!Number.isFinite(id)) {
-        console.warn('Delete: host id not valid for delete:', id);
         showToast('Host id not valid for delete', false);
         return;
     }
 
-    // Execute delete
     try {
-        // Fetch data
-        const res = await fetch(`/api/hosts/${id}`, {
-            method: 'DELETE',
-            headers: { 'Accept': 'application/json' },
-        });
-
-        // Check content-type to avoid parsing errors
-        const contentType = res.headers.get("content-type") || "";
-        if (!contentType.includes("application/json")) {
-            const err = new Error(`${res.status}: ${res.statusText}`);
-            err.status = res.status;
-            throw err;
-        }
-
-        // Check JSON
-        let data;
-        try {
-            data = await res.json();
-        } catch {
-            throw new Error('Invalid JSON payload');
-        }
+        const result = await serviceDeleteHost(id);
 
-        // Check JSON errors
-        if (!res.ok) {
-            const serverMsg = data?.detail?.message?.trim();
-            const base = `Error deleting host`;
-            const err = new Error(serverMsg ? `${base}: ${serverMsg}` : base);
-            err.status = res.status;
-            throw err;
-        }
+        const msg = (typeof result === 'object' && result?.message)
+            ? result.message
+            : 'Host deleted successfully';
 
-        // Success
-        showToast(data?.message || 'Host deleted successfully', true);
+        showToast(msg, true);
 
         // Reload hosts
         await fetchHosts();
         updateTable();
+
         return true;
 
     } catch (err) {
@@ -556,7 +449,7 @@ const actionHandlers = {
     // Reload DNS
     reloadDns: async () => {
         try {
-            const result = await reloadDNS();
+            const result = await serviceReloadDNS();
             const msg = (typeof result === 'object' && result?.message)
                         ? result.message
                         : 'DNS reload successfully';
@@ -568,7 +461,7 @@ const actionHandlers = {
     // Reload DHCP
     reloadDhcp: async () => {
         try {
-            const result = await reloadDHCP();
+            const result = await serviceReloadDHCP();
             const msg = (typeof result === 'object' && result?.message)
                         ? result.message
                         : 'DHCP reload successfully';
index d4d59f4e980d90aa6f7b9ad1d3f3b7d217a30cf0..249c2b1fe53bf5ece5f555b8d2664a1834fab34f 100644 (file)
@@ -2,7 +2,7 @@
 // IMPORT
 // -------------------------------------------------------
 import { loadModals, showToast } from './common.js';
-import { apiCheck, reloadDNS, reloadDHCP, CreateBackup, fetchBackups, RestoreBackup, deleteBackup, checkHealth } from './services.js';
+import { serviceCheckAbount, serviceCheckHealth , serviceReloadDNS, serviceReloadDHCP, serviceBackupCreate, serviceBackupList, serviceBackupRestore, deleteBackup} from './services.js';
 
 // -------------------------------------------------------
 // BACKUP MODAL OPEN/CLOSE
@@ -25,7 +25,7 @@ async function openBackupModal() {
     }
 
     try {
-        const data = await fetchBackups();
+        const data = await serviceBackupList();
         renderBackupList(data);
     } catch (err) {
         console.error(err);
@@ -133,7 +133,7 @@ function getSelectedBackup() {
 }
 
 // -------------------------------------------------------
-// HEALTH MODAL OPEN/CLOSE + RENDER (usa checkHealth())
+// HEALTH MODAL OPEN/CLOSE + RENDER
 // -------------------------------------------------------
 function openHealthModal() {
     const modal = document.getElementById('healthModal');
@@ -160,11 +160,11 @@ function openHealthModal() {
     }
     if (updatedAtEl) updatedAtEl.textContent = '';
 
-    // Usa checkHealth() per ottenere il payload health
+    // Usa serviceCheckHealth() per ottenere il payload health
     Promise.resolve()
-      .then(() => checkHealth())
+      .then(() => serviceCheckHealth())
       .then((data) => {
-          // Se checkHealth ritorna true o {message}, non abbiamo i dettagli: mostra un messaggio
+          // Se serviceCheckHealth ritorna true o {message}, non abbiamo i dettagli: mostra un messaggio
           const isDetailed =
               data && typeof data === 'object' &&
               ('status' in data || 'latency_ms' in data || 'database' in data);
@@ -267,7 +267,7 @@ const actionHandlers = {
         label.textContent = ' Exporting…';
 
         try {
-            const result = await CreateBackup();
+            const result = await serviceBackupCreate();
             const msg = (typeof result === 'object' && result?.message)
                         ? result.message
                         : 'Backup completed successfully';
@@ -299,7 +299,7 @@ const actionHandlers = {
         label.textContent = ' Restoring…';
 
         try {
-            const result = await RestoreBackup(id);
+            const result = await serviceBackupRestore(id);
             const msg = (typeof result === 'object' && result?.message)
                         ? result.message
                         : 'Restore completed successfully';
@@ -334,7 +334,7 @@ const actionHandlers = {
             showToast(msg, true);
 
             // reload list
-            const data = await fetchBackups();
+            const data = await serviceBackupList();
             renderBackupList(data);
 
         } catch (err) {
@@ -348,7 +348,7 @@ const actionHandlers = {
     // Reload DNS
     reloadDns: async () => {
         try {
-            const result = await reloadDNS();
+            const result = await serviceReloadDNS();
             const msg = (typeof result === 'object' && result?.message)
                         ? result.message
                         : 'DNS reload successfully';
@@ -360,7 +360,7 @@ const actionHandlers = {
     // Reload DHCP
     reloadDhcp: async () => {
         try {
-            const result = await reloadDHCP();
+            const result = await serviceReloadDHCP();
             const msg = (typeof result === 'object' && result?.message)
                         ? result.message
                         : 'DHCP reload successfully';
@@ -371,7 +371,7 @@ const actionHandlers = {
     },
     // Check API status
     apiCheck: async () => {
-        const result = await apiCheck();
+        const result = await serviceCheckAbount();
         if(result) {
             showToast('API status updated succesfully', true);
         } else {
@@ -450,7 +450,7 @@ function initBackupModal() {
 // Periodic API Check
 // -------------------------------------------------------
 async function periodicTest() {
-    await apiCheck();
+    await serviceCheckAbount();
     setTimeout(periodicTest, 10000);
 }
 
index 51ed645537de88c482e6f081ea709da3c8acf0fe..1a0144bbff16c8da217bad5d2600845372548390 100644 (file)
@@ -1,7 +1,7 @@
 // Import 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';
+// Import services
+import { serviceReloadDNS, serviceReloadDHCP, serviceGetDHCPLeases, serviceDeleteDHCPLease, serviceGetDHCPLease, serviceCreateHost} from './services.js';
 
 // -----------------------------
 // State variables
@@ -25,7 +25,7 @@ async function fetchLeases () {
         loader.style.display = "block";
 
         // Fetch leases
-        allLeases = await fetchData(apiMap.leases);
+        allLeases = await serviceGetDHCPLeases();
         viewLeases = [...allLeases];
 
     } catch (err) {
@@ -272,49 +272,27 @@ async function addHost(id) {
     // Clear form first
     clearAddHostForm();
 
-    // Fetch lease
-    const res = await fetch(`/api/dhcp/leases/${id}`, {
-        headers: { Accept: 'application/json' },
-    });
-
-    // Check content-type to avoid parsing errors
-    const contentType = res.headers.get("content-type") || "";
-    if (!contentType.includes("application/json")) {
-        const err = new Error(`Fetch failed for lease ${id}: ${res.statusText}`);
-        err.status = res.status;
-        throw err;
-    }
-
-    // Check JSON
-    let data;
     try {
-        data = await res.json();
-    } catch {
-        throw new Error(`Fetch failed for lease ${id}: Invalid JSON payload`);
-    }
-
-    // Check JSON errors
-    if (!res.ok) {
-        const serverMsg = data?.detail?.message?.trim();
-        const base = `Fetch failed for lease ${id}`;
-        const err = new Error(serverMsg ? `${base}: ${serverMsg}` : base);
-        err.status = res.status;
-        throw err;
-    }
+       const data = await serviceGetDHCPLease(id);
+
+      // Pre-fill the form fields
+      document.getElementById("hostName").value = data.name ?? "";
+      document.getElementById("hostIPv4").value = data.ipv4 ?? "";
+      document.getElementById("hostIPv6").value = data.ipv6 ?? "";
+      document.getElementById("hostMAC").value = data.mac ?? "";
+      document.getElementById("hostDescription").value = data.description ?? "";
+      document.getElementById("hostSSL").checked = !!data.ssl_enabled;
+      if (data.visibility == 2) {
+          document.getElementById("hostVisibilityAlias").checked = true;
+      } else if (data.visibility == 1){
+          document.getElementById("hostVisibilityGlobal").checked = true;
+      } else {
+          document.getElementById("hostVisibilityLocal").checked = true;
+        }
 
-    // Pre-fill the form fields
-    document.getElementById("hostName").value = data.name ?? "";
-    document.getElementById("hostIPv4").value = data.ipv4 ?? "";
-    document.getElementById("hostIPv6").value = data.ipv6 ?? "";
-    document.getElementById("hostMAC").value = data.mac ?? "";
-    document.getElementById("hostDescription").value = data.description ?? "";
-    document.getElementById("hostSSL").checked = !!data.ssl_enabled;
-    if (data.visibility == 2) {
-        document.getElementById("hostVisibilityAlias").checked = true;
-    } else if (data.visibility == 1){
-        document.getElementById("hostVisibilityGlobal").checked = true;
-    } else {
-        document.getElementById("hostVisibilityLocal").checked = true;
+    } catch (err) {
+        console.error(err?.message || "Error loading lease");
+        showToast(err?.message || "Error loading lease", false);
     }
 }
 
@@ -343,48 +321,26 @@ async function saveHost(hostData) {
         return false;
     }
 
-    // Create new host
-    const res = await fetch(`/api/hosts`, {
-        method: 'POST',
-        headers: { 'Content-Type': 'application/json' },
-        body: JSON.stringify(hostData)
-    });
+    try {
+        const result = await serviceCreateHost(hostData);
 
-    // Success without JSON
-    if (res.status === 204) {
-        showToast('Host created successfully', true);
-        return true;
-    }
+        const msg = (typeof result === 'object' && result?.message)
+            ? result.message
+            : 'Host created successfully';
 
-    // Check content-type to avoid parsing errors
-    const contentType = res.headers.get("content-type") || "";
-    if (!contentType.includes("application/json")) {
-        const err = new Error(`${res.status}: ${res.statusText}`);
-        err.status = res.status;
-        throw err;
-    }
+        showToast(msg, true);
 
-    // Check JSON
-    let data;
-    try {
-        data = await res.json();
-    } catch {
-        throw new Error('Invalid JSON payload');
-    }
+        return true;
 
-    // Check JSON errors
-    if (!res.ok) {
-        const serverMsg = data?.detail?.message?.trim();
-        const base = `Error adding host`;
-        const err = new Error(serverMsg ? `${base}: ${serverMsg}` : base);
-        err.status = res.status;
-        throw err;
+    } catch (err) {
+        console.error(err?.message || "Error saving host");
+        showToast(err?.message || "Error saving host", false);
     }
 
-    // Success
-    showToast(data?.message || 'Host created successfully', true);
-    return true
+    return false;
+
 }
+
 // -----------------------------
 // Prepare add host form
 // -----------------------------
@@ -451,50 +407,23 @@ async function handleDeleteLease(e, el) {
     // Get lease ID
     const id = Number(el.dataset.leaseId);
     if (!Number.isFinite(id)) {
-        console.warn('Delete: lease id not valid for delete:', id);
         showToast('Lease id not valid for delete', false);
         return;
     }
 
-    // Execute delete
     try {
-        // Fetch data
-        const res = await fetch(`/api/dhcp/leases/${id}`, {
-            method: 'DELETE',
-            headers: { 'Accept': 'application/json' },
-        });
-
-        // Check content-type to avoid parsing errors
-        const contentType = res.headers.get("content-type") || "";
-        if (!contentType.includes("application/json")) {
-            const err = new Error(`${res.status}: ${res.statusText}`);
-            err.status = res.status;
-            throw err;
-        }
+        const result = await serviceDeleteDHCPLease(id);
 
-        // Check JSON
-        let data;
-        try {
-            data = await res.json();
-        } catch {
-            throw new Error('Invalid JSON payload');
-        }
+        const msg = (typeof result === 'object' && result?.message)
+            ? result.message
+            : 'Lease deleted successfully';
 
-        // Check JSON errors
-        if (!res.ok) {
-            const serverMsg = data?.detail?.message?.trim();
-            const base = `Error deleting lease`;
-            const err = new Error(serverMsg ? `${base}: ${serverMsg}` : base);
-            err.status = res.status;
-            throw err;
-        }
-
-        // Success
-        showToast(data?.message || 'Lease deleted successfully', true);
+        showToast(msg, true);
 
         // Reload leases
         await fetchLeases();
         updateTable();
+
         return true;
 
     } catch (err) {
@@ -520,7 +449,7 @@ const actionHandlers = {
     // Reload DNS
     reloadDns: async () => {
         try {
-            const result = await reloadDNS();
+            const result = await serviceReloadDNS();
             const msg = (typeof result === 'object' && result?.message)
                         ? result.message
                         : 'DNS reload successfully';
@@ -532,7 +461,7 @@ const actionHandlers = {
     // Reload DHCP
     reloadDhcp: async () => {
         try {
-            const result = await reloadDHCP();
+            const result = await serviceReloadDHCP();
             const msg = (typeof result === 'object' && result?.message)
                         ? result.message
                         : 'DHCP reload successfully';
@@ -626,7 +555,7 @@ function initModalLifecycle() {
             try {
                 await addHost(id);
             } catch (err) {
-                showToast(err?.message || "Error loading host for edit", false);
+                showToast(err?.message || "Error loading host", false);
                 // Close modal
                 modalEl.addEventListener('shown.bs.modal', () => {
                     closeAddHostModal(lastTriggerEl);
index 894c5bb2f967bbb27c210a889db6707e0fae6281..e34a17bedd2f81c6d427e2630a49cef2b6f2c7a8 100644 (file)
@@ -1,7 +1,10 @@
+// import api
+import { apiRequest, apiGet, apiPost } from './api.js';
+
 // -------------------------------------------------------
-// API Health Check
+// Check Abount
 // -------------------------------------------------------
-export async function apiCheck() {
+export async function serviceCheckAbount() {
     const pill = document.getElementById('api-pill');
     if (!pill) return;
 
@@ -22,431 +25,269 @@ export async function apiCheck() {
     }
 }
 
+// -------------------------------------------------------
+// Check Health
+// -------------------------------------------------------
+export async function serviceCheckHealth() {
+    return await apiGet("/api/health", "Error performing health check");
+}
+
 // -----------------------------
 // Reload DNS
 // -----------------------------
-export async function reloadDNS() {
-    let res;
-    try {
-        // Fetch data
-        res = await fetch('/api/dns/reload', {
-            method: 'POST',
-            headers: { 'Accept': 'application/json' },
-        });
-    } catch (err) {
-        const msg = 'Network error while reloading DNS' + (err?.message ? `: ${err.message}` : '');
-        throw new Error(msg, { cause: err });
-    }
-
-    // Success without JSON
-    if (res.status === 204) {
-        return true;
-    }
+export async function serviceReloadDNS() {
+    const data = await apiPost(
+        "/api/dns/reload",
+        null,
+        "Error reloading DNS"
+    );
+
+    return data?.message ? { message: data.message } : true;
+}
 
-    // Check content-type to avoid parsing errors
-    const contentType = res.headers.get("content-type") || "";
-    if (!contentType.includes("application/json")) {
-        const err = new Error(`Error reloading DNS: ${res.status}: ${res.statusText || 'Unexpected response'}`);
-        err.status = res.status;
-        throw err;
-    }
+// -----------------------------
+// Reload DHCP action
+// -----------------------------
+export async function serviceReloadDHCP() {
+    const data = await apiPost(
+        "/api/dhcp/reload",
+        null,
+        "Error reloading DHCP"
+    );
+
+    return data?.message ? { message: data.message } : true;
+}
 
-    // Check JSON
-    let data = {};
-    try {
-        data = await res.json();
-    } catch {
-        throw new Error('Error reloading DNS: Invalid JSON payload');
-    }
+// -----------------------------
+// Get DHCP Leaseses
+// -----------------------------
+export async function serviceGetDHCPLeases() {
+    return await apiGet("/api/dhcp/leases", "Error loading DHCP leases");
+}
 
-    // Check JSON errors
-    if (!res.ok) {
-        const serverMsg =
-            data?.detail?.message?.trim()
-            || (typeof data?.detail === 'string' ? data.detail.trim() : '')
-            || data?.message?.trim()
-            || data?.error?.message?.trim()
-            || (typeof data?.error === 'string' ? data.error.trim() : '');
-        const err = new Error('Error reloading DNS' + (serverMsg ? `: ${serverMsg}` : ''));
-        err.status = res.status;
-        throw err;
-    }
+// -----------------------------
+// Get a single DHCP Leases
+// -----------------------------
+export async function serviceGetDHCPLease(id) {
+    return await apiRequest(
+        `/api/dhcp/leases/${id}`,
+        { method: "GET" },
+        `Error loading host ${id}`
+    );
+}
 
-    if (res.ok && (data.status === 'success' || data.code === 'DNS_RELOAD_OK')) {
-        // Success
-        return data?.message ? { message: data.message } : true;
-    } else {
-        // Failed with JSON error message
-        return data?.message ? { message: data.message } : false;
-    }
+// -----------------------------
+// Delete Hosts
+// -----------------------------
+export async function serviceDeleteDHCPLease(id) {
+    const data = await apiRequest(
+        `/api/dhcp/leases/${id}`,
+        { method: "DELETE" },
+        "Error deleting host"
+    );
+
+    return data?.message ? { message: data.message } : true;
 }
 
 // -----------------------------
-// Reload DHCP action
+// Get Hosts
 // -----------------------------
-export async function reloadDHCP() {
-    let res;
-    try {
-        // Fetch data
-        res = await fetch(`/api/dhcp/reload`, {
-            method: 'POST',
-            headers: { 'Accept': 'application/json' },
-        });
-    } catch (err) {
-        const msg = 'Network error while reloading DHCP' + (err?.message ? `: ${err.message}` : '');
-        throw new Error(msg, { cause: err });
-    }
+export async function serviceGetHosts() {
+    return await apiGet("/api/hosts", "Error loading hosts");
+}
 
-    // Success without JSON
-    if (res.status === 204) {
-        return true;
-    }
+// -----------------------------
+// Get a single host
+// -----------------------------
+export async function serviceGetHost(id) {
+    return await apiRequest(
+        `/api/hosts/${id}`,
+        { method: "GET" },
+        `Error loading host ${id}`
+    );
+}
 
-    // Check content-type to avoid parsing errors
-    const contentType = res.headers.get("content-type") || "";
-    if (!contentType.includes("application/json")) {
-        const err = new Error(`Error reloading DHCP: ${res.status}: ${res.statusText || 'Unexpected response'}`);
-        err.status = res.status;
-        throw err;
-    }
+// -----------------------------
+// Create a new host
+// -----------------------------
+export async function serviceCreateHost(hostData) {
+    const data = await apiRequest(
+        "/api/hosts",
+        {
+            method: "POST",
+            headers: { "Content-Type": "application/json" },
+            body: JSON.stringify(hostData)
+        },
+        "Error creating host"
+    );
+
+    return data?.message ? { message: data.message } : true;
+}
 
-    // Check JSON
-    let data = {};
-    try {
-        data = await res.json();
-    } catch {
-        throw new Error('Error reloading DHCP: Invalid JSON payload');
-    }
+// -----------------------------
+// Update an host
+// -----------------------------
+export async function serviceUpdateHost(id, hostData) {
+    const data = await apiRequest(
+        `/api/hosts/${id}`,
+        {
+            method: "PUT",
+            headers: { "Content-Type": "application/json" },
+            body: JSON.stringify(hostData)
+        },
+        "Error updating host"
+    );
+
+    return data?.message ? { message: data.message } : true;
+}
 
-    // Check JSON errors
-    if (!res.ok) {
-        const serverMsg =
-            data?.detail?.message?.trim()
-            || (typeof data?.detail === 'string' ? data.detail.trim() : '')
-            || data?.message?.trim()
-            || data?.error?.message?.trim()
-            || (typeof data?.error === 'string' ? data.error.trim() : '');
-        const err = new Error('Error reloading DHCP' + (serverMsg ? `: ${serverMsg}` : ''));
-        err.status = res.status;
-        throw err;
-    }
+// -----------------------------
+// Delete Hosts
+// -----------------------------
+export async function serviceDeleteHost(id) {
+    const data = await apiRequest(
+        `/api/hosts/${id}`,
+        { method: "DELETE" },
+        "Error deleting host"
+    );
+
+    return data?.message ? { message: data.message } : true;
+}
 
-    if (res.ok && (data.status === 'success' || data.code === 'DHCP_RELOAD_OK')) {
-        // Success
-        return data?.message ? { message: data.message } : true;
-    } else {
-        // Failed with JSON error message
-        return data?.message ? { message: data.message } : false;
-    }
+// -----------------------------
+// Get Aliases
+// -----------------------------
+export async function serviceGetAliases() {
+    return await apiGet("/api/aliases", "Error loading aliases");
 }
 
-// -------------------------------------------------------
-// Create a Backup
-// -------------------------------------------------------
-export async function CreateBackup() {
-    let res;
+// -----------------------------
+// Get a single alias
+// -----------------------------
+export async function serviceGetAlias(id) {
+    return await apiRequest(
+        `/api/aliases/${id}`,
+        { method: "GET" },
+        `Error loading alias ${id}`
+    );
+}
 
-    try {
-        // Fetch data
-        res = await fetch(`/api/backup/create`, {
-            method: 'POST',
-            headers: { 'Accept': 'application/json' },
-        });
-
-    } catch (err) {
-        const msg = 'Network error while performing backup' + (err?.message ? `: ${err.message}` : '');
-        throw new Error(msg, { cause: err });
-    }
+// -----------------------------
+// Create a new alias
+// -----------------------------
+export async function serviceCreateAlias(aliasData) {
+    const data = await apiRequest(
+        "/api/aliases",
+        {
+            method: "POST",
+            headers: { "Content-Type": "application/json" },
+            body: JSON.stringify(aliasData)
+        },
+        "Error creating alias"
+    );
+
+    return data?.message ? { message: data.message } : true;
+}
 
-    // Success without JSON
-    if (res.status === 204) {
-        return true;
-    }
+// -----------------------------
+// Update an alias
+// -----------------------------
+export async function serviceUpdateAlias(id, aliasData) {
+    const data = await apiRequest(
+        `/api/aliases/${id}`,
+        {
+            method: "PUT",
+            headers: { "Content-Type": "application/json" },
+            body: JSON.stringify(aliasData)
+        },
+        "Error updating alias"
+    );
+
+    return data?.message ? { message: data.message } : true;
+}
 
-    // Check content-type to avoid parsing errors
-    const contentType = res.headers.get("content-type") || "";
-    if (!contentType.includes("application/json")) {
-        const err = new Error(`Error performing backup: ${res.status}: ${res.statusText || 'Unexpected response'}`);
-        err.status = res.status;
-        throw err;
-    }
+// -----------------------------
+// Delete Alias
+// -----------------------------
+export async function serviceDeleteAlias(id) {
+    const data = await apiRequest(
+        `/api/aliases/${id}`,
+        { method: "DELETE" },
+        "Error deleting alias"
+    );
+
+    return data?.message ? { message: data.message } : true;
+}
 
-    // Check JSON
-    let data = {};
-    try {
-        data = await res.json();
-    } catch {
-        throw new Error('Error performing backup: Invalid JSON payload');
-    }
+// -----------------------------
+// Get Devices
+// -----------------------------
+export async function serviceGetDevices() {
+    return await apiGet("/api/devices", "Error loading Devices");
+}
 
-    // Check JSON errors
-    if (!res.ok) {
-        const serverMsg =
-            data?.detail?.message?.trim()
-            || (typeof data?.detail === 'string' ? data.detail.trim() : '')
-            || data?.message?.trim()
-            || data?.error?.message?.trim()
-            || (typeof data?.error === 'string' ? data.error.trim() : '');
-        const err = new Error('Error performing backup' + (serverMsg ? `: ${serverMsg}` : ''));
-        err.status = res.status;
-        throw err;
+// -------------------------------------------------------
+// Create a Backup
+// -------------------------------------------------------
+export async function serviceBackupCreate() {
+    const data = await apiPost(
+        "/api/backup/create",
+        null,
+        "Error performing backup"
+    );
+
+    if (data.status === 'success') {
+        return data?.message ? { message: data.message } : true;
     }
 
-    if (res.ok && (data.status === 'success' || data.code === 'BACKUP_CREATE_OK')) {
-        // Success
-        return data?.message ? { message: data.message } : true;
-    } else if (res.ok && (data.status === 'partial' || data.code === 'BACKUP_PARTIAL')) {
-        // Partial success
+    if (data.status === 'partial') {
         return data?.message
             ? { message: data.message, partial: true }
             : { partial: true };
-    } else {
-        // Failed with JSON error message
-        return data?.message ? { message: data.message } : false;
     }
+
+    return false;
 }
 
 // -------------------------------------------------------
 // Fetch Backups list
 // -------------------------------------------------------
-export async function fetchBackups() {
-    let res;
-
-    try {
-        // Fetch data
-        res = await fetch(`/api/backup/list`, {
-            method: 'GET',
-            headers: { 'Accept': 'application/json' },
-        });
-
-    } catch (err) {
-        const msg = 'Network error while fetching backups' + (err?.message ? `: ${err.message}` : '');
-        throw new Error(msg, { cause: err });
-    }
-
-    // Success without JSON
-    if (res.status === 204) {
-        return [];
-    }
-
-    // Check content-type to avoid parsing errors
-    const contentType = res.headers.get("content-type") || "";
-    if (!contentType.includes("application/json")) {
-        const err = new Error(`Error fetching backups: ${res.status}: ${res.statusText || 'Unexpected response'}`);
-        err.status = res.status;
-        throw err;
-    }
-
-    // Check JSON
-    let data = {};
-    try {
-        data = await res.json();
-    } catch {
-        throw new Error('Error fetching backups: Invalid JSON payload');
-    }
-
-    // Check JSON errors
-    if (!res.ok) {
-        const serverMsg =
-            data?.detail?.message?.trim()
-            || (typeof data?.detail === 'string' ? data.detail.trim() : '')
-            || data?.message?.trim()
-            || data?.error?.message?.trim()
-            || (typeof data?.error === 'string' ? data.error.trim() : '');
-        const err = new Error('Error fetching backups' + (serverMsg ? `: ${serverMsg}` : ''));
-        err.status = res.status;
-        throw err;
-    }
-
-    return (data ?? []);
+export async function serviceBackupList() {
+    return await apiGet("/api/backup/list", "Error fetching backups");
 }
 
 // -------------------------------------------------------
 // Restore a Backup
 // -------------------------------------------------------
-export async function RestoreBackup(id) {
-    let res;
-
-    try {
-        // Fetch data
-        res = await fetch(`/api/backup/restore`, {
-            method: 'POST',
-            headers: {
-                'Accept': 'application/json',
-                'Content-Type': 'application/json',
-            },
-            body: JSON.stringify({ backup_id: id })
-        });
-
-    } catch (err) {
-        const msg = 'Network error while performing restore' + (err?.message ? `: ${err.message}` : '');
-        throw new Error(msg, { cause: err });
-    }
-
-    // Success without JSON
-    if (res.status === 204) {
-        return true;
-    }
-
-    // Check content-type to avoid parsing errors
-    const contentType = res.headers.get("content-type") || "";
-    if (!contentType.includes("application/json")) {
-        const err = new Error(`Error performing restore: ${res.status}: ${res.statusText || 'Unexpected response'}`);
-        err.status = res.status;
-        throw err;
-    }
-
-    // Check JSON
-    let data = {};
-    try {
-        data = await res.json();
-    } catch {
-        throw new Error('Error performing restore: Invalid JSON payload');
-    }
-
-    // Check JSON errors
-    if (!res.ok) {
-        const serverMsg =
-            data?.detail?.message?.trim()
-            || (typeof data?.detail === 'string' ? data.detail.trim() : '')
-            || data?.message?.trim()
-            || data?.error?.message?.trim()
-            || (typeof data?.error === 'string' ? data.error.trim() : '');
-        const err = new Error('Error performing restore' + (serverMsg ? `: ${serverMsg}` : ''));
-        err.status = res.status;
-        throw err;
+export async function serviceBackupRestore(id) {
+    const data = await apiPost(
+        "/api/backup/restore",
+        { backup_id: id },
+        "Error performing restore"
+    );
+
+    if (data.status === 'success') {
+        return data?.message ? { message: data.message } : true;
     }
 
-    if (res.ok && (data.status === 'success' || data.code === 'BACKUP_RESTORE_OK')) {
-        // Success
-        return data?.message ? { message: data.message } : true;
-    } else if (res.ok && (data.status === 'partial' || data.code === 'BACKUP_RESTORE_PARTIAL')) {
-        // Partial success
+    if (data.status === 'partial') {
         return data?.message
             ? { message: data.message, partial: true }
             : { partial: true };
-    } else {
-        // Failed with JSON error message
-        return data?.message ? { message: data.message } : false;
     }
+
+    return false;
 }
 
 // -------------------------------------------------------
 // Delete a Backup
 // -------------------------------------------------------
 export async function deleteBackup(id) {
-    let res;
-
-    try {
-        // Fetch data
-        res = await fetch(`/api/backup/delete`, {
-            method: 'POST',
-            headers: {
-                'Accept': 'application/json',
-                'Content-Type': 'application/json',
-            },
-            body: JSON.stringify({ backup_id: id })
-        });
-
-    } catch (err) {
-        const msg = 'Network error while performing delete' + (err?.message ? `: ${err.message}` : '');
-        throw new Error(msg, { cause: err });
-    }
-
-    // Success without JSON
-    if (res.status === 204) {
-        return true;
-    }
-
-    // Check content-type to avoid parsing errors
-    const contentType = res.headers.get("content-type") || "";
-    if (!contentType.includes("application/json")) {
-        const err = new Error(`Error performing delete: ${res.status}: ${res.statusText || 'Unexpected response'}`);
-        err.status = res.status;
-        throw err;
-    }
-
-    // Check JSON
-    let data = {};
-    try {
-        data = await res.json();
-    } catch {
-        throw new Error('Error performing delete: Invalid JSON payload');
-    }
-
-    // Check JSON errors
-    if (!res.ok) {
-        const serverMsg =
-            data?.detail?.message?.trim()
-            || (typeof data?.detail === 'string' ? data.detail.trim() : '')
-            || data?.message?.trim()
-            || data?.error?.message?.trim()
-            || (typeof data?.error === 'string' ? data.error.trim() : '');
-        const err = new Error('Error performing delete' + (serverMsg ? `: ${serverMsg}` : ''));
-        err.status = res.status;
-        throw err;
-    }
-
-    if (res.ok && (data.status === 'success' || data.code === 'BACKUP_DELETEE_OK')) {
-        // Success
-        return data?.message ? { message: data.message } : true;
-    } else {
-        // Failed with JSON error message
-        return data?.message ? { message: data.message } : false;
-    }
-}
-
-// -------------------------------------------------------
-// Check Health
-// -------------------------------------------------------
-export async function checkHealth() {
-    let res;
-
-    try {
-        // Fetch data
-        res = await fetch(`/api/health`, {
-            method: 'GET',
-            headers: { 'Accept': 'application/json' }
-        });
-
-    } catch (err) {
-        const msg = 'Network error while performing health check' + (err?.message ? `: ${err.message}` : '');
-        throw new Error(msg, { cause: err });
-    }
-
-    // Success without JSON
-    if (res.status === 204) {
-        return true;
-    }
-
-    // Check content-type to avoid parsing errors
-    const contentType = res.headers.get("content-type") || "";
-    if (!contentType.includes("application/json")) {
-        const err = new Error(`Error performing health check: ${res.status}: ${res.statusText || 'Unexpected response'}`);
-        err.status = res.status;
-        throw err;
-    }
-
-    // Check JSON
-    let data = {};
-    try {
-        data = await res.json();
-    } catch {
-        throw new Error('Error performing health check: Invalid JSON payload');
-    }
-
-    // Check JSON errors
-    if (!res.ok) {
-        const serverMsg =
-            data?.detail?.message?.trim()
-            || (typeof data?.detail === 'string' ? data.detail.trim() : '')
-            || data?.message?.trim()
-            || data?.error?.message?.trim()
-            || (typeof data?.error === 'string' ? data.error.trim() : '');
-        const err = new Error('Error performing health check' + (serverMsg ? `: ${serverMsg}` : ''));
-        err.status = res.status;
-        throw err;
-    }
+    const data = await apiPost(
+        "/api/backup/delete",
+        { backup_id: id },
+        "Error performing delete"
+    );
 
-    return (data ?? []);
+    return data?.message ? { message: data.message } : true;
 }
index ccd3b16edf0d85b2e5a3a905cb77f2e769abb7ec..0247a83ca236b770009a1434b9ffc8cf0d3513ec 100644 (file)
 
             <div class="modal-footer modal-buttons">
                 <button type="button" class="btn btn-outline-primary" data-action="closeHealthModal">
-                    <span class="label">Close</span>
+                    <i class="bi bi-x-circle me-1"></i><span class="label">Close</span>
                 </button>
             </div>
         </div>