docs(phase-11): complete phase execution

All 4 plans complete. UIE-01..05 verified (15/15 must-haves). Human-approved.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
2026-04-15 15:08:53 +02:00
co-authored by Claude Sonnet 4.6
parent 1bec899f87
commit b0078a4fb2
5 changed files with 372 additions and 2 deletions
@@ -0,0 +1,127 @@
---
phase: 11-ui-enhancements
plan: "03"
subsystem: ui
tags: [alpine.js, i18n, theme, localStorage, pico-css, e2e, playwright]
# Dependency graph
requires:
- phase: 11-01
provides: base.html layout foundation with sidebar nav and Alpine.js loaded
provides:
- Alpine.store('theme') cycling Light/Dark/System with localStorage persistence
- Alpine.store('i18n') FR/EN toggle with full static UI translation dictionary
- Top-right topbar with theme and language toggle buttons in base.html
- 4 E2E Playwright tests covering both toggles and localStorage persistence
affects:
- Any future plan modifying base.html or adding new static UI strings
# Tech tracking
tech-stack:
added: []
patterns:
- alpine:init script placed before defer alpine.min.js for store registration timing
- Alpine.store() for global reactive state shared across all pages
- localStorage keys imptune_theme and imptune_lang for cross-reload persistence
- x-data on individual elements to scope Alpine binding where needed
- :aria-label binding used as Playwright selector anchor for theme button state
key-files:
created:
- tests/e2e/test_theme_toggle.py
- tests/e2e/test_i18n_toggle.py
modified:
- imptune/templates/base.html
- imptune/static/app.css
- tests/test_static.py
key-decisions:
- "Alpine stores registered via alpine:init event before defer script runs — ensures stores available at hydration"
- "x-data on topbar-controls div (not individual buttons) to scope Alpine scope once for both controls"
- ":aria-label bound to $store.theme.current to track current state — doubles as Playwright E2E selector"
- "Test assertion fixed: class-scoped check for 'class=empty-state>No printers configured' instead of raw string (which now also appears in i18n JS)"
patterns-established:
- "i18n pattern: Alpine.store('i18n').t('key') via x-text binding on any element needing translation"
- "Theme pattern: data-theme on <html> driven by Alpine.store('theme').cycle() on button click"
requirements-completed:
- UIE-04
- UIE-05
# Metrics
duration: 4min
completed: 2026-04-15
---
# Phase 11 Plan 03: Theme + Language Toggle Summary
**Alpine.js stores for Light/Dark/System theme cycling and FR/EN i18n toggle in base.html, both persisted via localStorage, with 4 passing Playwright E2E tests**
## Performance
- **Duration:** 4 min
- **Started:** 2026-04-15T09:05:49Z
- **Completed:** 2026-04-15T09:10:08Z
- **Tasks:** 2
- **Files modified:** 4 (base.html, app.css, test_static.py, + 2 created E2E test files)
## Accomplishments
- Alpine.store('theme') registered via alpine:init with Light/Dark/System cycling, localStorage persistence, and :aria-label binding for state tracking
- Alpine.store('i18n') with complete FR/EN translation dictionary covering all static UI strings (30+ keys per language)
- Top-right topbar added to base.html layout with theme toggle and lang toggle buttons, styled via new .main-wrapper + .topbar CSS classes
- 4 E2E Playwright tests: theme cycles, theme persists, lang switches nav label, lang persists — all GREEN
## Task Commits
Each task was committed atomically:
1. **Task 1: Alpine.js stores + top-right controls in base.html** - `3353f45` (feat)
2. **Task 2: E2E tests for theme toggle and language toggle** - `4db15d6` (test)
## Files Created/Modified
- `imptune/templates/base.html` - Alpine.js stores script (alpine:init), topbar with toggle buttons, x-text nav bindings
- `imptune/static/app.css` - Added .main-wrapper, .topbar, .topbar-controls styles
- `tests/test_static.py` - Added test_theme_toggle_present; fixed test_dashboard_shows_recent_printers assertion
- `tests/e2e/test_theme_toggle.py` - 2 E2E tests: theme cycles on click, theme persists across reload
- `tests/e2e/test_i18n_toggle.py` - 2 E2E tests: lang toggle switches nav label, lang persists across reload
## Decisions Made
- Alpine stores registered via alpine:init event before the defer alpine.min.js script — inline scripts run synchronously before any deferred scripts, guaranteeing stores are defined before Alpine initializes
- x-data placed on the .topbar-controls div wrapper instead of individual buttons — scopes Alpine once for both controls
- :aria-label bound to $store.theme.current — provides a reactive state indicator that doubles as a stable Playwright selector (button[aria-label='auto'], button[aria-label='light'], etc.)
- Test assertion in test_dashboard_shows_recent_printers updated: raw string "No printers configured yet" now appears in the inline i18n JS, so assertion narrowed to class-qualified check
## Deviations from Plan
### Auto-fixed Issues
**1. [Rule 1 - Bug] Fixed test_dashboard_shows_recent_printers false failure due to i18n string**
- **Found during:** Task 1 (base.html stores + controls)
- **Issue:** Adding the i18n translation dictionary inline in base.html embeds the string `'No printers configured yet.'` verbatim in the JS. The existing test asserted this string was absent from the response, which now always fails regardless of DB state.
- **Fix:** Narrowed assertion to `'class="empty-state">No printers configured yet'` — this checks for the server-rendered HTML element rather than the raw string, which correctly distinguishes actual empty-state rendering from JS dictionary content.
- **Files modified:** tests/test_static.py
- **Verification:** test_dashboard_shows_recent_printers passes; all 6 test_static.py tests GREEN
- **Committed in:** 3353f45 (Task 1 commit)
---
**Total deviations:** 1 auto-fixed (Rule 1 - bug in test assertion caused by i18n strings in HTML)
**Impact on plan:** Necessary correctness fix. No scope creep.
## Issues Encountered
- Two pre-existing failures in tests/test_printer_crud.py (test_client_detail_returns_200, test_client_links_in_printer_list) confirmed pre-existing by git stash check — out of scope, logged for deferred triage.
## User Setup Required
None - no external service configuration required.
## Next Phase Readiness
- UIE-04 (theme toggle) and UIE-05 (i18n FR/EN) complete and verified
- base.html now has Alpine.js stores available globally — future plans can use $store.i18n.t() for any new static UI strings
- To add new translation keys: extend translations.fr and translations.en objects in the inline script in base.html
---
*Phase: 11-ui-enhancements*
*Completed: 2026-04-15*