diff --git a/dashboard/src/skills/App.tsx b/dashboard/src/skills/App.tsx index 7813bf4e0..ecb9e3789 100644 --- a/dashboard/src/skills/App.tsx +++ b/dashboard/src/skills/App.tsx @@ -20,6 +20,21 @@ import { /** Number of trailing days shown in every graph. */ const WINDOW_DAYS = 10; +/** + * Build the Azure Data Explorer telemetry dashboard URL for a skill. + * The dashboard ID and item fragment are fixed; the skill name is passed + * through the `p-_selectedPluginSkill` parameter with a `v-` prefix. + */ +export function telemetryUrl(skillName: string): string { + const base = "https://dataexplorer.azure.com/dashboards/d1281268-c49e-4e82-bdc9-79e6c3c6cb43"; + const params = new URLSearchParams({ + "p-_startTime": "90days", + "p-_endTime": "now", + "p-_selectedPluginSkill": `v-${skillName}`, + }); + return `${base}?${params}#e9eade80-7b12-49db-a865-a6d3365d03eb`; +} + /** A plugin skill with its description, as surfaced by the frontmatter collector. */ interface Skill { name: string; @@ -264,6 +279,16 @@ export default function App() {

Files: {selectedSkill.fileCount}

+

+ + View telemetry ↗ + +

diff --git a/dashboard/src/skills/__tests__/telemetryUrl.test.ts b/dashboard/src/skills/__tests__/telemetryUrl.test.ts new file mode 100644 index 000000000..667c75ffe --- /dev/null +++ b/dashboard/src/skills/__tests__/telemetryUrl.test.ts @@ -0,0 +1,22 @@ +import { describe, it, expect } from "vitest"; +import { telemetryUrl } from "../App"; + +describe("telemetryUrl", () => { + it("builds the dashboard URL for a skill name", () => { + const url = new URL(telemetryUrl("azure-deploy")); + expect(url.origin).toBe("https://dataexplorer.azure.com"); + expect(url.pathname).toBe("/dashboards/d1281268-c49e-4e82-bdc9-79e6c3c6cb43"); + expect(url.searchParams.get("p-_startTime")).toBe("90days"); + expect(url.searchParams.get("p-_endTime")).toBe("now"); + expect(url.searchParams.get("p-_selectedPluginSkill")).toBe("v-azure-deploy"); + expect(url.hash).toBe("#e9eade80-7b12-49db-a865-a6d3365d03eb"); + }); + + it("encodes the skill name into the selectedPluginSkill parameter", () => { + const url = new URL(telemetryUrl("azure-cost-management")); + expect(url.searchParams.get("p-_selectedPluginSkill")).toBe("v-azure-cost-management"); + expect(url.searchParams.get("p-_startTime")).toBe("90days"); + expect(url.searchParams.get("p-_endTime")).toBe("now"); + expect(url.hash).toBe("#e9eade80-7b12-49db-a865-a6d3365d03eb"); + }); +}); diff --git a/dashboard/src/skills/skills.css b/dashboard/src/skills/skills.css index 4b70c6580..ea28b15cb 100644 --- a/dashboard/src/skills/skills.css +++ b/dashboard/src/skills/skills.css @@ -89,6 +89,20 @@ font-size: 0.9rem; } +.skills-telemetry { + margin: 0.5rem 0 0; +} + +.skills-telemetry-link { + color: var(--color-focus); + font-size: 0.9rem; + text-decoration: none; +} + +.skills-telemetry-link:hover { + text-decoration: underline; +} + .skills-tests-heading { margin: 1.5rem 0 0.75rem; font-size: 1.15rem;