]> git.giorgioravera.it Git - network-manager.git/commitdiff
Added icons for options & included external types for dns master
authorGiorgio Ravera <giorgio.ravera@gmail.com>
Tue, 10 Mar 2026 19:41:47 +0000 (20:41 +0100)
committerGiorgio Ravera <giorgio.ravera@gmail.com>
Tue, 10 Mar 2026 19:41:47 +0000 (20:41 +0100)
backend/db/aliases.py
backend/db/hosts.py
frontend/aliases.html
frontend/css/layout.css
frontend/hosts.html
frontend/js/aliases.js
frontend/js/hosts.js

index 0cbaf2a100eb94e2917ed7ac20329a75c52c0012..4c5a7cd30f08f41c3510fc629b272ee0cabc3c0b 100644 (file)
@@ -160,10 +160,12 @@ def init_db_alias_table(cur):
             name TEXT NOT NULL UNIQUE,
             target TEXT NOT NULL,
             note TEXT,
-            ssl_enabled INTEGER NOT NULL DEFAULT 0
+            ssl_enabled INTEGER NOT NULL DEFAULT 0,
+            external_mode INTEGER NOT NULL DEFAULT 0,
+            last_updated TIMESTAMP DEFAULT CURRENT_TIMESTAMP
         );
     """)
     cur.execute("CREATE INDEX idx_aliases_name ON aliases(name);")
 
     logger.info("ALIASES DB: Database initialized successfully for %s", settings.DOMAIN)
-    logger.info("ALIASES DB: Public IP: %s", settings.PUBLIC_IP)
+    logger.info("ALIASES DB: Public IP: %s", settings.EXTERNAL_NAME)
index 7a5ad05172064cb95ccab6983c1ea2d25c5187df..6decded53f71db2bf35008a905febbd78849962f 100644 (file)
@@ -208,7 +208,9 @@ def init_db_hosts_table(cur):
             ipv6 TEXT,
             mac TEXT,
             note TEXT,
-            ssl_enabled INTEGER NOT NULL DEFAULT 0
+            ssl_enabled INTEGER NOT NULL DEFAULT 0,
+            external_mode INTEGER NOT NULL DEFAULT 0,
+            last_updated TIMESTAMP DEFAULT CURRENT_TIMESTAMP
         );
     """)
     cur.execute("CREATE INDEX idx_hosts_name ON hosts(name);")
index 75f3355100ed78d17c1fc2eb1659df46f278af2a..d30267ca88c08ad119c593da23b1bc653050368c 100644 (file)
                 <th data-type="string" data-sortable="true">Alias    <span class="sort-arrow" aria-hidden="true"></span></th>
                 <th data-type="string" data-sortable="true">Target   <span class="sort-arrow" aria-hidden="true"></span></th>
                 <th data-type="string" data-sortable="true">Note     <span class="sort-arrow" aria-hidden="true"></span></th>
-                <th data-type="string" data-sortable="true">SSL      <span class="sort-arrow" aria-hidden="true"></span></th>
+                <th data-type="string" data-sortable="true">Options  <span class="sort-arrow" aria-hidden="true"></span></th>
                 <th data-type="string" data-sortable="false">Actions <span class="sort-arrow" aria-hidden="true"></span></th>
             </tr>
         </thead>
index b3458734428d3a00d0fddac9072098d69120d27e..3d59efd9878e6bc32dfa5cbf8019a35604e1507b 100644 (file)
@@ -266,12 +266,18 @@ select.form-select:focus,
 
 .icon-static {
     --icon-color-hover: var(--icon-color);
+    margin-right: 6px;
 }
 
 .icon-action {
     cursor: pointer;
 }
 
+.icon-placeholder {
+    opacity: 0;
+    pointer-events: none;
+}
+
 /* ================================
    Table
    ================================ */
index bf7dfab520915072d3c35dac95d506fbad49b3c4..8d8809dc31a8d8c2e25e409548047f4a41598c27 100644 (file)
                 <th data-type="ipv6"   data-sortable="true">IPv6     <span class="sort-arrow" aria-hidden="true"></span></th>
                 <th data-type="mac"    data-sortable="true">MAC      <span class="sort-arrow" aria-hidden="true"></span></th>
                 <th data-type="string" data-sortable="true">Note     <span class="sort-arrow" aria-hidden="true"></span></th>
