fix(agent-graph): center launch stepper hud
This commit is contained in:
parent
345fd3e41d
commit
19463edfc9
3 changed files with 18 additions and 63 deletions
|
|
@ -107,8 +107,8 @@ export function GraphControls({
|
|||
|
||||
return (
|
||||
<>
|
||||
<div className="absolute inset-x-3 top-3 z-20 flex items-start gap-2 pointer-events-none">
|
||||
<div className="flex shrink-0 items-center gap-0.5">
|
||||
<div className="pointer-events-none absolute inset-x-3 top-3 z-20 h-8">
|
||||
<div className="absolute left-0 top-0 flex shrink-0 items-center gap-0.5">
|
||||
{onToggleSidebar ? (
|
||||
<div
|
||||
className="pointer-events-auto flex items-center rounded-md p-0 backdrop-blur-sm"
|
||||
|
|
@ -165,15 +165,15 @@ export function GraphControls({
|
|||
) : null}
|
||||
</div>
|
||||
|
||||
<div className="flex min-w-0 flex-1 justify-end px-2">
|
||||
<div className="absolute left-1/2 top-0 w-[min(360px,38vw)] -translate-x-1/2 px-2">
|
||||
{topToolbarContent ? (
|
||||
<div className="pointer-events-auto min-w-0 max-w-[min(360px,42vw)]">
|
||||
<div className="pointer-events-auto min-w-0">
|
||||
{topToolbarContent}
|
||||
</div>
|
||||
) : null}
|
||||
</div>
|
||||
|
||||
<div className="flex shrink-0 items-center gap-0.5">
|
||||
<div className="absolute right-0 top-0 flex shrink-0 items-center gap-0.5">
|
||||
<div
|
||||
className="pointer-events-auto flex items-center rounded-md p-0 backdrop-blur-sm"
|
||||
style={{
|
||||
|
|
|
|||
|
|
@ -4,7 +4,6 @@ import { DISPLAY_STEPS } from '@renderer/components/team/provisioningSteps';
|
|||
import { StepProgressBar } from '@renderer/components/team/StepProgressBar';
|
||||
import { TeamProvisioningPanel } from '@renderer/components/team/TeamProvisioningPanel';
|
||||
import { useTeamProvisioningPresentation } from '@renderer/components/team/useTeamProvisioningPresentation';
|
||||
import { Badge } from '@renderer/components/ui/badge';
|
||||
import {
|
||||
Dialog,
|
||||
DialogContent,
|
||||
|
|
@ -13,7 +12,6 @@ import {
|
|||
DialogTitle,
|
||||
} from '@renderer/components/ui/dialog';
|
||||
import { cn } from '@renderer/lib/utils';
|
||||
import { AlertTriangle, CheckCircle2, Loader2 } from 'lucide-react';
|
||||
|
||||
import type { TeamProvisioningPresentation } from '@renderer/utils/teamProvisioningPresentation';
|
||||
import type { CSSProperties } from 'react';
|
||||
|
|
@ -42,38 +40,23 @@ function shouldRenderLaunchHud(presentation: TeamProvisioningPresentation | null
|
|||
|
||||
function getToneClasses(tone: TeamProvisioningPresentation['compactTone']): {
|
||||
border: string;
|
||||
badge: string;
|
||||
icon: React.ReactNode;
|
||||
iconClassName: string;
|
||||
} {
|
||||
switch (tone) {
|
||||
case 'error':
|
||||
return {
|
||||
border: 'border-red-400/35 bg-[rgba(26,10,16,0.92)]',
|
||||
badge: 'border-red-500/30 text-red-300',
|
||||
icon: <AlertTriangle size={12} />,
|
||||
iconClassName: 'text-red-400',
|
||||
border: 'border-red-400/35 bg-[rgba(26,10,16,0.9)]',
|
||||
};
|
||||
case 'warning':
|
||||
return {
|
||||
border: 'border-amber-400/35 bg-[rgba(31,18,8,0.92)]',
|
||||
badge: 'border-amber-500/30 text-amber-200',
|
||||
icon: <AlertTriangle size={12} />,
|
||||
iconClassName: 'text-amber-400',
|
||||
border: 'border-amber-400/35 bg-[rgba(31,18,8,0.9)]',
|
||||
};
|
||||
case 'success':
|
||||
return {
|
||||
border: 'border-emerald-400/35 bg-[rgba(8,24,18,0.92)]',
|
||||
badge: 'border-emerald-500/30 text-emerald-200',
|
||||
icon: <CheckCircle2 size={12} />,
|
||||
iconClassName: 'text-emerald-400',
|
||||
border: 'border-emerald-400/35 bg-[rgba(8,24,18,0.9)]',
|
||||
};
|
||||
default:
|
||||
return {
|
||||
border: 'border-cyan-400/25 bg-[rgba(8,14,26,0.92)]',
|
||||
badge: 'border-cyan-500/20 text-cyan-200',
|
||||
icon: <Loader2 size={12} className="animate-spin" />,
|
||||
iconClassName: 'text-cyan-300',
|
||||
border: 'border-cyan-400/25 bg-[rgba(8,14,26,0.9)]',
|
||||
};
|
||||
}
|
||||
}
|
||||
|
|
@ -109,14 +92,10 @@ export const GraphProvisioningHud = ({
|
|||
}
|
||||
}, [presentation]);
|
||||
|
||||
const compactLabel = useMemo(() => {
|
||||
if (!presentation?.compactDetail) {
|
||||
return null;
|
||||
}
|
||||
return presentation.compactDetail.length > 54
|
||||
? `${presentation.compactDetail.slice(0, 54)}...`
|
||||
: presentation.compactDetail;
|
||||
}, [presentation?.compactDetail]);
|
||||
const ariaLabel = useMemo(() => {
|
||||
const parts = [presentation?.compactTitle, presentation?.compactDetail].filter(Boolean);
|
||||
return parts.join(' - ') || 'Open launch details';
|
||||
}, [presentation?.compactDetail, presentation?.compactTitle]);
|
||||
|
||||
if (!shouldRender || !presentation || !tone) {
|
||||
return null;
|
||||
|
|
@ -131,44 +110,20 @@ export const GraphProvisioningHud = ({
|
|||
tone.border
|
||||
)}
|
||||
onClick={() => setDetailsOpen(true)}
|
||||
aria-label="Open launch details"
|
||||
aria-label={ariaLabel}
|
||||
>
|
||||
<div className="flex min-w-0 items-center gap-2">
|
||||
<span className={cn('shrink-0', tone.iconClassName)}>{tone.icon}</span>
|
||||
<div className="min-w-0 flex-1">
|
||||
<div className="flex min-w-0 items-center gap-2">
|
||||
<div className="truncate text-[11px] font-semibold text-slate-50">
|
||||
{presentation.compactTitle}
|
||||
</div>
|
||||
<Badge variant="outline" className={cn('px-1.5 py-0 text-[10px]', tone.badge)}>
|
||||
{presentation.isFailed
|
||||
? 'Issue'
|
||||
: presentation.hasMembersStillJoining
|
||||
? 'Joining'
|
||||
: presentation.isActive
|
||||
? 'Live'
|
||||
: 'Ready'}
|
||||
</Badge>
|
||||
</div>
|
||||
{compactLabel ? (
|
||||
<div className="mt-0.5 truncate text-[10px] leading-4 text-slate-300">
|
||||
{compactLabel}
|
||||
</div>
|
||||
) : null}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div
|
||||
className="border-cyan-300/12 mt-2 overflow-hidden rounded-lg border bg-[rgba(4,10,20,0.58)] px-2 py-1.5"
|
||||
className="overflow-hidden rounded-lg border border-white/10 bg-[rgba(4,10,20,0.54)] px-2.5 py-1.5"
|
||||
style={HUD_STEPPER_STYLE}
|
||||
>
|
||||
<StepProgressBar
|
||||
steps={MINI_STEPS}
|
||||
currentIndex={presentation.currentStepIndex}
|
||||
errorIndex={errorStepIndex}
|
||||
className="w-full"
|
||||
className="w-full origin-top scale-[0.9]"
|
||||
/>
|
||||
</div>
|
||||
<span className="sr-only">{ariaLabel}</span>
|
||||
</button>
|
||||
|
||||
<Dialog open={detailsOpen} onOpenChange={setDetailsOpen}>
|
||||
|
|
|
|||
|
|
@ -118,7 +118,7 @@ describe('GraphProvisioningHud', () => {
|
|||
await Promise.resolve();
|
||||
});
|
||||
|
||||
const openButton = host.querySelector('button[aria-label="Open launch details"]');
|
||||
const openButton = host.querySelector('button[aria-label]');
|
||||
expect(openButton).not.toBeNull();
|
||||
|
||||
await act(async () => {
|
||||
|
|
|
|||
Loading…
Reference in a new issue