mirror of
https://github.com/kernelkit/infix.git
synced 2026-07-22 01:13:00 +02:00
webui: add network browser shortcut to topbar and nav
Surface the mDNS network browser (netbrowse at network.local) from the WebUI: a radar icon in the topbar and a Network Browser entry under Status > Network, both opening it in a new tab. Like the console, this is a config-gated capability; fold the console and netbrowse enable flags into a single infix-services web read at login (DetectWebShortcuts) and render each entry only when enabled, fail-closed on a read error. The link is a static https://network.local/ since netbrowse is a fixed name-based vhost. Signed-off-by: Joachim Wiberg <troglobit@gmail.com>
This commit is contained in:
@@ -74,9 +74,12 @@ func (h *LoginHandler) DoLogin(w http.ResponseWriter, r *http.Request) {
|
||||
|
||||
// Probe optional features once at login and bake into the session.
|
||||
caps := handlers.DetectCapabilities(ctx, h.RC)
|
||||
// The web console (ttyd) is config-gated; fold it into the same feature
|
||||
// map so templates gate on .Capabilities.Has "console".
|
||||
caps.Features()["console"] = handlers.DetectConsole(ctx, h.RC)
|
||||
// The external web-app shortcuts (console/ttyd, netbrowse) are
|
||||
// config-gated; fold them into the same feature map so templates gate
|
||||
// on .Capabilities.Has "console" / "netbrowse".
|
||||
console, netbrowse := handlers.DetectWebShortcuts(ctx, h.RC)
|
||||
caps.Features()["console"] = console
|
||||
caps.Features()["netbrowse"] = netbrowse
|
||||
|
||||
// Trigger any post-login hooks (e.g. schema sync) with full credentials.
|
||||
if h.OnLogin != nil {
|
||||
|
||||
@@ -70,26 +70,31 @@ type yangLibrary struct {
|
||||
} `json:"ietf-yang-library:yang-library"`
|
||||
}
|
||||
|
||||
// webConsoleConfig mirrors the slice of infix-services we need for the
|
||||
// console gate.
|
||||
type webConsoleConfig struct {
|
||||
// webConfig mirrors the slice of infix-services we need to gate the
|
||||
// external web-app shortcuts (console, netbrowse).
|
||||
type webConfig struct {
|
||||
Web struct {
|
||||
Console struct {
|
||||
Enabled bool `json:"enabled"`
|
||||
} `json:"console"`
|
||||
Netbrowse struct {
|
||||
Enabled bool `json:"enabled"`
|
||||
} `json:"netbrowse"`
|
||||
} `json:"infix-services:web"`
|
||||
}
|
||||
|
||||
// DetectConsole reports whether the web console (ttyd on :7681) is enabled
|
||||
// in config, so the UI can show or hide the terminal entry. Fails closed:
|
||||
// a read error hides the entry rather than offering a dead link.
|
||||
func DetectConsole(ctx context.Context, rc restconf.Fetcher) bool {
|
||||
var cfg webConsoleConfig
|
||||
// DetectWebShortcuts reports whether the web console (ttyd on :7681) and
|
||||
// the mDNS network browser (netbrowse at network.local) are enabled in
|
||||
// config, so the UI can show or hide their shortcuts. One read covers
|
||||
// both. Fails closed: a read error hides both rather than offering a
|
||||
// dead link.
|
||||
func DetectWebShortcuts(ctx context.Context, rc restconf.Fetcher) (console, netbrowse bool) {
|
||||
var cfg webConfig
|
||||
if err := rc.Get(ctx, "/data/infix-services:web", &cfg); err != nil {
|
||||
log.Printf("web/console config: %v (console entry hidden)", err)
|
||||
return false
|
||||
log.Printf("web config: %v (console/netbrowse shortcuts hidden)", err)
|
||||
return false, false
|
||||
}
|
||||
return cfg.Web.Console.Enabled
|
||||
return cfg.Web.Console.Enabled, cfg.Web.Netbrowse.Enabled
|
||||
}
|
||||
|
||||
func DetectCapabilities(ctx context.Context, rc restconf.Fetcher) *Capabilities {
|
||||
|
||||
@@ -2133,8 +2133,8 @@ details[open] > .cfg-multi-summary {
|
||||
border-color: var(--fg-muted);
|
||||
}
|
||||
|
||||
/* Web console (terminal) shortcut in the topbar */
|
||||
.topbar-console {
|
||||
/* External web-app shortcuts (console, network browser) in the topbar */
|
||||
.topbar-link {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
@@ -2144,7 +2144,7 @@ details[open] > .cfg-multi-summary {
|
||||
text-decoration: none;
|
||||
transition: color 0.15s, background 0.15s;
|
||||
}
|
||||
.topbar-console:hover {
|
||||
.topbar-link:hover {
|
||||
color: var(--fg);
|
||||
background: var(--border);
|
||||
}
|
||||
|
||||
@@ -29,6 +29,7 @@ untouched.
|
||||
| logs.svg | scroll-text |
|
||||
| mdns.svg | radio |
|
||||
| nacm.svg | users |
|
||||
| netbrowse.svg | radar |
|
||||
| ntp.svg | clock |
|
||||
| routes.svg | git-compare-arrows |
|
||||
| routing.svg | git-compare-arrows |
|
||||
|
||||
@@ -0,0 +1 @@
|
||||
<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="M19.07 4.93A10 10 0 0 0 6.99 3.34"/><path d="M4 6h.01"/><path d="M2.29 9.62A10 10 0 1 0 21.31 8.35"/><path d="M16.24 7.76A6 6 0 1 0 8.23 16.67"/><path d="M12 18h.01"/><path d="M17.99 11.66A6 6 0 0 1 15.77 16.67"/><circle cx="12" cy="12" r="2"/><path d="m13.41 10.59 5.66-5.66"/></svg>
|
||||
|
After Width: | Height: | Size: 475 B |
@@ -24,10 +24,18 @@
|
||||
</button>
|
||||
<img src="/assets/img/logo.png" alt="Infix" class="topbar-logo">
|
||||
<div class="topbar-right">
|
||||
{{if .Capabilities.Has "netbrowse"}}
|
||||
{{/* mDNS network browser — fixed network.local vhost, so a static
|
||||
href (no JS, no CSP concern). */}}
|
||||
<a class="topbar-link" href="https://network.local/" target="_blank" rel="noopener"
|
||||
title="Browse mDNS neighbors (network.local) in a new tab" aria-label="Network browser">
|
||||
{{template "icon-radar"}}
|
||||
</a>
|
||||
{{end}}
|
||||
{{if .Capabilities.Has "console"}}
|
||||
{{/* Web console (ttyd) on :7681. href is set by JS from the current
|
||||
hostname since the port differs and CSP forbids inline script. */}}
|
||||
<a class="topbar-console" data-console-link href="#" target="_blank" rel="noopener"
|
||||
<a class="topbar-link" data-console-link href="#" target="_blank" rel="noopener"
|
||||
title="Open web console (terminal) in a new tab" aria-label="Web console">
|
||||
{{template "icon-terminal"}}
|
||||
</a>
|
||||
|
||||
@@ -11,6 +11,7 @@
|
||||
{{define "icon-reset"}}<svg width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><path d="M9 14 4 9l5-5" /><path d="M4 9h10.5a5.5 5.5 0 0 1 5.5 5.5a5.5 5.5 0 0 1-5.5 5.5H11" /></svg>{{end}}
|
||||
{{define "icon-menu"}}<svg width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-linecap="round" stroke-linejoin="round" stroke-width="2"><path d="M4 5h16" /><path d="M4 12h16" /><path d="M4 19h16" /></svg>{{end}}
|
||||
{{define "icon-terminal"}}<svg width="18" height="18" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-linecap="round" stroke-linejoin="round" stroke-width="2" aria-hidden="true"><polyline points="4 17 10 11 4 5" /><line x1="12" x2="20" y1="19" y2="19" /></svg>{{end}}
|
||||
{{define "icon-radar"}}<svg width="18" height="18" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-linecap="round" stroke-linejoin="round" stroke-width="2" aria-hidden="true"><path d="M19.07 4.93A10 10 0 0 0 6.99 3.34" /><path d="M4 6h.01" /><path d="M2.29 9.62A10 10 0 1 0 21.31 8.35" /><path d="M16.24 7.76A6 6 0 1 0 8.23 16.67" /><path d="M12 18h.01" /><path d="M17.99 11.66A6 6 0 0 1 15.77 16.67" /><circle cx="12" cy="12" r="2" /><path d="m13.41 10.59 5.66-5.66" /></svg>{{end}}
|
||||
{{define "icon-user"}}<svg width="15" height="15" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-linecap="round" stroke-linejoin="round" stroke-width="2" aria-hidden="true"><path d="M19 21v-2a4 4 0 0 0-4-4H9a4 4 0 0 0-4 4v2" /><circle cx="12" cy="7" r="4" /></svg>{{end}}
|
||||
{{define "icon-user-lg"}}<svg width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-linecap="round" stroke-linejoin="round" stroke-width="2" aria-hidden="true"><path d="M19 21v-2a4 4 0 0 0-4-4H9a4 4 0 0 0-4 4v2" /><circle cx="12" cy="7" r="4" /></svg>{{end}}
|
||||
{{define "icon-chevron-down"}}<svg width="12" height="12" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-linecap="round" stroke-linejoin="round" class="chevron" aria-hidden="true" stroke-width="2.5"><path d="m6 9 6 6 6-6" /></svg>{{end}}
|
||||
|
||||
@@ -103,6 +103,16 @@
|
||||
mDNS
|
||||
</a>
|
||||
</li>
|
||||
{{if .Capabilities.Has "netbrowse"}}
|
||||
{{/* External link to the mDNS network browser at network.local
|
||||
(new tab); not an htmx nav. */}}
|
||||
<li>
|
||||
<a href="https://network.local/" target="_blank" rel="noopener" class="nav-link">
|
||||
<span class="nav-icon" style="--icon: url('/assets/img/icons/netbrowse.svg')"></span>
|
||||
Network Browser
|
||||
</a>
|
||||
</li>
|
||||
{{end}}
|
||||
<li>
|
||||
<a href="/ntp"
|
||||
hx-get="/ntp"
|
||||
|
||||
Reference in New Issue
Block a user