From 6c6d746532b7b60a0f6a2942e7d49f323717cfe2 Mon Sep 17 00:00:00 2001 From: Oliver Kieselbach Date: Wed, 2 Sep 2026 16:34:37 +0200 Subject: [PATCH] feat(web): small "Docs" link in every portal page header Session details, diagnosis, annotations, fleet health, geographic performance, SLA, software, usage metrics, audit log, system health, IME log patterns and the rules pages link to their guide from the end of the header control group. Navbar help links use the DOCS_PATHS catalog (service announcements no longer goes through a redirect). Co-Authored-By: Claude Fable 5.1 --- .../app/analyze-rules/page.tsx | 8 ++- .../app/annotations/page.tsx | 7 ++- .../autopilot-monitor-web/app/apps/page.tsx | 3 ++ .../autopilot-monitor-web/app/audit/page.tsx | 3 ++ .../app/diagnosis/page.tsx | 3 ++ .../app/fleet-health/page.tsx | 3 ++ .../app/gather-rules/page.tsx | 8 ++- .../app/geographic-performance/page.tsx | 3 ++ .../app/health-check/page.tsx | 51 ++++++++++--------- .../app/ime-log-patterns/page.tsx | 15 ++++-- .../app/sessions/page.tsx | 3 ++ .../autopilot-monitor-web/app/sla/page.tsx | 3 ++ .../app/usage-metrics/page.tsx | 3 ++ .../components/Navbar.tsx | 9 ++-- .../autopilot-monitor-web/lib/docsPaths.ts | 15 ++++++ 15 files changed, 100 insertions(+), 37 deletions(-) diff --git a/src/Web/autopilot-monitor-web/app/analyze-rules/page.tsx b/src/Web/autopilot-monitor-web/app/analyze-rules/page.tsx index bae064fc..150ca481 100644 --- a/src/Web/autopilot-monitor-web/app/analyze-rules/page.tsx +++ b/src/Web/autopilot-monitor-web/app/analyze-rules/page.tsx @@ -33,6 +33,7 @@ import AnalyzeRuleCard, { RuleTrendPoint, RuleRegressionInfo } from "./component import TemplateConfigModal from "./components/TemplateConfigModal"; import { SectionCardHeader } from "@/components/SectionCardHeader"; import { DOCS_PATHS } from "@/lib/docsPaths"; +import { DocsLink } from "@/components/DocsLink"; export default function AnalyzeRulesPage() { const { user, getAccessToken } = useAuth(); @@ -545,14 +546,17 @@ export default function AnalyzeRulesPage() { {/* Header */}
-
+

Analyze Rules

Manage event analysis rules for issue detection

