60 lines
1.7 KiB
TypeScript
60 lines
1.7 KiB
TypeScript
'use client';
|
|
|
|
import {Card} from '@astryxdesign/core/Card';
|
|
import {VStack} from '@astryxdesign/core/Layout';
|
|
import {AsyncBoundary} from '@/shared/components/data/AsyncBoundary';
|
|
import {SectionHeader} from '@/shared/components/patterns/SectionHeader';
|
|
import type {AdminData} from '@/features/admin/hooks/useMonitoring';
|
|
import type {IconKey} from '@/shared/utils/icons';
|
|
import {PendingIntegration} from './PendingIntegration';
|
|
|
|
/**
|
|
* A panel over one level of the drill-down, in whichever of its three states
|
|
* it is in:
|
|
*
|
|
* unavailable no admin endpoint → PendingIntegration, no request sent
|
|
* loading / error / empty → AsyncBoundary, as everywhere else
|
|
* loaded → `children(data)`
|
|
*
|
|
* This is what makes "turn the level on" a flag flip: the section already
|
|
* renders the loaded branch; only the hook's answer changes.
|
|
*/
|
|
export function AdminSection<T>({
|
|
title,
|
|
subtitle,
|
|
actions,
|
|
data,
|
|
pending,
|
|
loading,
|
|
empty,
|
|
children,
|
|
}: {
|
|
title: string;
|
|
subtitle?: string;
|
|
actions?: React.ReactNode;
|
|
data: AdminData<T>;
|
|
pending: {icon: IconKey; title: string; description: string};
|
|
loading: React.ReactNode;
|
|
empty?: React.ReactNode;
|
|
children: (data: T) => React.ReactNode;
|
|
}) {
|
|
return (
|
|
<Card>
|
|
<VStack gap={4}>
|
|
<SectionHeader
|
|
title={title}
|
|
subtitle={subtitle}
|
|
actions={data.isAvailable ? actions : undefined}
|
|
/>
|
|
{data.isAvailable ? (
|
|
<AsyncBoundary resource={data.resource} loading={loading} empty={empty}>
|
|
{children}
|
|
</AsyncBoundary>
|
|
) : (
|
|
<PendingIntegration {...pending} />
|
|
)}
|
|
</VStack>
|
|
</Card>
|
|
);
|
|
}
|