From d06804b1455fcbd42d1dd632ddd7f95f68752788 Mon Sep 17 00:00:00 2001 From: stroblme Date: Fri, 16 Oct 2026 09:25:34 +0200 Subject: [PATCH] Panels dialog: opens without focusing a field, a panel title saves on blur, Enter or Escape instead of per keystroke, and a new panel's name previews its URL. Docs --- docs/interface/dashboards.md | 4 +- .../src/components/Dashboard/PanelsDialog.tsx | 115 +++++++++++------- 2 files changed, 76 insertions(+), 43 deletions(-) diff --git a/docs/interface/dashboards.md b/docs/interface/dashboards.md index dad99a5..d0c812d 100644 --- a/docs/interface/dashboards.md +++ b/docs/interface/dashboards.md @@ -447,7 +447,9 @@ For a dedicated screen, pair a panel. As a superuser: -1. Open **Dashboards → Panels**, add a panel and select its dashboards. +1. Open **Dashboards → Panels**, add a panel and select its dashboards. The + name you add it under sets its address, `/panel/{id}`, and a later change of + title keeps it. 2. Enable **Touch friendly** for larger controls. 3. Open the displayed pairing link on the device. It shows a six-character code. 4. Enter that code for the panel, check the device description, then press diff --git a/frontend/src/components/Dashboard/PanelsDialog.tsx b/frontend/src/components/Dashboard/PanelsDialog.tsx index 373209e..dc876b1 100644 --- a/frontend/src/components/Dashboard/PanelsDialog.tsx +++ b/frontend/src/components/Dashboard/PanelsDialog.tsx @@ -139,7 +139,7 @@ export function PanelsDialog({ focus }: { focus?: string } = {}) { write({ panels: panels.map((p) => (p.id === id ? panel : p)) }) // Closing saves every new port that is ready, in one write. Its port field - // only commits on blur, and Escape closes the dialog without one. + // only commits on blur, and closing does not always blur it. const saveDrafts = () => { const done = Object.keys(drafts).filter((id) => ready(drafts[id])) if (!done.length) return @@ -167,7 +167,17 @@ export function PanelsDialog({ focus }: { focus?: string } = {}) { return ( { + event.preventDefault() + const content = event.currentTarget as HTMLElement + content.focus() + }} + // Escape closes without a blur, and the fields here save on blur. + onEscapeKeyDown={() => (document.activeElement as HTMLElement).blur()} onCloseAutoFocus={saveDrafts} > @@ -211,43 +221,55 @@ export function PanelsDialog({ focus }: { focus?: string } = {}) { <> -
{ - event.preventDefault() - if (!newId || taken) return - write({ - panels: [...panels, { id: newId, title: name.trim() }], - }) - setName("") - }} - > -
- - setName(event.target.value)} - /> -
- -
- {taken ? ( -

- There is already a panel called {newId}. -

- ) : null} +
+ + setName(event.target.value)} + /> +
+ + + {taken ? ( +

+ There is already a panel called {newId}. +

+ ) : null} + {/* The name becomes the panel's address and stays its address, + while the title can change any time. */} + {newId && host && !taken ? ( +

+ Opens at {host}/panel/{newId} +

+ ) : null} + ) : null} @@ -352,13 +374,22 @@ function PanelRow({ >
- onChange({ ...panel, title: event.target.value }) - } + onKeyDown={(event) => { + if (event.key === "Enter") event.currentTarget.blur() + }} + onBlur={(event) => { + const title = event.currentTarget.value.trim() + event.currentTarget.value = title + if (title !== panel.title) onChange({ ...panel, title }) + }} /> {panel.id}