change outputs table to make room for evals
This commit is contained in:
40
src/components/OutputsTable/NewEvaluationButton.tsx
Normal file
40
src/components/OutputsTable/NewEvaluationButton.tsx
Normal file
@@ -0,0 +1,40 @@
|
|||||||
|
import { Button, type ButtonProps, HStack, Spinner, Icon } from "@chakra-ui/react";
|
||||||
|
import { BsPlus } from "react-icons/bs";
|
||||||
|
import { api } from "~/utils/api";
|
||||||
|
import { useExperiment, useHandledAsyncCallback } from "~/utils/hooks";
|
||||||
|
|
||||||
|
// Extracted Button styling into reusable component
|
||||||
|
const StyledButton = ({ children, onClick }: ButtonProps) => (
|
||||||
|
<Button
|
||||||
|
fontWeight="normal"
|
||||||
|
bgColor="transparent"
|
||||||
|
_hover={{ bgColor: "gray.100" }}
|
||||||
|
px={2}
|
||||||
|
onClick={onClick}
|
||||||
|
>
|
||||||
|
{children}
|
||||||
|
</Button>
|
||||||
|
);
|
||||||
|
|
||||||
|
export default function NewEvaluationButton() {
|
||||||
|
const experiment = useExperiment();
|
||||||
|
const mutation = api.scenarios.create.useMutation();
|
||||||
|
const utils = api.useContext();
|
||||||
|
|
||||||
|
const [onClick] = useHandledAsyncCallback(async () => {
|
||||||
|
if (!experiment.data) return;
|
||||||
|
await mutation.mutateAsync({
|
||||||
|
experimentId: experiment.data.id,
|
||||||
|
});
|
||||||
|
await utils.scenarios.list.invalidate();
|
||||||
|
}, [mutation]);
|
||||||
|
|
||||||
|
return (
|
||||||
|
<HStack spacing={2}>
|
||||||
|
<StyledButton onClick={onClick}>
|
||||||
|
<Icon as={BsPlus} boxSize={6} />
|
||||||
|
Add Evaluation
|
||||||
|
</StyledButton>
|
||||||
|
</HStack>
|
||||||
|
);
|
||||||
|
}
|
||||||
39
src/components/OutputsTable/ScenarioRow.tsx
Normal file
39
src/components/OutputsTable/ScenarioRow.tsx
Normal file
@@ -0,0 +1,39 @@
|
|||||||
|
import { Box, GridItem } from "@chakra-ui/react";
|
||||||
|
import React, { useState } from "react";
|
||||||
|
import { cellPadding } from "../constants";
|
||||||
|
import OutputCell from "./OutputCell";
|
||||||
|
import ScenarioEditor from "./ScenarioEditor";
|
||||||
|
import type { PromptVariant, Scenario } from "./types";
|
||||||
|
|
||||||
|
const ScenarioRow = (props: { scenario: Scenario; variants: PromptVariant[] }) => {
|
||||||
|
const [isHovered, setIsHovered] = useState(false);
|
||||||
|
|
||||||
|
const highlightStyle = { backgroundColor: "gray.50" };
|
||||||
|
|
||||||
|
return (
|
||||||
|
<>
|
||||||
|
<GridItem
|
||||||
|
onMouseEnter={() => setIsHovered(true)}
|
||||||
|
onMouseLeave={() => setIsHovered(false)}
|
||||||
|
sx={isHovered ? highlightStyle : undefined}
|
||||||
|
borderLeftWidth={1}
|
||||||
|
>
|
||||||
|
<ScenarioEditor scenario={props.scenario} hovered={isHovered} />
|
||||||
|
</GridItem>
|
||||||
|
{props.variants.map((variant) => (
|
||||||
|
<GridItem
|
||||||
|
key={variant.id}
|
||||||
|
onMouseEnter={() => setIsHovered(true)}
|
||||||
|
onMouseLeave={() => setIsHovered(false)}
|
||||||
|
sx={isHovered ? highlightStyle : undefined}
|
||||||
|
>
|
||||||
|
<Box h="100%" w="100%" px={cellPadding.x} py={cellPadding.y}>
|
||||||
|
<OutputCell key={variant.id} scenario={props.scenario} variant={variant} />
|
||||||
|
</Box>
|
||||||
|
</GridItem>
|
||||||
|
))}
|
||||||
|
</>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
export default ScenarioRow;
|
||||||
@@ -1,56 +1,20 @@
|
|||||||
import { Box, Grid, GridItem, type SystemStyleObject } from "@chakra-ui/react";
|
import { Grid, GridItem, Heading, type SystemStyleObject } from "@chakra-ui/react";
|
||||||
import React, { useState } from "react";
|
import ScenarioHeader from "~/server/ScenarioHeader";
|
||||||
import { api } from "~/utils/api";
|
import { api } from "~/utils/api";
|
||||||
|
import NewEvaluationButton from "./NewEvaluationButton";
|
||||||
import NewScenarioButton from "./NewScenarioButton";
|
import NewScenarioButton from "./NewScenarioButton";
|
||||||
import NewVariantButton from "./NewVariantButton";
|
import NewVariantButton from "./NewVariantButton";
|
||||||
import OutputCell from "./OutputCell";
|
import ScenarioRow from "./ScenarioRow";
|
||||||
import ScenarioEditor from "./ScenarioEditor";
|
|
||||||
import VariantConfigEditor from "./VariantConfigEditor";
|
import VariantConfigEditor from "./VariantConfigEditor";
|
||||||
import VariantHeader from "./VariantHeader";
|
import VariantHeader from "./VariantHeader";
|
||||||
import type { Scenario, PromptVariant } from "./types";
|
|
||||||
import ScenarioHeader from "~/server/ScenarioHeader";
|
|
||||||
import { cellPadding } from "../constants";
|
|
||||||
|
|
||||||
const stickyHeaderStyle: SystemStyleObject = {
|
const stickyHeaderStyle: SystemStyleObject = {
|
||||||
position: "sticky",
|
position: "sticky",
|
||||||
top: 0,
|
top: "-1px",
|
||||||
backgroundColor: "#fff",
|
backgroundColor: "#fff",
|
||||||
zIndex: 1,
|
zIndex: 1,
|
||||||
};
|
};
|
||||||
|
|
||||||
const ScenarioRow = (props: { scenario: Scenario; variants: PromptVariant[] }) => {
|
|
||||||
const [isHovered, setIsHovered] = useState(false);
|
|
||||||
|
|
||||||
const highlightStyle = {
|
|
||||||
backgroundColor: "gray.50", // or any color you prefer
|
|
||||||
};
|
|
||||||
|
|
||||||
return (
|
|
||||||
<React.Fragment>
|
|
||||||
<GridItem
|
|
||||||
onMouseEnter={() => setIsHovered(true)}
|
|
||||||
onMouseLeave={() => setIsHovered(false)}
|
|
||||||
sx={isHovered ? highlightStyle : undefined}
|
|
||||||
borderLeftWidth={1}
|
|
||||||
>
|
|
||||||
<ScenarioEditor scenario={props.scenario} hovered={isHovered} />
|
|
||||||
</GridItem>
|
|
||||||
{props.variants.map((variant) => (
|
|
||||||
<GridItem
|
|
||||||
key={variant.id}
|
|
||||||
onMouseEnter={() => setIsHovered(true)}
|
|
||||||
onMouseLeave={() => setIsHovered(false)}
|
|
||||||
sx={isHovered ? highlightStyle : undefined}
|
|
||||||
>
|
|
||||||
<Box h="100%" w="100%" px={cellPadding.x} py={cellPadding.y}>
|
|
||||||
<OutputCell key={variant.id} scenario={props.scenario} variant={variant} />
|
|
||||||
</Box>
|
|
||||||
</GridItem>
|
|
||||||
))}
|
|
||||||
</React.Fragment>
|
|
||||||
);
|
|
||||||
};
|
|
||||||
|
|
||||||
export default function OutputsTable({ experimentId }: { experimentId: string | undefined }) {
|
export default function OutputsTable({ experimentId }: { experimentId: string | undefined }) {
|
||||||
const variants = api.promptVariants.list.useQuery(
|
const variants = api.promptVariants.list.useQuery(
|
||||||
{ experimentId: experimentId as string },
|
{ experimentId: experimentId as string },
|
||||||
@@ -64,6 +28,8 @@ export default function OutputsTable({ experimentId }: { experimentId: string |
|
|||||||
|
|
||||||
if (!variants.data || !scenarios.data) return null;
|
if (!variants.data || !scenarios.data) return null;
|
||||||
|
|
||||||
|
const allCols = variants.data.length + 1;
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Grid
|
<Grid
|
||||||
p={4}
|
p={4}
|
||||||
@@ -80,16 +46,14 @@ export default function OutputsTable({ experimentId }: { experimentId: string |
|
|||||||
},
|
},
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
<GridItem display="flex" alignItems="flex-end" rowSpan={2}>
|
<GridItem borderBottomWidth={0} rowSpan={2} />
|
||||||
<ScenarioHeader />
|
|
||||||
</GridItem>
|
|
||||||
{variants.data.map((variant) => (
|
{variants.data.map((variant) => (
|
||||||
<GridItem key={variant.uiId} padding={0} sx={stickyHeaderStyle} borderTopWidth={1}>
|
<GridItem key={variant.uiId} padding={0} sx={stickyHeaderStyle} borderTopWidth={1}>
|
||||||
<VariantHeader variant={variant} />
|
<VariantHeader variant={variant} />
|
||||||
</GridItem>
|
</GridItem>
|
||||||
))}
|
))}
|
||||||
<GridItem
|
<GridItem
|
||||||
rowSpan={scenarios.data.length + 1}
|
rowSpan={scenarios.data.length + 2}
|
||||||
padding={0}
|
padding={0}
|
||||||
// Have to use `style` instead of emotion style props to work around css specificity issues conflicting with the "> *" selector on Grid
|
// Have to use `style` instead of emotion style props to work around css specificity issues conflicting with the "> *" selector on Grid
|
||||||
style={{ borderRightWidth: 0, borderBottomWidth: 0 }}
|
style={{ borderRightWidth: 0, borderBottomWidth: 0 }}
|
||||||
@@ -103,12 +67,31 @@ export default function OutputsTable({ experimentId }: { experimentId: string |
|
|||||||
<VariantConfigEditor variant={variant} />
|
<VariantConfigEditor variant={variant} />
|
||||||
</GridItem>
|
</GridItem>
|
||||||
))}
|
))}
|
||||||
|
<GridItem
|
||||||
|
display="flex"
|
||||||
|
alignItems="flex-end"
|
||||||
|
borderRightWidth={0}
|
||||||
|
pt={4}
|
||||||
|
sx={{ ...stickyHeaderStyle, top: -4 }}
|
||||||
|
>
|
||||||
|
<ScenarioHeader />
|
||||||
|
</GridItem>
|
||||||
|
<GridItem colSpan={allCols - 1} borderRightWidth={0} />
|
||||||
|
|
||||||
{scenarios.data.map((scenario) => (
|
{scenarios.data.map((scenario) => (
|
||||||
<ScenarioRow key={scenario.uiId} scenario={scenario} variants={variants.data} />
|
<ScenarioRow key={scenario.uiId} scenario={scenario} variants={variants.data} />
|
||||||
))}
|
))}
|
||||||
<GridItem borderBottomWidth={0} w="100%" colSpan={variants.data.length + 1} padding={0}>
|
<GridItem borderBottomWidth={0} w="100%" colSpan={allCols} padding={0}>
|
||||||
<NewScenarioButton />
|
<NewScenarioButton />
|
||||||
</GridItem>
|
</GridItem>
|
||||||
|
{/* <GridItem borderBottomWidth={0} colSpan={allCols} px={2} pt={4}>
|
||||||
|
<Heading size="sm" fontWeight="bold" flex={1}>
|
||||||
|
Evaluations
|
||||||
|
</Heading>
|
||||||
|
</GridItem>
|
||||||
|
<GridItem borderBottomWidth={0} w="100%" colSpan={allCols} padding={0}>
|
||||||
|
<NewEvaluationButton />
|
||||||
|
</GridItem> */}
|
||||||
</Grid>
|
</Grid>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user