- +
+ + +
diff --git a/src/Web/autopilot-monitor-web/app/annotations/page.tsx b/src/Web/autopilot-monitor-web/app/annotations/page.tsx index 1cf5f1c9..6c4dd4a1 100644 --- a/src/Web/autopilot-monitor-web/app/annotations/page.tsx +++ b/src/Web/autopilot-monitor-web/app/annotations/page.tsx @@ -21,6 +21,8 @@ import { type AnnotationLane, type AnnotationVerdict, } from "../sessions/components/sessionAnnotationLogic"; +import { DocsLink } from "@/components/DocsLink"; +import { DOCS_PATHS } from "@/lib/docsPaths"; /** * Annotations overview: every annotated session in one list, so a judged session can be @@ -150,7 +152,10 @@ export default function AnnotationsPage() { Every session your team has judged — open one to read or update the verdict.

- +
+ + +
diff --git a/src/Web/autopilot-monitor-web/app/apps/page.tsx b/src/Web/autopilot-monitor-web/app/apps/page.tsx index 080f4eef..f8c10f42 100644 --- a/src/Web/autopilot-monitor-web/app/apps/page.tsx +++ b/src/Web/autopilot-monitor-web/app/apps/page.tsx @@ -12,6 +12,8 @@ import InstallsTab from "./components/InstallsTab"; import InventoryTab from "./components/InventoryTab"; import VulnerabilitiesTab from "./components/VulnerabilitiesTab"; import type { TimeRange } from "./components/types"; +import { DocsLink } from "@/components/DocsLink"; +import { DOCS_PATHS } from "@/lib/docsPaths"; const TABS = [ { id: "installs", label: "Installs" }, @@ -54,6 +56,7 @@ function SoftwareHub() { value={timeRange} onChange={(v) => setTimeRange(v as typeof timeRange)} /> + diff --git a/src/Web/autopilot-monitor-web/app/audit/page.tsx b/src/Web/autopilot-monitor-web/app/audit/page.tsx index d668ea34..307aca47 100644 --- a/src/Web/autopilot-monitor-web/app/audit/page.tsx +++ b/src/Web/autopilot-monitor-web/app/audit/page.tsx @@ -11,6 +11,8 @@ import { extractContinuation } from "@/lib/paginationLink"; import { useAggregatedAdminScope } from "@/hooks"; import { TenantScopeSelector } from "@/components/TenantScopeSelector"; import { GlobalAdminBanner, globalAdminSubtitle } from "@/components/GlobalAdminBanner"; +import { DocsLink } from "@/components/DocsLink"; +import { DOCS_PATHS } from "@/lib/docsPaths"; interface AuditLogEntry { @@ -272,6 +274,7 @@ export default function AuditPage() { {refreshing ? 'Refreshing...' : 'Refresh'} + diff --git a/src/Web/autopilot-monitor-web/app/diagnosis/page.tsx b/src/Web/autopilot-monitor-web/app/diagnosis/page.tsx index 05952169..2e3f8a7c 100644 --- a/src/Web/autopilot-monitor-web/app/diagnosis/page.tsx +++ b/src/Web/autopilot-monitor-web/app/diagnosis/page.tsx @@ -17,6 +17,8 @@ import { Session, EnrollmentEvent, RuleResult } from "@/types"; import { useAdminMode } from "@/hooks/useAdminMode"; import { isGuid } from "@/utils/inputValidation"; import { safeHttpUrl } from "@/lib/safeDocUrl"; +import { DocsLink } from "@/components/DocsLink"; +import { DOCS_PATHS } from "@/lib/docsPaths"; export default function DiagnosisPage() { // useSearchParams() in DiagnosisContent requires a Suspense boundary for static prerender. @@ -363,6 +365,7 @@ function DiagnosisContent() { > Full Details + diff --git a/src/Web/autopilot-monitor-web/app/fleet-health/page.tsx b/src/Web/autopilot-monitor-web/app/fleet-health/page.tsx index 815332c3..d47dfcd7 100644 --- a/src/Web/autopilot-monitor-web/app/fleet-health/page.tsx +++ b/src/Web/autopilot-monitor-web/app/fleet-health/page.tsx @@ -24,6 +24,8 @@ import { SegmentedControl, TIME_RANGE_OPTIONS } from "@/components/SegmentedCont import { CardSkeleton } from "@/components/skeletons/PageSkeleton"; import { TableSkeleton } from "@/components/skeletons/TableSkeleton"; import { formatDuration } from "@/lib/formatting"; +import { DocsLink } from "@/components/DocsLink"; +import { DOCS_PATHS } from "@/lib/docsPaths"; interface AppMetric { appName: string; @@ -265,6 +267,7 @@ export default function FleetHealthPage() { value={timeRange} onChange={(v) => setTimeRange(v as typeof timeRange)} /> + diff --git a/src/Web/autopilot-monitor-web/app/gather-rules/page.tsx b/src/Web/autopilot-monitor-web/app/gather-rules/page.tsx index 476e7c98..9960a068 100644 --- a/src/Web/autopilot-monitor-web/app/gather-rules/page.tsx +++ b/src/Web/autopilot-monitor-web/app/gather-rules/page.tsx @@ -19,6 +19,7 @@ import { GatherRuleFormFields } from "./components/GatherRuleFormFields"; import { GatherRuleCard } from "./components/GatherRuleCard"; import { SectionCardHeader } from "@/components/SectionCardHeader"; import { DOCS_PATHS } from "@/lib/docsPaths"; +import { DocsLink } from "@/components/DocsLink"; export default function GatherRulesPage() { const { user, getAccessToken } = useAuth(); @@ -382,14 +383,17 @@ export default function GatherRulesPage() { {/* Header */}
-
+

Gather Rules

Manage data collection rules for device enrollment

