Skip to content

Commit abd629b

Browse files
committed
filters
1 parent b321bee commit abd629b

File tree

8 files changed

+79
-45
lines changed

8 files changed

+79
-45
lines changed

dashboard/ai-analytics/src/app/components/MetricsCards.tsx

Lines changed: 9 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -3,29 +3,33 @@
33
import SparkChartContainer from '../containers/SparkChartContainer';
44

55
interface MetricsCardsProps {
6-
filters: Record<string, string>;
6+
data: any;
7+
isLoading: boolean;
78
}
89

9-
export default function MetricsCards({ filters }: MetricsCardsProps) {
10+
export default function MetricsCards({ data, isLoading }: MetricsCardsProps) {
1011
return (
1112
<div className="h-full grid grid-rows-2">
1213
<SparkChartContainer
14+
data={data}
15+
isLoading={isLoading}
1316
chartType="line"
1417
metric="avg_duration"
1518
title="Average Duration"
16-
filters={filters}
1719
/>
1820
<SparkChartContainer
21+
data={data}
22+
isLoading={isLoading}
1923
chartType="stacked-bar"
2024
metric="total_requests"
2125
title="Total Requests"
22-
filters={filters}
2326
/>
2427
<SparkChartContainer
28+
data={data}
29+
isLoading={isLoading}
2530
chartType="stacked-area"
2631
metric="total_tokens"
2732
title="Total Tokens"
28-
filters={filters}
2933
/>
3034
</div>
3135
);

dashboard/ai-analytics/src/app/components/TabbedPane.tsx

Lines changed: 9 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -21,14 +21,8 @@ export default function TabbedPane({ filters, onFilterUpdate }: TabbedPaneProps)
2121
const [barListData, setBarListData] = useState<Array<{ name: string; value: number }>>([]);
2222
const [selectedValues, setSelectedValues] = useState<string[]>([]);
2323

24-
// Get all filters except current tab's filter
25-
const queryFilters = useMemo(() => {
26-
const filtered = { ...filters };
27-
delete filtered[selectedTab];
28-
return filtered;
29-
}, [filters, selectedTab]);
30-
31-
const { data, isLoading, error } = useGenericCounter(selectedTab, queryFilters);
24+
// Pass all filters to the query
25+
const { data, isLoading, error } = useGenericCounter(selectedTab, filters);
3226

3327
// Add effect to sync with URL params
3428
useEffect(() => {
@@ -44,18 +38,17 @@ export default function TabbedPane({ filters, onFilterUpdate }: TabbedPaneProps)
4438
const handleSelectionChange = (newSelection: string[]) => {
4539
setSelectedValues(newSelection);
4640

47-
// Update URL params
41+
// Update URL without scroll
4842
const params = new URLSearchParams(searchParams.toString());
4943
if (newSelection.length > 0) {
5044
params.set(selectedTab, newSelection.join(','));
5145
} else {
5246
params.delete(selectedTab);
53-
// Also remove the filter from URL when clearing
5447
if (filters[selectedTab]) {
5548
delete filters[selectedTab];
5649
}
5750
}
58-
router.push(`?${params.toString()}`);
51+
window.history.replaceState({}, '', `?${params.toString()}`);
5952

6053
// Notify parent to update filters
6154
onFilterUpdate(selectedTab, tabs.find(t => t.key === selectedTab)?.name || selectedTab, newSelection);
@@ -66,14 +59,14 @@ export default function TabbedPane({ filters, onFilterUpdate }: TabbedPaneProps)
6659
handleSelectionChange(newSelection);
6760
};
6861

69-
const handleTabChange = async (index: number) => {
62+
const handleTabChange = (index: number) => {
7063
const tab = tabs[index];
7164
const dimension = tab.key;
7265

73-
// Update URL
74-
const params = new URLSearchParams(searchParams);
66+
// Update URL without scroll
67+
const params = new URLSearchParams(searchParams.toString());
7568
params.set('dimension', dimension);
76-
router.push(`?${params.toString()}`);
69+
window.history.replaceState({}, '', `?${params.toString()}`);
7770

7871
setSelectedTab(dimension);
7972
};
@@ -93,7 +86,7 @@ export default function TabbedPane({ filters, onFilterUpdate }: TabbedPaneProps)
9386
<div className="h-full">
9487
<TabGroup
9588
defaultIndex={tabs.findIndex(t => t.key === selectedTab)}
96-
onChange={handleTabChange}
89+
onIndexChange={handleTabChange}
9790
>
9891
<TabList className="flex space-x-2">
9992
{tabs.map((tab) => (

dashboard/ai-analytics/src/app/components/TimeseriesChart.tsx

Lines changed: 7 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -37,9 +37,10 @@ interface TimeseriesChartProps {
3737
data: TimeseriesData[];
3838
};
3939
filters: Record<string, string>;
40+
onFiltersChange?: (filters: Record<string, string>) => void;
4041
}
4142

42-
export default function TimeseriesChart({ data, filters }: TimeseriesChartProps) {
43+
export default function TimeseriesChart({ data, filters, onFiltersChange }: TimeseriesChartProps) {
4344
const router = useRouter();
4445
const searchParams = useSearchParams();
4546

@@ -137,8 +138,11 @@ export default function TimeseriesChart({ data, filters }: TimeseriesChartProps)
137138
const params = new URLSearchParams(searchParams);
138139
params.set('column_name', tab.key);
139140
router.push(`?${params.toString()}`);
140-
// Update filters which will trigger data refetch
141-
filters.column_name = tab.key;
141+
142+
// Create new filters object
143+
const newFilters = { ...filters, column_name: tab.key };
144+
// Pass the new filters up to parent component
145+
onFiltersChange?.(newFilters);
142146
};
143147

144148
return (

dashboard/ai-analytics/src/app/containers/DataTableContainer.tsx

Lines changed: 3 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -3,14 +3,12 @@ import DataTable from '../components/DataTable';
33
import { useLLMUsage } from '@/hooks/useTinybirdData';
44

55
interface DataTableContainerProps {
6-
filters: Record<string, string>;
6+
data: any;
7+
isLoading: boolean;
78
}
89

9-
export default function DataTableContainer({ filters }: DataTableContainerProps) {
10-
const { data, isLoading, error } = useLLMUsage(filters);
11-
10+
export default function DataTableContainer({ data, isLoading }: DataTableContainerProps) {
1211
if (isLoading) return <div>Loading...</div>;
13-
if (error) return <div>Error loading data</div>;
1412

1513
return (
1614
<Card className="h-full rounded-none flex flex-col overflow-hidden" style={{ boxShadow: 'none' }}>

dashboard/ai-analytics/src/app/containers/SparkChartContainer.tsx

Lines changed: 4 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -5,22 +5,21 @@ import SparkChart from '../components/SparkChart';
55
import { type ChartType } from '@tremor/react';
66

77
interface SparkChartContainerProps {
8+
data: any;
9+
isLoading: boolean;
810
chartType?: ChartType;
911
metric: 'avg_duration' | 'total_requests' | 'total_tokens';
1012
title: string;
11-
filters: Record<string, string>;
1213
}
1314

1415
export default function SparkChartContainer({
16+
data,
17+
isLoading,
1518
chartType = 'area',
1619
metric,
1720
title,
18-
filters
1921
}: SparkChartContainerProps) {
20-
const { data, isLoading, error } = useLLMUsage(filters);
21-
2222
if (isLoading) return <div>Loading...</div>;
23-
if (error) return <div>Error loading data</div>;
2423

2524
// Get unique dates and categories
2625
const dates = [...new Set(data.data.map(d => d.date))].sort();

dashboard/ai-analytics/src/app/containers/TimeseriesChartContainer.tsx

Lines changed: 14 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -4,18 +4,27 @@ import TimeseriesChart from '../components/TimeseriesChart';
44
import { useLLMUsage } from '@/hooks/useTinybirdData';
55

66
interface TimeseriesChartContainerProps {
7+
data: any;
8+
isLoading: boolean;
79
filters: Record<string, string>;
10+
onFiltersChange: (filters: Record<string, string>) => void;
811
}
912

10-
export default function TimeseriesChartContainer({ filters }: TimeseriesChartContainerProps) {
11-
const { data, isLoading, error } = useLLMUsage(filters);
12-
13+
export default function TimeseriesChartContainer({
14+
data,
15+
isLoading,
16+
filters,
17+
onFiltersChange
18+
}: TimeseriesChartContainerProps) {
1319
if (isLoading) return <div>Loading...</div>;
14-
if (error) return <div>Error loading data</div>;
1520

1621
return (
1722
<div className="h-[60vh] overflow-hidden">
18-
<TimeseriesChart data={data} filters={filters} />
23+
<TimeseriesChart
24+
data={data}
25+
filters={filters}
26+
onFiltersChange={onFiltersChange}
27+
/>
1928
</div>
2029
);
2130
}

dashboard/ai-analytics/src/app/page.tsx

Lines changed: 27 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@ import TabbedPane from './components/TabbedPane';
88
import { useState, useEffect } from 'react';
99
import { useSearchParams } from 'next/navigation';
1010
import { tabs } from './constants';
11+
import { useLLMUsage } from '@/hooks/useTinybirdData';
1112

1213
interface Selection {
1314
dimension: string;
@@ -19,8 +20,11 @@ export default function Dashboard() {
1920
const [filters, setFilters] = useState<Record<string, string>>({});
2021
const [selections, setSelections] = useState<Selection[]>([]);
2122
const searchParams = useSearchParams();
23+
24+
// Shared LLM usage data
25+
const { data: llmData, isLoading, error } = useLLMUsage(filters);
2226

23-
// Initialize selections from URL params
27+
// Initialize from URL only once
2428
useEffect(() => {
2529
const params = new URLSearchParams(searchParams.toString());
2630
const newSelections: Selection[] = [];
@@ -39,9 +43,15 @@ export default function Dashboard() {
3943
}
4044
});
4145

46+
// Get column_name from URL if present
47+
const columnName = params.get('column_name');
48+
if (columnName) {
49+
newFilters.column_name = columnName;
50+
}
51+
4252
setSelections(newSelections);
4353
setFilters(newFilters);
44-
}, [searchParams]);
54+
}, []); // Only run once on mount
4555

4656
const handleFilterUpdate = (dimension: string, dimensionName: string, values: string[]) => {
4757
setSelections(prev => {
@@ -88,6 +98,10 @@ export default function Dashboard() {
8898
});
8999
};
90100

101+
const handleTimeseriesFilterChange = (newFilters: Record<string, string>) => {
102+
setFilters(newFilters);
103+
};
104+
91105
return (
92106
<div className="h-screen flex flex-col bg-gray-900 text-white">
93107
<TopBar
@@ -99,17 +113,25 @@ export default function Dashboard() {
99113
{/* Main Content - 2/3 width */}
100114
<div className="w-2/3 flex flex-col min-h-0">
101115
<div className="h-[60vh] border-b border-r border-gray-700">
102-
<TimeseriesChartContainer filters={filters} />
116+
<TimeseriesChartContainer
117+
data={llmData}
118+
isLoading={isLoading}
119+
filters={filters}
120+
onFiltersChange={handleTimeseriesFilterChange}
121+
/>
103122
</div>
104123
<div className="h-[35vh] border-r border-gray-700 overflow-hidden">
105-
<DataTableContainer filters={filters} />
124+
<DataTableContainer data={llmData} isLoading={isLoading} />
106125
</div>
107126
</div>
108127

109128
{/* Sidebar - 1/3 width */}
110129
<div className="w-1/3 overflow-auto">
111130
<div className="border-b border-gray-700">
112-
<MetricsCards filters={filters} />
131+
<MetricsCards
132+
data={llmData}
133+
isLoading={isLoading}
134+
/>
113135
</div>
114136
<div>
115137
<TabbedPane

dashboard/ai-analytics/src/hooks/useTinybirdData.ts

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,8 +9,13 @@ export function useLLMUsage(filters: Record<string, string>) {
99
}
1010

1111
export function useGenericCounter(dimension: string, filters: Record<string, string>) {
12+
const allFilters = {
13+
...filters,
14+
dimension
15+
};
16+
1217
return useQuery({
1318
queryKey: ['generic-counter', dimension, filters],
14-
queryFn: () => fetchGenericCounter({ ...filters, dimension })
19+
queryFn: () => fetchGenericCounter(allFilters)
1520
});
1621
}

0 commit comments

Comments
 (0)