diff --git a/frontend/src/App.tsx b/frontend/src/App.tsx index 6ac9558..df8f23d 100644 --- a/frontend/src/App.tsx +++ b/frontend/src/App.tsx @@ -404,6 +404,7 @@ export function App() { readProductEnvironmentConfigStatus( selectedProductOverview.product, environment.environment, + controller.signal, ).then((payload) => payload.config_status), ), ) diff --git a/frontend/src/ProductOverviewShell.tsx b/frontend/src/ProductOverviewShell.tsx index ee5e6c0..d19c5bb 100644 --- a/frontend/src/ProductOverviewShell.tsx +++ b/frontend/src/ProductOverviewShell.tsx @@ -144,6 +144,7 @@ function EnvironmentDetailStrip({ const blockedActions = environment.available_actions.filter( (action) => !action.enabled, ); + const baseUrl = safeExternalHttpUrl(environment.base_url); return (
@@ -151,11 +152,13 @@ function EnvironmentDetailStrip({ {environment.environment} {environment.context} - {environment.base_url ? ( - + {baseUrl ? ( + + ) : environment.base_url ? ( + {environment.base_url} ) : null}
@@ -193,3 +196,16 @@ function EnvironmentDetailStrip({
); } + +function safeExternalHttpUrl(value: string): URL | null { + const trimmed = value.trim(); + if (!trimmed) { + return null; + } + try { + const url = new URL(trimmed); + return url.protocol === "http:" || url.protocol === "https:" ? url : null; + } catch { + return null; + } +} diff --git a/frontend/src/api.ts b/frontend/src/api.ts index 6714d4f..96eaa01 100644 --- a/frontend/src/api.ts +++ b/frontend/src/api.ts @@ -35,6 +35,7 @@ async function requestJson( path: string, method: "GET" | "POST" = "GET", body?: unknown, + signal?: AbortSignal, ): Promise { const headers: HeadersInit = { Accept: "application/json", @@ -47,6 +48,7 @@ async function requestJson( credentials: "same-origin", headers, body: body === undefined ? undefined : JSON.stringify(body), + signal, }); const payload = (await response.json()) as T | ApiErrorPayload; if (!response.ok) { @@ -102,9 +104,13 @@ export function listProducts(): Promise { export function readProductEnvironmentConfigStatus( product: string, environment: string, + signal?: AbortSignal, ): Promise { return requestJson( `/v1/products/${encodeURIComponent(product)}/environments/${encodeURIComponent(environment)}/config-status`, + "GET", + undefined, + signal, ); }