Frontend spec parity: HSV mode, conflicts, regenerate confirm, audit-log page, carousel, static editor, guide, import panel #48
Labels
No labels
area/ai
area/backend
area/frontend
area/infra
area/scheduler
area/wled
good-first-issue
priority/high
priority/low
priority/medium
type/bug
type/chore
type/ci-cd
type/docs
type/feature
type/qa
v1.0.0
v1.1.0
v1.2.0
v2.0.0
No project
No assignees
1 participant
Notifications
Due date
No due date set.
Dependencies
No dependencies set
Reference
rbrooks/Iris-WLED#48
Loading…
Reference in a new issue
No description provided.
Delete branch "%!s()"
Deleting a branch is permanent. Although the deleted branch may continue to exist for a short time before it actually gets removed, it CANNOT be undone in most cases. Continue?
Split from #40 — the UI gaps against spec §§4.3, 10, 3.6, 5.4. Ordered roughly by user impact.
SidePanel.tsx:319. Was already present; my earlier claim that it was missing matched on hook wiring rather than the button'sonClick.ColorSlots.tsx(§10.1/10.2) —entryMode: "rgb" | "hsv", withrgbToHsv/hsvToRgbcovered bycolorConversion.test.tsAuditLogPage.tsx, routed inApp.tsx; actor + action filtered server-side, date range client-side (the API takes no date params)Header.tsx,SidePanel.tsx), which was the harder half. But the carousel still cyclesallSchemeIds = scheme ? [scheme.id] : [](SidePanel.tsx:94) — the selected day's single scheme, which is exactly what this item says is wrong. A one-element carousel is not a carousel. Still needs: cycle upcoming schemes (next week/month).SettingsPage.tsxreads/writesstatic_config, seeding a default when a segment first becomesstaticdefault_schemebound inSettingsPage.tsxReviewGuideBanner.tsx/json/effviauseWledEffects, plus a Custom ID input for anything absentexport_presets_jsonstill carriesDepends(require_admin)(backend/app/routers/import_export.py:37), though the spec allows viewer GETs. Backend change too.Remaining: 2 of 13
require_admintorequire_vieweronGET /export/presets.json, and check whether/export/events/{id}.jsonshould follow.Picking this up in batches (it's large). Batch A on
fix/48-frontend-parity-a: regenerate-confirm modal, no-eventdefault_schemeSettings control (pairs with merged #44), dismissible review guide, and the audit-log page. Remaining items (HSV color mode, conflict handling, import panel, EffectPicker, gradient swatches, carousel, static-segment editor, quick-push color path, un-gate presets export) will follow in a Batch B — leaving this issue open until they're all done. Note: #44 changed the no-event push responseactionfield to be mode-aware (no_event/default_dim_white/default_scheme).Batch B on
fix/48-frontend-parity-b: HSV color mode in ColorSlots (§10.1/10.2), static-segment editor (§3.2), EffectPicker full WLED effect list (fetch/json/effwhen connected, else complete static list), and exposing the newdaily_backup_retain_countSettings field (from #57). Remaining for a Batch C: conflict handling, import-panel overhaul, gradient swatches/month backdrop, preview carousel, quick-push arbitrary-color path, un-gate presets export (needs a backend viewer-GET change too).Batch B merged (PR #77, Docker-verified): HSV color mode, static-segment editor, corrected + live-fetchable EffectPicker,
daily_backup_retain_countcontrol.Two backend follow-ups this surfaced (needed to fully light up Batch B's frontend, but not blocking it):
GET /api/v1/wled/effectsproxy — proxy the controller's/json/effso EffectPicker's live list works (frontend already calls it and degrades to the static list on 404).static_configconsumer inscheme_translator— the static-segment editor persists a sensibleSegment.static_configshape, but nothing reads it yet.Batch C (still open on this issue): conflict handling (§4.3/§10) — note this needs a conflict-status definition (likely a small backend change too); import-panel overhaul (§3.6); day-swatch gradient strips + month backdrop (§10.1); preview carousel; quick-push arbitrary-color path (§6.1); un-gate
presets.jsonexport for viewers (backend auth change too). These are lower-impact polish/larger items — good for a focused follow-up pass.Batch C scope — audited against the code, not the original list
"Batch C" was never defined: this issue's body lists the whole parity gap from the 2026-07-15 review, and batches A and B were carved out ad hoc without recording what they closed. I read the current frontend against spec §10 to establish what actually remains.
Already closed by batches A/B — do not redo
components/panel/color.ts—hsvToRgb/rgbToHsv, used byColorSlots.tsxpages/AuditLogPage.tsxexists and is routedcomponents/layout/ReviewGuideBanner.tsxSchemeEditor.tsx— "Save as…" dialogSidePanel.tsxcomponents/panel/effects.tspages/SettingsPage.tsxSettingsPage.tsx—DefaultSchemeMode = "off" | "dim_white" | "scheme"That last one is worth noting: #40 listed it as missing, and it is now present. The original gap list is stale.
Batch C — what genuinely remains
1. Day-cell status icons mean the wrong things (
DayCell.tsx:13-16)Spec §10.1:
✓ approved, ⏳ candidate, ✕ no scheme, ⚠ conflict. So✕and⚠are both bound to the wrong concept. Cannot be fixed independently of item 2 — there is no conflict concept to bind⚠to yet.2. No conflict detection, and no "conflicts only" filter (
Toolbar.tsx:23)Spec wants
unapproved | conflicts | AI-sourced | stale.conflictsis absent. The backend already resolves conflicts (priority_resolver.get_events_for_datereturns primary + secondaries), so this is surfacing existing data, not new logic.3. Day swatches are solid blocks, not gradients (
DayCell.tsx:71-77)Spec: "one horizontal gradient strip per themed segment, blending that segment's colour slots (matches WLED's own preset thumbnails)". Only slot 0 is used; slots 1 and 2 are discarded. A
linear-gradientacross the segment's slots is the fix.4. Month backdrop is a header tint, not a bar behind the row (
YearCalendar.tsx:65-78)The backdrop renders as
backgroundColor: hsla(...,0.15)plus a left border on the month header div. Spec §10.1: "full-width coloured bar behind each month's row". The day grid itself has no backdrop.5. Carousel cannot be stopped from the UI
stopCarouselexists inapi/index.ts:141but has no hook and no caller —SidePanelimportsuseStartCarouselonly. A user can start a carousel and has no way to end it short of waiting it out. Arguably the worst of these for real use.6. Regenerate has no confirmation (
SidePanel.tsx:211)Fires
regenerate.mutateAsyncdirectly. Spec §4.3 requires a warning before replacing approved presets — this can silently destroy approved work.7. Import is raw JSON paste (
Toolbar.tsx:95-97, 223)JSON.parse(importText)from a<textarea>, plus a second textarea for segment mapping. Spec §10.1 wants a browsable multi-preset panel with a mapping wizard.8. Quick push takes a scheme ID only (
Toolbar.tsx:135-137){ id: quickPushId.trim(), mins }— no arbitrary-colour path.Suggested sequencing
Items 1 + 2 are one unit (icons are meaningless until conflicts exist). 3 + 4 are one visual unit in the calendar. 5 is small and high-value. 6 is small and prevents data loss. 7 is the largest and most self-contained. 8 is smallest.
If batch C needs trimming, 5 and 6 are the two that protect users from losing work or losing control of the controller, and I would keep those regardless.
Correction: item 6 is already done
Starting implementation, I checked
SidePanel.tsxproperly and the regenerate confirmation already exists. My audit was wrong.SidePanel.tsx:307renders:and the button is
onClick={() => setConfirmRegen(true)}, not a direct mutation.How I got it wrong: my grep matched
regenerate.mutateAsyncin the hook-wiring block near the top of the file and I inferred the button fired straight through, without reading the button's actualonClick. Spec §4.3 is satisfied, including the "approval is discarded" warning.Batch C is therefore seven items, not eight. Item 6 is struck; the other seven stand as audited — I re-checked item 5 the same way and
stopCarouselgenuinely has no hook and no caller, so that one is real.Renumbered:
Regenerate confirmation— already implementedBatch C item 8 — quick-push arbitrary colour: done in #97.
The gap was real and slightly wider than the item described: the spec says quick push takes "an arbitrary color or scheme", but the API only had the scheme half —
POST /wled/quick-pushrequired ascheme_idand looked up aSchemerow. So this needed a backend path, not just a UI control.What landed:
QuickPushRequesttakes exactly one ofscheme_idorcolor, with a validator rejecting both-or-neither instead of letting one silently win.scheme_translator.solid_color_state;dim_white_statenow delegates to it, since warm-white ambient was already the same operation with a fixed colour._startinquick_push_manager, so the revert paths (duration timer, scheduler revert, manual cancel, superseding) are identical either way.hexToRgbwould otherwise turn a typo into black.Nothing is written to the scheme library on the colour path, so an ad-hoc push leaves no residue.
Batch C status: 7 of 8 items complete. (Recall item 6 was withdrawn — regenerate confirmation already existed at
SidePanel.tsx:307; my original audit matched hook wiring rather than the button'sonClick.)Remaining: item 7, the browsable multi-preset import panel — currently a raw JSON textarea. That is the largest of the batch and I want to scope it against the spec before building rather than inventing a UI.
All 13 items are done — closing.
The last two landed today:
require_viewer, matching the spec's "GET endpoints allowviewerunless noted otherwise". The API change alone would have been useless: the Export button sat inside{isAdmin && …}, so viewers still couldn't reach it. Moved out, and pinned with two tests in the auth matrix.[scheme.id], the selected day's single scheme, which duplicated the Preview button beside it. Starting one moved to the toolbar with a 7/30/90-day window; it walks the resolved day map so it previews what will actually run (no-event days contribute nothing, a multi-day event appears once). Viewer-accessible, since both carousel endpoints arerequire_viewer.For the record, the checkbox audit on 2026-09-01 was the useful part of this issue's tail: 11 of 13 items had already shipped without being ticked, and two that read as open (regenerate confirm, HSV mode) had been done for weeks. Only the carousel and the export gate were genuinely outstanding. Worth remembering that a stale checklist misrepresents remaining work in both directions — it inflated the apparent scope here while hiding that the carousel was half-finished rather than done.