- +
+ + +
diff --git a/src/Web/autopilot-monitor-web/app/geographic-performance/page.tsx b/src/Web/autopilot-monitor-web/app/geographic-performance/page.tsx index 4b1567f6..a7a08c37 100644 --- a/src/Web/autopilot-monitor-web/app/geographic-performance/page.tsx +++ b/src/Web/autopilot-monitor-web/app/geographic-performance/page.tsx @@ -14,6 +14,8 @@ import { GlobalAdminBanner, globalAdminSubtitle } from "@/components/GlobalAdmin import { TenantScopeSelector } from "@/components/TenantScopeSelector"; import { SegmentedControl, TIME_RANGE_OPTIONS } from "@/components/SegmentedControl"; import { CalculatingCard } from "@/components/CalculatingCard"; +import { DocsLink } from "@/components/DocsLink"; +import { DOCS_PATHS } from "@/lib/docsPaths"; // A cross-tenant geo aggregation can take tens of seconds server-side; the default 30s fetch // timeout would abort it client-side while the server keeps computing. @@ -277,6 +279,7 @@ export default function GeographicPerformancePage() { value={groupBy} onChange={(v) => setGroupBy(v as GroupBy)} /> + diff --git a/src/Web/autopilot-monitor-web/app/health-check/page.tsx b/src/Web/autopilot-monitor-web/app/health-check/page.tsx index 7f072dc7..7709f822 100644 --- a/src/Web/autopilot-monitor-web/app/health-check/page.tsx +++ b/src/Web/autopilot-monitor-web/app/health-check/page.tsx @@ -11,6 +11,8 @@ import { api } from '@/lib/api'; import { authenticatedFetch, TokenExpiredError } from "@/lib/authenticatedFetch"; import { isUrlDetail, visibleHealthChecks, visibleHealthDetails } from '@/lib/healthCheckView'; import type { DetailedHealthCheckResponse, HealthCheck, McpHealthCheckResponse } from '@/utils/wire-types.generated'; +import { DocsLink } from "@/components/DocsLink"; +import { DOCS_PATHS } from "@/lib/docsPaths"; function formatDetailValue(value: unknown): string { return Array.isArray(value) ? value.join(', ') : typeof value === 'object' ? JSON.stringify(value) : String(value); @@ -231,30 +233,33 @@ export default function HealthCheckPage() {
{/* Header */}
-
+

System Health

