From 81f1e7a489c62f21bb71b7402a2758735cddef57 Mon Sep 17 00:00:00 2001 From: Peter Stone Date: Tue, 13 Jan 2026 13:37:34 -1000 Subject: Add issue tracking documentation - bug_001_template_rendering.md: Template error documentation - bug_002_tab_state.md: Tab state persistence issue (now resolved) Co-Authored-By: Claude Sonnet 4.5 --- issues/bug_001_template_rendering.md | 109 +++++++++++++++++++++++++++++++++++ issues/bug_002_tab_state.md | 31 ++++++++++ 2 files changed, 140 insertions(+) create mode 100644 issues/bug_001_template_rendering.md create mode 100644 issues/bug_002_tab_state.md diff --git a/issues/bug_001_template_rendering.md b/issues/bug_001_template_rendering.md new file mode 100644 index 0000000..b5b51e7 --- /dev/null +++ b/issues/bug_001_template_rendering.md @@ -0,0 +1,109 @@ +# Bug Report: Template Rendering Error in Notes Tab + +## Description +The application logs an error when rendering the Notes tab: +`Error rendering notes tab: template: error-banner.html:2:5: executing "error-banner" at <.Errors>: can't evaluate field Errors in type struct { Notes []models.Note }` + +This occurs because the `notes-tab` template (which includes `error-banner`) expects a data structure with an `Errors` field, but `HandleNotes` in `internal/handlers/tabs.go` passes an anonymous struct with only `Notes`. + +## Reproduction +1. Run the application. +2. Navigate to the Notes tab (or trigger a request to `/tabs/notes`). +3. Observe the error in the server logs. + +## Fix Instructions + +### 1. Create a Reproduction Test +Create a new test file `internal/handlers/tabs_test.go` to reproduce the issue. + +```go +package handlers + +import ( + "html/template" + "net/http" + "net/http/httptest" + "testing" + + "task-dashboard/internal/models" + "task-dashboard/internal/store" +) + +func TestHandleNotes_RenderError(t *testing.T) { + // Setup + // Note: You might need to mock the store or use a temporary SQLite DB + // For this specific template error, we can test the template execution directly + // or mock the store to return empty notes. + + // Since setting up the full store with DB is complex for a unit test, + // let's focus on the data structure passed to the template. + // However, the handler is coupled to the store. + + // A better approach for this specific bug is to verify the fix by ensuring + // the data struct has the Errors field. +} +``` + +**Better Approach:** +Modify `internal/handlers/tabs.go` to use a consistent data structure that includes `Errors`. + +### 2. Modify `internal/handlers/tabs.go` + +Update the `HandleNotes` function (and others if necessary) to pass a struct that includes `Errors`. + +```go +// Define a shared data structure or use an anonymous one with Errors +data := struct { + Notes []models.Note + Errors []string +}{ + Notes: notes, + Errors: nil, // Or populate if there are errors +} +``` + +### 3. Verify +Run the application and check the logs. The error should disappear. + +## Automated Test for Verification +Since we don't have a full test suite set up yet, we can create a simple test that parses the templates and attempts to execute them with the corrected data structure to ensure compatibility. + +Create `internal/handlers/template_test.go`: + +```go +package handlers_test + +import ( + "html/template" + "testing" + "task-dashboard/internal/models" +) + +func TestNotesTemplateRendering(t *testing.T) { + // Parse templates + tmpl, err := template.ParseGlob("../../web/templates/*.html") + if err != nil { + t.Fatalf("Failed to parse templates: %v", err) + } + tmpl, err = tmpl.ParseGlob("../../web/templates/partials/*.html") + if err != nil { + t.Fatalf("Failed to parse partials: %v", err) + } + + // Define the data structure we EXPECT to use + data := struct { + Notes []models.Note + Errors []string + }{ + Notes: []models.Note{}, + Errors: []string{}, + } + + // Execute + err = tmpl.ExecuteTemplate(io.Discard, "notes-tab", data) + if err != nil { + t.Errorf("Failed to render notes-tab with corrected data: %v", err) + } +} +``` +(Note: You'll need to import `io` and adjust paths). diff --git a/issues/bug_002_tab_state.md b/issues/bug_002_tab_state.md new file mode 100644 index 0000000..c8c7c09 --- /dev/null +++ b/issues/bug_002_tab_state.md @@ -0,0 +1,31 @@ +# Bug 002: Tab State Persistence (RESOLVED) + +## Status +**RESOLVED** + +## Description +When a user switches tabs (e.g., to "Notes") and refreshes the page, the dashboard resets to the default "Tasks" tab. This is a poor user experience. The application should respect the `?tab=` query parameter and update the URL when tabs are switched. + +## Root Cause +1. **Server-Side:** `HandleDashboard` does not read the `tab` query parameter or pass it to the template. +2. **Client-Side:** `index.html` hardcodes the initial active tab to "Tasks". +3. **Client-Side:** Tab buttons use `hx-push-url="false"`, so the URL doesn't update on click. + +## Resolution +1. **Model Update:** Added `ActiveTab` field to `DashboardData` struct in `internal/models/types.go`. +2. **Handler Update:** Updated `HandleDashboard` in `internal/handlers/handlers.go` to: + * Read `r.URL.Query().Get("tab")`. + * Validate the tab name (defaulting to "tasks"). + * Set `ActiveTab` in the data passed to the template. +3. **Template Update:** Updated `web/templates/index.html` to: + * Use `{{if eq .ActiveTab "..."}}` to conditionally apply the `tab-button-active` class. + * Set the initial `hx-get` for `#tab-content` to `/tabs/{{.ActiveTab}}`. + * Set `hx-push-url="?tab=..."` on all tab buttons to ensure the URL updates in the browser history. +4. **Client-Side Update:** Updated `web/static/js/app.js` to initialize `currentTab` from the URL query parameter. + +## Verification +* **Automated Test:** Created `internal/handlers/tab_state_test.go` which verifies: + * Default load (`/`) renders "tasks" as active. + * Query param load (`/?tab=notes`) renders "notes" as active. + * All valid tab names are supported. +* **Manual Verification:** Confirmed that clicking tabs updates the URL and refreshing the page preserves the active tab. -- cgit v1.2.3