-                <th data-type="string" data-sortable="true">SSL      <span class="sort-arrow" aria-hidden="true"></span></th>
+                <th data-type="string" data-sortable="true">Options  <span class="sort-arrow" aria-hidden="true"></span></th>
                 <th data-type="string" data-sortable="false">Actions <span class="sort-arrow" aria-hidden="true"></span></th>
             </tr>
         </thead>
index 96017566ade7a72194e4ed4e31fd9d7d4a21194e..72d24d5a1d26fd979afbc9374df60135b87f53ca 100644 (file)
@@ -107,71 +107,113 @@ async function loadAliases() {
             tr.appendChild(td);
         }
 
-        // SSL (icon)
+        // Options (icons)
         {
             const td = document.createElement("td");
+            td.style.textAlign = "center";
+            td.style.verticalAlign = "middle";
+
+            //
+            // SSL icon
+            //
             const sslEnabled = !!h.ssl_enabled;
             td.setAttribute("data-value", sslEnabled ? "true" : "false");
             td.setAttribute("aria-label", sslEnabled ? "SSL attivo" : "SSL non attivo");
-            td.style.textAlign = "center";
-            td.style.verticalAlign = "middle";
+            const icon = document.createElement("i");
             if (sslEnabled) {
-                const icon = document.createElement("i");
                 icon.className = "bi bi-shield-lock-fill icon icon-static";
                 icon.setAttribute("aria-hidden", "true");
+                icon.setAttribute("title", "SSL certificate enabled");
+            } else {
+                icon.className = "bi bi-shield-lock-fill icon icon-static icon-placeholder";
+                icon.setAttribute("aria-hidden", "true");
+            }
+            td.appendChild(icon);
+
+            //
+            // external_mode icon
+            //
+            const ext = (h.external_mode ?? "").toString();
+            let aria = "";
+            let iconClass = "";
+            switch (ext) {
+                case "0":
+                    // Only local (CNAME record internally resolved)
+                    aria = "Only local (CNAME record internally resolved)";
+                    iconClass = "bi bi-hdd-network";
+                    break;
+
+                case "1":
+                    // Local and external (CNAME record internally resolved, CNAME externally)
+                    aria = "Internal and external are identical";
+                    iconClass = "bi bi-globe2";
+                    break;
+
+                case "2":
+                    // CNAME -> DDNS / external_name
+                    aria = "External is a CNAME to external_name";
+                    iconClass = "bi bi-link-45deg";
+                    break;
+            }
+            if (iconClass) {
+                const icon = document.createElement("i");
+                icon.className = iconClass + " icon icon-static";
+                icon.setAttribute("aria-hidden", "true");
+                icon.setAttribute("title", aria);
                 td.appendChild(icon);
             }
+
             tr.appendChild(td);
         }
 