- +
+ + +
diff --git a/src/Web/autopilot-monitor-web/app/ime-log-patterns/page.tsx b/src/Web/autopilot-monitor-web/app/ime-log-patterns/page.tsx index 7720080a..7ae52845 100644 --- a/src/Web/autopilot-monitor-web/app/ime-log-patterns/page.tsx +++ b/src/Web/autopilot-monitor-web/app/ime-log-patterns/page.tsx @@ -15,6 +15,8 @@ import { EmptyState } from "@/components/rules/EmptyState"; import { ImeLogPattern, PatternForm, EMPTY_FORM, ACTION_LABELS } from "./types"; import ImePatternCard from "./components/ImePatternCard"; import { trackEvent } from "@/lib/appInsights"; +import { DocsLink } from "@/components/DocsLink"; +import { DOCS_PATHS } from "@/lib/docsPaths"; export default function ImeLogPatternsPage() { const { tenantId } = useTenant(); @@ -208,11 +210,14 @@ export default function ImeLogPatternsPage() { {/* Header */}
-
-

IME Log Patterns

-

- Regex patterns used by the agent to parse Intune Management Extension logs during enrollment tracking. -

+
+
+

IME Log Patterns

+

+ Regex patterns used by the agent to parse Intune Management Extension logs during enrollment tracking. +

+
+
diff --git a/src/Web/autopilot-monitor-web/app/sessions/page.tsx b/src/Web/autopilot-monitor-web/app/sessions/page.tsx index 49d485d9..ca706a93 100644 --- a/src/Web/autopilot-monitor-web/app/sessions/page.tsx +++ b/src/Web/autopilot-monitor-web/app/sessions/page.tsx @@ -47,6 +47,8 @@ import { generateUiExport, generateCsvExport, generateSessionCsvExport, generate import { trackEvent } from "@/lib/appInsights"; import { useAdminMode } from "@/hooks/useAdminMode"; import { useGlobalAdminUi } from "@/hooks/useGlobalAdminUi"; +import { DocsLink } from "@/components/DocsLink"; +import { DOCS_PATHS } from "@/lib/docsPaths"; export default function SessionDetailPage() { // useSearchParams() in SessionDetailContent requires a Suspense boundary for static prerender. @@ -573,6 +575,7 @@ function SessionDetailContent() { Inspector )} +
diff --git a/src/Web/autopilot-monitor-web/app/sla/page.tsx b/src/Web/autopilot-monitor-web/app/sla/page.tsx index f169121a..88e3cc71 100644 --- a/src/Web/autopilot-monitor-web/app/sla/page.tsx +++ b/src/Web/autopilot-monitor-web/app/sla/page.tsx @@ -59,6 +59,8 @@ interface SlaWeeklyTrend { // enum serialized as int; rendered via statusLabels below), unlike the string status // on SessionSummary. import type { SlaViolatorSession } from "@/utils/wire-types.generated"; +import { DocsLink } from "@/components/DocsLink"; +import { DOCS_PATHS } from "@/lib/docsPaths"; interface TopFailingApp { appName: string; @@ -240,6 +242,7 @@ export default function SlaPage() { {refreshing ? 'Refreshing...' : 'Refresh'} + diff --git a/src/Web/autopilot-monitor-web/app/usage-metrics/page.tsx b/src/Web/autopilot-monitor-web/app/usage-metrics/page.tsx index 1cccbc4c..b2655625 100644 --- a/src/Web/autopilot-monitor-web/app/usage-metrics/page.tsx +++ b/src/Web/autopilot-monitor-web/app/usage-metrics/page.tsx @@ -10,6 +10,8 @@ import { useGlobalAdminScope } from "@/hooks"; import { GlobalAdminBanner, globalAdminSubtitle } from "@/components/GlobalAdminBanner"; import { TenantScopeSelector } from "@/components/TenantScopeSelector"; import { CardSkeleton } from "@/components/skeletons/PageSkeleton"; +import { DocsLink } from "@/components/DocsLink"; +import { DOCS_PATHS } from "@/lib/docsPaths"; interface SessionMetrics { total: number; @@ -209,6 +211,7 @@ export default function UsageMetricsPage() { {refreshing ? 'Refreshing...' : 'Refresh'} + diff --git a/src/Web/autopilot-monitor-web/components/Navbar.tsx b/src/Web/autopilot-monitor-web/components/Navbar.tsx index aa295031..de84e85c 100644 --- a/src/Web/autopilot-monitor-web/components/Navbar.tsx +++ b/src/Web/autopilot-monitor-web/components/Navbar.tsx @@ -15,6 +15,7 @@ import { useAdminMode } from '@/hooks/useAdminMode'; import { useEditionInfo } from '@/hooks/useEditionInfo'; import GlobalSearch from './GlobalSearch'; import { DOCS_URL } from "@/utils/config"; +import { DOCS_PATHS } from "@/lib/docsPaths"; export default function Navbar() { const { isAuthenticated, user, hasGlobalScope, logout } = useAuth(); @@ -503,7 +504,7 @@ export default function Navbar() { Documentation - { setShowOverflow(false); setOverflowSubmenu(null); }}> + { setShowOverflow(false); setOverflowSubmenu(null); }}> Changelog - { setShowOverflow(false); setOverflowSubmenu(null); }}> + { setShowOverflow(false); setOverflowSubmenu(null); }}> Service Announcements diff --git a/src/Web/autopilot-monitor-web/lib/docsPaths.ts b/src/Web/autopilot-monitor-web/lib/docsPaths.ts index 81cbc537..35ceae1b 100644 --- a/src/Web/autopilot-monitor-web/lib/docsPaths.ts +++ b/src/Web/autopilot-monitor-web/lib/docsPaths.ts @@ -30,6 +30,21 @@ export const DOCS_PATHS = { // Rules analyzeRules: "/rules/analyze-rules", gatherRules: "/rules/gather-rules", + imeLogPatterns: "/rules/ime-log-patterns", + // Portal pages (page-header "Docs" link) + sessionDetails: "/portal-guide/session-details-and-diagnosis", + guidedDiagnosis: "/portal-guide/session-details-and-diagnosis#guided-diagnosis", + annotations: "/portal-guide/session-details-and-diagnosis#annotations", + fleetHealth: "/portal-guide/fleet-health", + geographicPerformance: "/portal-guide/geographic-performance", + slaCompliance: "/portal-guide/sla-compliance", + softwareInventory: "/portal-guide/software-inventory-and-vulnerabilities", + usageMetrics: "/portal-guide/usage-metrics", + auditLog: "/portal-guide/audit-log-and-system-health#audit-log", + systemHealth: "/portal-guide/audit-log-and-system-health#system-health", + // Navbar help menu + platformChangelog: "/changelog/platform-changelog", + serviceAnnouncements: "/troubleshooting-and-support/service-announcements", // Dual app-registration window (sign-in banners, failed-sign-in screen) appRegistrationMigration: "/troubleshooting-and-support/app-registration-migration", appRegistrationMigrationAfter: "/troubleshooting-and-support/app-registration-migration#after-the-migration",