Version 3 of the kit: - Radix UI replaced with Base UI (using the Shadcn UI patterns) - next-intl replaces react-i18next - enhanceAction deprecated; usage moved to next-safe-action - main layout now wrapped with [locale] path segment - Teams only mode - Layout updates - Zod v4 - Next.js 16.2 - Typescript 6 - All other dependencies updated - Removed deprecated Edge CSRF - Dynamic Github Action runner
187 lines
6.2 KiB
TypeScript
187 lines
6.2 KiB
TypeScript
import { Card, CardContent, CardHeader, CardTitle } from '@kit/ui/card';
|
|
import { Page, PageBody, PageHeader } from '@kit/ui/page';
|
|
|
|
import { loadDashboardKitPrerequisites } from './lib/prerequisites-dashboard.loader';
|
|
import { loadDashboardKitStatus } from './lib/status-dashboard.loader';
|
|
|
|
import { ServiceCard } from '@/components/status-tile';
|
|
|
|
export default async function DashboardPage() {
|
|
const [status, prerequisites] = await Promise.all([
|
|
loadDashboardKitStatus(),
|
|
loadDashboardKitPrerequisites(),
|
|
]);
|
|
|
|
const failedRequiredCount = prerequisites.prerequisites.filter(
|
|
(item) => item.required && item.status === 'fail',
|
|
).length;
|
|
|
|
const warnCount = prerequisites.prerequisites.filter(
|
|
(item) => item.status === 'warn',
|
|
).length;
|
|
|
|
const failedRequired = prerequisites.prerequisites.filter(
|
|
(item) => item.required && item.status === 'fail',
|
|
);
|
|
|
|
const prerequisiteRemedies = Array.from(
|
|
new Set(
|
|
failedRequired.flatMap((item) => [
|
|
...(item.remedies ?? []),
|
|
...(item.install_command ? [item.install_command] : []),
|
|
...(item.install_url ? [item.install_url] : []),
|
|
]),
|
|
),
|
|
);
|
|
|
|
return (
|
|
<Page style={'custom'}>
|
|
<PageHeader
|
|
title={'Dev Tool'}
|
|
description={'Kit MCP status for this workspace'}
|
|
/>
|
|
|
|
<PageBody className={'space-y-8 py-2'}>
|
|
<div className="grid grid-cols-1 gap-4 md:grid-cols-4">
|
|
<ServiceCard
|
|
name={'Variant'}
|
|
status={{
|
|
status: 'success',
|
|
message: `${status.variant} (${status.variant_family})`,
|
|
}}
|
|
/>
|
|
|
|
<ServiceCard
|
|
name={'Runtime'}
|
|
status={{
|
|
status: 'success',
|
|
message: `${status.framework} • Node ${status.node_version} • ${status.package_manager}`,
|
|
}}
|
|
/>
|
|
|
|
<ServiceCard
|
|
name={'Dependencies'}
|
|
status={{
|
|
status: status.deps_installed ? 'success' : 'error',
|
|
message: status.deps_installed
|
|
? 'Dependencies installed'
|
|
: 'node_modules not found',
|
|
}}
|
|
/>
|
|
|
|
<ServiceCard
|
|
name={'Git'}
|
|
status={{
|
|
status:
|
|
status.git_branch === 'unknown'
|
|
? 'info'
|
|
: status.git_clean
|
|
? 'success'
|
|
: 'warning',
|
|
message: `${status.git_branch} (${status.git_clean ? 'clean' : 'dirty'}) • ${status.git_modified_files.length} modified • ${status.git_untracked_files.length} untracked`,
|
|
}}
|
|
/>
|
|
|
|
<ServiceCard
|
|
name={'Dev Server'}
|
|
status={{
|
|
status: status.services.app.running ? 'success' : 'error',
|
|
message: status.services.app.running
|
|
? `Running on port ${status.services.app.port}`
|
|
: 'Not running',
|
|
}}
|
|
/>
|
|
|
|
<ServiceCard
|
|
name={'Supabase'}
|
|
status={{
|
|
status: status.services.supabase.running ? 'success' : 'error',
|
|
message: status.services.supabase.running
|
|
? `Running${status.services.supabase.api_port ? ` (API ${status.services.supabase.api_port})` : ''}${status.services.supabase.studio_port ? ` (Studio ${status.services.supabase.studio_port})` : ''}`
|
|
: 'Not running',
|
|
}}
|
|
/>
|
|
|
|
<ServiceCard
|
|
name={'Merge Check'}
|
|
status={{
|
|
status:
|
|
status.git_merge_check.has_conflicts === true
|
|
? 'warning'
|
|
: status.git_merge_check.detectable
|
|
? 'success'
|
|
: 'info',
|
|
message: status.git_merge_check.detectable
|
|
? status.git_merge_check.has_conflicts
|
|
? `${status.git_merge_check.conflict_files.length} potential conflicts vs ${status.git_merge_check.target_branch}`
|
|
: `No conflicts vs ${status.git_merge_check.target_branch}`
|
|
: status.git_merge_check.message,
|
|
}}
|
|
/>
|
|
|
|
<ServiceCard
|
|
name={'Prerequisites'}
|
|
status={{
|
|
status:
|
|
prerequisites.overall === 'fail'
|
|
? 'error'
|
|
: prerequisites.overall === 'warn'
|
|
? 'warning'
|
|
: 'success',
|
|
message:
|
|
prerequisites.overall === 'fail'
|
|
? `${failedRequiredCount} required tools missing/mismatched`
|
|
: prerequisites.overall === 'warn'
|
|
? `${warnCount} optional warnings`
|
|
: 'All prerequisites satisfied',
|
|
}}
|
|
/>
|
|
</div>
|
|
|
|
{failedRequired.length > 0 ? (
|
|
<Card>
|
|
<CardHeader>
|
|
<CardTitle>Prerequisites Details</CardTitle>
|
|
</CardHeader>
|
|
|
|
<CardContent className={'space-y-4'}>
|
|
<div className={'space-y-2'}>
|
|
<p className={'text-sm font-medium'}>Missing or Mismatched</p>
|
|
<ul
|
|
className={
|
|
'text-muted-foreground list-disc space-y-1 pl-5 text-sm'
|
|
}
|
|
>
|
|
{failedRequired.map((item) => (
|
|
<li key={item.id}>
|
|
{item.name}
|
|
{item.version
|
|
? ` (installed ${item.version}, requires >= ${item.minimum_version})`
|
|
: ' (not installed)'}
|
|
</li>
|
|
))}
|
|
</ul>
|
|
</div>
|
|
|
|
<div className={'space-y-2'}>
|
|
<p className={'text-sm font-medium'}>Remediation</p>
|
|
<ul
|
|
className={
|
|
'text-muted-foreground list-disc space-y-1 pl-5 text-sm'
|
|
}
|
|
>
|
|
{prerequisiteRemedies.map((remedy) => (
|
|
<li key={remedy}>
|
|
<code>{remedy}</code>
|
|
</li>
|
|
))}
|
|
</ul>
|
|
</div>
|
|
</CardContent>
|
|
</Card>
|
|
) : null}
|
|
</PageBody>
|
|
</Page>
|
|
);
|
|
}
|