Skip to content

Commit 641a704

Browse files
author
Dylan Huang
committed
parameterize pivottab
1 parent fc6c320 commit 641a704

2 files changed

Lines changed: 174 additions & 20 deletions

File tree

vite-app/src/components/Dashboard.tsx

Lines changed: 1 addition & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -123,11 +123,7 @@ const Dashboard = observer(({ onRefresh }: DashboardProps) => {
123123

124124
{/* Tab content */}
125125
<div className="p-3">
126-
{activeTab === "table" ? (
127-
<EvaluationTable />
128-
) : (
129-
<PivotTab data={state.flattenedDataset} />
130-
)}
126+
{activeTab === "table" ? <EvaluationTable /> : <PivotTab />}
131127
</div>
132128
</div>
133129
)}

vite-app/src/components/PivotTab.tsx

Lines changed: 173 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -1,27 +1,185 @@
11
import { observer } from "mobx-react";
22
import PivotTable from "./PivotTable";
3+
import Select from "./Select";
4+
import { state } from "../App";
5+
import { useState } from "react";
36

4-
interface PivotTabProps {
5-
data: any[];
7+
interface FieldSelectorProps {
8+
title: string;
9+
fields: string[];
10+
onFieldChange: (index: number, value: string) => void;
11+
onAddField: () => void;
12+
onRemoveField: (index: number) => void;
13+
availableKeys: string[];
614
}
715

8-
const PivotTab = observer(({ data }: PivotTabProps) => {
16+
const FieldSelector = ({
17+
title,
18+
fields,
19+
onFieldChange,
20+
onAddField,
21+
onRemoveField,
22+
availableKeys,
23+
}: FieldSelectorProps) => (
24+
<div className="mb-4">
25+
<div className="text-xs font-medium text-gray-700 mb-2">{title}:</div>
26+
<div className="space-y-2">
27+
{fields.map((field, index) => (
28+
<div key={index} className="flex items-center space-x-2">
29+
<Select
30+
value={field}
31+
onChange={(e) => onFieldChange(index, e.target.value)}
32+
size="sm"
33+
className="min-w-48"
34+
>
35+
<option value="">Select a field...</option>
36+
{availableKeys?.map((key) => (
37+
<option key={key} value={key}>
38+
{key}
39+
</option>
40+
))}
41+
</Select>
42+
{fields.length > 0 && (
43+
<button
44+
onClick={() => onRemoveField(index)}
45+
className="text-xs text-red-600 hover:text-red-800 px-2 py-1"
46+
>
47+
Remove
48+
</button>
49+
)}
50+
</div>
51+
))}
52+
{fields.length < 3 && (
53+
<button
54+
onClick={onAddField}
55+
className="text-xs text-blue-600 hover:text-blue-800 px-2 py-1"
56+
>
57+
+ Add {title.slice(0, -1)} Field
58+
</button>
59+
)}
60+
</div>
61+
</div>
62+
);
63+
64+
const SingleFieldSelector = ({
65+
title,
66+
field,
67+
onFieldChange,
68+
availableKeys,
69+
}: {
70+
title: string;
71+
field: string;
72+
onFieldChange: (value: string) => void;
73+
availableKeys: string[];
74+
}) => (
75+
<div className="mb-4">
76+
<div className="text-xs font-medium text-gray-700 mb-2">{title}:</div>
77+
<Select
78+
value={field}
79+
onChange={(e) => onFieldChange(e.target.value)}
80+
size="sm"
81+
className="min-w-48"
82+
>
83+
<option value="">Select a field...</option>
84+
{availableKeys?.map((key) => (
85+
<option key={key} value={key}>
86+
{key}
87+
</option>
88+
))}
89+
</Select>
90+
</div>
91+
);
92+
93+
const PivotTab = observer(() => {
94+
const [selectedRowFields, setSelectedRowFields] = useState<string[]>([
95+
"$.eval_metadata.name",
96+
]);
97+
const [selectedColumnFields, setSelectedColumnFields] = useState<string[]>([
98+
"$.input_metadata.completion_params.model",
99+
]);
100+
const [selectedValueField, setSelectedValueField] = useState<string>(
101+
"$.evaluation_result.score"
102+
);
103+
104+
const createFieldHandler = (
105+
setter: React.Dispatch<React.SetStateAction<string[]>>
106+
) => {
107+
return (index: number, value: string) => {
108+
setter((prev) => {
109+
const newFields = [...prev];
110+
newFields[index] = value;
111+
return newFields;
112+
});
113+
};
114+
};
115+
116+
const createAddHandler = (
117+
setter: React.Dispatch<React.SetStateAction<string[]>>
118+
) => {
119+
return () => {
120+
setter((prev) => (prev.length < 3 ? [...prev, ""] : prev));
121+
};
122+
};
123+
124+
const createRemoveHandler = (
125+
setter: React.Dispatch<React.SetStateAction<string[]>>
126+
) => {
127+
return (index: number) => {
128+
setter((prev) => prev.filter((_, i) => i !== index));
129+
};
130+
};
131+
132+
const availableKeys = state.flattenedDatasetKeys[0] || [];
133+
9134
return (
10135
<div>
11-
<div className="text-xs text-gray-600 mb-2">
12-
Showing pivot of flattened rows (JSONPath keys). Defaults: rows by eval
13-
name and status; columns by model; values average score.
136+
<div className="text-xs text-gray-600 mb-2 max-w-2xl">
137+
Configure your pivot table by selecting fields for rows, columns, and
138+
values. Use the dropdowns below to choose from available flattened
139+
JSONPath keys. You can add/remove fields and change the value field to
140+
pivot on different metrics.
14141
</div>
142+
143+
<FieldSelector
144+
title="Row Fields"
145+
fields={selectedRowFields}
146+
onFieldChange={createFieldHandler(setSelectedRowFields)}
147+
onAddField={createAddHandler(setSelectedRowFields)}
148+
onRemoveField={createRemoveHandler(setSelectedRowFields)}
149+
availableKeys={availableKeys}
150+
/>
151+
152+
<FieldSelector
153+
title="Column Fields"
154+
fields={selectedColumnFields}
155+
onFieldChange={createFieldHandler(setSelectedColumnFields)}
156+
onAddField={createAddHandler(setSelectedColumnFields)}
157+
onRemoveField={createRemoveHandler(setSelectedColumnFields)}
158+
availableKeys={availableKeys}
159+
/>
160+
161+
<SingleFieldSelector
162+
title="Value Field"
163+
field={selectedValueField}
164+
onFieldChange={setSelectedValueField}
165+
availableKeys={availableKeys}
166+
/>
167+
15168
<PivotTable
16-
data={data}
17-
rowFields={[
18-
"$.eval_metadata.name" as keyof (typeof data)[number],
19-
"$.eval_metadata.status" as keyof (typeof data)[number],
20-
]}
21-
columnFields={[
22-
"$.input_metadata.completion_params.model" as keyof (typeof data)[number],
23-
]}
24-
valueField={"$.evaluation_result.score" as keyof (typeof data)[number]}
169+
data={state.flattenedDataset}
170+
rowFields={
171+
selectedRowFields.filter(
172+
(field) => field !== ""
173+
) as (keyof (typeof state.flattenedDataset)[number])[]
174+
}
175+
columnFields={
176+
selectedColumnFields.filter(
177+
(field) => field !== ""
178+
) as (keyof (typeof state.flattenedDataset)[number])[]
179+
}
180+
valueField={
181+
selectedValueField as keyof (typeof state.flattenedDataset)[number]
182+
}
25183
aggregator="avg"
26184
showRowTotals
27185
showColumnTotals

0 commit comments

Comments
 (0)