-    // Actions
-    {
-        const td = document.createElement("td");
-        td.className = "actions";
-        td.style.textAlign = "center";
-        td.style.verticalAlign = "middle";
-
-        const id = Number(h.id);
-
-        // Usa elementi reali invece di innerHTML con entity
-        const editSpan = document.createElement("span");
-        editSpan.className = "action-icon";
-        editSpan.setAttribute("role", "button");
-        editSpan.tabIndex = 0;
-        editSpan.title = "Edit alias";
-        editSpan.setAttribute("aria-label", "Edit alias");
-        editSpan.setAttribute("data-bs-toggle", "modal");
-        editSpan.setAttribute("data-bs-target", "#addAliasModal");
-        editSpan.setAttribute("data-action", "edit");
-        editSpan.setAttribute("data-alias-id", String(id));
+        // Actions
         {
-            const i = document.createElement("i");
-            i.className = "bi bi-pencil-fill icon icon-action";
-            i.setAttribute("aria-hidden", "true");
-            editSpan.appendChild(i);
-        }
+            const td = document.createElement("td");
+            td.className = "actions";
+            td.style.textAlign = "center";
+            td.style.verticalAlign = "middle";
 
-        const delSpan = document.createElement("span");
-        delSpan.className = "action-icon";
-        delSpan.setAttribute("role", "button");
-        delSpan.tabIndex = 0;
-        delSpan.title = "Delete alias";
-        delSpan.setAttribute("aria-label", "Delete alias");
-        delSpan.setAttribute("data-action", "delete");
-        delSpan.setAttribute("data-alias-id", String(id));
-        {
-            const i = document.createElement("i");
-            i.className = "bi bi-trash-fill icon icon-action";
-            i.setAttribute("aria-hidden", "true");
-            delSpan.appendChild(i);
-        }
+            const id = Number(h.id);
+
+            // Usa elementi reali invece di innerHTML con entity
+            const editSpan = document.createElement("span");
+            editSpan.className = "action-icon";
+            editSpan.setAttribute("role", "button");
+            editSpan.tabIndex = 0;
+            editSpan.title = "Edit alias";
+            editSpan.setAttribute("aria-label", "Edit alias");
+            editSpan.setAttribute("data-bs-toggle", "modal");
+            editSpan.setAttribute("data-bs-target", "#addAliasModal");
+            editSpan.setAttribute("data-action", "edit");
+            editSpan.setAttribute("data-alias-id", String(id));
+            {
+                const i = document.createElement("i");
+                i.className = "bi bi-pencil-fill icon icon-action";
+                i.setAttribute("aria-hidden", "true");
+                editSpan.appendChild(i);
+            }
 
-        td.appendChild(editSpan);
-        td.appendChild(delSpan);
-        tr.appendChild(td);
-    }
+            const delSpan = document.createElement("span");
+            delSpan.className = "action-icon";
+            delSpan.setAttribute("role", "button");
+            delSpan.tabIndex = 0;
+            delSpan.title = "Delete alias";
+            delSpan.setAttribute("aria-label", "Delete alias");
+            delSpan.setAttribute("data-action", "delete");
+            delSpan.setAttribute("data-alias-id", String(id));
+            {
+                const i = document.createElement("i");
+                i.className = "bi bi-trash-fill icon icon-action";
+                i.setAttribute("aria-hidden", "true");
+                delSpan.appendChild(i);
+            }
+
+            td.appendChild(editSpan);
+            td.appendChild(delSpan);
+            tr.appendChild(td);
+        }
 
-    frag.appendChild(tr);
+        frag.appendChild(tr);
     });
 
     // publish all rows
index 6c3b54a6d9e21b9a623243443846add6cb7100c5..834822c3c9e1e0ce96c299f5647bf4824b798f56 100644 (file)
@@ -126,71 +126,113 @@ async function loadHosts() {
             tr.appendChild(td);
         }
 
-        // SSL (icon)
+        // Options (icons)
         {
             const td = document.createElement("td");
+            td.style.textAlign = "center";
+            td.style.verticalAlign = "middle";
+
+            //
+            // SSL icon
+            //
             const sslEnabled = !!h.ssl_enabled;
             td.setAttribute("data-value", sslEnabled ? "true" : "false");
             td.setAttribute("aria-label", sslEnabled ? "SSL attivo" : "SSL non attivo");
-            td.style.textAlign = "center";
-            td.style.verticalAlign = "middle";
+            const icon = document.createElement("i");
             if (sslEnabled) {
-                const icon = document.createElement("i");
                 icon.className = "bi bi-shield-lock-fill icon icon-static";
                 icon.setAttribute("aria-hidden", "true");
+                icon.setAttribute("title", "SSL certificate enabled");
+            } else {
+                icon.className = "bi bi-shield-lock-fill icon icon-static icon-placeholder";
+                icon.setAttribute("aria-hidden", "true");
+            }
+            td.appendChild(icon);
+
+            //
+            // external_mode icon
+            //
+            const ext = (h.external_mode ?? "").toString();
+            let aria = "";
+            let iconClass = "";
+            switch (ext) {
+                case "0":
+                    // Only local (A record internally resolved)
+                    aria = "Only local (A record internally resolved)";
+                    iconClass = "bi bi-hdd-network";
+                    break;
+
+                case "1":
+                    // Local and external (A record internally resolved, A externally)
+                    aria = "Internal and external are identical";
+                    iconClass = "bi bi-globe2";
+                    break;
+
+                case "2":
+                    // CNAME -> DDNS / external_name
+                    aria = "External is a CNAME to external_name";
+                    iconClass = "bi bi-link-45deg";
+                    break;
+            }
+            if (iconClass) {
+                const icon = document.createElement("i");
+                icon.className = iconClass + " icon icon-static";
+                icon.setAttribute("aria-hidden", "true");
+                icon.setAttribute("title", aria);
                 td.appendChild(icon);
             }
+
             tr.appendChild(td);
         }
 
