support expand/collapse on all components on session details page

This commit is contained in:
Oliver Kieselbach
2026-03-06 15:34:14 +01:00
parent 63ad99ab76
commit f43354c2f4
3 changed files with 48 additions and 20 deletions
@@ -100,6 +100,8 @@ export default function SessionDetailPage() {
const [analysisResults, setAnalysisResults] = useState<RuleResult[]>([]);
const [loadingAnalysis, setLoadingAnalysis] = useState(false);
const [analysisExpanded, setAnalysisExpanded] = useState(true);
const [phaseTimelineExpanded, setPhaseTimelineExpanded] = useState(true);
const [perfExpanded, setPerfExpanded] = useState(true);
const [timelineExpanded, setTimelineExpanded] = useState(true);
const [adminMode, setAdminMode] = useState(() => {
if (typeof window !== 'undefined') {
@@ -897,16 +899,26 @@ export default function SessionDetailPage() {
{/* Phase Timeline */}
{!isGatherRulesSession && session && (
<div id="section-enrollment-progress" className="bg-white shadow rounded-lg p-6 mb-6">
<h2 className="text-xl font-semibold text-gray-900 mb-6">Enrollment Progress</h2>
<PhaseTimeline
currentPhase={session.currentPhase}
completedPhases={session.status === 'Succeeded' ? [7] : []}
events={events}
sessionStatus={session.status}
enrollmentType={session.enrollmentType}
isPreProvisioned={isWhiteGloveSession}
onPhaseClick={scrollToPhase}
/>
<button
onClick={() => setPhaseTimelineExpanded(!phaseTimelineExpanded)}
className="flex items-center justify-between w-full text-left"
>
<h2 className="text-xl font-semibold text-gray-900">Enrollment Progress</h2>
<svg className={`w-5 h-5 text-gray-400 transition-transform duration-200 ${phaseTimelineExpanded ? 'rotate-90' : ''}`} fill="none" stroke="currentColor" viewBox="0 0 24 24">
<path strokeLinecap="round" strokeLinejoin="round" strokeWidth={2} d="M9 5l7 7-7 7" />
</svg>
</button>
{phaseTimelineExpanded && (
<PhaseTimeline
currentPhase={session.currentPhase}
completedPhases={session.status === 'Succeeded' ? [7] : []}
events={events}
sessionStatus={session.status}
enrollmentType={session.enrollmentType}
isPreProvisioned={isWhiteGloveSession}
onPhaseClick={scrollToPhase}
/>
)}
</div>
)}
@@ -928,6 +940,8 @@ export default function SessionDetailPage() {
<div id="section-performance">
<PerformanceChart
events={events.filter(e => e.eventType === "performance_snapshot")}
expanded={perfExpanded}
setExpanded={setPerfExpanded}
/>
</div>
)}
@@ -9,6 +9,8 @@ interface PerformanceEvent {
interface PerformanceChartProps {
events: PerformanceEvent[];
expanded?: boolean;
setExpanded?: (expanded: boolean) => void;
}
interface SparklineProps {
@@ -229,7 +231,11 @@ function DiskFreeChart({ values, timestamps }: DiskFreeChartProps) {
);
}
export default function PerformanceChart({ events }: PerformanceChartProps) {
export default function PerformanceChart({ events, expanded: expandedProp, setExpanded: setExpandedProp }: PerformanceChartProps) {
const isControlled = expandedProp !== undefined;
const [internalExpanded, setInternalExpanded] = useState(true);
const expanded = isControlled ? expandedProp : internalExpanded;
const setExpanded = isControlled ? setExpandedProp! : setInternalExpanded;
const metrics = useMemo(() => {
if (events.length === 0) return null;
@@ -307,15 +313,23 @@ export default function PerformanceChart({ events }: PerformanceChartProps) {
return (
<div className="bg-white shadow rounded-lg p-6 mb-6">
<div className="flex items-center space-x-2 mb-4">
<svg className="w-5 h-5 text-indigo-500" fill="none" viewBox="0 0 24 24" stroke="currentColor">
<path strokeLinecap="round" strokeLinejoin="round" strokeWidth={2} d="M9 19v-6a2 2 0 00-2-2H5a2 2 0 00-2 2v6a2 2 0 002 2h2a2 2 0 002-2zm0 0V9a2 2 0 012-2h2a2 2 0 012 2v10m-6 0a2 2 0 002 2h2a2 2 0 002-2m0 0V5a2 2 0 012-2h2a2 2 0 012 2v14a2 2 0 01-2 2h-2a2 2 0 01-2-2z" />
<button
onClick={() => setExpanded(!expanded)}
className="flex items-center justify-between w-full text-left"
>
<div className="flex items-center space-x-2">
<svg className="w-5 h-5 text-indigo-500" fill="none" viewBox="0 0 24 24" stroke="currentColor">
<path strokeLinecap="round" strokeLinejoin="round" strokeWidth={2} d="M9 19v-6a2 2 0 00-2-2H5a2 2 0 00-2 2v6a2 2 0 002 2h2a2 2 0 002-2zm0 0V9a2 2 0 012-2h2a2 2 0 012 2v10m-6 0a2 2 0 002 2h2a2 2 0 002-2m0 0V5a2 2 0 012-2h2a2 2 0 012 2v14a2 2 0 01-2 2h-2a2 2 0 01-2-2z" />
</svg>
<h2 className="text-lg font-semibold text-gray-900">Performance Metrics</h2>
<span className="text-xs text-gray-400">({metrics.sampleCount} samples)</span>
</div>
<svg className={`w-5 h-5 text-gray-400 transition-transform duration-200 ${expanded ? 'rotate-90' : ''}`} fill="none" stroke="currentColor" viewBox="0 0 24 24">
<path strokeLinecap="round" strokeLinejoin="round" strokeWidth={2} d="M9 5l7 7-7 7" />
</svg>
<h2 className="text-lg font-semibold text-gray-900">Performance Metrics</h2>
<span className="text-xs text-gray-400">({metrics.sampleCount} samples)</span>
</div>
</button>
<div className={`grid grid-cols-1 sm:grid-cols-2 md:grid-cols-3 ${metrics.netReceiveValues.length >= 2 ? "lg:grid-cols-6" : "lg:grid-cols-4"} gap-4`}>
{expanded && <div className={`grid grid-cols-1 sm:grid-cols-2 md:grid-cols-3 ${metrics.netReceiveValues.length >= 2 ? "lg:grid-cols-6" : "lg:grid-cols-4"} gap-4 mt-4`}>
{/* CPU */}
<div className="bg-gray-50 rounded-lg p-3">
<div className="flex items-center justify-between mb-1">
@@ -458,7 +472,7 @@ export default function PerformanceChart({ events }: PerformanceChartProps) {
/>
</div>
)}
</div>
</div>}
</div>
);
}
File diff suppressed because one or more lines are too long