Skip to content

Commit e2e9e97

Browse files
sarg3ntclaude
andcommitted
fix: empty default dashboard and auto-redirect to edit mode with widget palette
The default dashboard referenced a non-existent `alert-banner` widget type, causing a "Widget Error" on first load. Now the default dashboard starts empty, and empty editable dashboards auto-redirect to the editor with the widget palette open so users can immediately start adding widgets. Closes #6 Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
1 parent 3eb9d45 commit e2e9e97

4 files changed

Lines changed: 37 additions & 24 deletions

File tree

gearbox/internal/framework/dashboard/storage.go

Lines changed: 5 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -209,7 +209,9 @@ func (s *Storage) CreateDefaultDashboard() error {
209209
return nil
210210
}
211211

212-
// Create default dashboard
212+
// Create default dashboard with no widgets.
213+
// Empty dashboards auto-redirect to edit mode with the widget palette open,
214+
// so users can immediately start adding widgets.
213215
dashboard := &Dashboard{
214216
Version: "1.0",
215217
Name: "Dashboard",
@@ -221,25 +223,8 @@ func (s *Storage) CreateDefaultDashboard() error {
221223
Columns: 12,
222224
Gap: 4,
223225
},
224-
Widgets: []Widget{
225-
{
226-
ID: "welcome-1",
227-
Type: "alert-banner",
228-
Position: WidgetPosition{
229-
Row: 1,
230-
Column: 1,
231-
Width: 12,
232-
Height: "auto",
233-
},
234-
Config: map[string]interface{}{
235-
"severity": "info",
236-
"message": "Welcome to Gearbox! This is your default dashboard. You can customize it by adding widgets.",
237-
"icon": "info",
238-
"dismissible": true,
239-
},
240-
},
241-
},
242-
Slug: "dashboard",
226+
Widgets: []Widget{},
227+
Slug: "dashboard",
243228
}
244229

245230
// Save dashboard

gearbox/internal/framework/handler/dashboard.go

Lines changed: 10 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -120,6 +120,12 @@ func (h *DashboardHandler) ViewDashboard(w http.ResponseWriter, r *http.Request)
120120
return
121121
}
122122

123+
// If dashboard is empty and editable, redirect to edit mode with palette open
124+
if dash.Editable && len(dash.Widgets) == 0 {
125+
http.Redirect(w, r, "/dashboards/"+slug+"/edit?open_palette=1", http.StatusSeeOther)
126+
return
127+
}
128+
123129
// Render dashboard
124130
content, err := h.renderer.Render(r.Context(), dash, h.boxID, h.userID)
125131
if err != nil {
@@ -169,11 +175,14 @@ func (h *DashboardHandler) EditDashboardPage(w http.ResponseWriter, r *http.Requ
169175
// Get available widgets
170176
widgets := h.widgetRegistry.List()
171177

178+
// Check if palette should be auto-opened (e.g., redirected from empty dashboard)
179+
openPalette := r.URL.Query().Get("open_palette") == "1"
180+
172181
// Get user from context
173182
user, _ := auth.GetUserFromContext(r.Context())
174183

175184
// Render editor with live content
176-
component := pages.DashboardEditorPage(dash, content, widgets, user, r.URL.Path)
185+
component := pages.DashboardEditorPage(dash, content, widgets, user, r.URL.Path, openPalette)
177186
if err := component.Render(r.Context(), w); err != nil {
178187
h.logger.Error("failed to render dashboard editor", "error", err)
179188
http.Error(w, "Failed to render page", http.StatusInternalServerError)

gearbox/internal/framework/templates/pages/dashboard_editor.templ

Lines changed: 11 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@ import (
1010
)
1111

1212
// DashboardEditorPage renders the visual dashboard editor with live widget preview
13-
templ DashboardEditorPage(dash *dashboard.Dashboard, content templ.Component, widgets []*widget.WidgetDefinition, user *models.User, currentPath string) {
13+
templ DashboardEditorPage(dash *dashboard.Dashboard, content templ.Component, widgets []*widget.WidgetDefinition, user *models.User, currentPath string, openPalette bool) {
1414
@layouts.Base("Edit Dashboard", user, currentPath) {
1515
<!-- Widget Palette CSS -->
1616
<link rel="stylesheet" href="/static/css/dashboard/palette.css"/>
@@ -49,8 +49,8 @@ templ DashboardEditorPage(dash *dashboard.Dashboard, content templ.Component, wi
4949
</div>
5050
</div>
5151

52-
<!-- Widget Palette Panel (collapsible) -->
53-
<div id="widget-palette-panel" class="hidden mb-4 bg-white dark:bg-slate-900 border border-gray-300 dark:border-slate-600 rounded-lg shadow-lg">
52+
<!-- Widget Palette Panel (collapsible, auto-opened when dashboard is empty) -->
53+
<div id="widget-palette-panel" class={ widgetPaletteClass(openPalette) }>
5454
<!-- Fixed Header -->
5555
<div class="p-4 border-b border-gray-200 dark:border-slate-700 sticky top-0 bg-white dark:bg-slate-900 z-10">
5656
<div class="flex items-center justify-between mb-3">
@@ -393,6 +393,14 @@ templ DashboardEditorScript(dash *dashboard.Dashboard) {
393393
}
394394

395395
// Helper functions
396+
397+
func widgetPaletteClass(openPalette bool) string {
398+
if openPalette {
399+
return "mb-4 bg-white dark:bg-slate-900 border border-gray-300 dark:border-slate-600 rounded-lg shadow-lg"
400+
}
401+
return "hidden mb-4 bg-white dark:bg-slate-900 border border-gray-300 dark:border-slate-600 rounded-lg shadow-lg"
402+
}
403+
396404
func getWidgetStyle(pos dashboard.WidgetPosition) string {
397405
return fmt.Sprintf("grid-column: span %d;", pos.Width)
398406
}

gearbox/static/js/dashboard/palette.js

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -427,6 +427,17 @@ function toggleWidgetPalette() {
427427
}
428428
}
429429

430+
// Auto-initialize palette if it's already visible on page load
431+
// (e.g., when redirected from an empty dashboard with open_palette=1)
432+
document.addEventListener('DOMContentLoaded', function() {
433+
const panel = document.getElementById('widget-palette-panel');
434+
if (panel && !panel.classList.contains('hidden')) {
435+
const dashboardElement = document.getElementById('dashboard-grid-editor');
436+
const boxID = dashboardElement ? dashboardElement.dataset.boxId : '';
437+
initializeWidgetPalette(boxID);
438+
}
439+
});
440+
430441
// Export functions for use in other scripts
431442
window.initializeWidgetPalette = initializeWidgetPalette;
432443
window.toggleWidgetPalette = toggleWidgetPalette;

0 commit comments

Comments
 (0)