Point the panel link at the installation, not at the browser's origin
Both links out of the dashboard editor were built root-relative, so a portal
serving the app under `/i/{id}` got a URL to itself: the hub has no route
there and answers a bare 404. That is what a device link and "open what a
wall panel sees" both landed on.
They want different answers. The view link is for the person already looking,
so it takes the router's basepath — `appPath` in `lib/portal` is the same
prefix the router applies to every `Link`, for the places that step outside
it. The device link is for a screen, which cannot go through the portal at
all: the shell is served only to a portal session, and the credential that
page carries is the portal's rather than the panel's. So the server now says
where it answers, and `FRONTEND_HOST` is that answer — the same setting the
password-reset links already use.
Also fixes the panel branch in the query error handler, which compared a raw
pathname and so never fired under a portal.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01AHpLJHozysQXjsxAyU1WHj
This commit is contained in:
@@ -51,6 +51,7 @@ import {
|
||||
import useCustomToast from "@/hooks/useCustomToast"
|
||||
import { useIsMobile } from "@/hooks/useMobile"
|
||||
import { slideUp, transitions } from "@/lib/motion"
|
||||
import { appPath } from "@/lib/portal"
|
||||
import { cn } from "@/lib/utils"
|
||||
import { handleError } from "@/utils"
|
||||
import {
|
||||
@@ -644,7 +645,7 @@ export function DashboardEditor({
|
||||
asChild
|
||||
>
|
||||
<a
|
||||
href={`/view/${draft.name}`}
|
||||
href={appPath(`/view/${draft.name}`)}
|
||||
target="_blank"
|
||||
rel="noreferrer"
|
||||
>
|
||||
|
||||
@@ -49,6 +49,11 @@ export function PanelsDialog() {
|
||||
|
||||
const panels = config?.panels ?? []
|
||||
const known = dashboards?.data ?? []
|
||||
// The installation's own address, not this browser's: administering through
|
||||
// the portal puts the page on the portal's origin, and a screen cannot be
|
||||
// sent there — it has no portal session and could not hold a panel
|
||||
// credential if it had one.
|
||||
const host = config?.frontend_host ?? ""
|
||||
|
||||
const write = (next: PanelsConfig) =>
|
||||
save.mutate(next, {
|
||||
@@ -67,7 +72,8 @@ export function PanelsDialog() {
|
||||
<DialogTitle>Panels</DialogTitle>
|
||||
<DialogDescription>
|
||||
A panel is one screen and the dashboards it shows. Point the device at
|
||||
the link, and it asks for a code you enter here.
|
||||
the link — the installation's own address, reachable from wherever the
|
||||
screen hangs — and it asks for a code you enter here.
|
||||
</DialogDescription>
|
||||
</DialogHeader>
|
||||
|
||||
@@ -82,6 +88,7 @@ export function PanelsDialog() {
|
||||
<PanelRow
|
||||
key={panel.id}
|
||||
panel={panel}
|
||||
host={host}
|
||||
dashboards={known.map((dashboard) => ({
|
||||
name: dashboard.name,
|
||||
title: dashboard.title || dashboard.name,
|
||||
@@ -137,11 +144,14 @@ export function PanelsDialog() {
|
||||
|
||||
function PanelRow({
|
||||
panel,
|
||||
host,
|
||||
dashboards,
|
||||
onChange,
|
||||
onRemove,
|
||||
}: {
|
||||
panel: PanelDef
|
||||
/** Where this installation answers, as it knows itself. */
|
||||
host: string
|
||||
dashboards: { name: string; title: string }[]
|
||||
onChange: (next: PanelDef) => void
|
||||
onRemove: () => void
|
||||
@@ -175,7 +185,7 @@ function PanelRow({
|
||||
: [...assigned, dashboard],
|
||||
})
|
||||
|
||||
const link = `${window.location.origin}/panel/${panel.id}`
|
||||
const link = host ? `${host}/panel/${panel.id}` : ""
|
||||
|
||||
return (
|
||||
<div className="grid gap-3" data-testid={`panel-${panel.id}`}>
|
||||
@@ -240,6 +250,7 @@ function PanelRow({
|
||||
<Input
|
||||
readOnly
|
||||
value={link}
|
||||
placeholder="This installation has no address set"
|
||||
aria-label={`Link for ${panel.id}`}
|
||||
className="text-muted-foreground"
|
||||
onFocus={(event) => event.currentTarget.select()}
|
||||
|
||||
Reference in New Issue
Block a user