NORY-42: fix dashboard status cards (#43)

This commit is contained in:
Markus Thielker 2024-12-27 10:30:14 +01:00 committed by GitHub
commit c943cba6ec
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
2 changed files with 103 additions and 86 deletions

View file

@ -1,49 +1,40 @@
import { getHydraMetadataApi, getKetoMetadataApi, getKratosMetadataApi } from '@/ory/sdk/server'; import { getHydraMetadataApi, getKetoMetadataApi, getKratosMetadataApi } from '@/ory/sdk/server';
import { Card, CardContent, CardDescription, CardHeader, CardTitle } from '@/components/ui/card'; import { MetadataApiReady, StatusCard } from '@/components/status-card';
import { Badge } from '@/components/ui/badge';
export default async function RootPage() { export default async function RootPage() {
const kratosMetadataApi = await getKratosMetadataApi(); const kratosMetadataApi = await getKratosMetadataApi();
const kratosVersion = await kratosMetadataApi.getVersion()
const kratosVersion = await kratosMetadataApi
.getVersion()
.then(res => res.data.version) .then(res => res.data.version)
.catch(() => ''); .catch(() => undefined);
const kratosStatus = await fetch(process.env.ORY_KRATOS_ADMIN_URL + '/health/ready')
const kratosStatusData = await fetch(process.env.ORY_KRATOS_ADMIN_URL + '/health/alive'); .then((response) => response.json() as MetadataApiReady)
const kratosStatus = await kratosStatusData.json() as { status: string }; .catch(() => {
return { errors: ['No instance running'] } as MetadataApiReady;
const kratosDBStatusData = await fetch(process.env.ORY_KRATOS_ADMIN_URL + '/health/ready'); });
const kratosDBStatus = await kratosDBStatusData.json() as { status: string };
const hydraMetadataApi = await getHydraMetadataApi(); const hydraMetadataApi = await getHydraMetadataApi();
const hydraVersion = await hydraMetadataApi.getVersion()
const hydraVersion = await hydraMetadataApi
.getVersion()
.then(res => res.data.version) .then(res => res.data.version)
.catch(() => ''); .catch(() => undefined);
const hydraStatus = await fetch(process.env.ORY_HYDRA_ADMIN_URL + '/health/ready')
const hydraStatusData = await fetch(process.env.ORY_KRATOS_ADMIN_URL + '/health/alive'); .then((response) => response.json() as MetadataApiReady)
const hydraStatus = await hydraStatusData.json() as { status: string }; .catch(() => {
return { errors: ['No instance running'] } as MetadataApiReady;
const hydraDBStatusData = await fetch(process.env.ORY_KRATOS_ADMIN_URL + '/health/ready'); });
const hydraDBStatus = await hydraDBStatusData.json() as { status: string };
const ketoMetadataApi = await getKetoMetadataApi(); const ketoMetadataApi = await getKetoMetadataApi();
const ketoVersion = await ketoMetadataApi.getVersion()
const ketoVersion = await ketoMetadataApi
.getVersion()
.then(res => res.data.version) .then(res => res.data.version)
.catch(() => ''); .catch(() => undefined);
const ketoStatus = await fetch(process.env.ORY_KETO_ADMIN_URL + '/health/ready')
.then((response) => response.json() as MetadataApiReady)
.catch(() => {
return { errors: ['No instance running'] } as MetadataApiReady;
});
const ketoStatusData = await fetch(process.env.ORY_KETO_ADMIN_URL + '/health/alive');
const ketoStatus = await ketoStatusData.json() as { status: string };
const ketoDBStatusData = await fetch(process.env.ORY_KETO_ADMIN_URL + '/health/ready');
const ketoDBStatus = await ketoDBStatusData.json() as { status: string };
return ( return (
<div className="flex flex-col space-y-4"> <div className="flex flex-col space-y-4">
@ -52,61 +43,25 @@ export default async function RootPage() {
<p className="text-lg font-light">See the list of all applications in your stack</p> <p className="text-lg font-light">See the list of all applications in your stack</p>
</div> </div>
<div className="grid grid-cols-1 md:grid-cols-4 gap-4"> <div className="grid grid-cols-1 md:grid-cols-4 gap-4">
<Card className="flex-1"> <StatusCard
<CardHeader> title="Ory Kratos"
<CardTitle> version={kratosVersion}
Ory Kratos name="Kratos"
</CardTitle> status={kratosStatus}
<CardDescription> className="flex-1"/>
Version {kratosVersion} <StatusCard
</CardDescription> title="Ory Hydra"
</CardHeader> version={hydraVersion}
<CardContent className="space-x-1"> name="Hydra"
<Badge variant={kratosStatus.status === 'ok' ? 'success' : 'destructive'}> status={hydraStatus}
Kratos {kratosStatus.status.toUpperCase()} className="flex-1"/>
</Badge> <StatusCard
<Badge variant={kratosStatus.status === 'ok' ? 'success' : 'destructive'}> title="Ory Keto"
Database {kratosDBStatus.status.toUpperCase()} version={ketoVersion}
</Badge> name="Keto"
</CardContent> status={ketoStatus}
</Card> className="flex-1"/>
<Card className="flex-1"> <div className="flex-1"/>
<CardHeader>
<CardTitle>
Ory Hydra
</CardTitle>
<CardDescription>
Version {hydraVersion}
</CardDescription>
</CardHeader>
<CardContent className="space-x-1">
<Badge variant={kratosStatus.status === 'ok' ? 'success' : 'destructive'}>
Hydra {hydraStatus.status.toUpperCase()}
</Badge>
<Badge variant={kratosStatus.status === 'ok' ? 'success' : 'destructive'}>
Database {hydraDBStatus.status.toUpperCase()}
</Badge>
</CardContent>
</Card>
<Card className="flex-1">
<CardHeader>
<CardTitle>
Ory Keto
</CardTitle>
<CardDescription>
Version {ketoVersion}
</CardDescription>
</CardHeader>
<CardContent className="space-x-1">
<Badge variant={kratosStatus.status === 'ok' ? 'success' : 'destructive'}>
Keto {ketoStatus.status.toUpperCase()}
</Badge>
<Badge variant={kratosStatus.status === 'ok' ? 'success' : 'destructive'}>
Database {ketoDBStatus.status.toUpperCase()}
</Badge>
</CardContent>
</Card>
<div className="flex-1"></div>
</div> </div>
</div> </div>
); );

View file

@ -0,0 +1,62 @@
import { Card, CardDescription, CardFooter, CardHeader, CardTitle } from '@/components/ui/card';
import { Badge } from '@/components/ui/badge';
import { Tooltip, TooltipContent, TooltipTrigger } from '@/components/ui/tooltip';
export type MetadataApiReady = {
status?: 'ok',
errors?: string[]
}
interface StatusCardProps {
title: string;
version?: string;
name: string;
status: MetadataApiReady;
className?: string;
}
export function StatusCard({ title, version, name, status, className }: StatusCardProps) {
return (
<Card className={className}>
<CardHeader>
<CardTitle>
{title}
</CardTitle>
<CardDescription>
{
version ?
<span>Version {version}</span>
:
<span>OFFLINE</span>
}
</CardDescription>
</CardHeader>
<CardFooter className="space-x-1">
{
status.status && (
<Badge variant="success">
{name} {status.status.toUpperCase()}
</Badge>
)
}
{
status.errors && (
<Tooltip>
<TooltipTrigger>
<Badge variant="destructive">
{name} Error
</Badge>
</TooltipTrigger>
<TooltipContent>
{
status.errors.map((error) => <span>{error}</span>)
}
</TooltipContent>
</Tooltip>
)
}
</CardFooter>
</Card>
);
}