From 019c9e8cb44a866bc88eab51aa9666385b5f6264 Mon Sep 17 00:00:00 2001 From: silent-cipher Date: Mon, 29 Jun 2026 23:40:17 +0530 Subject: [PATCH 1/3] feat(web): add per-network betterstack url configuration --- apps/web/.env.example | 13 ++++++++-- apps/web/docker-entrypoint.sh | 14 ++++++++++- apps/web/src/pages/Landing.tsx | 45 +++++++++++++++++++++++++++++++--- apps/web/src/vite-env.d.ts | 8 ++++++ 4 files changed, 74 insertions(+), 6 deletions(-) diff --git a/apps/web/.env.example b/apps/web/.env.example index 71d59fb5..abb3819b 100644 --- a/apps/web/.env.example +++ b/apps/web/.env.example @@ -6,9 +6,15 @@ VITE_API_BASE_URL=http://localhost:8080 # Example values: dealbot.filoz.org or staging.dealbot.filoz.org VITE_PLAUSIBLE_DATA_DOMAIN= -# Dashboard URL linked from the landing page +# Metrics dashboard URL linked from the per-SP rows on the landing page. +# BetterStack keeps a separate dashboard per network, so set the per-network +# vars below for deployments that monitor more than one network. VITE_DASHBOARD_URL +# is the fallback used when the selected network's var is unset, so existing +# single-network deployments keep working until infra sets the per-network vars. # Example: https://your-team.betteruptime.com VITE_DASHBOARD_URL= +VITE_DASHBOARD_URL_MAINNET= +VITE_DASHBOARD_URL_CALIBRATION= # Dashboard URL to embed as an iframe on the landing page (optional) # Example: https://your-team.betteruptime.com/embed/... @@ -21,5 +27,8 @@ VITE_DASHBOARD_EMBED_URL= VITE_APPROVED_SP_DASHBOARD_URL_MAINNET= VITE_APPROVED_SP_DASHBOARD_URL_CALIBRATION= -# Logs URL linked from the landing page (optional) +# Logs URL linked from the per-SP rows on the landing page (optional). +# Per-network vars take precedence; VITE_LOGS_URL is the fallback when unset. VITE_LOGS_URL= +VITE_LOGS_URL_MAINNET= +VITE_LOGS_URL_CALIBRATION= diff --git a/apps/web/docker-entrypoint.sh b/apps/web/docker-entrypoint.sh index 06b88235..a7a367ea 100644 --- a/apps/web/docker-entrypoint.sh +++ b/apps/web/docker-entrypoint.sh @@ -10,28 +10,40 @@ escape_js() { API_BASE_URL="${DEALBOT_API_BASE_URL:-${VITE_API_BASE_URL:-}}" PLAUSIBLE_DATA_DOMAIN="${VITE_PLAUSIBLE_DATA_DOMAIN:-}" DASHBOARD_URL="${DASHBOARD_URL:-${VITE_DASHBOARD_URL:-}}" +DASHBOARD_URL_MAINNET="${DASHBOARD_URL_MAINNET:-${VITE_DASHBOARD_URL_MAINNET:-}}" +DASHBOARD_URL_CALIBRATION="${DASHBOARD_URL_CALIBRATION:-${VITE_DASHBOARD_URL_CALIBRATION:-}}" DASHBOARD_EMBED_URL="${DASHBOARD_EMBED_URL:-${VITE_DASHBOARD_EMBED_URL:-}}" APPROVED_SP_DASHBOARD_URL_MAINNET="${APPROVED_SP_DASHBOARD_URL_MAINNET:-${VITE_APPROVED_SP_DASHBOARD_URL_MAINNET:-}}" APPROVED_SP_DASHBOARD_URL_CALIBRATION="${APPROVED_SP_DASHBOARD_URL_CALIBRATION:-${VITE_APPROVED_SP_DASHBOARD_URL_CALIBRATION:-}}" LOGS_URL="${LOGS_URL:-${VITE_LOGS_URL:-}}" +LOGS_URL_MAINNET="${LOGS_URL_MAINNET:-${VITE_LOGS_URL_MAINNET:-}}" +LOGS_URL_CALIBRATION="${LOGS_URL_CALIBRATION:-${VITE_LOGS_URL_CALIBRATION:-}}" API_BASE_URL_ESCAPED="$(escape_js "$API_BASE_URL")" PLAUSIBLE_DATA_DOMAIN_ESCAPED="$(escape_js "$PLAUSIBLE_DATA_DOMAIN")" DASHBOARD_URL_ESCAPED="$(escape_js "$DASHBOARD_URL")" +DASHBOARD_URL_MAINNET_ESCAPED="$(escape_js "$DASHBOARD_URL_MAINNET")" +DASHBOARD_URL_CALIBRATION_ESCAPED="$(escape_js "$DASHBOARD_URL_CALIBRATION")" DASHBOARD_EMBED_URL_ESCAPED="$(escape_js "$DASHBOARD_EMBED_URL")" APPROVED_SP_DASHBOARD_URL_MAINNET_ESCAPED="$(escape_js "$APPROVED_SP_DASHBOARD_URL_MAINNET")" APPROVED_SP_DASHBOARD_URL_CALIBRATION_ESCAPED="$(escape_js "$APPROVED_SP_DASHBOARD_URL_CALIBRATION")" LOGS_URL_ESCAPED="$(escape_js "$LOGS_URL")" +LOGS_URL_MAINNET_ESCAPED="$(escape_js "$LOGS_URL_MAINNET")" +LOGS_URL_CALIBRATION_ESCAPED="$(escape_js "$LOGS_URL_CALIBRATION")" cat > "$RUNTIME_CONFIG_PATH" < { return { safe, isInvalid: Boolean(raw) && !safe }; }; +type NetworkUrlSource = { runtime?: string; build?: string }; + +/** + * Resolves a URL that may be configured per network, falling back to a bare + * global value so single-network deployments keep working before infra sets the + * per-network vars. Precedence within each tier (runtime, build) is + * per-network → global; runtime still wins over build (see getConfigUrl). + */ +const getNetworkConfigUrl = ( + network: Network | null, + perNetwork: Record, + global: NetworkUrlSource, +) => { + const scoped = network ? perNetwork[network] : undefined; + return getConfigUrl(scoped?.runtime ?? global.runtime, scoped?.build ?? global.build); +}; + const getConfig = (network: Network | null) => { const runtimeConfig = typeof window === "undefined" ? undefined : window.__DEALBOT_CONFIG__; - const dashboardUrl = getConfigUrl(runtimeConfig?.DASHBOARD_URL, import.meta.env.VITE_DASHBOARD_URL); - const approvedSpSources: Record = { + // Metrics dashboard and SP logs live in a distinct BetterStack dashboard per + // network, so prefer a per-network URL and fall back to the bare global var so + // single-network deployments keep working until infra sets the per-network vars. + const dashboardUrl = getNetworkConfigUrl( + network, + { + mainnet: { runtime: runtimeConfig?.DASHBOARD_URL_MAINNET, build: import.meta.env.VITE_DASHBOARD_URL_MAINNET }, + calibration: { + runtime: runtimeConfig?.DASHBOARD_URL_CALIBRATION, + build: import.meta.env.VITE_DASHBOARD_URL_CALIBRATION, + }, + }, + { runtime: runtimeConfig?.DASHBOARD_URL, build: import.meta.env.VITE_DASHBOARD_URL }, + ); + const logsUrl = getNetworkConfigUrl( + network, + { + mainnet: { runtime: runtimeConfig?.LOGS_URL_MAINNET, build: import.meta.env.VITE_LOGS_URL_MAINNET }, + calibration: { runtime: runtimeConfig?.LOGS_URL_CALIBRATION, build: import.meta.env.VITE_LOGS_URL_CALIBRATION }, + }, + { runtime: runtimeConfig?.LOGS_URL, build: import.meta.env.VITE_LOGS_URL }, + ); + + // Approved-SP dashboard: per-network only (two separate curated dashboards; no global fallback). + const approvedSpSources: Record = { mainnet: { runtime: runtimeConfig?.APPROVED_SP_DASHBOARD_URL_MAINNET, build: import.meta.env.VITE_APPROVED_SP_DASHBOARD_URL_MAINNET, @@ -68,7 +108,6 @@ const getConfig = (network: Network | null) => { const approvedSpDashboardUrl = network ? getConfigUrl(approvedSpSources[network].runtime, approvedSpSources[network].build) : { safe: "", isInvalid: false }; - const logsUrl = getConfigUrl(runtimeConfig?.LOGS_URL, import.meta.env.VITE_LOGS_URL); return { dashboardUrl: dashboardUrl.safe, diff --git a/apps/web/src/vite-env.d.ts b/apps/web/src/vite-env.d.ts index e2df724c..1b62de2b 100644 --- a/apps/web/src/vite-env.d.ts +++ b/apps/web/src/vite-env.d.ts @@ -7,10 +7,14 @@ interface ImportMeta { readonly VITE_API_BASE_URL: string; readonly VITE_PLAUSIBLE_DATA_DOMAIN?: string; readonly VITE_DASHBOARD_URL?: string; + readonly VITE_DASHBOARD_URL_MAINNET?: string; + readonly VITE_DASHBOARD_URL_CALIBRATION?: string; readonly VITE_DASHBOARD_EMBED_URL?: string; readonly VITE_APPROVED_SP_DASHBOARD_URL_MAINNET?: string; readonly VITE_APPROVED_SP_DASHBOARD_URL_CALIBRATION?: string; readonly VITE_LOGS_URL?: string; + readonly VITE_LOGS_URL_MAINNET?: string; + readonly VITE_LOGS_URL_CALIBRATION?: string; }; } @@ -19,9 +23,13 @@ interface Window { API_BASE_URL?: string; PLAUSIBLE_DATA_DOMAIN?: string; DASHBOARD_URL?: string; + DASHBOARD_URL_MAINNET?: string; + DASHBOARD_URL_CALIBRATION?: string; DASHBOARD_EMBED_URL?: string; APPROVED_SP_DASHBOARD_URL_MAINNET?: string; APPROVED_SP_DASHBOARD_URL_CALIBRATION?: string; LOGS_URL?: string; + LOGS_URL_MAINNET?: string; + LOGS_URL_CALIBRATION?: string; }; } From f2a32217d04c2916bc34d7549eb69ceab2fbc4b3 Mon Sep 17 00:00:00 2001 From: silent-cipher Date: Thu, 2 Jul 2026 01:10:18 +0530 Subject: [PATCH 2/3] feat: rescope url configuration --- apps/web/.env.example | 24 ++++---- apps/web/docker-entrypoint.sh | 17 ++---- apps/web/src/pages/Landing.test.tsx | 42 +++++++++++++- apps/web/src/pages/Landing.tsx | 90 +++++++++++++++-------------- apps/web/src/vite-env.d.ts | 10 +--- 5 files changed, 105 insertions(+), 78 deletions(-) diff --git a/apps/web/.env.example b/apps/web/.env.example index abb3819b..4fe9c2dd 100644 --- a/apps/web/.env.example +++ b/apps/web/.env.example @@ -7,28 +7,26 @@ VITE_API_BASE_URL=http://localhost:8080 VITE_PLAUSIBLE_DATA_DOMAIN= # Metrics dashboard URL linked from the per-SP rows on the landing page. -# BetterStack keeps a separate dashboard per network, so set the per-network -# vars below for deployments that monitor more than one network. VITE_DASHBOARD_URL -# is the fallback used when the selected network's var is unset, so existing -# single-network deployments keep working until infra sets the per-network vars. +# One dashboard per environment; the app adds a vs[network] filter per row so it +# serves every network the deployment monitors (a no-op until the dashboard +# defines a {{network}} variable). # Example: https://your-team.betteruptime.com VITE_DASHBOARD_URL= -VITE_DASHBOARD_URL_MAINNET= -VITE_DASHBOARD_URL_CALIBRATION= # Dashboard URL to embed as an iframe on the landing page (optional) # Example: https://your-team.betteruptime.com/embed/... VITE_DASHBOARD_EMBED_URL= -# Combined approved-SP dashboard URL linked from the landing page, per network (optional) -# The frontend picks the URL matching the backend's network (mainnet vs calibration). -# Example mainnet: https://telemetry.betterstack.com/dashboards/Zz8k7L?rf=now-72h&rt=now -# Example calibration: https://telemetry.betterstack.com/dashboards/wt6QCw?rf=now-3d&rt=now +# Combined approved-SP dashboard URL linked from the landing page (optional). +# Preferred: one per-environment dashboard; the app adds a vs[network] filter. +# When set, it wins over the legacy per-network vars below. +# Example: https://telemetry.betterstack.com/dashboards/Zz8k7L?rf=now-72h&rt=now +VITE_APPROVED_SP_DASHBOARD_URL= +# Legacy per-network approved-SP dashboards (fallback used when the combined var +# above is unset). Each deployment sets the one matching its network. VITE_APPROVED_SP_DASHBOARD_URL_MAINNET= VITE_APPROVED_SP_DASHBOARD_URL_CALIBRATION= # Logs URL linked from the per-SP rows on the landing page (optional). -# Per-network vars take precedence; VITE_LOGS_URL is the fallback when unset. +# One dashboard per environment; the app adds a vs[network] filter per row. VITE_LOGS_URL= -VITE_LOGS_URL_MAINNET= -VITE_LOGS_URL_CALIBRATION= diff --git a/apps/web/docker-entrypoint.sh b/apps/web/docker-entrypoint.sh index a7a367ea..893dd17f 100644 --- a/apps/web/docker-entrypoint.sh +++ b/apps/web/docker-entrypoint.sh @@ -10,40 +10,31 @@ escape_js() { API_BASE_URL="${DEALBOT_API_BASE_URL:-${VITE_API_BASE_URL:-}}" PLAUSIBLE_DATA_DOMAIN="${VITE_PLAUSIBLE_DATA_DOMAIN:-}" DASHBOARD_URL="${DASHBOARD_URL:-${VITE_DASHBOARD_URL:-}}" -DASHBOARD_URL_MAINNET="${DASHBOARD_URL_MAINNET:-${VITE_DASHBOARD_URL_MAINNET:-}}" -DASHBOARD_URL_CALIBRATION="${DASHBOARD_URL_CALIBRATION:-${VITE_DASHBOARD_URL_CALIBRATION:-}}" DASHBOARD_EMBED_URL="${DASHBOARD_EMBED_URL:-${VITE_DASHBOARD_EMBED_URL:-}}" +APPROVED_SP_DASHBOARD_URL="${APPROVED_SP_DASHBOARD_URL:-${VITE_APPROVED_SP_DASHBOARD_URL:-}}" APPROVED_SP_DASHBOARD_URL_MAINNET="${APPROVED_SP_DASHBOARD_URL_MAINNET:-${VITE_APPROVED_SP_DASHBOARD_URL_MAINNET:-}}" APPROVED_SP_DASHBOARD_URL_CALIBRATION="${APPROVED_SP_DASHBOARD_URL_CALIBRATION:-${VITE_APPROVED_SP_DASHBOARD_URL_CALIBRATION:-}}" LOGS_URL="${LOGS_URL:-${VITE_LOGS_URL:-}}" -LOGS_URL_MAINNET="${LOGS_URL_MAINNET:-${VITE_LOGS_URL_MAINNET:-}}" -LOGS_URL_CALIBRATION="${LOGS_URL_CALIBRATION:-${VITE_LOGS_URL_CALIBRATION:-}}" API_BASE_URL_ESCAPED="$(escape_js "$API_BASE_URL")" PLAUSIBLE_DATA_DOMAIN_ESCAPED="$(escape_js "$PLAUSIBLE_DATA_DOMAIN")" DASHBOARD_URL_ESCAPED="$(escape_js "$DASHBOARD_URL")" -DASHBOARD_URL_MAINNET_ESCAPED="$(escape_js "$DASHBOARD_URL_MAINNET")" -DASHBOARD_URL_CALIBRATION_ESCAPED="$(escape_js "$DASHBOARD_URL_CALIBRATION")" DASHBOARD_EMBED_URL_ESCAPED="$(escape_js "$DASHBOARD_EMBED_URL")" +APPROVED_SP_DASHBOARD_URL_ESCAPED="$(escape_js "$APPROVED_SP_DASHBOARD_URL")" APPROVED_SP_DASHBOARD_URL_MAINNET_ESCAPED="$(escape_js "$APPROVED_SP_DASHBOARD_URL_MAINNET")" APPROVED_SP_DASHBOARD_URL_CALIBRATION_ESCAPED="$(escape_js "$APPROVED_SP_DASHBOARD_URL_CALIBRATION")" LOGS_URL_ESCAPED="$(escape_js "$LOGS_URL")" -LOGS_URL_MAINNET_ESCAPED="$(escape_js "$LOGS_URL_MAINNET")" -LOGS_URL_CALIBRATION_ESCAPED="$(escape_js "$LOGS_URL_CALIBRATION")" cat > "$RUNTIME_CONFIG_PATH" < { + afterEach(() => { + window.__DEALBOT_CONFIG__ = undefined; + }); + it("renders string providerId in the table", () => { setupMock([makeProvider({ providerId: "42" })]); renderLanding(); @@ -81,4 +85,40 @@ describe("Landing", () => { const cells = row.querySelectorAll("td"); expect(cells[1].textContent).toBe("—"); }); + + it("scopes per-SP metrics and logs links with vs[network]", () => { + window.__DEALBOT_CONFIG__ = { + DASHBOARD_URL: "https://telemetry.betterstack.com/dashboards/metrics", + LOGS_URL: "https://telemetry.betterstack.com/dashboards/logs", + }; + setupMock([makeProvider({ providerId: "42" })]); + renderLanding(); + const metrics = screen.getByRole("link", { name: /Metrics/ }); + const logs = screen.getByRole("link", { name: /Logs/ }); + expect(metrics.getAttribute("href")).toContain("vs%5Bnetwork%5D=mainnet"); + expect(logs.getAttribute("href")).toContain("vs%5Bnetwork%5D=mainnet"); + }); + + it("prefers the combined approved-SP dashboard and scopes it with vs[network]", () => { + window.__DEALBOT_CONFIG__ = { + APPROVED_SP_DASHBOARD_URL: "https://telemetry.betterstack.com/dashboards/combined", + APPROVED_SP_DASHBOARD_URL_MAINNET: "https://telemetry.betterstack.com/dashboards/legacy-mainnet", + }; + setupMock(); + renderLanding(); + const href = screen.getByRole("link", { name: /View dashboard/ }).getAttribute("href") ?? ""; + expect(href).toContain("/dashboards/combined"); + expect(href).toContain("vs%5Bnetwork%5D=mainnet"); + }); + + it("falls back to the legacy per-network approved-SP dashboard when the combined var is unset", () => { + window.__DEALBOT_CONFIG__ = { + APPROVED_SP_DASHBOARD_URL_MAINNET: "https://telemetry.betterstack.com/dashboards/legacy-mainnet", + }; + setupMock(); + renderLanding(); + const href = screen.getByRole("link", { name: /View dashboard/ }).getAttribute("href") ?? ""; + expect(href).toContain("/dashboards/legacy-mainnet"); + expect(href).not.toContain("vs%5Bnetwork%5D"); + }); }); diff --git a/apps/web/src/pages/Landing.tsx b/apps/web/src/pages/Landing.tsx index 143d5a6e..35f9057d 100644 --- a/apps/web/src/pages/Landing.tsx +++ b/apps/web/src/pages/Landing.tsx @@ -10,8 +10,9 @@ import type { Network } from "@/types/config"; /** * Builds a BetterStack dashboard or logs URL scoped to a single provider. - * Appends time range (now-24h to now) and provider filter. - * Metrics dashboard uses vs[provider_id]; logs dashboard uses vs[providerId]. + * Appends time range and provider filter. Metrics dashboard uses vs[provider_id]; + * logs dashboard uses vs[providerId]. Network scoping is layered on separately + * via withNetworkParam. */ function buildBetterStackUrlWithProvider( baseUrl: string, @@ -54,48 +55,39 @@ const getConfigUrl = (runtimeValue?: string, buildValue?: string) => { type NetworkUrlSource = { runtime?: string; build?: string }; /** - * Resolves a URL that may be configured per network, falling back to a bare - * global value so single-network deployments keep working before infra sets the - * per-network vars. Precedence within each tier (runtime, build) is - * per-network → global; runtime still wins over build (see getConfigUrl). + * Adds the vs[network] dashboard filter to a URL, preserving existing params. + * Empty/invalid input yields "", and a null network returns the URL unchanged. + * A no-op until the BetterStack dashboard defines a {{network}} variable, so it + * is safe to emit ahead of that dashboard change. */ -const getNetworkConfigUrl = ( - network: Network | null, - perNetwork: Record, - global: NetworkUrlSource, -) => { - const scoped = network ? perNetwork[network] : undefined; - return getConfigUrl(scoped?.runtime ?? global.runtime, scoped?.build ?? global.build); +const withNetworkParam = (baseUrl: string, network: Network | null): string => { + if (!baseUrl || !network) return baseUrl; + try { + const url = new URL(baseUrl); + url.searchParams.set("vs[network]", network); + return url.toString(); + } catch { + return ""; + } }; const getConfig = (network: Network | null) => { const runtimeConfig = typeof window === "undefined" ? undefined : window.__DEALBOT_CONFIG__; - // Metrics dashboard and SP logs live in a distinct BetterStack dashboard per - // network, so prefer a per-network URL and fall back to the bare global var so - // single-network deployments keep working until infra sets the per-network vars. - const dashboardUrl = getNetworkConfigUrl( - network, - { - mainnet: { runtime: runtimeConfig?.DASHBOARD_URL_MAINNET, build: import.meta.env.VITE_DASHBOARD_URL_MAINNET }, - calibration: { - runtime: runtimeConfig?.DASHBOARD_URL_CALIBRATION, - build: import.meta.env.VITE_DASHBOARD_URL_CALIBRATION, - }, - }, - { runtime: runtimeConfig?.DASHBOARD_URL, build: import.meta.env.VITE_DASHBOARD_URL }, - ); - const logsUrl = getNetworkConfigUrl( - network, - { - mainnet: { runtime: runtimeConfig?.LOGS_URL_MAINNET, build: import.meta.env.VITE_LOGS_URL_MAINNET }, - calibration: { runtime: runtimeConfig?.LOGS_URL_CALIBRATION, build: import.meta.env.VITE_LOGS_URL_CALIBRATION }, - }, - { runtime: runtimeConfig?.LOGS_URL, build: import.meta.env.VITE_LOGS_URL }, - ); + // Metrics dashboard and SP logs are a single per-environment dashboard; the + // per-SP rows add a vs[network] filter (see withNetworkParam) so one dashboard + // serves every network the deployment monitors. + const dashboardUrl = getConfigUrl(runtimeConfig?.DASHBOARD_URL, import.meta.env.VITE_DASHBOARD_URL); + const logsUrl = getConfigUrl(runtimeConfig?.LOGS_URL, import.meta.env.VITE_LOGS_URL); - // Approved-SP dashboard: per-network only (two separate curated dashboards; no global fallback). - const approvedSpSources: Record = { + // Approved-SP dashboard: prefer the combined per-environment dashboard scoped + // with vs[network]; fall back to the legacy per-network dashboards so existing + // deployments keep working until infra sets APPROVED_SP_DASHBOARD_URL. + const approvedSpGlobal = getConfigUrl( + runtimeConfig?.APPROVED_SP_DASHBOARD_URL, + import.meta.env.VITE_APPROVED_SP_DASHBOARD_URL, + ); + const approvedSpPerNetworkSources: Record = { mainnet: { runtime: runtimeConfig?.APPROVED_SP_DASHBOARD_URL_MAINNET, build: import.meta.env.VITE_APPROVED_SP_DASHBOARD_URL_MAINNET, @@ -105,9 +97,15 @@ const getConfig = (network: Network | null) => { build: import.meta.env.VITE_APPROVED_SP_DASHBOARD_URL_CALIBRATION, }, }; - const approvedSpDashboardUrl = network - ? getConfigUrl(approvedSpSources[network].runtime, approvedSpSources[network].build) + const approvedSpPerNetwork = network + ? getConfigUrl(approvedSpPerNetworkSources[network].runtime, approvedSpPerNetworkSources[network].build) : { safe: "", isInvalid: false }; + let approvedSpDashboardUrl = approvedSpPerNetwork; + if (approvedSpGlobal.safe) { + approvedSpDashboardUrl = { safe: withNetworkParam(approvedSpGlobal.safe, network), isInvalid: false }; + } else if (approvedSpGlobal.isInvalid) { + approvedSpDashboardUrl = approvedSpGlobal; + } return { dashboardUrl: dashboardUrl.safe, @@ -180,8 +178,8 @@ export default function Landing() {

