diff --git a/.claude/skills/make-widget/SKILL.md b/.claude/skills/make-widget/SKILL.md index bf6d2d9..b1c3887 100644 --- a/.claude/skills/make-widget/SKILL.md +++ b/.claude/skills/make-widget/SKILL.md @@ -1,6 +1,6 @@ --- name: make-widget -description: Scaffold a new widget type for the espresso_frame server (the ~13-file checklist a widget type touches -- config table, grid footprint, render module, registry, migration, config-save + endpoints, dialog template + JS, script tag, WIDGET_LABELS, docs, tests). Use when asked to add a new widget type to a frame's panel (e.g. "add a text widget", "add an RSS widget", "add a weather-only widget"). +description: Scaffold a new widget type for the espresso_frame server (the ~14-file checklist a widget type touches -- config table, grid footprint, render module, registry, migration, config-save + endpoints, dialog template + JS, script tag, WIDGET_LABELS, docs, saved-layout config allowlist, tests). Use when asked to add a new widget type to a frame's panel (e.g. "add a text widget", "add an RSS widget", "add a weather-only widget"). --- Adding a widget type is a very consistent, repeated pattern in this @@ -114,6 +114,16 @@ Pick your template accordingly: `MIN_FOOTPRINT` prose line, the `app/widgets/` module list. This is the project's own "start here" doc per `CLAUDE.md` -- don't ship a widget without it staying accurate. +14. **`app/routers/api_layouts.py`** -- add a `"": (...)` entry to + `LAYOUT_CONFIG_FIELDS` listing the config columns that are an + authored *setting* (as opposed to runtime/cache state like a fetch + cache or queue position, which a saved layout deliberately leaves + out -- see the dict's own comment). Skipping this doesn't error or + warn anywhere: the widget just silently saves/applies with an empty + `{}` config forever, resetting to defaults on every layout apply or + hold-to-cycle. This actually shipped missing for the weather widget + -- caught only because a user noticed layout-cycling kept resetting + its city/mode. ## Tests (`server/tests/`) @@ -138,6 +148,13 @@ Pick your template accordingly: - Any pure-logic helper module (decoding, parsing -- like `app/image_upload.py`) gets its own `test_.py`: no HTTP, no DB, just the function. +- `test_saved_layouts.py` -- a `test_save_and_apply_round_trip__settings` + test: set every field the new `LAYOUT_CONFIG_FIELDS` entry lists, + save a layout, assert the `SavedLayoutWidget.config` snapshot has them + all, delete the frame's widgets, apply the layout back, assert the + new widget's config matches -- and that any runtime/cache field + (`checked_at`, a fetch cache, a queue) was *not* carried over. See + `test_save_and_apply_round_trip_weather_settings` for the pattern. Run the full suite before calling it done: