fix(admin): restore display layout switching

This commit is contained in:
Mitchell R 2026-05-21 08:57:54 +02:00
parent 3d5e27bdfb
commit 6cfb37aa64
No known key found for this signature in database
3 changed files with 34 additions and 24 deletions

View file

@ -18,7 +18,8 @@ services:
context: . context: .
dockerfile: deploy/docker/Dockerfile.server dockerfile: deploy/docker/Dockerfile.server
args: args:
BF_SERVER_VERSION: ${BF_SERVER_VERSION:-} BF_SERVER_VERSION: ${BF_SERVER_VERSION:-${SOURCE_COMMIT:-dev}}
SOURCE_COMMIT: ${SOURCE_COMMIT:-}
container_name: betterframe-server container_name: betterframe-server
restart: unless-stopped restart: unless-stopped
environment: environment:
@ -27,8 +28,7 @@ services:
- BF_SQLITE_PATH=/var/lib/betterframe/betterframe.db - BF_SQLITE_PATH=/var/lib/betterframe/betterframe.db
- BF_NODERED_URL=http://nodered:1880 - BF_NODERED_URL=http://nodered:1880
- BF_SELF_URL=http://server:18080 - BF_SELF_URL=http://server:18080
- BF_SERVER_VERSION=${BF_SERVER_VERSION:-} - BF_SERVER_VERSION=${BF_SERVER_VERSION:-${SOURCE_COMMIT:-dev}}
- COOLIFY_GIT_COMMIT=${COOLIFY_GIT_COMMIT:-}
- SOURCE_COMMIT=${SOURCE_COMMIT:-} - SOURCE_COMMIT=${SOURCE_COMMIT:-}
volumes: volumes:
- betterframe-data:/var/lib/betterframe - betterframe-data:/var/lib/betterframe

View file

