improved ux

This commit is contained in:
William Guss
2024-08-11 19:22:26 -07:00
parent 45a6d59bc7
commit a35bb9ef59
4 changed files with 141 additions and 84 deletions

View File

@@ -1,15 +1,15 @@
import React, { useMemo } from 'react'; import React, { useMemo } from 'react';
import { Link } from 'react-router-dom'; import { Link } from 'react-router-dom';
import { FiClock, FiTag, FiGitCommit, FiZap, FiHash, FiCalendar, FiChevronRight } from 'react-icons/fi'; import { FiClock, FiTag, FiZap, FiHash, FiChevronRight, FiCode } from 'react-icons/fi';
import { getTimeAgo } from '../utils/lmpUtils'; import { getTimeAgo } from '../utils/lmpUtils';
import VersionBadge from './VersionBadge'; import VersionBadge from './VersionBadge';
import { useInvocationsFromLMP } from '../hooks/useBackend'; import { useInvocationsFromLMP } from '../hooks/useBackend';
import { LMPCardTitle } from './depgraph/LMPCardTitle'; import { LMPCardTitle } from './depgraph/LMPCardTitle';
import { format } from 'date-fns'; import { format } from 'date-fns';
import SidePanel from './common/SidePanel'; import SidePanel from './common/SidePanel';
import StatItem from './common/StatItem'; import MetricChart from './MetricChart';
import MetricCard from './common/MetricCard';
import { motion } from 'framer-motion'; import { motion } from 'framer-motion';
import {Card} from './common/Card';
function LMPDetailsSidePanel({ lmp, uses, versionHistory }) { function LMPDetailsSidePanel({ lmp, uses, versionHistory }) {
const { data: invocations } = useInvocationsFromLMP(lmp.name, lmp.lmp_id, 0, 100); const { data: invocations } = useInvocationsFromLMP(lmp.name, lmp.lmp_id, 0, 100);
@@ -38,52 +38,72 @@ function LMPDetailsSidePanel({ lmp, uses, versionHistory }) {
initial={{ opacity: 0, y: 20 }} initial={{ opacity: 0, y: 20 }}
animate={{ opacity: 1, y: 0 }} animate={{ opacity: 1, y: 0 }}
transition={{ duration: 0.3 }} transition={{ duration: 0.3 }}
className="space-y-6" className="space-y-2 text-sm"
> >
<div className="bg-card p-4 rounded-lg shadow-md"> <div className="bg-card p-2 rounded">
<div className="flex justify-between items-center mb-4"> <div className="flex justify-between items-center mb-1">
<h3 className="text-lg font-semibold text-card-foreground">Version Info</h3> <h3 className="text-sm font-semibold text-card-foreground">Version Info</h3>
<VersionBadge version={lmp.version_number + 1} hash={lmp.lmp_id} /> <VersionBadge version={lmp.version_number + 1} hash={lmp.lmp_id} />
</div> </div>
<div className="grid grid-cols-2 gap-4"> <div className="grid grid-cols-2 gap-y-0.5">
<StatItem icon={FiClock} label="Created" value={getTimeAgo(new Date(lmp.created_at))} /> <div className="flex items-center">
<StatItem icon={FiTag} label="Is LMP" value={lmp.is_lm ? 'Yes' : 'No'} /> <FiClock className="mr-1 text-muted-foreground" size={12} />
<StatItem icon={FiZap} label="Total Invocations" value={totalInvocations} /> <span className="text-muted-foreground">Created:</span>
<StatItem icon={FiHash} label="Avg. Latency" value={`${avgLatency.toFixed(2)}ms`} /> </div>
<div className="text-right">{getTimeAgo(new Date(lmp.created_at))}</div>
<div className="flex items-center">
<FiTag className="mr-1 text-muted-foreground" size={12} />
<span className="text-muted-foreground">Is LMP:</span>
</div>
<div className="text-right">{lmp.is_lm ? 'Yes' : 'No'}</div>
<div className="flex items-center">
<FiZap className="mr-1 text-muted-foreground" size={12} />
<span className="text-muted-foreground">Invocations:</span>
</div>
<div className="text-right">{totalInvocations}</div>
<div className="flex items-center">
<FiHash className="mr-1 text-muted-foreground" size={12} />
<span className="text-muted-foreground">Avg. Latency:</span>
</div>
<div className="text-right">{avgLatency.toFixed(2)}ms</div>
</div> </div>
</div> </div>
{lmp.lm_kwargs && ( {lmp.lm_kwargs && (
<div className="bg-card p-4 rounded-lg shadow-md"> <div className="bg-card p-2 rounded">
<h3 className="text-lg font-semibold text-card-foreground mb-3">LM Keywords</h3> <h3 className="text-sm font-semibold text-card-foreground mb-1 flex items-center">
<pre className="overflow-x-auto text-sm text-muted-foreground bg-muted p-3 rounded-md"> <FiCode className="mr-1" size={14} /> LM Keywords
</h3>
<pre className="overflow-x-auto text-xs text-muted-foreground bg-muted p-1 rounded">
<code>{JSON.stringify(lmp.lm_kwargs, null, 2)}</code> <code>{JSON.stringify(lmp.lm_kwargs, null, 2)}</code>
</pre> </pre>
</div> </div>
)} )}
<div className="bg-card p-4 rounded-lg shadow-md"> <div className="bg-card p-2 rounded">
<h3 className="text-lg font-semibold text-card-foreground mb-3">Uses</h3> <h3 className="text-sm font-semibold text-card-foreground mb-1">Uses</h3>
{uses && uses.length > 0 ? ( {uses && uses.length > 0 ? (
<ul className="space-y-2"> <ul className="space-y-0.5">
{uses.filter(use => !!use).map((use) => ( {uses.filter(use => !!use).map((use) => (
<motion.li <motion.li
key={use.lmp_id} key={use.lmp_id}
whileHover={{ scale: 1.02 }} whileHover={{ scale: 1.01 }}
className="text-sm bg-muted p-2 rounded-md" className=" p-0.5 rounded"
> >
<Link to={`/lmp/${use.name}/${use.lmp_id}`} className="text-primary hover:text-primary/80 transition-colors"> <Link to={`/lmp/${use.name}/${use.lmp_id}`} className="text-primary hover:text-primary/80 transition-colors">
<LMPCardTitle lmp={use} displayVersion scale={50} shortVersion={true} /> <Card>
<LMPCardTitle lmp={use} displayVersion scale={50} />
</Card>
</Link> </Link>
</motion.li> </motion.li>
))} ))}
</ul> </ul>
) : ( ) : (
<p className="text-sm text-muted-foreground">No dependencies</p> <p className="text-muted-foreground">No dependencies</p>
)} )}
</div> </div>
<MetricCard <MetricChart
title="Invocations" title="Invocations"
rawData={chartData} rawData={chartData}
dataKey="count" dataKey="count"
@@ -91,7 +111,7 @@ function LMPDetailsSidePanel({ lmp, uses, versionHistory }) {
yAxisLabel="Count" yAxisLabel="Count"
/> />
<MetricCard <MetricChart
title="Latency" title="Latency"
rawData={chartData} rawData={chartData}
dataKey="latency" dataKey="latency"
@@ -99,35 +119,32 @@ function LMPDetailsSidePanel({ lmp, uses, versionHistory }) {
aggregation="avg" aggregation="avg"
yAxisLabel="ms" yAxisLabel="ms"
/> />
{/*
<div className="bg-card p-4 rounded-lg shadow-md"> <div className="bg-card p-2 rounded">
<h3 className="text-lg font-semibold text-card-foreground mb-3">Version History</h3> <h3 className="text-sm font-semibold text-card-foreground mb-1">Version History</h3>
<div className="space-y-2 max-h-64 overflow-y-auto pr-2"> <div className="space-y-0.5 max-h-40 overflow-y-auto pr-1">
{versionHistory.map((version, index) => ( {versionHistory.map((version, index) => (
<motion.div <motion.div
key={version.lmp_id} key={version.lmp_id}
whileHover={{ scale: 1.02 }} whileHover={{ scale: 1.01 }}
className={`p-3 rounded-md text-sm ${ className={`p-0.5 rounded ${
version.lmp_id === lmp.lmp_id version.lmp_id === lmp.lmp_id
? 'bg-primary/10' ? 'bg-primary/10 border-l-2 border-primary'
: 'bg-muted hover:bg-muted/80' : 'bg-muted hover:bg-muted/80'
}`} }`}
> >
<Link to={`/lmp/${version.name}/${version.lmp_id}`} className="block"> <Link to={`/lmp/${version.name}/${version.lmp_id}`} className="block">
<div className="flex justify-between items-center"> <div className="flex items-center justify-between">
<span className={`font-medium ${ <div className="flex items-center space-x-1">
version.lmp_id === lmp.lmp_id ? 'text-primary' : 'text-card-foreground' <span className="font-semibold">v{versionHistory.length - index}</span>
}`}> <span className="text-xs text-muted-foreground">
v{versionHistory.length - index} {format(new Date(version.created_at), 'MMM d, yyyy HH:mm')}
</span> </span>
<span className="text-muted-foreground"> </div>
<FiCalendar className="inline mr-1" size={12} /> <FiChevronRight className="text-muted-foreground" size={12} />
{format(new Date(version.created_at), 'MMM d, yyyy')}
</span>
</div> </div>
{version.commit_message && ( {version.commit_message && (
<p className="text-muted-foreground mt-1 truncate"> <p className="text-xs text-muted-foreground truncate">
<FiGitCommit className="inline mr-1" size={12} />
{version.commit_message} {version.commit_message}
</p> </p>
)} )}
@@ -135,7 +152,7 @@ function LMPDetailsSidePanel({ lmp, uses, versionHistory }) {
</motion.div> </motion.div>
))} ))}
</div> </div>
</div> </div> */}
</motion.div> </motion.div>
</SidePanel> </SidePanel>
); );

View File

@@ -149,11 +149,11 @@ function MetricChart({ rawData, dataKey, color, yAxisLabel, aggregation="sum", t
); );
return ( return (
<div className="bg-card p-4 rounded-lg shadow-md"> <div className="bg-card p-2 rounded">
<div className="flex justify-between items-center mb-4"> <div className="flex justify-between items-center mb-2">
<h3 className="text-lg font-semibold text-card-foreground">{title}</h3> <h3 className="text-sm font-semibold text-card-foreground">{title}</h3>
<select <select
className="bg-muted text-muted-foreground text-sm border border-input rounded px-2 py-1" className="bg-muted text-muted-foreground text-xs border border-input rounded px-1 py-0.5"
value={selectedTimeRange} value={selectedTimeRange}
onChange={(e) => setSelectedTimeRange(e.target.value)} onChange={(e) => setSelectedTimeRange(e.target.value)}
> >
@@ -164,11 +164,11 @@ function MetricChart({ rawData, dataKey, color, yAxisLabel, aggregation="sum", t
))} ))}
</select> </select>
</div> </div>
<div className="h-64"> <div className="h-48">
<ResponsiveContainer width="100%" height="100%"> <ResponsiveContainer width="100%" height="100%">
<AreaChart <AreaChart
data={aggregatedData} data={aggregatedData}
margin={{ top: 10, right: 30, left: 0, bottom: 0 }} margin={{ top: 5, right: 5, left: 0, bottom: 0 }}
> >
<defs> <defs>
<linearGradient id={`color${dataKey}`} x1="0" y1="0" x2="0" y2="1"> <linearGradient id={`color${dataKey}`} x1="0" y1="0" x2="0" y2="1">
@@ -179,18 +179,18 @@ function MetricChart({ rawData, dataKey, color, yAxisLabel, aggregation="sum", t
<XAxis <XAxis
dataKey="date" dataKey="date"
stroke="#718096" stroke="#718096"
tick={{ fill: "#718096", fontSize: 10 }} tick={{ fill: "#718096", fontSize: 9 }}
tickFormatter={formatXAxis} tickFormatter={formatXAxis}
/> />
<YAxis <YAxis
stroke="#718096" stroke="#718096"
tick={{ fill: "#718096", fontSize: 10 }} tick={{ fill: "#718096", fontSize: 9 }}
label={{ label={{
value: yAxisLabel, value: yAxisLabel,
angle: -90, angle: -90,
position: "insideLeft", position: "insideLeft",
fill: "#718096", fill: "#718096",
fontSize: 12, fontSize: 10,
}} }}
/> />
<CartesianGrid strokeDasharray="3 3" stroke="#4A5568" /> <CartesianGrid strokeDasharray="3 3" stroke="#4A5568" />
@@ -199,7 +199,7 @@ function MetricChart({ rawData, dataKey, color, yAxisLabel, aggregation="sum", t
backgroundColor: "#2D3748", backgroundColor: "#2D3748",
border: "1px solid #4A5568", border: "1px solid #4A5568",
color: "#E2E8F0", color: "#E2E8F0",
fontSize: 12, fontSize: 10,
}} }}
labelFormatter={(label) => format(new Date(label), "PPpp")} labelFormatter={(label) => format(new Date(label), "PPpp")}
formatter={formatTooltip} formatter={formatTooltip}
@@ -213,7 +213,7 @@ function MetricChart({ rawData, dataKey, color, yAxisLabel, aggregation="sum", t
/> />
<Brush <Brush
dataKey="date" dataKey="date"
height={20} height={15}
stroke={color} stroke={color}
fill="#2D3748" fill="#2D3748"
tickFormatter={formatXAxis} tickFormatter={formatXAxis}

View File

@@ -1,9 +1,11 @@
import React from 'react'; import React from 'react';
import { FiZap, FiClock, FiHash, FiUsers, FiPercent, FiBox } from 'react-icons/fi'; import { FiZap, FiClock, FiHash, FiUsers, FiPercent, FiBox } from 'react-icons/fi';
import { Link } from 'react-router-dom';
import SidePanel from '../common/SidePanel'; import SidePanel from '../common/SidePanel';
import StatItem from '../common/StatItem'; import MetricChart from '../MetricChart';
import MetricCard from '../common/MetricCard';
import { motion } from 'framer-motion'; import { motion } from 'framer-motion';
import { LMPCardTitle } from '../depgraph/LMPCardTitle';
import { Card } from '../common/Card';
const InvocationsAnalyticsSidePanel = ({ aggregateData, sidebarMetrics }) => { const InvocationsAnalyticsSidePanel = ({ aggregateData, sidebarMetrics }) => {
if (!aggregateData || !sidebarMetrics) return null; if (!aggregateData || !sidebarMetrics) return null;
@@ -14,21 +16,45 @@ const InvocationsAnalyticsSidePanel = ({ aggregateData, sidebarMetrics }) => {
initial={{ opacity: 0, y: 20 }} initial={{ opacity: 0, y: 20 }}
animate={{ opacity: 1, y: 0 }} animate={{ opacity: 1, y: 0 }}
transition={{ duration: 0.3 }} transition={{ duration: 0.3 }}
className="space-y-6" className="space-y-2 text-sm"
> >
<div className="bg-card p-4 rounded-lg shadow-md"> <div className="bg-card p-2 rounded">
<h3 className="text-lg font-semibold text-card-foreground mb-4">Overview</h3> <h3 className="text-sm font-semibold text-card-foreground mb-1">Overview</h3>
<div className="grid grid-cols-2 gap-4"> <div className="grid grid-cols-2 gap-y-0.5">
<StatItem icon={FiZap} label="Total Invocations" value={sidebarMetrics.totalInvocations} /> <div className="flex items-center">
<StatItem icon={FiClock} label="Avg. Latency" value={`${sidebarMetrics.avgLatency.toFixed(2)}ms`} /> <FiZap className="mr-1 text-muted-foreground" size={12} />
<StatItem icon={FiHash} label="Total Tokens" value={sidebarMetrics.totalTokens} /> <span className="text-muted-foreground">Total Invocations:</span>
<StatItem icon={FiUsers} label="Unique LMPs" value={sidebarMetrics.uniqueLMPs} /> </div>
<StatItem icon={FiPercent} label="Success Rate" value={`${sidebarMetrics.successRate.toFixed(2)}%`} /> <div className="text-right">{sidebarMetrics.totalInvocations}</div>
<StatItem icon={FiBox} label="Avg Tokens/Invocation" value={(sidebarMetrics.totalTokens / sidebarMetrics.totalInvocations).toFixed(2)} /> <div className="flex items-center">
<FiClock className="mr-1 text-muted-foreground" size={12} />
<span className="text-muted-foreground">Avg. Latency:</span>
</div>
<div className="text-right">{sidebarMetrics.avgLatency?.toFixed(2)}ms</div>
<div className="flex items-center">
<FiHash className="mr-1 text-muted-foreground" size={12} />
<span className="text-muted-foreground">Total Tokens:</span>
</div>
<div className="text-right">{sidebarMetrics.totalTokens}</div>
<div className="flex items-center">
<FiUsers className="mr-1 text-muted-foreground" size={12} />
<span className="text-muted-foreground">Unique LMPs:</span>
</div>
<div className="text-right">{sidebarMetrics.uniqueLMPs}</div>
<div className="flex items-center">
<FiPercent className="mr-1 text-muted-foreground" size={12} />
<span className="text-muted-foreground">Success Rate:</span>
</div>
<div className="text-right">{sidebarMetrics.successRate.toFixed(2)}%</div>
<div className="flex items-center">
<FiBox className="mr-1 text-muted-foreground" size={12} />
<span className="text-muted-foreground">Avg Tokens/Invocation:</span>
</div>
<div className="text-right">{(sidebarMetrics.totalTokens / sidebarMetrics.totalInvocations)?.toFixed(2)}</div>
</div> </div>
</div> </div>
<MetricCard <MetricChart
title="Invocations Over Time" title="Invocations Over Time"
rawData={aggregateData.graph_data} rawData={aggregateData.graph_data}
dataKey="count" dataKey="count"
@@ -37,7 +63,7 @@ const InvocationsAnalyticsSidePanel = ({ aggregateData, sidebarMetrics }) => {
yAxisLabel="Count" yAxisLabel="Count"
/> />
<MetricCard <MetricChart
title="Latency Over Time" title="Latency Over Time"
rawData={aggregateData.graph_data} rawData={aggregateData.graph_data}
dataKey="avg_latency" dataKey="avg_latency"
@@ -46,7 +72,7 @@ const InvocationsAnalyticsSidePanel = ({ aggregateData, sidebarMetrics }) => {
yAxisLabel="ms" yAxisLabel="ms"
/> />
<MetricCard <MetricChart
title="Tokens Over Time" title="Tokens Over Time"
rawData={aggregateData.graph_data} rawData={aggregateData.graph_data}
dataKey="tokens" dataKey="tokens"
@@ -54,24 +80,37 @@ const InvocationsAnalyticsSidePanel = ({ aggregateData, sidebarMetrics }) => {
yAxisLabel="Tokens" yAxisLabel="Tokens"
/> />
<div className="bg-card p-4 rounded-lg shadow-md"> {/* <div className="bg-card p-2 rounded">
<h3 className="text-lg font-semibold text-card-foreground mb-3">Top 5 LMPs</h3> <h3 className="text-sm font-semibold text-card-foreground mb-1">Top 5 LMPs</h3>
<ul className="space-y-2"> <ul className="space-y-0.5">
{sidebarMetrics.topLMPs.map(([lmp, count], index) => ( {sidebarMetrics.topLMPs.map(([lmpName, count], index) => (
<motion.li <motion.li
key={lmp} key={lmpName}
whileHover={{ scale: 1.02 }} whileHover={{ scale: 1.01 }}
className="flex justify-between items-center text-sm bg-muted p-2 rounded-md" className="p-0.5 rounded"
> >
<span className="text-card-foreground"> <Link to={`/lmp/${lmpName}`} className="text-primary hover:text-primary/80 transition-colors">
<span className="text-primary mr-2">{index + 1}.</span> <Card className="relative">
{lmp} <LMPCardTitle
</span> lmp={{ name: lmpName, is_lm: false }} // Assuming we don't have full LMP data here
<span className="text-muted-foreground">{count} invocations</span> displayVersion={false}
scale={50}
/>
<div className="absolute top-0 right-0 bg-muted text-muted-foreground text-xs px-1 rounded-bl">
{count} invocations
</div>
<div className="mt-1 bg-primary/5 h-1 rounded-full overflow-hidden">
<div
className="bg-primary h-full"
style={{ width: `${(count / sidebarMetrics.totalInvocations) * 100}%` }}
></div>
</div>
</Card>
</Link>
</motion.li> </motion.li>
))} ))}
</ul> </ul>
</div> </div> */}
</motion.div> </motion.div>
</SidePanel> </SidePanel>
); );

View File

@@ -104,4 +104,5 @@
to { to {
stroke-dashoffset: -10; stroke-dashoffset: -10;
} }
} }