Skip to content

Commit af882be

Browse files
sarg3ntclaude
andcommitted
fix: hide sidebar nav until plugins enabled, route to first active plugin
- Hide Dashboard link and sidebar nav items when no plugins are enabled - OverviewPage (/) now redirects to the first enabled plugin page instead of always going to /dashboards/dashboard - When no plugins are enabled, redirect to /settings/plugins - Add hasAnyEnabledIntegration() and integrationPath() helpers Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
1 parent 6f5ef33 commit af882be

2 files changed

Lines changed: 93 additions & 10 deletions

File tree

gearbox/internal/framework/templates/layouts/base.templ

Lines changed: 55 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1213,10 +1213,12 @@ templ Sidebar(user *models.User, currentPath string) {
12131213
</div>
12141214
</div>
12151215

1216-
<!-- Navigation -->
1216+
<!-- Navigation (only show items when plugins are enabled) -->
12171217
<nav class="flex-1 py-4">
12181218
<ul id="sidebar-nav-list" class="space-y-1">
1219-
@SidebarLink("/", "Dashboard", SidebarIconDashboard(), currentPath)
1219+
if hasAnyEnabledIntegration(ctx) {
1220+
@SidebarLink("/", "Dashboard", SidebarIconDashboard(), currentPath)
1221+
}
12201222
@OrderedIntegrationLinks(currentPath)
12211223
</ul>
12221224
</nav>
@@ -1570,6 +1572,57 @@ templ SidebarLinkWithIntegration(href string, label string, icon templ.Component
15701572
}
15711573
}
15721574

1575+
// hasAnyEnabledIntegration checks if any integration (plugin) is enabled in the current context.
1576+
func hasAnyEnabledIntegration(ctx context.Context) bool {
1577+
integrations, ok := auth.GetPluginOrderFromContext(ctx)
1578+
if !ok {
1579+
return false
1580+
}
1581+
for _, integration := range integrations {
1582+
if integration.Enabled {
1583+
return true
1584+
}
1585+
}
1586+
return false
1587+
}
1588+
1589+
// integrationPath returns the URL path for a given integration name.
1590+
func integrationPath(name string) string {
1591+
switch name {
1592+
case "metrics":
1593+
return "/history"
1594+
case "logs":
1595+
return "/logs"
1596+
case "services":
1597+
return "/services"
1598+
case "certificates":
1599+
return "/certificates"
1600+
case "traffic":
1601+
return "/traffic"
1602+
case "alerts":
1603+
return "/alerts"
1604+
case "os_updates":
1605+
return "/os-updates"
1606+
default:
1607+
return "/"
1608+
}
1609+
}
1610+
1611+
// firstEnabledIntegrationPath returns the URL path for the first enabled integration.
1612+
// Returns "/" if no integrations are enabled.
1613+
func firstEnabledIntegrationPath(ctx context.Context) string {
1614+
integrations, ok := auth.GetPluginOrderFromContext(ctx)
1615+
if !ok {
1616+
return "/"
1617+
}
1618+
for _, integration := range integrations {
1619+
if integration.Enabled {
1620+
return integrationPath(integration.Name)
1621+
}
1622+
}
1623+
return "/"
1624+
}
1625+
15731626
// canViewIntegration checks if the user has permission to view an integration.
15741627
// Maps integration names to component View permissions.
15751628
func canViewIntegration(ctx context.Context, integrationName string) bool {

gearbox/internal/plugins/dashboard/handlers.go

Lines changed: 38 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@ package dashboard
33
import (
44
"net/http"
55

6+
"github.com/sarg3nt/gearbox/internal/framework/auth"
67
"github.com/sarg3nt/gearbox/internal/framework/plugin"
78
"github.com/sarg3nt/gearbox/internal/framework/services"
89
)
@@ -19,8 +20,7 @@ func NewHandlers(deps plugin.Dependencies) *Handlers {
1920
}
2021

2122
// OverviewPage serves the main dashboard page.
22-
// It redirects to the default dashboard which uses the widget system.
23-
// If no servers are configured, redirects to the servers settings page.
23+
// It redirects to the first enabled plugin page, or to setup pages if not configured.
2424
func (h *Handlers) OverviewPage(w http.ResponseWriter, r *http.Request) {
2525
// Get enabled servers using the ServerAdapter
2626
serverAdapter, ok := h.deps.Servers.(*services.ServerAdapter)
@@ -37,14 +37,44 @@ func (h *Handlers) OverviewPage(w http.ResponseWriter, r *http.Request) {
3737
return
3838
}
3939

40-
// Redirect to the default dashboard (widget-based dashboard)
41-
http.Redirect(w, r, "/dashboards/dashboard", http.StatusSeeOther)
40+
// Redirect to the first enabled plugin page if available
41+
if integrations, ok := auth.GetPluginOrderFromContext(r.Context()); ok {
42+
for _, integration := range integrations {
43+
if integration.Enabled {
44+
http.Redirect(w, r, integrationPathFromName(integration.Name), http.StatusSeeOther)
45+
return
46+
}
47+
}
48+
}
49+
50+
// No plugins enabled — send to plugins settings page
51+
http.Redirect(w, r, "/settings/plugins", http.StatusSeeOther)
52+
}
53+
54+
// integrationPathFromName maps an integration name to its URL path.
55+
func integrationPathFromName(name string) string {
56+
switch name {
57+
case "metrics":
58+
return "/history"
59+
case "logs":
60+
return "/logs"
61+
case "services":
62+
return "/services"
63+
case "certificates":
64+
return "/certificates"
65+
case "traffic":
66+
return "/traffic"
67+
case "alerts":
68+
return "/alerts"
69+
case "os_updates":
70+
return "/os-updates"
71+
default:
72+
return "/dashboards/dashboard"
73+
}
4274
}
4375

4476
// StatusGridPage serves the status grid page.
45-
// For now, redirects to the main dashboard. In the future, this could
46-
// render a different dashboard layout focused on status grid view.
77+
// For now, redirects to the overview page which handles routing.
4778
func (h *Handlers) StatusGridPage(w http.ResponseWriter, r *http.Request) {
48-
// Redirect to main dashboard for now
49-
http.Redirect(w, r, "/dashboards/dashboard", http.StatusSeeOther)
79+
http.Redirect(w, r, "/", http.StatusSeeOther)
5080
}

0 commit comments

Comments
 (0)