-    // Actions
-    {
-        const td = document.createElement("td");
-        td.className = "actions";
-        td.style.textAlign = "center";
-        td.style.verticalAlign = "middle";
-
-        const id = Number(h.id);
-
-        // Usa elementi reali invece di innerHTML con entity
-        const editSpan = document.createElement("span");
-        editSpan.className = "action-icon";
-        editSpan.setAttribute("role", "button");
-        editSpan.tabIndex = 0;
-        editSpan.title = "Edit host";
-        editSpan.setAttribute("aria-label", "Edit host");
-        editSpan.setAttribute("data-bs-toggle", "modal");
-        editSpan.setAttribute("data-bs-target", "#addHostModal");
-        editSpan.setAttribute("data-action", "edit");
-        editSpan.setAttribute("data-host-id", String(id));
+        // Actions
         {
-            const i = document.createElement("i");
-            i.className = "bi bi-pencil-fill icon icon-action";
-            i.setAttribute("aria-hidden", "true");
-            editSpan.appendChild(i);
-        }
+            const td = document.createElement("td");
+            td.className = "actions";
+            td.style.textAlign = "center";
+            td.style.verticalAlign = "middle";
 
-        const delSpan = document.createElement("span");
-        delSpan.className = "action-icon";
-        delSpan.setAttribute("role", "button");
-        delSpan.tabIndex = 0;
-        delSpan.title = "Delete host";
-        delSpan.setAttribute("aria-label", "Delete host");
-        delSpan.setAttribute("data-action", "delete");
-        delSpan.setAttribute("data-host-id", String(id));
-        {
-            const i = document.createElement("i");
-            i.className = "bi bi-trash-fill icon icon-action";
-            i.setAttribute("aria-hidden", "true");
-            delSpan.appendChild(i);
-        }
+            const id = Number(h.id);
+
+            // Usa elementi reali invece di innerHTML con entity
+            const editSpan = document.createElement("span");
+            editSpan.className = "action-icon";
+            editSpan.setAttribute("role", "button");
+            editSpan.tabIndex = 0;
+            editSpan.title = "Edit host";
+            editSpan.setAttribute("aria-label", "Edit host");
+            editSpan.setAttribute("data-bs-toggle", "modal");
+            editSpan.setAttribute("data-bs-target", "#addHostModal");
+            editSpan.setAttribute("data-action", "edit");
+            editSpan.setAttribute("data-host-id", String(id));
+            {
+                const i = document.createElement("i");
+                i.className = "bi bi-pencil-fill icon icon-action";
+                i.setAttribute("aria-hidden", "true");
+                editSpan.appendChild(i);
+            }
 
-        td.appendChild(editSpan);
-        td.appendChild(delSpan);
-        tr.appendChild(td);
-    }
+            const delSpan = document.createElement("span");
+            delSpan.className = "action-icon";
+            delSpan.setAttribute("role", "button");
+            delSpan.tabIndex = 0;
+            delSpan.title = "Delete host";
+            delSpan.setAttribute("aria-label", "Delete host");
+            delSpan.setAttribute("data-action", "delete");
+            delSpan.setAttribute("data-host-id", String(id));
+            {
+                const i = document.createElement("i");
+                i.className = "bi bi-trash-fill icon icon-action";
+                i.setAttribute("aria-hidden", "true");
+                delSpan.appendChild(i);
+            }
+
+            td.appendChild(editSpan);
+            td.appendChild(delSpan);
+            tr.appendChild(td);
+        }
 
-    frag.appendChild(tr);
+        frag.appendChild(tr);
     });
 
     // publish all rows