Report
User on the Tauri desktop client sees this in the Monitors list:
- The monitor thumbnail shows a "camera with a line through it" (broken) icon with an MJPEG badge.
- Hovering the tile shows a popup preview that streams correctly.
- Clicking the tile opens the monitor detail view, where nothing plays and console shows requests like:
http://server.localdomain:0/zm/api/monitors/alarm/id:1/command:status.json?token=...
Note the hostname server.localdomain and port 0.
Root cause
Two different URL-construction paths:
- Hover preview (
components/monitors/MonitorHoverPreview.tsx:83-88) uses currentProfile.cgiUrl directly — the URL the user configured. Works.
- Monitor detail view (
pages/MonitorDetail.tsx:129) calls useServerUrls(monitor.Monitor.ServerId), which goes through lib/server-resolver.ts.
server-resolver.ts:67-96 builds a per-server URL map from /zm/api/servers/index.json. At line 76:
const port = server.Port ?? 443;
Nullish coalescing lets Port: 0 through unchanged. Combined with a placeholder Hostname: "server.localdomain" that many ZM single-server installs have by default in their Servers table, the resolver produces http://server.localdomain:0/zm/api and that base is passed to getAlarmStatus and every other API call for that monitor.
Expected behavior
The app should use the user's configured profile URL when the ZM Servers row looks like placeholder data (empty/missing Hostname, non-positive Port, or obvious placeholder hostnames like localhost, *.localdomain). The resolver already has a fallback path for missing rows — this issue is about treating obviously-broken rows as equivalent to missing.
Fix plan
In lib/server-resolver.ts::buildServerMap, skip rows that:
- Have no
Hostname (already skipped today)
- Have
Port <= 0 or non-numeric Port
- Have a placeholder Hostname (
localhost, *.localdomain)
Skipped rows won't land in the map, so resolveMonitorUrls naturally falls back to the profile defaults (same path as when ServerId is absent).
Test plan
- Unit tests in
lib/__tests__/server-resolver.test.ts:
buildServerMap skips rows with Port: 0
buildServerMap skips rows with Port: null
buildServerMap skips rows with placeholder hostnames (localhost, *.localdomain)
resolveMonitorUrls falls back to profile defaults when the ServerId points at a skipped row
- Manual verification on the user's setup that the monitor detail view loads correctly.
Report
User on the Tauri desktop client sees this in the Monitors list:
Note the hostname
server.localdomainand port0.Root cause
Two different URL-construction paths:
components/monitors/MonitorHoverPreview.tsx:83-88) usescurrentProfile.cgiUrldirectly — the URL the user configured. Works.pages/MonitorDetail.tsx:129) callsuseServerUrls(monitor.Monitor.ServerId), which goes throughlib/server-resolver.ts.server-resolver.ts:67-96builds a per-server URL map from/zm/api/servers/index.json. At line 76:Nullish coalescing lets
Port: 0through unchanged. Combined with a placeholderHostname: "server.localdomain"that many ZM single-server installs have by default in theirServerstable, the resolver produceshttp://server.localdomain:0/zm/apiand that base is passed togetAlarmStatusand every other API call for that monitor.Expected behavior
The app should use the user's configured profile URL when the ZM Servers row looks like placeholder data (empty/missing Hostname, non-positive Port, or obvious placeholder hostnames like
localhost,*.localdomain). The resolver already has a fallback path for missing rows — this issue is about treating obviously-broken rows as equivalent to missing.Fix plan
In
lib/server-resolver.ts::buildServerMap, skip rows that:Hostname(already skipped today)Port <= 0or non-numeric Portlocalhost,*.localdomain)Skipped rows won't land in the map, so
resolveMonitorUrlsnaturally falls back to the profile defaults (same path as when ServerId is absent).Test plan
lib/__tests__/server-resolver.test.ts:buildServerMapskips rows withPort: 0buildServerMapskips rows withPort: nullbuildServerMapskips rows with placeholder hostnames (localhost,*.localdomain)resolveMonitorUrlsfalls back to profile defaults when the ServerId points at a skipped row