{approvedSpDashboardUrlInvalid && selectedNetwork && (

- Warning: APPROVED_SP_DASHBOARD_URL_{selectedNetwork.toUpperCase()} (or{" "} - VITE_APPROVED_SP_DASHBOARD_URL_{selectedNetwork.toUpperCase()}) configured but invalid. Link + Warning: approved-SP dashboard URL (APPROVED_SP_DASHBOARD_URL or{" "} + APPROVED_SP_DASHBOARD_URL_{selectedNetwork.toUpperCase()}) configured but invalid. Link unavailable.

)} @@ -283,11 +281,17 @@ export default function Landing() { const providerId = provider.providerId; const metricsHref = dashboardUrl && providerId != null - ? buildBetterStackUrlWithProvider(dashboardUrl, providerId, "vs[provider_id]") + ? withNetworkParam( + buildBetterStackUrlWithProvider(dashboardUrl, providerId, "vs[provider_id]"), + selectedNetwork, + ) : ""; const logsHref = logsUrl && providerId != null - ? buildBetterStackUrlWithProvider(logsUrl, providerId, "vs[providerId]") + ? withNetworkParam( + buildBetterStackUrlWithProvider(logsUrl, providerId, "vs[providerId]"), + selectedNetwork, + ) : ""; return ( diff --git a/apps/web/src/vite-env.d.ts b/apps/web/src/vite-env.d.ts index 1b62de2b..9eda4711 100644 --- a/apps/web/src/vite-env.d.ts +++ b/apps/web/src/vite-env.d.ts @@ -7,14 +7,11 @@ interface ImportMeta { readonly VITE_API_BASE_URL: string; readonly VITE_PLAUSIBLE_DATA_DOMAIN?: string; readonly VITE_DASHBOARD_URL?: string; - readonly VITE_DASHBOARD_URL_MAINNET?: string; - readonly VITE_DASHBOARD_URL_CALIBRATION?: string; readonly VITE_DASHBOARD_EMBED_URL?: string; + readonly VITE_APPROVED_SP_DASHBOARD_URL?: string; readonly VITE_APPROVED_SP_DASHBOARD_URL_MAINNET?: string; readonly VITE_APPROVED_SP_DASHBOARD_URL_CALIBRATION?: string; readonly VITE_LOGS_URL?: string; - readonly VITE_LOGS_URL_MAINNET?: string; - readonly VITE_LOGS_URL_CALIBRATION?: string; }; } @@ -23,13 +20,10 @@ interface Window { API_BASE_URL?: string; PLAUSIBLE_DATA_DOMAIN?: string; DASHBOARD_URL?: string; - DASHBOARD_URL_MAINNET?: string; - DASHBOARD_URL_CALIBRATION?: string; DASHBOARD_EMBED_URL?: string; + APPROVED_SP_DASHBOARD_URL?: string; APPROVED_SP_DASHBOARD_URL_MAINNET?: string; APPROVED_SP_DASHBOARD_URL_CALIBRATION?: string; LOGS_URL?: string; - LOGS_URL_MAINNET?: string; - LOGS_URL_CALIBRATION?: string; }; } From 3951c768b7e2a389cebb67470162a70942bff950 Mon Sep 17 00:00:00 2001 From: silent-cipher Date: Thu, 2 Jul 2026 01:33:46 +0530 Subject: [PATCH 3/3] chore: address copilot comments --- apps/web/src/pages/Landing.tsx | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/apps/web/src/pages/Landing.tsx b/apps/web/src/pages/Landing.tsx index 35f9057d..5d4a74b9 100644 --- a/apps/web/src/pages/Landing.tsx +++ b/apps/web/src/pages/Landing.tsx @@ -179,8 +179,8 @@ export default function Landing() { {approvedSpDashboardUrlInvalid && selectedNetwork && (

Warning: approved-SP dashboard URL (APPROVED_SP_DASHBOARD_URL or{" "} - APPROVED_SP_DASHBOARD_URL_{selectedNetwork.toUpperCase()}) configured but invalid. Link - unavailable. + APPROVED_SP_DASHBOARD_URL_{selectedNetwork.toUpperCase()}, or their VITE_-prefixed + build-time equivalents) configured but invalid. Link unavailable.

)}