Skip to content

Commit 137eedf

Browse files
author
Dylan Huang
committed
styling + add parameterization for aggregate method
1 parent 641a704 commit 137eedf

File tree

3 files changed

+189
-67
lines changed

3 files changed

+189
-67
lines changed

vite-app/src/components/PivotTab.tsx

Lines changed: 82 additions & 39 deletions
Original file line numberDiff line numberDiff line change
@@ -20,46 +20,55 @@ const FieldSelector = ({
2020
onAddField,
2121
onRemoveField,
2222
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"
23+
variant = "default",
24+
}: FieldSelectorProps & { variant?: "row" | "column" | "default" }) => {
25+
const variantStyles = {
26+
row: "border-l-4 border-l-blue-500 pl-3",
27+
column: "border-l-4 border-l-green-500 pl-3",
28+
default: "",
29+
};
30+
31+
return (
32+
<div className={`mb-4 ${variantStyles[variant]}`}>
33+
<div className="text-xs font-medium text-gray-700 mb-2">{title}:</div>
34+
<div className="space-y-2">
35+
{fields.map((field, index) => (
36+
<div key={index} className="flex items-center space-x-2">
37+
<Select
38+
value={field}
39+
onChange={(e) => onFieldChange(index, e.target.value)}
40+
size="sm"
41+
className="min-w-48"
4642
>
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-
)}
43+
<option value="">Select a field...</option>
44+
{availableKeys?.map((key) => (
45+
<option key={key} value={key}>
46+
{key}
47+
</option>
48+
))}
49+
</Select>
50+
{fields.length > 0 && (
51+
<button
52+
onClick={() => onRemoveField(index)}
53+
className="text-xs text-red-600 hover:text-red-800 px-2 py-1"
54+
>
55+
Remove
56+
</button>
57+
)}
58+
</div>
59+
))}
60+
{fields.length < 3 && (
61+
<button
62+
onClick={onAddField}
63+
className="text-xs text-blue-600 hover:text-blue-800 px-2 py-1"
64+
>
65+
+ Add {title.slice(0, -1)} Field
66+
</button>
67+
)}
68+
</div>
6069
</div>
61-
</div>
62-
);
70+
);
71+
};
6372

