feat: add diagnostics page and broken link checker
All checks were successful
Deploy eolas-app / deploy (push) Successful in 1m7s

This commit is contained in:
Thomas Bishop 2025-12-22 17:08:40 +00:00
parent 7454a42f80
commit caef8ddf6b
3 changed files with 163 additions and 69 deletions

View file

@ -7,6 +7,7 @@ import TagTemplate from "./templates/TagTemplate"
import EntryTemplate from "./templates/EntryTemplate"
import Settings from "./pages/settings"
import About from "./pages/about"
import Diagnostics from "./pages/diagnostics"
const queryClient = new QueryClient({
defaultOptions: {
@ -27,6 +28,7 @@ export default function App() {
<Routes>
<Route index element={<Home />} />
<Route path="/settings" element={<Settings />} />
<Route path="/diagnostics" element={<Diagnostics />} />
<Route path="/about" element={<About />} />
<Route path="/entries/:entry" element={<EntryTemplate />} />
<Route path="/tags/:tag" element={<TagTemplate />} />

View file

@ -1,57 +1,72 @@
import { Info, FileText, Waypoints, SquareLibrary, Settings, ChevronRight } from "lucide-react"
import {
Info,
FileText,
Waypoints,
SquareLibrary,
Settings,
ChevronRight,
TestTubeDiagonal,
TestTube2,
FlaskConical,
} from "lucide-react"
import {
Sidebar,
SidebarContent,
SidebarGroup,
SidebarGroupContent,
SidebarMenu,
SidebarMenuButton,
SidebarMenuItem,
SidebarHeader,
SidebarFooter,
Sidebar,
SidebarContent,
SidebarGroup,
SidebarGroupContent,
SidebarMenu,
SidebarMenuButton,
SidebarMenuItem,
SidebarHeader,
SidebarFooter,
} from "@/components/ui/sidebar"
import TagListSidebar from "@/components/TagListSidebar"
import EntriesListSidebar from "@/components/EntriesListSidebar"
import { Link } from "react-router"
const footerMenu = [
{
title: "About",
url: "/about",
icon: Info,
},
{
title: "About",
url: "/about",
icon: Info,
},
{
title: "Diagnostics",
url: "/diagnostics",
icon: FlaskConical,
},
{
title: "Settings",
url: "/settings",
icon: Settings,
},
{
title: "Settings",
url: "/settings",
icon: Settings,
},
]
export function AppSidebar() {
return (
<Sidebar>
<SidebarHeader className="border-b h-12">
<SidebarMenu>
<SidebarMenuItem>
<SidebarMenuButton
asChild
className="data-[slot=sidebar-menu-button]:!p-1.5 rounded-none"
>
<Link to="/">
<SquareLibrary className="h-5 w-5" />
<span className="text-base font-semibold">Eólas</span>
</Link>
</SidebarMenuButton>
</SidebarMenuItem>
</SidebarMenu>
</SidebarHeader>
<SidebarContent>
<SidebarGroup>
<SidebarGroupContent>
<SidebarMenu>
{/*
return (
<Sidebar>
<SidebarHeader className="border-b h-12">
<SidebarMenu>
<SidebarMenuItem>
<SidebarMenuButton
asChild
className="data-[slot=sidebar-menu-button]:!p-1.5 rounded-none"
>
<Link to="/">
<SquareLibrary className="h-5 w-5" />
<span className="text-base font-semibold">Eólas</span>
</Link>
</SidebarMenuButton>
</SidebarMenuItem>
</SidebarMenu>
</SidebarHeader>
<SidebarContent>
<SidebarGroup>
<SidebarGroupContent>
<SidebarMenu>
{/*
<SidebarMenuItem key="graph">
<SidebarMenuButton asChild>
<a href="#">
@ -62,38 +77,38 @@ export function AppSidebar() {
</SidebarMenuItem>
*/}
<EntriesListSidebar />
<TagListSidebar />
</SidebarMenu>
</SidebarGroupContent>
</SidebarGroup>
</SidebarContent>
<SidebarFooter>
<SidebarGroup>
<SidebarGroupContent>
<SidebarMenu>
{footerMenu.map((item) => (
<SidebarMenuItem key={item.title}>
<SidebarMenuButton asChild className="rounded-none">
<Link to={item.url}>
<item.icon />
<span className="font-medium">{item.title}</span>
</Link>
<EntriesListSidebar />
<TagListSidebar />
</SidebarMenu>
</SidebarGroupContent>
</SidebarGroup>
</SidebarContent>
<SidebarFooter>
<SidebarGroup>
<SidebarGroupContent>
<SidebarMenu>
{footerMenu.map((item) => (
<SidebarMenuItem key={item.title}>
<SidebarMenuButton asChild className="rounded-none">
<Link to={item.url}>
<item.icon />
<span className="font-medium">{item.title}</span>
</Link>
{/*
{/*
<a href={item.url}>
<item.icon />
<span>{item.title}</span>
</a>
*/}
</SidebarMenuButton>
</SidebarMenuItem>
))}
</SidebarMenu>
</SidebarGroupContent>
</SidebarGroup>
</SidebarFooter>
</Sidebar>
)
</SidebarMenuButton>
</SidebarMenuItem>
))}
</SidebarMenu>
</SidebarGroupContent>
</SidebarGroup>
</SidebarFooter>
</Sidebar>
)
}

77
src/pages/diagnostics.tsx Normal file
View file

@ -0,0 +1,77 @@
import { Button } from "@/components/ui/button"
import PageTemplate from "@/templates/PageTemplate"
import api from "@/api/eolas-api"
import { useQuery } from "@tanstack/react-query"
import {
Table,
TableBody,
TableCell,
TableHead,
TableHeader,
TableRow,
} from "@/components/ui/table"
import { Link } from "react-router"
const PageBody = () => {
const { data, refetch, isLoading, error } = useQuery({
queryKey: ["diagnostics_broken-link"],
queryFn: () => api.get("/diagnostics/broken-links").then((res) => res.data),
enabled: false,
})
data?.data.sort((a, b) => a.source_entry_title.localeCompare(b.source_entry_title))
return (
<div className="max-w-2xl p-4 lg:p-6">
<div className="flex flex-row justify-between">
<h3 className="font-semibold mb-4">Broken links</h3>
<Button size="sm" variant="secondary" onClick={() => refetch()}>
Find broken links
</Button>
</div>
{isLoading ? (
<p>Generating list...</p>
) : error ? (
<div className="p-4 text-sm dark:text-red-300 text-red-700">
<div className="p-2 border-2 dark:border-red-800 border-red-500 dark:bg-red-900 bg-red-300">
Error fetching broken links
</div>{" "}
</div>
) : (
data && (
<>
<p className="leading-[1.5] mb-4 not-first:mt-4">
There are <b>{data?.count}</b> broken links.
</p>
<Table>
<TableHeader>
<TableRow>
<TableHead>Source entry</TableHead>
<TableHead>Broken link</TableHead>
</TableRow>
</TableHeader>
<TableBody>
{data?.data.map((link, i) => (
<TableRow key={i}>
<TableCell>
<Link
to={`/entries/${link?.source_entry_title}`} // Fixed: to={ instead of to=
className="text-foreground underline-offset-3 text-sm underline hover:text-gray-700 dark:hover:text-green-300"
>
{link?.source_entry_title.replace(/_/g, " ")}{" "}
</Link>{" "}
</TableCell>
<TableCell>{link?.broken_link_title}</TableCell>
</TableRow>
))}
</TableBody>
</Table>
</>
)
)}
</div>
)
}
export default function Diagnostics() {
return <PageTemplate pageTitle="Diagnostics" pageBody={<PageBody />} />
}