Skip to content

Commit

Permalink
issue #327 filters to logs Eliza UI sections to select run and date r…
Browse files Browse the repository at this point in the history
…ange
  • Loading branch information
Software Engineer - Frontend authored and Software Engineer - Frontend committed Feb 4, 2025
1 parent 84e55da commit 0bc0e81
Show file tree
Hide file tree
Showing 3 changed files with 259 additions and 5 deletions.
7 changes: 2 additions & 5 deletions client/src/App.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ import Chat from "./routes/chat";
import Overview from "./routes/overview";
import Home from "./routes/home";
import useVersion from "./hooks/use-version";
import Logs from "./components/ui/logs";
import Logs from "./components/ui/logging";

const queryClient = new QueryClient({
defaultOptions: {
Expand Down Expand Up @@ -45,10 +45,7 @@ function App() {
path="settings/:agentId"
element={<Overview />}
/>
<Route
path="logs"
element={<Logs />}
/>
<Route path="logs" element={<Logs />} />
</Routes>
</div>
</SidebarInset>
Expand Down
72 changes: 72 additions & 0 deletions client/src/components/ui/logging/hooks/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,72 @@
import { useState } from "react";

export const use = () => {
const [uniqueRuns, setUniqueRuns] = useState<string[]>([]);
const [traceData, setTraceData] = useState<any[]>([]);
const [selectedRun, setSelectedRun] = useState<string | null>(null);
const [loading, setLoading] = useState<boolean>(false);
const [error, setError] = useState<string | null>(null);
const [isRun, setIsRun] = useState<boolean>(false);

// Fetch all unique runs
const fetchUniqueRuns = async () => {
setLoading(true);
try {
const response = await fetch(
"http://localhost:4000/api/traces/unique-runs"
);
if (!response.ok)
throw new Error(`HTTP error! Status: ${response.status}`);
const data = await response.json();
setUniqueRuns(data.unique_runs || []);
} catch (err: any) {
setError(err.message);
} finally {
setLoading(false);
}
};

// Fetch traces for a selected RUN ID with filters
const fetchTraceData = async (
runId: string | null,
filters: any,
page = 1
) => {
if (!runId) return;

setLoading(true);
setSelectedRun(runId);
try {
const queryParams = new URLSearchParams({
page: page.toString(),
...(filters.name && { name: filters.name }),
...(filters.start_date && { start_date: filters.start_date }),
...(filters.end_date && { end_date: filters.end_date }),
});

const response = await fetch(
`http://localhost:4000/api/traces/by-run/${runId}?${queryParams.toString()}`
);
if (!response.ok)
throw new Error(`HTTP error! Status: ${response.status}`);
const data = await response.json();
setTraceData(data.data || []);
} catch (err: any) {
setError(err.message);
} finally {
setLoading(false);
}
};

return {
uniqueRuns,
traceData,
selectedRun,
loading,
error,
fetchUniqueRuns,
fetchTraceData,
isRun,
setIsRun,
};
};
185 changes: 185 additions & 0 deletions client/src/components/ui/logging/index.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,185 @@
import { useEffect, useState } from "react";
import { Label } from "../label";
import { use } from "./hooks";

function Logs() {
const {
uniqueRuns,
traceData,
selectedRun,
loading,
error,
fetchUniqueRuns,
fetchTraceData,
isRun,
setIsRun,
} = use();

// Get today's date in YYYY-MM-DD format
const today = new Date().toISOString().split("T")[0];

// State for filters (default start_date and end_date to today)
const [filters, setFilters] = useState({
name: "",
start_date: today,
end_date: today,
});

useEffect(() => {
fetchUniqueRuns();
}, []);

return (
<div className="flex flex-col p-6 h-[100vh]">
{/* Filter Section at the Top */}
<div className="p-4 rounded-lg bg-[#161616] shadow-lg sticky top-0">
<Label className="text-white text-lg font-semibold">
Filters
</Label>
<div className="grid grid-cols-4 gap-4 mt-2">
<input
type="text"
placeholder="Name"
className="p-2 rounded-lg bg-gray-800 text-white border border-gray-600"
value={filters.name}
onChange={(e) =>
setFilters({ ...filters, name: e.target.value })
}
/>
<input
type="date"
className="p-2 rounded-lg bg-gray-800 text-white border border-gray-600"
value={filters.start_date}
onChange={(e) =>
setFilters({
...filters,
start_date: e.target.value,
})
}
/>
<input
type="date"
className="p-2 rounded-lg bg-gray-800 text-white border border-gray-600"
value={filters.end_date}
onChange={(e) =>
setFilters({ ...filters, end_date: e.target.value })
}
/>
<button
className="px-4 py-2 bg-gray-600 text-white rounded-lg shadow-md hover:bg-blue-700 transition"
onClick={() => fetchTraceData(selectedRun, filters)}
>
Apply Filters
</button>
</div>
</div>

<div className="flex flex-grow h-full overflow-hidden mt-4">
{/* Left: Unique Runs List (Scrollable) */}
<div className="w-1/3 p-4 rounded-lg shadow-lg overflow-y-auto h-full">
<Label className="text-xl font-semibold text-white">
Unique Runs
</Label>

{loading && (
<div className="flex justify-center items-center mt-4">
<div className="animate-spin rounded-full h-8 w-8 border-b-2 border-blue-500"></div>
</div>
)}

{error && (
<div className="mt-4 p-3 bg-red-500 text-white text-sm rounded-lg">
❌ Error: {error}
</div>
)}

<div className="mt-4 grid grid-cols-1 gap-4 text-xs">
{uniqueRuns.map((run, index) => (
<div
key={index}
onClick={() => {
setIsRun(true);
fetchTraceData(run, filters);
}}
className={`p-4 bg-gray-800 rounded-lg shadow-md hover:shadow-xl transition duration-300 cursor-pointer ${
selectedRun === run
? "border-2 border-blue-500"
: ""
}`}
>
<p className="text-white font-medium">{run}</p>
</div>
))}
</div>
</div>

{/* Right: Trace Details (Scrollable) */}
{isRun && (
<div className="w-2/3 p-4 rounded-lg shadow-lg overflow-y-auto h-full">
<Label className="text-xl font-semibold text-white">
{selectedRun
? `Traces for: ${selectedRun}`
: "Select a Run"}
</Label>

{loading && (
<p className="mt-4 text-white">Loading traces...</p>
)}

{traceData.length > 0 ? (
<ul className="mt-4 space-y-4">
{traceData.map((trace, index) => (
<li
key={index}
className="p-4 bg-gray-700 rounded-lg shadow-md"
>
<p className="text-gray-300 font-semibold">
ID:{" "}
<span className="text-white">
{trace.id}
</span>
</p>
<p className="text-gray-300 font-semibold">
Run:{" "}
<span className="text-white">
{trace.run}
</span>
</p>
<p className="text-gray-300 font-semibold">
Time:{" "}
<span className="text-white">
{trace.time}
</span>
</p>
<p className="text-gray-300 font-semibold">
Name:{" "}
<span className="text-white">
{trace.name}
</span>
</p>
<p className="text-gray-300 font-semibold">
Data:
</p>
<pre className="text-white bg-gray-900 p-2 rounded-md overflow-x-auto text-sm">
{JSON.stringify(
trace.data,
null,
2
)}
</pre>
</li>
))}
</ul>
) : selectedRun && !loading ? (
<p className="mt-4 text-gray-400">
No trace data available.
</p>
) : null}
</div>
)}
</div>
</div>
);
}

export default Logs;

0 comments on commit 0bc0e81

Please sign in to comment.