Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
93 changes: 0 additions & 93 deletions vite-app/dist/assets/index-CpPWargc.js

This file was deleted.

1 change: 0 additions & 1 deletion vite-app/dist/assets/index-CpPWargc.js.map

This file was deleted.

1 change: 0 additions & 1 deletion vite-app/dist/assets/index-CpScNe1P.css

This file was deleted.

93 changes: 93 additions & 0 deletions vite-app/dist/assets/index-D1ErODUS.js

Large diffs are not rendered by default.

1 change: 1 addition & 0 deletions vite-app/dist/assets/index-D1ErODUS.js.map

Large diffs are not rendered by default.

1 change: 1 addition & 0 deletions vite-app/dist/assets/index-D5KxcfFQ.css

Large diffs are not rendered by default.

4 changes: 2 additions & 2 deletions vite-app/dist/index.html
Original file line number Diff line number Diff line change
Expand Up @@ -5,8 +5,8 @@
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>EP | Log Viewer</title>
<link rel="icon" href="/assets/favicon-BkAAWQga.png" />
<script type="module" crossorigin src="/assets/index-CpPWargc.js"></script>
<link rel="stylesheet" crossorigin href="/assets/index-CpScNe1P.css">
<script type="module" crossorigin src="/assets/index-D1ErODUS.js"></script>
<link rel="stylesheet" crossorigin href="/assets/index-D5KxcfFQ.css">
</head>
<body>
<div id="root"></div>
Expand Down
97 changes: 41 additions & 56 deletions vite-app/src/GlobalState.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -11,11 +11,10 @@ const DEFAULT_PIVOT_CONFIG: PivotConfig = {
selectedColumnFields: ["$.input_metadata.completion_params.model"],
selectedValueField: "$.evaluation_result.score",
selectedAggregator: "avg",
filters: [],
};

// Default table filter configuration
const DEFAULT_TABLE_FILTER_CONFIG: FilterGroup[] = [];
// Default filter configuration
const DEFAULT_FILTER_CONFIG: FilterGroup[] = [];