6473
const SingleFieldSelector = ({
6574
title,
@@ -90,6 +99,32 @@ const SingleFieldSelector = ({
9099
</div>
91100
);
92101

102+
const AggregatorSelector = ({
103+
aggregator,
104+
onAggregatorChange,
105+
}: {
106+
aggregator: string;
107+
onAggregatorChange: (value: string) => void;
108+
}) => (
109+
<div className="mb-4">
110+
<div className="text-xs font-medium text-gray-700 mb-2">
111+
Aggregation Method:
112+
</div>
113+
<Select
114+
value={aggregator}
115+
onChange={(e) => onAggregatorChange(e.target.value)}
116+
size="sm"
117+
className="min-w-48"
118+
>
119+
<option value="count">Count</option>
120+
<option value="sum">Sum</option>
121+
<option value="avg">Average</option>
122+
<option value="min">Minimum</option>
123+
<option value="max">Maximum</option>
124+
</Select>
125+
</div>
126+
);
127+
93128
const PivotTab = observer(() => {
94129
const [selectedRowFields, setSelectedRowFields] = useState<string[]>([
95130
"$.eval_metadata.name",
@@ -100,6 +135,7 @@ const PivotTab = observer(() => {
100135
const [selectedValueField, setSelectedValueField] = useState<string>(
101136
"$.evaluation_result.score"
102137
);
138+
const [selectedAggregator, setSelectedAggregator] = useState<string>("avg");
103139

104140
const createFieldHandler = (
105141
setter: React.Dispatch<React.SetStateAction<string[]>>
@@ -147,6 +183,7 @@ const PivotTab = observer(() => {
147183
onAddField={createAddHandler(setSelectedRowFields)}
148184
onRemoveField={createRemoveHandler(setSelectedRowFields)}
149185
availableKeys={availableKeys}
186+
variant="row"
150187
/>
151188

152189
<FieldSelector
@@ -156,6 +193,7 @@ const PivotTab = observer(() => {
156193
onAddField={createAddHandler(setSelectedColumnFields)}
157194
onRemoveField={createRemoveHandler(setSelectedColumnFields)}
158195
availableKeys={availableKeys}
196+
variant="column"
159197
/>
160198

161199
<SingleFieldSelector
@@ -165,6 +203,11 @@ const PivotTab = observer(() => {
165203
availableKeys={availableKeys}
166204
/>
167205

206+
<AggregatorSelector
207+
aggregator={selectedAggregator}
208+
onAggregatorChange={setSelectedAggregator}
209+
/>
210+
168211
<PivotTable
169212
data={state.flattenedDataset}
170213
rowFields={
@@ -180,7 +223,7 @@ const PivotTab = observer(() => {
180223
valueField={
181224
selectedValueField as keyof (typeof state.flattenedDataset)[number]
182225
}
183-
aggregator="avg"
226+
aggregator={selectedAggregator as any}
184227
showRowTotals
185228
showColumnTotals
186229
/>

vite-app/src/components/PivotTable.tsx

Lines changed: 75 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -104,28 +104,48 @@ export function PivotTable<T extends Record<string, unknown>>({
104104
<table className="w-full min-w-max">
105105
<TableHead>
106106
<tr>
107-
{/* Row header labels */}
107+
{/* Row header labels with enhanced styling */}
108108
{rowFields.map((f) => (
109-
<TableHeader key={String(f)}>{String(f)}</TableHeader>
109+
<TableHeader key={String(f)} className="bg-blue-50">
110+
<div className="text-xs font-medium text-blue-700">
111+
{String(f)}
112+
</div>
113+
</TableHeader>
110114
))}
111-
{/* Column headers (flattened) */}
115+
{/* Column headers with enhanced styling */}
112116
{colKeyTuples.map((tuple, idx) => (
113-
<TableHeader key={`col-${idx}`} align="right" nowrap>
114-
{tuple.map((v) => String(v ?? "")).join(" / ")}
117+
<TableHeader
118+
key={`col-${idx}`}
119+
align="right"
120+
nowrap
121+
className="bg-green-50"
122+
>
123+
<div className="text-xs font-medium text-green-700">
124+
{tuple.map((v) => String(v ?? "")).join(" / ")}
125+
</div>
115126
</TableHeader>
116127
))}
117-
{showRowTotals && <TableHeader align="right">Total</TableHeader>}
128+
{showRowTotals && (
129+
<TableHeader align="right" className="bg-gray-100">
130+
<div className="text-xs font-medium text-gray-700">Total</div>
131+
</TableHeader>
132+
)}
118133
</tr>
119134
</TableHead>
120135
<TableBody>
121136
{rowKeyTuples.map((rTuple, rIdx) => {
122137
const rKey = toKey(rTuple);
123138
return (
124-
<TableRow key={`row-${rIdx}`} className="text-xs">
125-
{/* Row header cells */}
139+
<TableRow
140+
key={`row-${rIdx}`}
141+
className="text-xs hover:bg-gray-50"
142+
>
143+
{/* Row header cells with enhanced styling */}
126144
{rTuple.map((value, i) => (
127-
<TableCell key={`rh-${i}`} nowrap>
128-
{String(value ?? "")}
145+
<TableCell key={`rh-${i}`} nowrap className="bg-blue-50">
146+
<div className="font-medium text-blue-900">
147+
{String(value ?? "")}
148+
</div>
129149
</TableCell>
130150
))}
131151
{/* Data cells */}
@@ -134,39 +154,70 @@ export function PivotTable<T extends Record<string, unknown>>({
134154
const cell = cells[rKey]?.[cKey];
135155
const content = cell ? formatter(cell.value) : emptyValue;
136156
return (
137-
<TableCell key={`c-${cIdx}`} align="right" nowrap>
138-
{content}
157+
<TableCell
158+
key={`c-${cIdx}`}
159+
align="right"
160+
nowrap
161+
className="bg-white"
162+
>
163+
<div className="font-mono text-sm">{content}</div>
139164
</TableCell>
140165
);
141166
})}
142-
{/* Row total */}
167+
{/* Row total with enhanced styling */}
143168
{showRowTotals && (
144-
<TableCell align="right" nowrap medium>
145-
{formatter(rowTotals[rKey] ?? 0)}
169+
<TableCell
170+
align="right"
171+
nowrap
172+
medium
173+
className="bg-gray-100"
174+
>
175+
<div className="font-semibold text-gray-900">
176+
{formatter(rowTotals[rKey] ?? 0)}
177+
</div>
146178
</TableCell>
147179
)}
148180
</TableRow>
149181
);
150182
})}
151183
{showColumnTotals && (
152-
<TableRow gray>
184+
<TableRow gray className="border-t-2 border-gray-300">
153185
{/* Total label spanning row header columns */}
154-
<TableCell colSpan={Math.max(1, rowFields.length)} semibold>
155-
Total
186+
<TableCell
187+
colSpan={Math.max(1, rowFields.length)}
188+
semibold
189+
className="bg-gray-100"
190+
>
191+
<div className="text-sm font-semibold text-gray-900">Total</div>
156192
</TableCell>
157-
{/* Column totals */}
193+
{/* Column totals with enhanced styling */}
158194
{colKeyTuples.map((cTuple, cIdx) => {
159195
const cKey = toKey(cTuple);
160196
return (
161-
<TableCell key={`ct-${cIdx}`} align="right" nowrap medium>
162-
{formatter(colTotals[cKey] ?? 0)}
197+
<TableCell
198+
key={`ct-${cIdx}`}
199+
align="right"
200+
nowrap
201+
medium
202+
className="bg-gray-100"
203+
>
204+
<div className="font-semibold text-gray-900">
205+
{formatter(colTotals[cKey] ?? 0)}
206+
</div>
163207
</TableCell>
164208
);
165209
})}
166-
{/* Grand total */}
210+
{/* Grand total with enhanced styling */}
167211
{showRowTotals && (
168-
<TableCell align="right" nowrap semibold>
169-
{formatter(grandTotal)}
212+
<TableCell
213+
align="right"
214+
nowrap
215+
semibold
216+
className="bg-gray-200"
217+
>
218+
<div className="text-sm font-bold text-gray-900">
219+
{formatter(grandTotal)}
220+
</div>
170221
</TableCell>
171222
)}
172223
</TableRow>

0 commit comments

Comments
 (0)