feat(pagespeed): add API client, SWR hooks, and sidebar navigation
- PageSpeed API client with types for config, checks, and audits - SWR hooks: usePageSpeedConfig, usePageSpeedLatest, usePageSpeedHistory - GaugeIcon added to sidebar under Infrastructure group
This commit is contained in:
@@ -18,6 +18,7 @@ import {
|
|||||||
SearchIcon,
|
SearchIcon,
|
||||||
CloudUploadIcon,
|
CloudUploadIcon,
|
||||||
HeartbeatIcon,
|
HeartbeatIcon,
|
||||||
|
GaugeIcon,
|
||||||
SettingsIcon,
|
SettingsIcon,
|
||||||
CollapseLeftIcon,
|
CollapseLeftIcon,
|
||||||
CollapseRightIcon,
|
CollapseRightIcon,
|
||||||
@@ -88,6 +89,7 @@ const NAV_GROUPS: NavGroup[] = [
|
|||||||
items: [
|
items: [
|
||||||
{ label: 'CDN', href: (id) => `/sites/${id}/cdn`, icon: CloudUploadIcon, matchPrefix: true },
|
{ label: 'CDN', href: (id) => `/sites/${id}/cdn`, icon: CloudUploadIcon, matchPrefix: true },
|
||||||
{ label: 'Uptime', href: (id) => `/sites/${id}/uptime`, icon: HeartbeatIcon, matchPrefix: true },
|
{ label: 'Uptime', href: (id) => `/sites/${id}/uptime`, icon: HeartbeatIcon, matchPrefix: true },
|
||||||
|
{ label: 'PageSpeed', href: (id) => `/sites/${id}/pagespeed`, icon: GaugeIcon, matchPrefix: true },
|
||||||
],
|
],
|
||||||
},
|
},
|
||||||
]
|
]
|
||||||
|
|||||||
83
lib/api/pagespeed.ts
Normal file
83
lib/api/pagespeed.ts
Normal file
@@ -0,0 +1,83 @@
|
|||||||
|
import apiRequest from './client'
|
||||||
|
|
||||||
|
// * Types for PageSpeed Insights monitoring
|
||||||
|
|
||||||
|
export interface PageSpeedConfig {
|
||||||
|
site_id: string
|
||||||
|
enabled: boolean
|
||||||
|
frequency: 'daily' | 'weekly' | 'monthly'
|
||||||
|
url: string | null
|
||||||
|
next_check_at: string | null
|
||||||
|
created_at: string
|
||||||
|
updated_at: string
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface AuditSummary {
|
||||||
|
id: string
|
||||||
|
title: string
|
||||||
|
description: string
|
||||||
|
score: number | null
|
||||||
|
display_value?: string
|
||||||
|
savings_ms?: number
|
||||||
|
category: 'opportunity' | 'diagnostic' | 'passed'
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface PageSpeedCheck {
|
||||||
|
id: string
|
||||||
|
site_id: string
|
||||||
|
strategy: 'mobile' | 'desktop'
|
||||||
|
performance_score: number | null
|
||||||
|
accessibility_score: number | null
|
||||||
|
best_practices_score: number | null
|
||||||
|
seo_score: number | null
|
||||||
|
lcp_ms: number | null
|
||||||
|
cls: number | null
|
||||||
|
tbt_ms: number | null
|
||||||
|
fcp_ms: number | null
|
||||||
|
si_ms: number | null
|
||||||
|
tti_ms: number | null
|
||||||
|
audits: AuditSummary[] | null
|
||||||
|
triggered_by: 'scheduled' | 'manual'
|
||||||
|
checked_at: string
|
||||||
|
}
|
||||||
|
|
||||||
|
export async function getPageSpeedConfig(siteId: string): Promise<PageSpeedConfig> {
|
||||||
|
return apiRequest<PageSpeedConfig>(`/sites/${siteId}/pagespeed/config`)
|
||||||
|
}
|
||||||
|
|
||||||
|
export async function updatePageSpeedConfig(
|
||||||
|
siteId: string,
|
||||||
|
config: { enabled: boolean; frequency: string; url?: string }
|
||||||
|
): Promise<PageSpeedConfig> {
|
||||||
|
return apiRequest<PageSpeedConfig>(`/sites/${siteId}/pagespeed/config`, {
|
||||||
|
method: 'PUT',
|
||||||
|
body: JSON.stringify(config),
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
export async function getPageSpeedLatest(siteId: string): Promise<PageSpeedCheck[]> {
|
||||||
|
const res = await apiRequest<{ checks: PageSpeedCheck[] }>(`/sites/${siteId}/pagespeed/latest`)
|
||||||
|
return res?.checks ?? []
|
||||||
|
}
|
||||||
|
|
||||||
|
export async function getPageSpeedHistory(
|
||||||
|
siteId: string,
|
||||||
|
strategy: 'mobile' | 'desktop' = 'mobile',
|
||||||
|
days = 90
|
||||||
|
): Promise<PageSpeedCheck[]> {
|
||||||
|
const res = await apiRequest<{ checks: PageSpeedCheck[] }>(
|
||||||
|
`/sites/${siteId}/pagespeed/history?strategy=${strategy}&days=${days}`
|
||||||
|
)
|
||||||
|
return res?.checks ?? []
|
||||||
|
}
|
||||||
|
|
||||||
|
export async function getPageSpeedCheck(siteId: string, checkId: string): Promise<PageSpeedCheck> {
|
||||||
|
return apiRequest<PageSpeedCheck>(`/sites/${siteId}/pagespeed/checks/${checkId}`)
|
||||||
|
}
|
||||||
|
|
||||||
|
export async function triggerPageSpeedCheck(siteId: string): Promise<PageSpeedCheck[]> {
|
||||||
|
const res = await apiRequest<{ checks: PageSpeedCheck[] }>(`/sites/${siteId}/pagespeed/check`, {
|
||||||
|
method: 'POST',
|
||||||
|
})
|
||||||
|
return res?.checks ?? []
|
||||||
|
}
|
||||||
@@ -31,6 +31,7 @@ import { getSite } from '@/lib/api/sites'
|
|||||||
import type { Site } from '@/lib/api/sites'
|
import type { Site } from '@/lib/api/sites'
|
||||||
import { listFunnels, type Funnel } from '@/lib/api/funnels'
|
import { listFunnels, type Funnel } from '@/lib/api/funnels'
|
||||||
import { getUptimeStatus, type UptimeStatusResponse } from '@/lib/api/uptime'
|
import { getUptimeStatus, type UptimeStatusResponse } from '@/lib/api/uptime'
|
||||||
|
import { getPageSpeedConfig, getPageSpeedLatest, getPageSpeedHistory, type PageSpeedConfig, type PageSpeedCheck } from '@/lib/api/pagespeed'
|
||||||
import { listGoals, type Goal } from '@/lib/api/goals'
|
import { listGoals, type Goal } from '@/lib/api/goals'
|
||||||
import { listReportSchedules, listAlertSchedules, type ReportSchedule } from '@/lib/api/report-schedules'
|
import { listReportSchedules, listAlertSchedules, type ReportSchedule } from '@/lib/api/report-schedules'
|
||||||
import { listSessions, getBotFilterStats, type SessionSummary, type BotFilterStats } from '@/lib/api/bot-filter'
|
import { listSessions, getBotFilterStats, type SessionSummary, type BotFilterStats } from '@/lib/api/bot-filter'
|
||||||
@@ -79,6 +80,9 @@ const fetchers = {
|
|||||||
getJourneyEntryPoints(siteId, start, end),
|
getJourneyEntryPoints(siteId, start, end),
|
||||||
funnels: (siteId: string) => listFunnels(siteId),
|
funnels: (siteId: string) => listFunnels(siteId),
|
||||||
uptimeStatus: (siteId: string) => getUptimeStatus(siteId),
|
uptimeStatus: (siteId: string) => getUptimeStatus(siteId),
|
||||||
|
pageSpeedConfig: (siteId: string) => getPageSpeedConfig(siteId),
|
||||||
|
pageSpeedLatest: (siteId: string) => getPageSpeedLatest(siteId),
|
||||||
|
pageSpeedHistory: (siteId: string, strategy: 'mobile' | 'desktop', days: number) => getPageSpeedHistory(siteId, strategy, days),
|
||||||
goals: (siteId: string) => listGoals(siteId),
|
goals: (siteId: string) => listGoals(siteId),
|
||||||
reportSchedules: (siteId: string) => listReportSchedules(siteId),
|
reportSchedules: (siteId: string) => listReportSchedules(siteId),
|
||||||
alertSchedules: (siteId: string) => listAlertSchedules(siteId),
|
alertSchedules: (siteId: string) => listAlertSchedules(siteId),
|
||||||
@@ -550,5 +554,32 @@ export function useBotFilterStats(siteId: string) {
|
|||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// * Hook for PageSpeed config
|
||||||
|
export function usePageSpeedConfig(siteId: string) {
|
||||||
|
return useSWR<PageSpeedConfig>(
|
||||||
|
siteId ? ['pageSpeedConfig', siteId] : null,
|
||||||
|
() => fetchers.pageSpeedConfig(siteId),
|
||||||
|
{ ...dashboardSWRConfig, refreshInterval: 0, dedupingInterval: 10 * 1000 }
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
// * Hook for latest PageSpeed checks (mobile + desktop)
|
||||||
|
export function usePageSpeedLatest(siteId: string) {
|
||||||
|
return useSWR<PageSpeedCheck[]>(
|
||||||
|
siteId ? ['pageSpeedLatest', siteId] : null,
|
||||||
|
() => fetchers.pageSpeedLatest(siteId),
|
||||||
|
{ ...dashboardSWRConfig, refreshInterval: 60 * 1000, dedupingInterval: 10 * 1000, keepPreviousData: true }
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
// * Hook for PageSpeed score history (trend chart)
|
||||||
|
export function usePageSpeedHistory(siteId: string, strategy: 'mobile' | 'desktop', days = 90) {
|
||||||
|
return useSWR<PageSpeedCheck[]>(
|
||||||
|
siteId ? ['pageSpeedHistory', siteId, strategy, days] : null,
|
||||||
|
() => fetchers.pageSpeedHistory(siteId, strategy, days),
|
||||||
|
{ ...dashboardSWRConfig, refreshInterval: 60 * 1000, dedupingInterval: 10 * 1000, keepPreviousData: true }
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
// * Re-export for convenience
|
// * Re-export for convenience
|
||||||
export { fetchers }
|
export { fetchers }
|
||||||
|
|||||||
Reference in New Issue
Block a user