refactor(design): adopt TanStack DataTable on /veeam-analysis, fill gaps
Follow-on polish for the nav-design overhaul (#9bfb575).
- /veeam-analysis migrates the bespoke TicketRow + custom pagination to
the new DataTable using getRowCanExpand + renderSubRow. Drops ~85
lines of fragment/colspan markup in favor of the standard pattern.
- PageHeader on the last common stragglers — /settings,
/settings/security, /sentinelone/coverage, /sentinelone/mappings.
Settings is reachable from the new top-bar UserMenu so it had to
match the rest of the visual system.
- /dashboard and /status load with the new Skeleton helpers
(SkeletonRows, SkeletonChart, SkeletonTable) so loading shells now
approximate the post-load layout instead of a single h-NN bar.
- DESIGN.md: closed the straggler PageHeader item; deprioritized the
hard-coded palette audit with a note that ~770 references are mostly
semantic via the documented bg-{hue}-500/15 / text-{hue}-700 recipe.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
parent
9bfb57553d
commit
ab78e7bd4f
8 changed files with 242 additions and 250 deletions
|
|
@ -5,6 +5,7 @@ import { Card, CardContent, CardHeader, CardTitle } from '@/components/ui/card';
|
|||
import { Badge } from '@/components/ui/badge';
|
||||
import { Input } from '@/components/ui/input';
|
||||
import { Button } from '@/components/ui/button';
|
||||
import { PageHeader } from '@/components/navigation/page-header';
|
||||
import {
|
||||
Table, TableBody, TableCell, TableHead, TableHeader, TableRow,
|
||||
} from '@/components/ui/table';
|
||||
|
|
@ -64,19 +65,20 @@ export default function S1CoveragePage() {
|
|||
});
|
||||
|
||||
return (
|
||||
<div className="container mx-auto py-8 space-y-6">
|
||||
<div className="flex items-center justify-between">
|
||||
<div>
|
||||
<h1 className="text-3xl font-bold flex items-center gap-3">
|
||||
<Shield className="w-8 h-8 text-purple-600" />
|
||||
SentinelOne Coverage
|
||||
</h1>
|
||||
<p className="text-muted-foreground mt-1">AV agent coverage and threat status per site</p>
|
||||
</div>
|
||||
<Button variant="outline" size="sm" onClick={fetchData} disabled={loading}>
|
||||
<RefreshCw className={`w-4 h-4 mr-2 ${loading ? 'animate-spin' : ''}`} />Refresh
|
||||
</Button>
|
||||
</div>
|
||||
<>
|
||||
<PageHeader
|
||||
title="SentinelOne coverage"
|
||||
description="AV agent coverage and threat status per site"
|
||||
breadcrumbs={[{ label: 'SentinelOne' }, { label: 'Coverage' }]}
|
||||
accent
|
||||
actions={
|
||||
<Button variant="outline" size="sm" onClick={fetchData} disabled={loading}>
|
||||
<RefreshCw className={`w-4 h-4 mr-2 ${loading ? 'animate-spin' : ''}`} />
|
||||
Refresh
|
||||
</Button>
|
||||
}
|
||||
/>
|
||||
<div className="container mx-auto px-6 py-6 space-y-6">
|
||||
|
||||
{/* Summary cards */}
|
||||
{summary && (
|
||||
|
|
@ -182,6 +184,7 @@ export default function S1CoveragePage() {
|
|||
</Table>
|
||||
</CardContent>
|
||||
</Card>
|
||||
</div>
|
||||
</div>
|
||||
</>
|
||||
);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -3,6 +3,7 @@
|
|||
import { useState, useEffect } from 'react';
|
||||
import { Card, CardContent, CardDescription, CardHeader, CardTitle } from '@/components/ui/card';
|
||||
import { Badge } from '@/components/ui/badge';
|
||||
import { PageHeader } from '@/components/navigation/page-header';
|
||||
import { Button } from '@/components/ui/button';
|
||||
import { Input } from '@/components/ui/input';
|
||||
import {
|
||||
|
|
@ -95,26 +96,26 @@ export default function S1MappingsPage() {
|
|||
};
|
||||
|
||||
return (
|
||||
<div className="container mx-auto py-8 space-y-6">
|
||||
<div className="flex items-center justify-between">
|
||||
<div>
|
||||
<h1 className="text-3xl font-bold flex items-center gap-3">
|
||||
<Shield className="w-8 h-8 text-purple-600" />
|
||||
SentinelOne Site Mappings
|
||||
</h1>
|
||||
<p className="text-muted-foreground mt-2">Map SentinelOne sites to Autotask companies</p>
|
||||
</div>
|
||||
<div className="flex gap-2">
|
||||
<Button onClick={handleSync} variant="outline" size="sm" disabled={syncing}>
|
||||
{syncing
|
||||
? <><RefreshCw className="w-4 h-4 mr-2 animate-spin" />Syncing...</>
|
||||
: <><RefreshCw className="w-4 h-4 mr-2" />Sync S1</>}
|
||||
</Button>
|
||||
<Button onClick={fetchData} variant="outline" size="sm">
|
||||
<RefreshCw className="w-4 h-4 mr-2" />Refresh
|
||||
</Button>
|
||||
</div>
|
||||
</div>
|
||||
<>
|
||||
<PageHeader
|
||||
title="SentinelOne site mappings"
|
||||
description="Map SentinelOne sites to Autotask companies"
|
||||
breadcrumbs={[{ label: 'SentinelOne' }, { label: 'Mappings' }]}
|
||||
accent
|
||||
actions={
|
||||
<>
|
||||
<Button onClick={handleSync} variant="outline" size="sm" disabled={syncing}>
|
||||
<RefreshCw className={`w-4 h-4 mr-2 ${syncing ? 'animate-spin' : ''}`} />
|
||||
{syncing ? 'Syncing…' : 'Sync S1'}
|
||||
</Button>
|
||||
<Button onClick={fetchData} variant="outline" size="sm">
|
||||
<RefreshCw className="w-4 h-4 mr-2" />
|
||||
Refresh
|
||||
</Button>
|
||||
</>
|
||||
}
|
||||
/>
|
||||
<div className="container mx-auto px-6 py-6 space-y-6">
|
||||
|
||||
{/* Stats */}
|
||||
<div className="grid grid-cols-3 gap-4">
|
||||
|
|
@ -182,7 +183,8 @@ export default function S1MappingsPage() {
|
|||
</div>
|
||||
</CardContent>
|
||||
</Card>
|
||||
</div>
|
||||
</div>
|
||||
</>
|
||||
);
|
||||
}
|
||||
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue