From bc724a21521db837140061517824f3a9d3dcf625 Mon Sep 17 00:00:00 2001 From: Rob Bos Date: Wed, 24 Jun 2026 23:28:08 +0200 Subject: [PATCH] fix: power user popup chart errors when toggling models and model list overflow --- src/App.tsx | 318 ++++++++++++++++++++++++++++------------------------ 1 file changed, 172 insertions(+), 146 deletions(-) diff --git a/src/App.tsx b/src/App.tsx index 78d9af4..f5ee8fa 100644 --- a/src/App.tsx +++ b/src/App.tsx @@ -505,6 +505,7 @@ function App() { const [selectedPlan, setSelectedPlan] = useState(COPILOT_PLANS.BUSINESS); // Default to Business const [isProcessing, setIsProcessing] = useState(false); const [visibleBars, setVisibleBars] = useState(['compliantRequests', 'exceedingRequests']); + const [hiddenPowerUserModelNames, setHiddenPowerUserModelNames] = useState([]); const [showExceededDetails, setShowExceededDetails] = useState(false); const [exceededDetailsData, setExceededDetailsData] = useState([]); const [selectedDate, setSelectedDate] = useState(null); @@ -744,6 +745,12 @@ function App() { return getUniqueModelsFromBreakdown(breakdown); }, [getFilteredPowerUserBreakdown]); + // Get visible power user models (excluding hidden ones) + const getVisiblePowerUserModels = useCallback(() => { + const allModels = getPowerUserModels(); + return allModels.filter(model => !hiddenPowerUserModelNames.includes(model)); + }, [getPowerUserModels, hiddenPowerUserModelNames]); + const resetDataState = useCallback(() => { setData(null); setRawData(null); @@ -1095,17 +1102,29 @@ function App() { return item.multiplier === 0 ? "Unlimited" : limit.toLocaleString(); }, [selectedPlan]); - const handleLegendClick = (barKey) => { + const handleLegendClick = (barKey: string) => { if (barKey === 'all') { setVisibleBars(['compliantRequests', 'exceedingRequests']); + return; + } + + // Map the display names back to data keys + const dataKeyMap: Record = { + 'Compliant Requests': 'compliantRequests', + 'Exceeding Requests': 'exceedingRequests' + }; + const actualKey = dataKeyMap[barKey] || barKey; + + // Check if this is a compliance bar (compliantRequests/exceedingRequests) + if (actualKey === 'compliantRequests' || actualKey === 'exceedingRequests') { + setVisibleBars(prev => + prev.includes(actualKey) ? prev.filter(k => k !== actualKey) : [...prev, actualKey] + ); } else { - // Map the display names back to data keys - const dataKeyMap = { - 'Compliant Requests': 'compliantRequests', - 'Exceeding Requests': 'exceedingRequests' - }; - const actualKey = dataKeyMap[barKey] || barKey; - setVisibleBars([actualKey]); + // This is a model name - toggle in hidden list + setHiddenPowerUserModelNames(prev => + prev.includes(actualKey) ? prev.filter(m => m !== actualKey) : [...prev, actualKey] + ); } }; @@ -1122,13 +1141,13 @@ function App() { setShowExceededDetails(true); }; - const CustomLegend = ({ payload }) => { + const CustomLegend = ({ payload }: { payload: any[] }) => { // Define all possible bars const allPossibleBars = ['compliantRequests', 'exceedingRequests']; - const showAllOption = allPossibleBars.length > 1 && visibleBars.length === 1; + const showAllOption = allPossibleBars.length > 1 && visibleBars.length < 2; return ( -
    +
      {/* Only show "All Requests" if there are multiple filter options and not all are currently visible */} {showAllOption && (
    • )} - {payload.map((entry) => ( -
    • handleLegendClick(entry.dataKey)} - > - - {entry.value} -
    • - ))} + {payload.map((entry) => { + const isModel = entry.dataKey !== 'compliantRequests' && entry.dataKey !== 'exceedingRequests'; + const isHidden = isModel && hiddenPowerUserModelNames.includes(entry.dataKey); + const isComplianceHidden = !isModel && !visibleBars.includes(entry.dataKey); + const dimmed = isHidden || isComplianceHidden; + + return ( +
    • handleLegendClick(entry.dataKey)} + > + + {entry.value} +
    • + ); + })}
    ); }; @@ -1566,21 +1592,21 @@ function App() { - +

    {unitLabel} per Model

    -
    - +
    +
    - Model - {unitLabel} + Model + {unitLabel} {powerUserSummary.powerUserModelSummary.map((item) => ( - {item.model} - {item.totalRequests.toLocaleString(undefined, {maximumFractionDigits: 2, minimumFractionDigits: 2})} + {item.model} + {item.totalRequests.toLocaleString(undefined, {maximumFractionDigits: 2, minimumFractionDigits: 2})} ))} @@ -1592,12 +1618,12 @@ function App() { {/* Power User Activity Chart */}

    Power User Activity Over Time

    -
    +
    @@ -1669,10 +1695,10 @@ function App() { )}
    -
    +
    { - const models = getPowerUserModels(); + const models = getVisiblePowerUserModels(); const modelColors = getModelColors(); const config: Record = { compliantRequests: { color: "#10b981" }, // green @@ -1680,137 +1706,137 @@ function App() { }; // Add each model with its color - models.forEach((model, index) => { + models.forEach((model) => { config[model] = { color: modelColors[model] || "#94a3b8" }; }); return config; })()} - className="h-full w-full" + className="h-full w-full min-w-0" > - - - - - { - if (!active || !payload?.length) return null; - - // Filter to only show data for visible bars - const visibleData = payload.filter(p => visibleBars.includes(p.dataKey)); - if (!visibleData.length) return null; - - // Configuration for tooltip items - const tooltipConfig = { - compliantRequests: { - label: 'Compliant', - color: 'bg-[#10b981]' - }, - exceedingRequests: { - label: 'Exceeding', - color: 'bg-[#ef4444]' - } - }; - - const formatNumber = (value) => - Number(value).toLocaleString(undefined, { - maximumFractionDigits: 2, - minimumFractionDigits: 2 - }); - - // Single filter view - show only the filtered data - if (visibleData.length === 1) { - const item = visibleData[0]; - const config = tooltipConfig[item.dataKey]; + {getVisiblePowerUserModels().length > 0 || visibleBars.length > 0 ? ( + + + + + { + if (!active || !payload?.length) return null; + + // Filter to only show data for visible bars + const allVisibleKeys = [...visibleBars, ...getVisiblePowerUserModels()]; + const visibleData = payload.filter(p => allVisibleKeys.includes(p.dataKey)); + if (!visibleData.length) return null; + const formatNumber = (value) => + Number(value).toLocaleString(undefined, { + maximumFractionDigits: 2, + minimumFractionDigits: 2 + }); + + // Single item view + if (visibleData.length === 1) { + const item = visibleData[0]; + const modelColors = getModelColors(); + const bgColor = item.dataKey === 'compliantRequests' ? '#10b981' + : item.dataKey === 'exceedingRequests' ? '#ef4444' + : modelColors[item.dataKey] || '#94a3b8'; + const displayName = item.dataKey === 'compliantRequests' ? 'Compliant' + : item.dataKey === 'exceedingRequests' ? 'Exceeding' + : item.dataKey; + + return ( +
    +
    {label}
    +
    +
    + {displayName}: {formatNumber(item.value)} +
    +
    + ); + } + + // Multi-item view + const modelColors = getModelColors(); + const total = visibleData.reduce((sum: number, item: any) => sum + Number(item.value), 0); + return (
    {label}
    -
    -
    - {config.label}: {formatNumber(item.value)} +
    + {visibleData.map(item => { + const bgColor = item.dataKey === 'compliantRequests' ? '#10b981' + : item.dataKey === 'exceedingRequests' ? '#ef4444' + : modelColors[item.dataKey] || '#94a3b8'; + const displayName = item.dataKey === 'compliantRequests' ? 'Compliant' + : item.dataKey === 'exceedingRequests' ? 'Exceeding' + : item.dataKey; + return ( + +
    +
    + {displayName}: +
    +
    {formatNumber(item.value)}
    + + ); + })} +
    Total:
    +
    {formatNumber(total)}
    ); - } - - // Multi-filter view - show detailed breakdown - const values = visibleData.reduce((acc, item) => { - acc[item.dataKey] = Number(item.value); - return acc; - }, {} as Record); - - const total = Object.values(values).reduce((sum: number, val: number) => sum + val, 0); - + }} + /> + } /> + + {/* Dynamic stacked bars for each model */} + {getVisiblePowerUserModels().map((model) => { + const modelColors = getModelColors(); return ( -
    -
    {label}
    -
    - {visibleData.map(item => { - const config = tooltipConfig[item.dataKey]; - return ( - -
    -
    - {config.label}: -
    -
    {formatNumber(item.value)}
    - - ); - })} -
    Total:
    -
    {formatNumber(total)}
    -
    -
    + ); - }} - /> - } /> - - {/* Dynamic stacked bars for each model */} - {getPowerUserModels().map((model) => { - const modelColors = getModelColors(); - return ( + })} + + {/* Keep the original compliant/exceeding bars but make them toggleable */} + {visibleBars.includes('compliantRequests') && ( - ); - })} - - {/* Keep the original compliant/exceeding bars but make them toggleable */} - {visibleBars.includes('compliantRequests') && ( - console.log('Hovered Compliant', e)} - /> - )} - {visibleBars.includes('exceedingRequests') && ( - console.log('Hovered Exceeding', e)} - /> - )} - + )} + {visibleBars.includes('exceedingRequests') && ( + + )} + + ) : ( +
    + No data to display. All models and request types are hidden. +
    + )}