Skip to content

Commit 5004bd0

Browse files
committed
charts
1 parent b50cc8e commit 5004bd0

File tree

2 files changed

+292
-119
lines changed

2 files changed

+292
-119
lines changed

ell-studio/src/components/LMPDetailsSidePanel.js

Lines changed: 33 additions & 119 deletions
Original file line numberDiff line numberDiff line change
@@ -3,10 +3,10 @@ import { Link } from 'react-router-dom';
33
import { FiClock, FiTag, FiGitCommit, FiZap, FiHash, FiCalendar } from 'react-icons/fi';
44
import { getTimeAgo } from '../utils/lmpUtils';
55
import VersionBadge from './VersionBadge';
6-
import { AreaChart, Area, XAxis, YAxis, Tooltip, ResponsiveContainer, CartesianGrid } from 'recharts';
7-
import { format } from 'date-fns';
6+
import MetricChart from './MetricChart';
87
import { useInvocationsFromLMP } from '../hooks/useBackend';
98
import { LMPCardTitle } from './depgraph/LMPCardTitle';
9+
import { subDays, format, addDays, endOfMonth } from 'date-fns';
1010

1111
function StatItem({ icon: Icon, label, value }) {
1212
return (
@@ -18,68 +18,26 @@ function StatItem({ icon: Icon, label, value }) {
1818
}
1919

2020
function LMPDetailsSidePanel({ lmp, uses, versionHistory }) {
21-
const [timeScale, setTimeScale] = useState('1h');
22-
const [movingAverage, setMovingAverage] = useState(1);
23-
const { data: invocations } = useInvocationsFromLMP(lmp.name, lmp.lmp_id);
21+
const { data: invocations } = useInvocationsFromLMP(lmp.name, lmp.lmp_id, 0, 100);
2422

2523
const chartData = useMemo(() => {
26-
if (!invocations) return [];
27-
28-
const now = new Date();
29-
const timeScaleDays = {
30-
'15m': 15 / (24 * 60), '1h': 1 / 24, '6h': 6 / 24, '1d': 1, '1w': 7, '1m': 30, '3m': 90, '1y': 365
31-
}[timeScale];
32-
const startDate = new Date(now.getTime() - timeScaleDays * 24 * 60 * 60 * 1000);
33-
34-
const filteredInvocations = invocations.filter(inv => new Date(inv.created_at) >= startDate);
35-
36-
// Group invocations by time intervals
37-
const intervalMs = timeScaleDays * 24 * 60 * 60 * 1000 / 20; // Divide the time range into 20 intervals
38-
const groupedData = filteredInvocations.reduce((acc, inv) => {
39-
const date = new Date(inv.created_at);
40-
const intervalIndex = Math.floor((date - startDate) / intervalMs);
41-
const intervalDate = new Date(startDate.getTime() + intervalIndex * intervalMs);
42-
const key = intervalDate.toISOString();
43-
acc[key] = (acc[key] || 0) + 1;
44-
return acc;
45-
}, {});
46-
47-
const sortedData = Object.entries(groupedData)
48-
.map(([date, count]) => ({ date, count }))
24+
if (!invocations || invocations.length === 0) return [];
25+
26+
return invocations
27+
.map(inv => ({
28+
date: new Date(inv.created_at),
29+
count: 1,
30+
latency: inv.latency_ms
31+
}))
4932
.sort((a, b) => new Date(a.date) - new Date(b.date));
33+
}, [invocations]);
5034

51-
// Calculate moving average
52-
return sortedData.map((item, index, array) => {
53-
const start = Math.max(0, index - movingAverage + 1);
54-
const windowSlice = array.slice(start, index + 1);
55-
const avg = windowSlice.reduce((sum, i) => sum + i.count, 0) / windowSlice.length;
56-
return { ...item, movingAvg: avg };
57-
});
58-
}, [invocations, timeScale, movingAverage]);
59-
60-
const formatXAxis = (tickItem) => {
61-
const date = new Date(tickItem);
62-
switch(timeScale) {
63-
case '15m':
64-
case '1h':
65-
case '6h':
66-
return format(date, 'HH:mm');
67-
case '1d':
68-
return format(date, 'HH:mm');
69-
case '1w':
70-
return format(date, 'EEE');
71-
case '1m':
72-
case '3m':
73-
return format(date, 'MMM d');
74-
case '1y':
75-
return format(date, 'MMM');
76-
default:
77-
return format(date, 'MMM d');
78-
}
79-
};
80-
81-
const totalInvocations = invocations?.length || 0;
82-
const avgLatency = invocations?.reduce((sum, inv) => sum + inv.latency_ms, 0) / totalInvocations || 0;
35+
const totalInvocations = useMemo(() => invocations?.length || 0, [invocations]);
36+
const avgLatency = useMemo(() => {
37+
if (!invocations || invocations.length === 0) return 0;
38+
const sum = invocations.reduce((acc, inv) => acc + inv.latency_ms, 0);
39+
return sum / invocations.length;
40+
}, [invocations]);
8341

8442
return (
8543
<aside className="w-[500px] bg-[#0d1117] p-4 overflow-y-auto">
@@ -122,65 +80,21 @@ function LMPDetailsSidePanel({ lmp, uses, versionHistory }) {
12280
)}
12381
</div>
12482

125-
<div className="bg-[#161b22] p-3 rounded">
126-
<h3 className="text-sm font-semibold mb-2 text-white">Invocations Over Time</h3>
127-
<div className="flex space-x-2 mb-2">
128-
<select
129-
className="bg-[#0d1117] text-white text-xs p-1 rounded"
130-
value={timeScale}
131-
onChange={(e) => setTimeScale(e.target.value)}
132-
>
133-
<option value="15m">15 Minutes</option>
134-
<option value="1h">1 Hour</option>
135-
<option value="6h">6 Hours</option>
136-
<option value="1d">1 Day</option>
137-
<option value="1w">1 Week</option>
138-
<option value="1m">1 Month</option>
139-
<option value="3m">3 Months</option>
140-
<option value="1y">1 Year</option>
141-
</select>
142-
<select
143-
className="bg-[#0d1117] text-white text-xs p-1 rounded"
144-
value={movingAverage}
145-
onChange={(e) => setMovingAverage(Number(e.target.value))}
146-
>
147-
<option value="1">No Average</option>
148-
<option value="3">3-Day Avg</option>
149-
<option value="7">7-Day Avg</option>
150-
<option value="30">30-Day Avg</option>
151-
</select>
152-
</div>
153-
<div className="h-60">
154-
<ResponsiveContainer width="100%" height="100%">
155-
<AreaChart data={chartData} margin={{ top: 10, right: 30, left: 0, bottom: 0 }}>
156-
<defs>
157-
<linearGradient id="colorCount" x1="0" y1="0" x2="0" y2="1">
158-
<stop offset="5%" stopColor="#8884d8" stopOpacity={0.8}/>
159-
<stop offset="95%" stopColor="#8884d8" stopOpacity={0}/>
160-
</linearGradient>
161-
<linearGradient id="colorAvg" x1="0" y1="0" x2="0" y2="1">
162-
<stop offset="5%" stopColor="#82ca9d" stopOpacity={0.8}/>
163-
<stop offset="95%" stopColor="#82ca9d" stopOpacity={0}/>
164-
</linearGradient>
165-
</defs>
166-
<XAxis
167-
dataKey="date"
168-
stroke="#4a5568"
169-
tick={{ fill: '#4a5568' }}
170-
tickFormatter={formatXAxis}
171-
/>
172-
<YAxis stroke="#4a5568" tick={{ fill: '#4a5568' }} />
173-
<CartesianGrid strokeDasharray="3 3" stroke="#2d3748" />
174-
<Tooltip
175-
contentStyle={{ backgroundColor: '#1f2937', border: 'none', color: '#fff' }}
176-
labelFormatter={(label) => format(new Date(label), 'PPpp')}
177-
/>
178-
<Area type="monotone" dataKey="count" stroke="#8884d8" fillOpacity={1} fill="url(#colorCount)" name="Count" />
179-
<Area type="monotone" dataKey="movingAvg" stroke="#82ca9d" fillOpacity={1} fill="url(#colorAvg)" name="Moving Avg" />
180-
</AreaChart>
181-
</ResponsiveContainer>
182-
</div>
183-
</div>
83+
<MetricChart
84+
rawData={chartData}
85+
dataKey="count"
86+
color="#8884d8"
87+
title="Invocations"
88+
yAxisLabel="Count"
89+
/>
90+
91+
<MetricChart
92+
rawData={chartData}
93+
dataKey="latency"
94+
color="#82ca9d"
95+
title="Latency"
96+
yAxisLabel="ms"
97+
/>
18498

18599
<div className="bg-[#161b22] p-3 rounded">
186100
<h3 className="text-sm font-semibold mb-2 text-white">Version History</h3>

0 commit comments

Comments
 (0)