fixed SEO meta and search route conflicts

This commit is contained in:
Oliver Kieselbach
2026-03-27 22:23:55 +01:00
parent e63929cb30
commit 4eec3767a7
14 changed files with 41 additions and 41 deletions
@@ -1 +1 @@
644
646
@@ -26,7 +26,7 @@ public class QuickSearchSessionsFunction
[Function("QuickSearchSessions")]
public async Task<HttpResponseData> Run(
[HttpTrigger(AuthorizationLevel.Anonymous, "get", Route = "quick-search")] HttpRequestData req)
[HttpTrigger(AuthorizationLevel.Anonymous, "get", Route = "search/quick")] HttpRequestData req)
{
try
{
@@ -20,12 +20,12 @@ public class SearchSessionsByCveFunction
[Function("SearchSessionsByCve")]
public async Task<HttpResponseData> Run(
[HttpTrigger(AuthorizationLevel.Anonymous, "get", Route = "sessions/search-by-cve")] HttpRequestData req)
[HttpTrigger(AuthorizationLevel.Anonymous, "get", Route = "search/sessions-by-cve")] HttpRequestData req)
=> await HandleAsync(req, isTenantScoped: true);
[Function("SearchSessionsByCveGlobal")]
public async Task<HttpResponseData> RunGlobal(
[HttpTrigger(AuthorizationLevel.Anonymous, "get", Route = "global/sessions/search-by-cve")] HttpRequestData req)
[HttpTrigger(AuthorizationLevel.Anonymous, "get", Route = "global/search/sessions-by-cve")] HttpRequestData req)
=> await HandleAsync(req, isTenantScoped: false);
private async Task<HttpResponseData> HandleAsync(HttpRequestData req, bool isTenantScoped)
@@ -20,12 +20,12 @@ public class SearchSessionsByEventFunction
[Function("SearchSessionsByEvent")]
public async Task<HttpResponseData> Run(
[HttpTrigger(AuthorizationLevel.Anonymous, "get", Route = "sessions/search-by-event")] HttpRequestData req)
[HttpTrigger(AuthorizationLevel.Anonymous, "get", Route = "search/sessions-by-event")] HttpRequestData req)
=> await HandleAsync(req, isTenantScoped: true);
[Function("SearchSessionsByEventGlobal")]
public async Task<HttpResponseData> RunGlobal(
[HttpTrigger(AuthorizationLevel.Anonymous, "get", Route = "global/sessions/search-by-event")] HttpRequestData req)
[HttpTrigger(AuthorizationLevel.Anonymous, "get", Route = "global/search/sessions-by-event")] HttpRequestData req)
=> await HandleAsync(req, isTenantScoped: false);
private async Task<HttpResponseData> HandleAsync(HttpRequestData req, bool isTenantScoped)
@@ -21,12 +21,12 @@ public class SearchSessionsFunction
[Function("SearchSessions")]
public async Task<HttpResponseData> Run(
[HttpTrigger(AuthorizationLevel.Anonymous, "get", Route = "sessions/search")] HttpRequestData req)
[HttpTrigger(AuthorizationLevel.Anonymous, "get", Route = "search/sessions")] HttpRequestData req)
=> await HandleAsync(req, isTenantScoped: true);
[Function("SearchSessionsGlobal")]
public async Task<HttpResponseData> RunGlobal(
[HttpTrigger(AuthorizationLevel.Anonymous, "get", Route = "global/sessions/search")] HttpRequestData req)
[HttpTrigger(AuthorizationLevel.Anonymous, "get", Route = "global/search/sessions")] HttpRequestData req)
=> await HandleAsync(req, isTenantScoped: false);
private async Task<HttpResponseData> HandleAsync(HttpRequestData req, bool isTenantScoped)
@@ -101,10 +101,10 @@ public static class EndpointAccessPolicyCatalog
new("POST", "feedback", EndpointPolicy.AuthenticatedUser),
// ── MemberRead (Admin + Operator, later + Viewer) ───────────────
new("GET", "quick-search", EndpointPolicy.MemberRead),
new("GET", "sessions/search", EndpointPolicy.MemberRead),
new("GET", "sessions/search-by-event", EndpointPolicy.MemberRead),
new("GET", "sessions/search-by-cve", EndpointPolicy.MemberRead),
new("GET", "search/quick", EndpointPolicy.MemberRead),
new("GET", "search/sessions", EndpointPolicy.MemberRead),
new("GET", "search/sessions-by-event", EndpointPolicy.MemberRead),
new("GET", "search/sessions-by-cve", EndpointPolicy.MemberRead),
new("GET", "metrics/summary", EndpointPolicy.MemberRead),
new("GET", "api-keys", EndpointPolicy.GlobalAdminOnly),
new("POST", "api-keys", EndpointPolicy.GlobalAdminOnly),
@@ -156,9 +156,9 @@ public static class EndpointAccessPolicyCatalog
new("DELETE", "bootstrap/sessions/{code}", EndpointPolicy.BootstrapManagerOrGA),
// ── GlobalAdminOnly ────────────────────────────────────────────
new("GET", "global/sessions/search", EndpointPolicy.GlobalAdminOnly),
new("GET", "global/sessions/search-by-event", EndpointPolicy.GlobalAdminOnly),
new("GET", "global/sessions/search-by-cve", EndpointPolicy.GlobalAdminOnly),
new("GET", "global/search/sessions", EndpointPolicy.GlobalAdminOnly),
new("GET", "global/search/sessions-by-event", EndpointPolicy.GlobalAdminOnly),
new("GET", "global/search/sessions-by-cve", EndpointPolicy.GlobalAdminOnly),
new("GET", "global/metrics/summary", EndpointPolicy.GlobalAdminOnly),
new("GET", "global/api-keys", EndpointPolicy.GlobalAdminOnly),
new("GET", "global/config", EndpointPolicy.GlobalAdminOnly),
@@ -184,12 +184,12 @@ async function executeTool(name: string, input: Record<string, unknown>): Promis
switch (name) {
case 'search_sessions': {
// Use global endpoint when tenantId not set (global API key scope)
const endpoint = input.tenantId ? '/api/sessions/search' : '/api/global/sessions/search';
const endpoint = input.tenantId ? '/api/search/sessions' : '/api/global/search/sessions';
const data = await apiFetch(`${endpoint}${qs(input as Record<string, string | number | boolean>)}`);
return JSON.stringify(data, null, 2);
}
case 'search_sessions_by_event': {
const endpoint = input.tenantId ? '/api/sessions/search-by-event' : '/api/global/sessions/search-by-event';
const endpoint = input.tenantId ? '/api/search/sessions-by-event' : '/api/global/search/sessions-by-event';
const data = await apiFetch(`${endpoint}${qs(input as Record<string, string | number | boolean>)}`);
return JSON.stringify(data, null, 2);
}
@@ -231,7 +231,7 @@ async function executeTool(name: string, input: Record<string, unknown>): Promis
return JSON.stringify({ summary, apps }, null, 2);
}
case 'search_sessions_by_cve': {
const endpoint = input.tenantId ? '/api/sessions/search-by-cve' : '/api/global/sessions/search-by-cve';
const endpoint = input.tenantId ? '/api/search/sessions-by-cve' : '/api/global/search/sessions-by-cve';
const data = await apiFetch(`${endpoint}${qs(input as Record<string, string | number | boolean>)}`);
return JSON.stringify(data, null, 2);
}
@@ -45,7 +45,7 @@ export function registerTools(server: McpServer, knowledgeBase?: SearchProvider)
queryParams[`prop.${key}`] = value;
}
}
const data = await apiFetch(`/api/sessions/search${buildQuery(queryParams)}`);
const data = await apiFetch(`/api/search/sessions${buildQuery(queryParams)}`);
return { content: [{ type: 'text' as const, text: JSON.stringify(data, null, 2) }] };
}
);
@@ -60,7 +60,7 @@ export function registerTools(server: McpServer, knowledgeBase?: SearchProvider)
limit: z.number().min(1).max(100).optional().default(50),
},
async (args) => {
const data = await apiFetch(`/api/sessions/search-by-event${buildQuery(args as Record<string, string | number | boolean | undefined | null>)}`);
const data = await apiFetch(`/api/search/sessions-by-event${buildQuery(args as Record<string, string | number | boolean | undefined | null>)}`);
return { content: [{ type: 'text' as const, text: JSON.stringify(data, null, 2) }] };
}
);
@@ -149,7 +149,7 @@ export function registerTools(server: McpServer, knowledgeBase?: SearchProvider)
limit: z.number().min(1).max(100).optional().default(50),
},
async (args) => {
const data = await apiFetch(`/api/sessions/search-by-cve${buildQuery(args as Record<string, string | number | undefined | null>)}`);
const data = await apiFetch(`/api/search/sessions-by-cve${buildQuery(args as Record<string, string | number | undefined | null>)}`);
return { content: [{ type: 'text' as const, text: JSON.stringify(data, null, 2) }] };
}
);
@@ -195,7 +195,7 @@ export function registerTools(server: McpServer, knowledgeBase?: SearchProvider)
sessionIds = [sessionId];
} else {
const searchQ = buildQuery({ status: 'Failed', tenantId, limit: 5 } as Record<string, string | number | undefined>);
const sessions = await apiFetch(`/api/sessions/search${searchQ}`) as {
const sessions = await apiFetch(`/api/search/sessions${searchQ}`) as {
sessions?: Array<{ sessionId?: string }>;
};
const ids = (sessions?.sessions ?? []).map((s) => s.sessionId).filter(Boolean) as string[];
@@ -112,9 +112,9 @@ namespace AutopilotMonitor.Shared
public const string ValidateBootstrapCode = "/api/bootstrap/validate/{code}";
// MCP/Agent API search endpoints
public const string SearchSessions = "/api/sessions/search";
public const string SearchSessionsByEvent = "/api/sessions/search-by-event";
public const string SearchSessionsByCve = "/api/sessions/search-by-cve";
public const string SearchSessions = "/api/search/sessions";
public const string SearchSessionsByEvent = "/api/search/sessions-by-event";
public const string SearchSessionsByCve = "/api/search/sessions-by-cve";
public const string MetricsSummary = "/api/metrics/summary";
public const string ApiKeysEndpoint = "/api/api-keys";
@@ -1,15 +1,15 @@
export const NAV_SECTIONS = [
{ id: "private-preview", label: "Private Preview", description: "Private preview access and onboarding for Autopilot Monitor." },
{ id: "overview", label: "Overview", description: "Overview of Autopilot Monitor architecture and capabilities." },
{ id: "general", label: "General", description: "General concepts: Admin Mode, session statuses, and user roles." },
{ id: "setup", label: "Setup", description: "Step-by-step setup guide for deploying Autopilot Monitor." },
{ id: "agent", label: "Agent", description: "Autopilot Monitor agent overview, version, and configuration details." },
{ id: "agent-setup", label: "Agent Setup", description: "Configure and deploy the Autopilot Monitor agent via Intune." },
{ id: "settings", label: "Settings", description: "Autopilot Monitor settings and configuration options." },
{ id: "gather-rules", label: "Gather Rules", description: "Configure data gathering rules for Autopilot Monitor diagnostics." },
{ id: "analyze-rules", label: "Analyze Rules", description: "Configure analysis rules for Autopilot enrollment evaluation." },
{ id: "ime-log-patterns", label: "IME Log Patterns", description: "Regex patterns for parsing the Intune Management Extension log into structured events." },
{ id: "faq", label: "FAQ", description: "Frequently asked questions about Autopilot Monitor setup, agent behavior, and troubleshooting." },
{ id: "private-preview", label: "Private Preview", description: "Join the Autopilot Monitor private preview for early access. Learn about onboarding steps, requirements, and how to start monitoring Windows Autopilot enrollments." },
{ id: "overview", label: "Overview", description: "Explore the Autopilot Monitor architecture and core components. Learn how the agent, backend, and web dashboard work together to monitor Windows Autopilot enrollments." },
{ id: "general", label: "General", description: "Learn general Autopilot Monitor concepts including Admin Mode, session lifecycle statuses, user roles, and how enrollment data flows through the platform." },
{ id: "setup", label: "Setup", description: "Step-by-step guide to setting up Autopilot Monitor. Deploy the bootstrapper package via Microsoft Intune and start monitoring Windows Autopilot enrollments." },
{ id: "agent", label: "Agent", description: "Understand the Autopilot Monitor agent — how it collects enrollment data, communicates with the backend, and provides real-time visibility into Windows deployments." },
{ id: "agent-setup", label: "Agent Setup", description: "Configure and deploy the Autopilot Monitor agent via Microsoft Intune. Covers bootstrapper deployment, agent configuration, and verification of installation." },
{ id: "settings", label: "Settings", description: "Configure Autopilot Monitor settings including tenant options, diagnostics, notification preferences, and advanced platform options for Windows Autopilot monitoring." },
{ id: "gather-rules", label: "Gather Rules", description: "Configure gather rules to control which diagnostics data the Autopilot Monitor agent collects. Define custom log paths and collection criteria for troubleshooting." },
{ id: "analyze-rules", label: "Analyze Rules", description: "Set up analyze rules to automatically evaluate Windows Autopilot enrollments. Define conditions, severity levels, and custom logic to detect issues in real time." },
{ id: "ime-log-patterns", label: "IME Log Patterns", description: "Define regex patterns for parsing the Intune Management Extension (IME) log into structured events. Customize how Autopilot Monitor extracts log entries." },
{ id: "faq", label: "FAQ", description: "Frequently asked questions about Autopilot Monitor — covering setup, agent behavior, troubleshooting common issues, and tips for getting the most out of the platform." },
] as const;
export type SectionId = (typeof NAV_SECTIONS)[number]["id"];
@@ -7,7 +7,7 @@ export const metadata: Metadata = {
default: "Documentation – Autopilot Monitor",
},
description:
"Complete setup and configuration guide for Autopilot Monitor. Learn how to deploy the bootstrapper via Intune, configure the agent, and start monitoring Windows Autopilot enrollments in real time.",
"Complete setup and configuration guide for Autopilot Monitor. Deploy the bootstrapper via Intune, configure the agent, and monitor enrollments in real time.",
keywords: [
"Autopilot Monitor documentation",
"Autopilot Monitor setup guide",
@@ -3,10 +3,10 @@ import type { Metadata } from "next";
export const metadata: Metadata = {
title: "Terms of Use",
description:
"Terms of Use for Autopilot Monitor. Read the usage terms and conditions for the Windows Autopilot monitoring platform.",
"Terms of Use for Autopilot Monitor. Read the usage terms, conditions, and acceptable use policies for the Windows Autopilot monitoring and troubleshooting platform.",
openGraph: {
title: "Terms of Use – Autopilot Monitor",
description: "Terms of Use for Autopilot Monitor. Read the usage terms and conditions.",
description: "Terms of Use for Autopilot Monitor. Read the usage terms, conditions, and acceptable use policies for the monitoring platform.",
url: "https://www.autopilotmonitor.com/terms",
},
alternates: {
+1 -1
View File
@@ -40,7 +40,7 @@ export const api = {
report: (sessionId: string, tenantId?: string) =>
`${API_BASE_URL}/api/sessions/${sessionId}/report${qs({ tenantId })}`,
quickSearch: (q: string) =>
`${API_BASE_URL}/api/quick-search${qs({ q })}`,
`${API_BASE_URL}/api/search/quick${qs({ q })}`,
},
// ── Global Sessions (global admin) ────────────────────────────────────────
File diff suppressed because one or more lines are too long