@ -1498,9 +1498,13 @@ export function registerAdminRoutes(app: H3, deps: AdminDeps): void {
}); });
}; };
const displayLayoutSwitch = (event: any) => { const displayLayoutSwitch = async (event: any) => {
const displayId = Number(getRouterParam(event, "displayId")); const displayId = Number(getRouterParam(event, "displayId"));
const layoutId = Number(getRouterParam(event, "layoutId")); let layoutId = Number(getRouterParam(event, "layoutId"));
if (!Number.isFinite(layoutId) || layoutId <= 0) {
const body = await readBody<Record<string, string>>(event);
layoutId = Number(body?.["layout_id"]);
}
if (Number.isFinite(displayId) && Number.isFinite(layoutId)) { if (Number.isFinite(displayId) && Number.isFinite(layoutId)) {
const display = deps.repo.getDisplayById(displayId); const display = deps.repo.getDisplayById(displayId);
const attached = deps.repo.listLayoutsForDisplay(displayId); const attached = deps.repo.listLayoutsForDisplay(displayId);
@ -1516,6 +1520,7 @@ export function registerAdminRoutes(app: H3, deps: AdminDeps): void {
} }
return new Response(null, { status: 302, headers: { location: `/admin/displays/${displayId}` } }); return new Response(null, { status: 302, headers: { location: `/admin/displays/${displayId}` } });
}; };
app.post("/admin/displays/:displayId/layout", displayLayoutSwitch);
app.post("/admin/displays/:displayId/layout/:layoutId", displayLayoutSwitch); app.post("/admin/displays/:displayId/layout/:layoutId", displayLayoutSwitch);
app.get("/admin/displays/:displayId/layout/:layoutId", displayLayoutSwitch); app.get("/admin/displays/:displayId/layout/:layoutId", displayLayoutSwitch);

View file

@ -1561,13 +1561,21 @@ export function KioskEditPage(props: KioskEditProps) {
<div style="font-size:0.85rem; font-weight:600; margin-bottom:0.5rem">Switch Layout By Display</div> <div style="font-size:0.85rem; font-weight:600; margin-bottom:0.5rem">Switch Layout By Display</div>
<div style="display:grid; gap:0.75rem"> <div style="display:grid; gap:0.75rem">
{props.displayLayouts.map(({ display, layouts }) => ( {props.displayLayouts.map(({ display, layouts }) => (
<div style="display:grid; grid-template-columns:minmax(130px, 0.8fr) minmax(180px, 1fr) auto; gap:0.5rem; align-items:center"> <form
method="post"
action={`/admin/displays/${String(display.id)}/layout`}
style="display:grid; grid-template-columns:minmax(130px, 0.8fr) minmax(180px, 1fr) auto; gap:0.5rem; align-items:center"
{...{
"hx-post": `/admin/displays/${String(display.id)}/layout`,
"hx-swap": "none",
}}
>
<div style="font-size:0.85rem"> <div style="font-size:0.85rem">
<a href={`/admin/displays/${String(display.id)}`}><strong>{display.name}</strong></a> <a href={`/admin/displays/${String(display.id)}`}><strong>{display.name}</strong></a>
<div style="color:#666; font-size:0.75rem">{String(display.width_px)}x{String(display.height_px)}</div> <div style="color:#666; font-size:0.75rem">{String(display.width_px)}x{String(display.height_px)}</div>
</div> </div>
{layouts.length > 0 ? ( {layouts.length > 0 ? (
<select id={`display-layout-pick-${String(display.id)}`} class="form-input"> <select name="layout_id" class="form-input">
{layouts.map((l) => ( {layouts.map((l) => (
<option value={String(l.id)}>{l.name}</option> <option value={String(l.id)}>{l.name}</option>
))} ))}
@ -1576,16 +1584,11 @@ export function KioskEditPage(props: KioskEditProps) {
<span style="color:#999; font-size:0.85rem">No attached layouts</span> <span style="color:#999; font-size:0.85rem">No attached layouts</span>
)} )}
<button <button
type="button" type="submit"
class="btn btn-sm" class="btn btn-sm"
disabled={layouts.length === 0} disabled={layouts.length === 0}
{...{
"hx-post": `/admin/displays/${String(display.id)}/layout/0`,
"hx-swap": "none",
"hx-on::config-request": `event.detail.path = event.detail.path.replace(/\\/layout\\/.*/, '/layout/' + document.getElementById('display-layout-pick-${String(display.id)}').value);`,
}}
>Switch</button> >Switch</button>
</div> </form>
)).join("")} )).join("")}
</div> </div>
</div> </div>
@ -2518,23 +2521,25 @@ export function DisplayEditPage(props: DisplayEditPageProps) {
{props.attachedLayouts.length > 0 && d.kiosk_id ? ( {props.attachedLayouts.length > 0 && d.kiosk_id ? (
<div style="margin-bottom:1rem; padding:0.75rem; background:#f9fafb; border-radius:4px"> <div style="margin-bottom:1rem; padding:0.75rem; background:#f9fafb; border-radius:4px">
<div style="font-size:0.85rem; font-weight:600; margin-bottom:0.5rem">Switch Layout Now</div> <div style="font-size:0.85rem; font-weight:600; margin-bottom:0.5rem">Switch Layout Now</div>
<div style="display:flex; gap:0.5rem; align-items:center"> <form
<select id={`layout-pick-${d.id}`} class="form-input" style="flex:1"> method="post"
action={`/admin/displays/${d.id}/layout`}
style="display:flex; gap:0.5rem; align-items:center"
{...{
"hx-post": `/admin/displays/${d.id}/layout`,
"hx-swap": "none",
}}
>
<select name="layout_id" class="form-input" style="flex:1">
{props.attachedLayouts.map((l) => ( {props.attachedLayouts.map((l) => (
<option value={String(l.id)}>{l.name}</option> <option value={String(l.id)}>{l.name}</option>
))} ))}
</select> </select>
<button <button
type="button" type="submit"
class="btn btn-sm" class="btn btn-sm"
{...{
"hx-post": `/admin/displays/${d.id}/layout/0`,
"hx-swap": "none",
"hx-vals": "js:{}",
"hx-on::config-request": `event.detail.path = event.detail.path.replace(/\\/layout\\/.*/, '/layout/' + document.getElementById('layout-pick-${d.id}').value);`,
}}
>Switch</button> >Switch</button>
</div> </form>
</div> </div>
) : null} ) : null}