- Add 7-SUMMARY.md with implementation details and self-check - Update STATE.md with quick task 007 entry and session context
13 KiB
phase, plan, type, wave, depends_on, files_modified, autonomous, requirements, must_haves
| phase | plan | type | wave | depends_on | files_modified | autonomous | requirements | must_haves | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
| quick-7 | 1 | execute | 1 |
|
true |
|
|
Purpose: Users who rely on a favorites playlist want instant access without scrolling/sorting to find it. Output: Full-stack feature — config field, backend getter/setter, frontend store/controller, sort logic, and settings toggle.
<execution_context> @/home/caleb/.config/Claude/get-shit-done/workflows/execute-plan.md @/home/caleb/.config/Claude/get-shit-done/templates/summary.md </execution_context>
@backend/favorites/config.go @backend/config/config.go @frontend/src/store/favorites-store.ts @frontend/src/store/controllers/favorites-controller.ts @frontend/src/components/playlist-view/playlist-view.ts @frontend/src/components/config-page/config-page.tsFrom backend/favorites/config.go:
type Config struct {
PlaylistID int64 `toml:"PlaylistID"`
IconStyle IconStyle `toml:"IconStyle"`
}
From backend/config/config.go:
// Pattern for getter/setter — follow GetFavoritesPlaylistID / SetFavoritesPlaylistID exactly
func (c *Config) GetFavoritesPlaylistID() int64 { ... }
func (c *Config) SetFavoritesPlaylistID(id int64) error { ... }
func (c *Config) emitFavoritesChanged() {
runtime.EventsEmit(c.ctx, events.FavoritesConfigChanged, map[string]any{
"PlaylistID": c.Favorites.PlaylistID,
"IconStyle": string(c.Favorites.IconStyle),
})
}
From frontend/src/store/favorites-store.ts:
// Event handler in constructor:
EventsOn(Events.FavoritesConfigChanged, (data: {
PlaylistID: number;
IconStyle: string;
}) => { ... });
// loadConfig pattern:
private async loadConfig(): Promise<void> {
const [id, style] = await Promise.all([
GetFavoritesPlaylistID(),
GetFavoritesIconStyle(),
]);
...
}
From frontend/src/components/playlist-view/playlist-view.ts:
private get sortedEntries(): PlaylistEntry[] {
const entries = this.filteredEntries;
const dir = this.sortDirection === 'asc' ? 1 : -1;
return [...entries].sort((a, b) => { ... });
}
From frontend/src/components/config-page/config-page.ts:
// Favorites section uses config-field with type: 'select'
// Pattern for toggle: use type: 'toggle' with boolean value
private renderFavoritesSection() { ... }
- In
backend/config/config.go:- Add
GetPinDefaultPlaylist() boolmethod following the exact pattern ofGetFavoritesPlaylistID():func (c *Config) GetPinDefaultPlaylist() bool { if c.Favorites == nil { return true // default: pinned } return c.Favorites.PinDefault } - Add
SetPinDefaultPlaylist(pin bool) errormethod following the pattern ofSetFavoritesPlaylistID():- Ensure
c.Favoritesis initialized (same nil guard pattern) - Set
c.Favorites.PinDefault = pin - Call
c.Save(), return error if save fails - Call
c.emitFavoritesChanged() - Log the change
- Ensure
- Update
emitFavoritesChanged()to include"PinDefault": c.Favorites.PinDefaultin the event payload map - In the
applyDefaults()method, ensure when creating a newfavorites.Config{},PinDefaultis set totrue
- Add
NOTE: The Wails bindings (frontend/wailsjs/go/config/Config.js and .d.ts) are auto-generated by wails generate module. Run wails generate module after making Go changes, or if not available, manually add the binding stubs to match the pattern of existing bindings.
Run go build ./... from the backend directory to verify compilation. Grep for PinDefault in backend/ to confirm it appears in both files.
- favorites.Config has PinDefault bool field with TOML tag
- config.Config has GetPinDefaultPlaylist() and SetPinDefaultPlaylist() methods
- emitFavoritesChanged includes PinDefault in event payload
- Default value is true (pin enabled)
- Code compiles without errors
-
favorites-store.ts:
- Import
GetPinDefaultPlaylistandSetPinDefaultPlaylistfrom@go/config/Config - Add
private pinDefault = true;field (default true) - Add
getPinDefault(): booleangetter - Add
async setPinDefault(pin: boolean): Promise<void>action (same pattern assetIconStyle) - In
loadConfig(): addGetPinDefaultPlaylist()to thePromise.allcall, store result inthis.pinDefault - In the
FavoritesConfigChangedevent handler: readdata.PinDefault(asboolean) and store inthis.pinDefault, then notify
- Import
-
favorites-controller.ts:
- Add
get pinDefault(): booleangetter that delegates tofavoritesStore.getPinDefault() - Add
async setPinDefault(pin: boolean): Promise<void>that delegates tofavoritesStore.setPinDefault(pin)
- Add
-
playlist-view.ts — Update
sortedEntriesgetter to pin default playlist when enabled:private get sortedEntries(): PlaylistEntry[] { const entries = this.filteredEntries; const dir = this.sortDirection === 'asc' ? 1 : -1; const sorted = [...entries].sort((a, b) => { // Pin default playlist to top when enabled if (this.favCtrl.pinDefault) { const aIsDefault = a.summary.ID === this.favCtrl.playlistId; const bIsDefault = b.summary.ID === this.favCtrl.playlistId; if (aIsDefault && !bIsDefault) return -1; if (!aIsDefault && bIsDefault) return 1; } let cmp = 0; switch (this.sortField) { // ... existing sort cases unchanged } return cmp * dir; }); return sorted; } -
config-page.ts — Add a toggle in
renderFavoritesSection()AFTER the existing Icon Style field:<config-field .schema=${{ key: 'pinDefaultPlaylist', label: 'Pin to Top', description: 'Always show the default playlist first, regardless of sort order.', type: 'toggle' as const, }} .value=${this.favCtrl.pinDefault} @config-change=${this.handlePinDefaultChange} ></config-field>- Add handler
private handlePinDefaultChange:private handlePinDefaultChange = ( e: CustomEvent<ConfigFieldChangeEvent>, ): void => { const pin = Boolean(e.detail.value); this.favCtrl .setPinDefault(pin) .catch((err: unknown) => { console.error('Failed to set pin default:', err); }); };
- Add handler
IMPORTANT: Check if config-field supports type: 'toggle'. If not, check what boolean toggle type it supports (could be 'switch' or 'checkbox'). Look at the config-field component to determine the correct type string. If toggle isn't supported, use whatever boolean field type the component supports.
Run npm run build (or the project's frontend build command) from the frontend directory to verify TypeScript compilation. Visually verify by launching the app that: (1) The favorites playlist appears at the top of the playlist list regardless of sort, (2) The setting toggle appears in Settings > Favorites, (3) Disabling the toggle causes the favorites playlist to sort normally.
- Favorites store exposes pinDefault state with getter/setter
- FavoritesController exposes pinDefault getter and setPinDefault action
- sortedEntries in playlist-view pins default playlist to index 0 when pinDefault is true
- Config page shows "Pin to Top" toggle in Favorites section
- Toggling the setting immediately updates the playlist view (reactive via store subscription)
- Setting persists across app restarts (saved to config.toml via backend)
- Frontend builds without TypeScript errors
<success_criteria>
- Default playlist pinned to top of playlist view when setting enabled (default: enabled)
- Toggle in Settings > Favorites controls the behavior
- Setting persists in config.toml across restarts
- All other sort functionality (field + direction) works normally for non-default playlists
- No regressions to existing playlist features (sorting, filtering, drag-drop, context menu) </success_criteria>