// Default pagination configuration
const DEFAULT_PAGINATION_CONFIG = {
Expand All @@ -31,10 +30,10 @@ export class GlobalState {
expandedRows: Record<string, boolean> = {};
// Pivot configuration
pivotConfig: PivotConfig;
// Table filter configuration
tableFilterConfig: FilterGroup[];
// Debounced, actually applied table filter configuration (for performance while typing)
appliedTableFilterConfig: FilterGroup[];
// Unified filter configuration for both pivot and table views
filterConfig: FilterGroup[];
// Debounced, actually applied filter configuration (for performance while typing)
appliedFilterConfig: FilterGroup[];
// Pagination configuration
currentPage: number;
pageSize: number;
Expand All @@ -49,19 +48,18 @@ export class GlobalState {

// Debounce timers for localStorage saves and filter application
private savePivotConfigTimer: ReturnType<typeof setTimeout> | null = null;
private saveTableFilterConfigTimer: ReturnType<typeof setTimeout> | null =
null;
private saveFilterConfigTimer: ReturnType<typeof setTimeout> | null = null;
private savePaginationConfigTimer: ReturnType<typeof setTimeout> | null =
null;
private applyTableFilterTimer: ReturnType<typeof setTimeout> | null = null;
private applyFilterTimer: ReturnType<typeof setTimeout> | null = null;

constructor() {
// Load pivot config from localStorage or use defaults
this.pivotConfig = this.loadPivotConfig();
// Load table filter config from localStorage or use defaults
this.tableFilterConfig = this.loadTableFilterConfig();
// Load filter config from localStorage or use defaults
this.filterConfig = this.loadFilterConfig();
// Initialize applied filter config with current value
this.appliedTableFilterConfig = this.tableFilterConfig.slice();
this.appliedFilterConfig = this.filterConfig.slice();
// Load pagination config from localStorage or use defaults
const paginationConfig = this.loadPaginationConfig();
this.currentPage = paginationConfig.currentPage;
Expand All @@ -84,21 +82,18 @@ export class GlobalState {
return { ...DEFAULT_PIVOT_CONFIG };
}

// Load table filter configuration from localStorage
private loadTableFilterConfig(): FilterGroup[] {
// Load filter configuration from localStorage
private loadFilterConfig(): FilterGroup[] {
try {
const stored = localStorage.getItem("tableFilterConfig");
const stored = localStorage.getItem("filterConfig");
if (stored) {
const parsed = JSON.parse(stored);
return Array.isArray(parsed) ? parsed : DEFAULT_TABLE_FILTER_CONFIG;
return Array.isArray(parsed) ? parsed : DEFAULT_FILTER_CONFIG;
}
} catch (error) {
console.warn(
"Failed to load table filter config from localStorage:",
error
);
console.warn("Failed to load filter config from localStorage:", error);
}
return DEFAULT_TABLE_FILTER_CONFIG;
return DEFAULT_FILTER_CONFIG;
}

// Load pagination configuration from localStorage
Expand All @@ -116,7 +111,7 @@ export class GlobalState {
error
);
}
return { ...DEFAULT_PAGINATION_CONFIG };
return DEFAULT_PAGINATION_CONFIG;
}

// Save pivot configuration to localStorage
Expand All @@ -131,21 +126,14 @@ export class GlobalState {
}, 200);
}

// Save table filter configuration to localStorage
private saveTableFilterConfig() {
if (this.saveTableFilterConfigTimer)
clearTimeout(this.saveTableFilterConfigTimer);
this.saveTableFilterConfigTimer = setTimeout(() => {
// Save filter configuration to localStorage
private saveFilterConfig() {
if (this.saveFilterConfigTimer) clearTimeout(this.saveFilterConfigTimer);
this.saveFilterConfigTimer = setTimeout(() => {
try {
localStorage.setItem(
"tableFilterConfig",
JSON.stringify(this.tableFilterConfig)
);
localStorage.setItem("filterConfig", JSON.stringify(this.filterConfig));
} catch (error) {
console.warn(
"Failed to save table filter config to localStorage:",
error
);
console.warn("Failed to save filter config to localStorage:", error);
}
}, 200);
}
Expand Down Expand Up @@ -178,15 +166,15 @@ export class GlobalState {
this.savePivotConfig();
}

// Update table filter configuration and save to localStorage
updateTableFilterConfig(filters: FilterGroup[]) {
this.tableFilterConfig = filters;
this.saveTableFilterConfig();
// Update filter configuration and save to localStorage
updateFilterConfig(filters: FilterGroup[]) {
this.filterConfig = filters;
this.saveFilterConfig();

// Debounce application of filters to avoid re-filtering on every keystroke
if (this.applyTableFilterTimer) clearTimeout(this.applyTableFilterTimer);
this.applyTableFilterTimer = setTimeout(() => {
this.appliedTableFilterConfig = this.tableFilterConfig.slice();
if (this.applyFilterTimer) clearTimeout(this.applyFilterTimer);
this.applyFilterTimer = setTimeout(() => {
this.appliedFilterConfig = this.filterConfig.slice();
}, 150);
}

Expand All @@ -205,18 +193,15 @@ export class GlobalState {

// Reset pivot configuration to defaults
resetPivotConfig() {
this.pivotConfig = {
...DEFAULT_PIVOT_CONFIG,
filters: [], // Ensure filters is an empty array of FilterGroups
};
this.pivotConfig = { ...DEFAULT_PIVOT_CONFIG };
this.savePivotConfig();
}

// Reset table filter configuration to defaults
resetTableFilterConfig() {
this.tableFilterConfig = [...DEFAULT_TABLE_FILTER_CONFIG];
this.appliedTableFilterConfig = [...DEFAULT_TABLE_FILTER_CONFIG];
this.saveTableFilterConfig();
// Reset filter configuration to defaults
resetFilterConfig() {
this.filterConfig = [...DEFAULT_FILTER_CONFIG];
this.appliedFilterConfig = [...DEFAULT_FILTER_CONFIG];
this.saveFilterConfig();
}

// Reset pagination configuration to defaults
Expand Down Expand Up @@ -315,20 +300,20 @@ export class GlobalState {
}

get filteredFlattenedDataset() {
if (this.appliedTableFilterConfig.length === 0) {
if (this.appliedFilterConfig.length === 0) {
return this.flattenedDataset;
}

const filterFunction = createFilterFunction(this.appliedTableFilterConfig)!;
const filterFunction = createFilterFunction(this.appliedFilterConfig)!;
return this.flattenedDataset.filter(filterFunction);
}

get filteredOriginalDataset() {
if (this.appliedTableFilterConfig.length === 0) {
if (this.appliedFilterConfig.length === 0) {
return this.sortedDataset;
}

const filterFunction = createFilterFunction(this.appliedTableFilterConfig)!;
const filterFunction = createFilterFunction(this.appliedFilterConfig)!;
return this.sortedIds
.filter((id) => filterFunction(this.flattenedById[id]))
.map((id) => this.dataset[id]);
Expand Down
129 changes: 128 additions & 1 deletion vite-app/src/components/EvaluationRow.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,110 @@ import { MetadataSection } from "./MetadataSection";
import StatusIndicator from "./StatusIndicator";
import { state } from "../App";
import { TableCell, TableRowInteractive } from "./TableContainer";
import { useState } from "react";
import type { FilterGroup, FilterConfig } from "../types/filters";
import { Tooltip } from "./Tooltip";

// Add filter button component
const AddFilterButton = observer(
({
fieldPath,
value,
label,
}: {
fieldPath: string;
value: string;
label: string;
}) => {
const [added, setAdded] = useState(false);

const handleClick = (e: React.MouseEvent) => {
e.stopPropagation(); // Prevent row expansion

// Create a new filter for this field/value
const newFilter: FilterConfig = {
field: fieldPath,
operator: "==",
value: value,
type: "text",
};

// Add the filter to the existing filter configuration
const currentFilters = state.filterConfig;
let newFilters: FilterGroup[];

if (currentFilters.length === 0) {
// If no filters exist, create a new filter group
newFilters = [
{
logic: "AND",
filters: [newFilter],
},
];
} else {
// Add to the first filter group (assuming AND logic)
newFilters = [...currentFilters];
newFilters[0] = {
...newFilters[0],
filters: [...newFilters[0].filters, newFilter],
};
}

state.updateFilterConfig(newFilters);
setAdded(true);

// Reset to "Add Filter" state after 2 seconds
setTimeout(() => setAdded(false), 2000);
};

return (
<Tooltip
content={added ? "Filter Added!" : `Add ${label} Filter`}
position="top"
className="text-gray-400 hover:text-gray-600 transition-colors"
>
<div className="flex items-center gap-1">
<button
className="cursor-pointer"
onClick={handleClick}
title="Add filter for this value"
>
{/* Icon */}
{added ? (
<svg
className="w-3 h-3 text-green-600"
fill="none"
stroke="currentColor"
viewBox="0 0 24 24"
>
<path
strokeLinecap="round"
strokeLinejoin="round"
strokeWidth={2}
d="M5 13l4 4L19 7"
/>
</svg>
) : (
<svg
className="w-3 h-3"
fill="none"
stroke="currentColor"
viewBox="0 0 24 24"
>
<path
strokeLinecap="round"
strokeLinejoin="round"
strokeWidth={2}
d="M3 4a1 1 0 011-1h16a1 1 0 011 1v2.586a1 1 0 01-.293.707l-6.414 6.414a1 1 0 00-.293.707V17l-4 4v-6.586a1 1 0 00-.293-.707L3.293 7.207A1 1 0 013 6.5V4z"
/>
</svg>
)}
</button>
</div>
</Tooltip>
);
}
);

// Small, focused components following "dereference values late" principle
const ExpandIcon = observer(({ rolloutId }: { rolloutId?: string }) => {
Expand Down Expand Up @@ -64,6 +168,22 @@ const RolloutId = observer(
}
);

const InvocationId = observer(({ invocationId }: { invocationId?: string }) => {
if (!invocationId) {
return null;
}
return (
<span className="font-mono text-gray-900 whitespace-nowrap flex items-center gap-1">
{invocationId}
<AddFilterButton
fieldPath="$.execution_metadata.invocation_id"
value={invocationId}
label="Invocation"
/>
</span>
);
});

const RowModel = observer(({ model }: { model: string | undefined }) => (
<span className="text-gray-900 truncate block">{model || "N/A"}</span>
));
Expand Down Expand Up @@ -224,6 +344,13 @@ export const EvaluationRow = observer(
/>
</TableCell>

{/* Invocation ID */}
<TableCell className="py-3 text-xs">
<InvocationId
invocationId={row.execution_metadata?.invocation_id}
/>
</TableCell>

{/* Rollout ID */}
<TableCell className="py-3 text-xs">
<RolloutId rolloutId={row.execution_metadata?.rollout_id} />
Expand All @@ -248,7 +375,7 @@ export const EvaluationRow = observer(
{/* Expanded Content Row */}
{isExpanded && (
<tr>
<td colSpan={8} className="p-0">
<td colSpan={9} className="p-0">
<ExpandedContent
row={row}
messages={row.messages}
Expand Down
7 changes: 4 additions & 3 deletions vite-app/src/components/EvaluationTable.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -48,7 +48,7 @@ export const EvaluationTable = observer(() => {
};

const handleFiltersChange = (filters: any[]) => {
state.updateTableFilterConfig(filters);
state.updateFilterConfig(filters);
};

return (
Expand All @@ -59,7 +59,7 @@ export const EvaluationTable = observer(() => {
<div className="flex items-center gap-4">
<h3 className="text-sm font-medium text-gray-700">Table Filters</h3>
<div className="text-xs text-gray-600">
{state.tableFilterConfig.length > 0 ? (
{state.filterConfig.length > 0 ? (
<>
Showing {totalRows} of {state.sortedDataset.length} rows
{totalRows !== state.sortedDataset.length && (
Expand All @@ -74,7 +74,7 @@ export const EvaluationTable = observer(() => {
</div>
<div className="bg-white rounded-lg">
<FilterSelector
filters={state.tableFilterConfig}
filters={state.filterConfig}
onFiltersChange={handleFiltersChange}
availableKeys={state.flattenedDatasetKeys}
title=""
Expand Down Expand Up @@ -162,6 +162,7 @@ export const EvaluationTable = observer(() => {
<TableHeader className="w-8">&nbsp;</TableHeader>
<TableHeader>Name</TableHeader>
<TableHeader>Status</TableHeader>
<TableHeader>Invocation ID</TableHeader>
<TableHeader>Rollout ID</TableHeader>
<TableHeader>Model</TableHeader>
<TableHeader>Score</TableHeader>
Expand Down
Loading
Loading