NORY-42: fix dashboard status cards (#43)
This commit is contained in:
commit
c943cba6ec
2 changed files with 103 additions and 86 deletions
|
@ -1,49 +1,40 @@
|
|||
import { getHydraMetadataApi, getKetoMetadataApi, getKratosMetadataApi } from '@/ory/sdk/server';
|
||||
import { Card, CardContent, CardDescription, CardHeader, CardTitle } from '@/components/ui/card';
|
||||
import { Badge } from '@/components/ui/badge';
|
||||
import { MetadataApiReady, StatusCard } from '@/components/status-card';
|
||||
|
||||
export default async function RootPage() {
|
||||
|
||||
const kratosMetadataApi = await getKratosMetadataApi();
|
||||
|
||||
const kratosVersion = await kratosMetadataApi
|
||||
.getVersion()
|
||||
const kratosVersion = await kratosMetadataApi.getVersion()
|
||||
.then(res => res.data.version)
|
||||
.catch(() => '');
|
||||
|
||||
const kratosStatusData = await fetch(process.env.ORY_KRATOS_ADMIN_URL + '/health/alive');
|
||||
const kratosStatus = await kratosStatusData.json() as { status: string };
|
||||
|
||||
const kratosDBStatusData = await fetch(process.env.ORY_KRATOS_ADMIN_URL + '/health/ready');
|
||||
const kratosDBStatus = await kratosDBStatusData.json() as { status: string };
|
||||
.catch(() => undefined);
|
||||
const kratosStatus = await fetch(process.env.ORY_KRATOS_ADMIN_URL + '/health/ready')
|
||||
.then((response) => response.json() as MetadataApiReady)
|
||||
.catch(() => {
|
||||
return { errors: ['No instance running'] } as MetadataApiReady;
|
||||
});
|
||||
|
||||
|
||||
const hydraMetadataApi = await getHydraMetadataApi();
|
||||
|
||||
const hydraVersion = await hydraMetadataApi
|
||||
.getVersion()
|
||||
const hydraVersion = await hydraMetadataApi.getVersion()
|
||||
.then(res => res.data.version)
|
||||
.catch(() => '');
|
||||
|
||||
const hydraStatusData = await fetch(process.env.ORY_KRATOS_ADMIN_URL + '/health/alive');
|
||||
const hydraStatus = await hydraStatusData.json() as { status: string };
|
||||
|
||||
const hydraDBStatusData = await fetch(process.env.ORY_KRATOS_ADMIN_URL + '/health/ready');
|
||||
const hydraDBStatus = await hydraDBStatusData.json() as { status: string };
|
||||
.catch(() => undefined);
|
||||
const hydraStatus = await fetch(process.env.ORY_HYDRA_ADMIN_URL + '/health/ready')
|
||||
.then((response) => response.json() as MetadataApiReady)
|
||||
.catch(() => {
|
||||
return { errors: ['No instance running'] } as MetadataApiReady;
|
||||
});
|
||||
|
||||
|
||||
const ketoMetadataApi = await getKetoMetadataApi();
|
||||
|
||||
const ketoVersion = await ketoMetadataApi
|
||||
.getVersion()
|
||||
const ketoVersion = await ketoMetadataApi.getVersion()
|
||||
.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 (
|
||||
<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>
|
||||
</div>
|
||||
<div className="grid grid-cols-1 md:grid-cols-4 gap-4">
|
||||
<Card className="flex-1">
|
||||
<CardHeader>
|
||||
<CardTitle>
|
||||
Ory Kratos
|
||||
</CardTitle>
|
||||
<CardDescription>
|
||||
Version {kratosVersion}
|
||||
</CardDescription>
|
||||
</CardHeader>
|
||||
<CardContent className="space-x-1">
|
||||
<Badge variant={kratosStatus.status === 'ok' ? 'success' : 'destructive'}>
|
||||
Kratos {kratosStatus.status.toUpperCase()}
|
||||
</Badge>
|
||||
<Badge variant={kratosStatus.status === 'ok' ? 'success' : 'destructive'}>
|
||||
Database {kratosDBStatus.status.toUpperCase()}
|
||||
</Badge>
|
||||
</CardContent>
|
||||
</Card>
|
||||
<Card 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>
|
||||
<StatusCard
|
||||
title="Ory Kratos"
|
||||
version={kratosVersion}
|
||||
name="Kratos"
|
||||
status={kratosStatus}
|
||||
className="flex-1"/>
|
||||
<StatusCard
|
||||
title="Ory Hydra"
|
||||
version={hydraVersion}
|
||||
name="Hydra"
|
||||
status={hydraStatus}
|
||||
className="flex-1"/>
|
||||
<StatusCard
|
||||
title="Ory Keto"
|
||||
version={ketoVersion}
|
||||
name="Keto"
|
||||
status={ketoStatus}
|
||||
className="flex-1"/>
|
||||
<div className="flex-1"/>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
|
|
62
dashboard/src/components/status-card.tsx
Normal file
62
dashboard/src/components/status-card.tsx
Normal 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>
|
||||
);
|
||||
}
|
Loading…
Add table
Reference in a new issue