From c59fa464512e2361a837a84b62b81e0f98f1ab5d Mon Sep 17 00:00:00 2001
From: davion-knight <298846663+davion-knight@users.noreply.github.com>
Date: Sun, 12 Jul 2026 11:39:17 -0500
Subject: [PATCH] feat(miner-ui): add an optional ORB/Grafana footer link to
the root layout
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
Render a footer link to an operator-configured ORB/Grafana dashboard (#5194), shown only when
VITE_MINER_UI_GRAFANA_URL is set and non-empty (nothing rendered otherwise). Vite exposes only
VITE_-prefixed vars to the client bundle, so the name is VITE_-prefixed — a bare name would be
undefined at build. Opens in a new tab (target=_blank rel=noopener noreferrer); the URL is
rendered as a plain href (React escapes it, no dangerouslySetInnerHTML) and no token/credential
is ever appended. Extracted as a small GrafanaFooterLink component for direct testing.
Closes #5194
---
apps/gittensory-miner-ui/README.md | 6 ++++
.../src/components/grafana-footer-link.tsx | 19 +++++++++++
.../src/grafana-footer-link.test.tsx | 32 +++++++++++++++++++
.../gittensory-miner-ui/src/routes/__root.tsx | 4 +++
4 files changed, 61 insertions(+)
create mode 100644 apps/gittensory-miner-ui/src/components/grafana-footer-link.tsx
create mode 100644 apps/gittensory-miner-ui/src/grafana-footer-link.test.tsx
diff --git a/apps/gittensory-miner-ui/README.md b/apps/gittensory-miner-ui/README.md
index a0ce711092..893c586246 100644
--- a/apps/gittensory-miner-ui/README.md
+++ b/apps/gittensory-miner-ui/README.md
@@ -9,3 +9,9 @@ The miner package invariant is client-side only with no required phone-home to b
local miner CLI can serve later — not a Wrangler deploy target.
Phase 6 data views (run history, portfolio cards) land in follow-up issues after this empty shell.
+
+## Configuration
+
+| Env var | Required | Description |
+| --------------------------- | -------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ |
+| `VITE_MINER_UI_GRAFANA_URL` | No | If set (and non-empty), renders a footer link to your ORB/Grafana dashboard at this URL. Unset ⇒ no link. Must be `VITE_`-prefixed so Vite exposes it to the client bundle. It is a plain navigational link — no token or credential is ever appended. |
diff --git a/apps/gittensory-miner-ui/src/components/grafana-footer-link.tsx b/apps/gittensory-miner-ui/src/components/grafana-footer-link.tsx
new file mode 100644
index 0000000000..dd4e94f475
--- /dev/null
+++ b/apps/gittensory-miner-ui/src/components/grafana-footer-link.tsx
@@ -0,0 +1,19 @@
+// Optional footer link to an operator's ORB/Grafana dashboard (#5194). Rendered only when the operator sets
+// VITE_MINER_UI_GRAFANA_URL (Vite exposes only VITE_-prefixed vars to the client bundle; a bare name would be
+// undefined at build time). The URL is a plain navigational link — no auth/session token or credential is ever
+// appended, and it is rendered as a normal href attribute (React escapes it, so a misconfigured value cannot
+// inject markup). Renders nothing when the var is unset or empty.
+export function GrafanaFooterLink() {
+ const url = import.meta.env.VITE_MINER_UI_GRAFANA_URL;
+ if (!url) return null;
+ return (
+
+ ORB / Grafana dashboard ↗
+
+ );
+}
diff --git a/apps/gittensory-miner-ui/src/grafana-footer-link.test.tsx b/apps/gittensory-miner-ui/src/grafana-footer-link.test.tsx
new file mode 100644
index 0000000000..57fe7cb617
--- /dev/null
+++ b/apps/gittensory-miner-ui/src/grafana-footer-link.test.tsx
@@ -0,0 +1,32 @@
+import { render, screen } from "@testing-library/react";
+import { afterEach, describe, expect, it, vi } from "vitest";
+import { GrafanaFooterLink } from "./components/grafana-footer-link";
+
+afterEach(() => vi.unstubAllEnvs());
+
+describe("GrafanaFooterLink (#5194)", () => {
+ it("renders a new-tab link to the configured dashboard URL", () => {
+ vi.stubEnv("VITE_MINER_UI_GRAFANA_URL", "https://grafana.example.internal/d/ams");
+ render();
+ const link = screen.getByRole("link", { name: /Grafana dashboard/i });
+ expect(link.getAttribute("href")).toBe("https://grafana.example.internal/d/ams");
+ expect(link.getAttribute("target")).toBe("_blank");
+ expect(link.getAttribute("rel")).toBe("noopener noreferrer");
+ });
+
+ it("renders nothing when the env var is unset or empty", () => {
+ vi.stubEnv("VITE_MINER_UI_GRAFANA_URL", "");
+ const { container } = render();
+ expect(container.firstChild).toBeNull();
+ expect(screen.queryByRole("link")).toBeNull();
+ });
+
+ it("uses the URL verbatim as the href — never appends a token or credential", () => {
+ const url = "https://dash.example.internal/grafana";
+ vi.stubEnv("VITE_MINER_UI_GRAFANA_URL", url);
+ render();
+ const href = screen.getByRole("link").getAttribute("href") ?? "";
+ expect(href).toBe(url); // exact — no `?token=`, no appended session/credential
+ expect(href).not.toMatch(/token|api[_-]?key|secret|session|auth=/i);
+ });
+});
diff --git a/apps/gittensory-miner-ui/src/routes/__root.tsx b/apps/gittensory-miner-ui/src/routes/__root.tsx
index 07dc49f3c1..86499a8179 100644
--- a/apps/gittensory-miner-ui/src/routes/__root.tsx
+++ b/apps/gittensory-miner-ui/src/routes/__root.tsx
@@ -1,4 +1,5 @@
import { Outlet, createRootRoute, Link } from "@tanstack/react-router";
+import { GrafanaFooterLink } from "@/components/grafana-footer-link";
export const Route = createRootRoute({
component: RootLayout,
@@ -29,6 +30,9 @@ function RootLayout() {
+
);
}