feat(settings): move Hide IP toggle into Settings modal, persist it

Hide-IP was a sidebar button held only in memory, so it reset on reload.
Moved it into the Settings modal Canvas section and persist it to
localStorage (new ipDisplay util); the canvas store now seeds hideIp from
storage and writes through on toggleHideIp/setHideIp. Settings is now also
reachable in standalone (no-backend) builds, with the backend-only status
interval guarded so the modal still works there.

ha-relevant: yes
This commit is contained in:
Pouzor
2026-06-05 11:26:28 +02:00
parent c67b1775a5
commit b52bbc6d9f
8 changed files with 124 additions and 32 deletions
@@ -12,6 +12,7 @@ vi.mock('@/api/client', () => ({
import { settingsApi } from '@/api/client'
import { toast } from 'sonner'
import { useCanvasStore } from '@/stores/canvasStore'
describe('SettingsModal', () => {
beforeEach(() => {
@@ -64,6 +65,17 @@ describe('SettingsModal', () => {
expect(onClose).not.toHaveBeenCalled()
})
it('reflects and persists the hide-IP preference', async () => {
useCanvasStore.setState({ hideIp: false })
localStorage.removeItem('homelable.hideIp')
render(<SettingsModal open onClose={vi.fn()} />)
const checkbox = screen.getByLabelText('Toggle IP address masking') as HTMLInputElement
expect(checkbox.checked).toBe(false)
fireEvent.click(checkbox)
expect(useCanvasStore.getState().hideIp).toBe(true)
expect(localStorage.getItem('homelable.hideIp')).toBe('true')
})
it('calls onClose on Cancel', async () => {
const onClose = vi.fn()
render(<SettingsModal open onClose={onClose} />)