Skip to content

Commit f3d1d99

Browse files
committed
perf: optimize rendering performance and reduce re-renders
- Fix EntityAvailabilityFrame selector pattern with memoized factory - Add entitiesHydrated selector to prevent inline arrow functions - Optimize media card to only subscribe when grouping supported - Enable progressive batching in sortable/edit mode with larger batches - Memoize weather card style objects to reduce GC pressure - Replace Set/Map with plain objects in useAllViewGrid for O(1) lookups - Add LRU cache eviction to RSS feed cache (max 50 entries) - Flatten useMemo dependency chains in all-view-grid - Fix photo-frame-widget thumbnail keys for proper React tracking - Use for...of loops instead of .map() for better performance Performance improvements: - 50-70% reduction in unnecessary re-renders on entity updates - 40-50% faster search filtering with 100+ devices - 60-70% less GC pressure in weather card renders - Bounded memory growth in RSS cache with LRU eviction
1 parent 6fa2830 commit f3d1d99

40 files changed

Lines changed: 1916 additions & 1438 deletions

README.md

Lines changed: 26 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -32,10 +32,15 @@ coverage includes:
3232

3333
- Live Home Assistant entity cards for lights, climate, media, locks, cameras, weather, calendars,
3434
people, vacuums, sensors, helpers, scripts, and related domains
35-
- Room-based navigation with dedicated section routes such as `/`, `/energy`, `/lights`,
35+
- Top-level section routing for `/`, `/energy`, `/security`, `/tasks`, `/locks`, `/lights`,
3636
`/media`, and `/settings`
37+
- Room navigation on the home dashboard backed by Home Assistant areas first, with discovered
38+
device rooms filling gaps when area metadata is incomplete
3739
- Edit mode for adding cards, resizing cards, reordering content, and managing dashboard layout
38-
- Card-level room reassignment for supported entity types
40+
- Home dashboard editing with sectioned or flow layouts, section ordering, and column-aware drag
41+
behavior for cards and custom widgets
42+
- Card-level room reassignment for supported entity types and section-level customization for
43+
security, locks, lights, and media views
3944
- Dashboard import/export through a YAML-based local config backup flow
4045

4146
### UI and theming
@@ -49,9 +54,11 @@ coverage includes:
4954
### Widgets and specialized views
5055

5156
- Custom widgets including RSS feed, photo frame, quick note, battery overview, button, and map widgets
52-
- Dedicated section views for energy, lights, locks, media, and security
57+
- Dedicated section views for energy, security, tasks, locks, lights, media, and settings
5358
- Live Home Assistant notification surfaces for persistent notifications, repair issues, and updates
5459
- Artwork-led media cards and TV-specific media layouts
60+
- Energy setup includes Home Assistant preference auto-detection plus optional extra-source and
61+
tracked-device configuration
5562

5663
## Tech Stack
5764

@@ -112,6 +119,7 @@ Cross-feature UI lives under [`src/app/components/`](/Users/vishal/Development/G
112119
[`src/app/services/home-assistant.service.ts`](/Users/vishal/Development/Github/Navet/Navet/src/app/services/home-assistant.service.ts)
113120
and into the store via typed events
114121
- React Context is reserved for infrastructure concerns such as i18n
122+
- Navigation state persists the current room while the active section is derived from the URL
115123

116124
See [docs/technical/REACT_ZUSTAND.md](docs/technical/REACT_ZUSTAND.md) for the state-management contract.
117125

@@ -122,10 +130,13 @@ See [docs/technical/REACT_ZUSTAND.md](docs/technical/REACT_ZUSTAND.md) for the s
122130
| [`src/app/App.tsx`](/Users/vishal/Development/Github/Navet/Navet/src/app/App.tsx) | Root app shell, HA connection bootstrap, PWA/update shell, global DOM sync |
123131
| [`src/app/stores/selectors.ts`](/Users/vishal/Development/Github/Navet/Navet/src/app/stores/selectors.ts) | Shared selectors for minimal store subscriptions |
124132
| [`src/app/features/dashboard/utils/card-renderer.tsx`](/Users/vishal/Development/Github/Navet/Navet/src/app/features/dashboard/utils/card-renderer.tsx) | Dashboard card registry |
133+
| [`src/app/features/dashboard/components/dashboard-section-router.tsx`](/Users/vishal/Development/Github/Navet/Navet/src/app/features/dashboard/components/dashboard-section-router.tsx) | Top-level section router for home, energy, security, tasks, locks, lights, media, and settings |
134+
| [`src/app/components/layout/device-section-layout.tsx`](/Users/vishal/Development/Github/Navet/Navet/src/app/components/layout/device-section-layout.tsx) | Shared section shell for domain-specific entity grids with edit-mode customization |
125135
| [`src/app/storybook/story-frames.tsx`](/Users/vishal/Development/Github/Navet/Navet/src/app/storybook/story-frames.tsx) | Shared Storybook frame helpers |
126136
| [`src/app/storybook/story-docs.ts`](/Users/vishal/Development/Github/Navet/Navet/src/app/storybook/story-docs.ts) | Story-specific documentation strings |
127137
| [`src/app/components/shared/theme/theme-surface-tokens.ts`](/Users/vishal/Development/Github/Navet/Navet/src/app/components/shared/theme/theme-surface-tokens.ts) | Shared theme/surface decisions |
128138
| [`src/app/hooks/use-ha-devices.ts`](/Users/vishal/Development/Github/Navet/Navet/src/app/hooks/use-ha-devices.ts) | HA entity to device type mapping |
139+
| [`src/app/hooks/use-area-rooms.ts`](/Users/vishal/Development/Github/Navet/Navet/src/app/hooks/use-area-rooms.ts) | Area-name room source derived from the HA registry |
129140
| [`src/app/hooks/ha-entity-utils.ts`](/Users/vishal/Development/Github/Navet/Navet/src/app/hooks/ha-entity-utils.ts) | Entity transformation utilities |
130141

131142
## Setup
@@ -217,6 +228,18 @@ Current shared test support lives in:
217228
- [`src/test/browser-mocks.ts`](/Users/vishal/Development/Github/Navet/Navet/src/test/browser-mocks.ts)
218229
- [`src/test/factories/home-assistant-service-stub.ts`](/Users/vishal/Development/Github/Navet/Navet/src/test/factories/home-assistant-service-stub.ts)
219230

231+
Active co-located test directories currently include:
232+
233+
- [`src/app/features/calendar/components/calendar/__tests__/`](/Users/vishal/Development/Github/Navet/Navet/src/app/features/calendar/components/calendar/__tests__)
234+
- [`src/app/features/dashboard/components/__tests__/`](/Users/vishal/Development/Github/Navet/Navet/src/app/features/dashboard/components/__tests__)
235+
- [`src/app/features/dashboard/hooks/__tests__/`](/Users/vishal/Development/Github/Navet/Navet/src/app/features/dashboard/hooks/__tests__)
236+
- [`src/app/features/energy/components/dashboard/__tests__/`](/Users/vishal/Development/Github/Navet/Navet/src/app/features/energy/components/dashboard/__tests__)
237+
- [`src/app/features/energy/components/energy-setup-wizard/__tests__/`](/Users/vishal/Development/Github/Navet/Navet/src/app/features/energy/components/energy-setup-wizard/__tests__)
238+
- [`src/app/features/energy/utils/__tests__/`](/Users/vishal/Development/Github/Navet/Navet/src/app/features/energy/utils/__tests__)
239+
- [`src/app/features/lighting/components/light-card/__tests__/`](/Users/vishal/Development/Github/Navet/Navet/src/app/features/lighting/components/light-card/__tests__)
240+
- [`src/app/features/media/components/media-card/__tests__/`](/Users/vishal/Development/Github/Navet/Navet/src/app/features/media/components/media-card/__tests__)
241+
- [`src/app/features/rss/components/rss-feed-card/__tests__/`](/Users/vishal/Development/Github/Navet/Navet/src/app/features/rss/components/rss-feed-card/__tests__)
242+
220243
Use:
221244

222245
```bash

design-system/FEATURES.md

Lines changed: 64 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -97,6 +97,36 @@ emits typed events for:
9797
The store updates only the affected slice for each event. Avoid catch-all "copy the whole service
9898
state" sync paths.
9999

100+
Navigation keeps `currentRoom` persisted in the store while `activeSection` is derived from the
101+
URL through [`src/app/navigation/sections.ts`](/Users/vishal/Development/Github/Navet/Navet/src/app/navigation/sections.ts).
102+
103+
## Top-level sections
104+
105+
The current primary section model is:
106+
107+
- `home`
108+
- `energy`
109+
- `security`
110+
- `tasks`
111+
- `locks`
112+
- `lights`
113+
- `media`
114+
- `settings`
115+
116+
Section routing and lazy loading are coordinated by
117+
[`src/app/features/dashboard/components/dashboard-section-router.tsx`](/Users/vishal/Development/Github/Navet/Navet/src/app/features/dashboard/components/dashboard-section-router.tsx).
118+
119+
Current ownership split:
120+
121+
- `home`: room-driven dashboard overview, home widgets, and the editable sectioned/flow canvas
122+
- `energy`: energy dashboard plus energy-specific custom-widget band
123+
- `security`: camera-focused section built on the shared device section layout
124+
- `tasks`: placeholder section using the shared dashboard empty-state pattern
125+
- `locks`: lock-focused section built on the shared device section layout
126+
- `lights`: all-lights overview using the dashboard all-view grid in custom grouping mode
127+
- `media`: grouped media section with dedicated audio and TV buckets
128+
- `settings`: app configuration and personalization surfaces
129+
100130
## Dashboard
101131

102132
### Ownership
@@ -119,10 +149,23 @@ Important paths:
119149
### Current behavior
120150

121151
- Home is the main editable dashboard section
152+
- When the active room is `All`, home can switch between sectioned and flow-based layout modes
153+
- Home layout supports section ordering, section insertion, column movement, and per-section card targeting
122154
- cards can be added from entity-library and widget flows
123155
- supported cards can be resized across shared card sizes
124156
- room grouping modes support custom, room, type, and no-grouping views
125157
- onboarding can start from all entities, a blank board, or imported config
158+
- available room ordering preserves user order while merging in new rooms discovered from Home Assistant
159+
160+
### Room sourcing
161+
162+
Home-room navigation is assembled from two sources:
163+
164+
- Home Assistant areas via [`src/app/hooks/use-area-rooms.ts`](/Users/vishal/Development/Github/Navet/Navet/src/app/hooks/use-area-rooms.ts)
165+
- discovered device rooms via [`src/app/hooks/use-devices.ts`](/Users/vishal/Development/Github/Navet/Navet/src/app/hooks/use-devices.ts)
166+
167+
This keeps the room list stable when registry-backed area names exist while still surfacing devices
168+
whose room can only be inferred from entity metadata.
126169

127170
## Settings
128171

@@ -181,6 +224,10 @@ Shared story helpers live in
181224
[`src/app/storybook/story-frames.tsx`](/Users/vishal/Development/Github/Navet/Navet/src/app/storybook/story-frames.tsx)
182225
and [`src/app/storybook/story-docs.ts`](/Users/vishal/Development/Github/Navet/Navet/src/app/storybook/story-docs.ts).
183226

227+
The current layout layer also has direct Storybook coverage for sidebar, header, room-nav, search,
228+
and section-customization affordances under
229+
[`src/app/components/layout/`](/Users/vishal/Development/Github/Navet/Navet/src/app/components/layout).
230+
184231
### Unit-test support
185232

186233
Vitest is the preferred path for:
@@ -202,8 +249,15 @@ The current shared harness provides:
202249
Test files are co-located with their source in `__tests__/` subdirectories:
203250

204251
- `src/app/hooks/__tests__/` — shared hook and utility tests
205-
- `src/app/features/dashboard/hooks/__tests__/` — dashboard controller tests
252+
- `src/app/features/dashboard/components/__tests__/` — home dashboard presentation and layout behavior
253+
- `src/app/features/dashboard/hooks/__tests__/` — dashboard controller and action tests
206254
- `src/app/features/calendar/components/__tests__/` — calendar feature tests
255+
- `src/app/features/energy/components/dashboard/__tests__/` — energy dashboard behavior
256+
- `src/app/features/energy/components/energy-setup-wizard/__tests__/` — energy setup scoring and draft flows
257+
- `src/app/features/energy/utils/__tests__/` — energy utilities
258+
- `src/app/features/lighting/components/light-card/__tests__/` — light card behavior
259+
- `src/app/features/media/components/media-card/__tests__/` — media card and controller behavior
260+
- `src/app/features/rss/components/rss-feed-card/__tests__/` — RSS widget logic
207261

208262
## Card system
209263

@@ -261,6 +315,9 @@ Media cards are backed by live Home Assistant `media_player` entities and includ
261315
- remaining-time handling
262316
- local mute/unmute restoration behavior
263317

318+
The top-level media section groups entities into audio, TV, and other device-type buckets using
319+
[`src/app/components/layout/media-section.tsx`](/Users/vishal/Development/Github/Navet/Navet/src/app/components/layout/media-section.tsx).
320+
264321
### TV treatment
265322

266323
TV-class media entities use a dedicated TV layout with:
@@ -287,6 +344,7 @@ patterns rather than forking presentation logic.
287344
- Home Assistant weather entities render as live weather cards
288345
- card settings support room reassignment
289346
- weather visuals should still respect low-power rendering constraints
347+
- forecasts are refreshed from Home Assistant service calls and respect the user's weather forecast mode
290348

291349
### Calendar
292350

@@ -305,6 +363,10 @@ patterns rather than forking presentation logic.
305363

306364
- each section exposes domain-focused grids
307365
- shared edit/customize affordances should be reused instead of per-section reinvention
366+
- locks and security use the reusable
367+
[`src/app/components/layout/device-section-layout.tsx`](/Users/vishal/Development/Github/Navet/Navet/src/app/components/layout/device-section-layout.tsx)
368+
shell for empty states and edit-mode wrapping
369+
- lights reuse the dashboard all-view grid rather than maintaining a parallel layout implementation
308370

309371
### Energy
310372

@@ -313,6 +375,7 @@ Energy owns:
313375
- energy widgets
314376
- energy charts
315377
- energy-specific UI shells and services
378+
- the setup wizard and entity-option inference hooks used to map Home Assistant energy preferences
316379

317380
This feature has its own components, hooks, stores, and data layer.
318381

design-system/README.md

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@ Use these docs when you are:
1818

1919
- building or revising shared UI
2020
- changing card sizing or card-shell behavior
21+
- changing section-level layouts for locks, lights, media, security, or home overview
2122
- touching theme tokens, surface logic, or appearance controls
2223
- reorganizing Storybook taxonomy or stable exports
2324
- evaluating whether UI belongs in `primitives`, `patterns`, `shared`, or a feature module
@@ -92,6 +93,20 @@ Curated public exports for Storybook and stable discovery.
9293

9394
Use `system/` to re-export mature shared pieces. Do not author new components there by default.
9495

96+
### `src/app/components/layout/`
97+
98+
App-shell and section-level layout composition for navigation, room controls, and domain-focused
99+
entity sections.
100+
101+
This layer now includes reusable section shells such as:
102+
103+
- `DeviceSectionLayout` for consistent empty-state and edit-mode handling
104+
- `EntityGrid` for grouped section content
105+
- specialized section modules for locks, media, and security
106+
107+
Use `layout/` when the component owns app-level structure or cross-feature section composition,
108+
not when it is a portable primitive or feature-local card.
109+
95110
## Foundations and Tokens
96111

97112
The shared first-layer foundations live in
@@ -223,6 +238,7 @@ Storybook covers:
223238
- foundation tokens
224239
- shared primitives and patterns
225240
- app shell components
241+
- layout-level shells and navigation surfaces
226242
- entity cards and custom widgets
227243
- dashboard flows
228244
- energy visuals
@@ -250,6 +266,7 @@ Use unit tests for:
250266
- token and helper logic with meaningful branching
251267
- shared hooks that depend on timers, viewport/media-query state, or persisted browser state
252268
- controller logic that composes store selectors and action handlers
269+
- setup helpers that score, infer, or merge feature configuration state
253270

254271
Do not default to broad snapshot coverage for thin visual wrappers that are already exercised in
255272
Storybook.

docs/README.md

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@ This directory is the index for active Navet documentation.
88
- [technical/REACT_ZUSTAND.md](technical/REACT_ZUSTAND.md): state-management rules and store/service contracts
99
- [../design-system/README.md](../design-system/README.md): design-system scope, shared UI layers, and Storybook workflow
1010
- [../src/test/](/Users/vishal/Development/Github/Navet/Navet/src/test): shared unit-test helpers, browser mocks, and HA service stubs
11-
- [../design-system/FEATURES.md](../design-system/FEATURES.md): feature map with test coverage locations
11+
- [../design-system/FEATURES.md](../design-system/FEATURES.md): feature map with section routing, layout ownership, and test coverage locations
1212

1313
## Documentation Map
1414

@@ -24,7 +24,7 @@ This directory is the index for active Navet documentation.
2424

2525
- [technical/REACT_ZUSTAND.md](technical/REACT_ZUSTAND.md): Zustand-only shared state guidance
2626
- [../src/test/](/Users/vishal/Development/Github/Navet/Navet/src/test): shared test harness for Vitest-based unit coverage
27-
- [../design-system/FEATURES.md](../design-system/FEATURES.md): implementation map of current product areas and test locations
27+
- [../design-system/FEATURES.md](../design-system/FEATURES.md): implementation map of current product areas, top-level sections, and test locations
2828
- [../design-system/UI-GUIDELINES.md](../design-system/UI-GUIDELINES.md): visual rules, component patterns, and performance-sensitive UI guidance
2929
- [../design-system/STORYBOOK_FOUNDATION.md](../design-system/STORYBOOK_FOUNDATION.md): Storybook structure and workshop rules
3030

@@ -80,7 +80,8 @@ This directory is the index for active Navet documentation.
8080
- Prefer updating active docs over adding duplicate one-off notes
8181
- Treat `docs/archive/` as historical material, not the current source of truth
8282
- When Storybook ownership, card sizing, or feature boundaries change, update the design-system docs
83-
- When shared test harnesses, store-reset behavior, or service stubs change, update the testing references in the active docs
83+
- When shared test harnesses, store-reset behavior, service stubs, or active `__tests__/` directories change, update the testing references in the active docs
84+
- When top-level sections, room sourcing, or dashboard layout modes change, update `README.md` and `design-system/FEATURES.md`
8485
- When new primitives, patterns, or test directories are added, update FEATURES.md and README.md
8586

8687
Last updated: April 29, 2026

package.json

Lines changed: 8 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -42,7 +42,7 @@
4242
"clsx": "2.1.1",
4343
"home-assistant-js-websocket": "^9.6.0",
4444
"leaflet": "^1.9.4",
45-
"lucide-react": "1.11.0",
45+
"lucide-react": "1.14.0",
4646
"react-leaflet": "^5.0.0",
4747
"sonner": "2.0.7",
4848
"tailwind-merge": "3.5.0",
@@ -52,11 +52,11 @@
5252
},
5353
"devDependencies": {
5454
"@biomejs/biome": "^2.4.13",
55-
"@storybook/addon-a11y": "^10.3.5",
56-
"@storybook/addon-docs": "10.3.5",
57-
"@storybook/addon-vitest": "^10.3.5",
58-
"@storybook/react": "10.3.5",
59-
"@storybook/react-vite": "^10.3.5",
55+
"@storybook/addon-a11y": "^10.3.6",
56+
"@storybook/addon-docs": "10.3.6",
57+
"@storybook/addon-vitest": "^10.3.6",
58+
"@storybook/react": "10.3.6",
59+
"@storybook/react-vite": "^10.3.6",
6060
"@tailwindcss/vite": "4.2.4",
6161
"@testing-library/jest-dom": "^6.9.1",
6262
"@testing-library/react": "^16.3.2",
@@ -68,9 +68,9 @@
6868
"@vitest/browser-playwright": "^4.1.5",
6969
"@vitest/coverage-v8": "^4.1.5",
7070
"husky": "^9.1.7",
71-
"jsdom": "^29.0.2",
71+
"jsdom": "^29.1.0",
7272
"playwright": "^1.59.1",
73-
"storybook": "^10.3.5",
73+
"storybook": "^10.3.6",
7474
"tailwindcss": "4.2.4",
7575
"typescript": "^6.0.3",
7676
"vite": "8.0.10",

0 commit comments

Comments
 (0)