From 55465b87f66bc9d5480be6a8eca32603c613369f Mon Sep 17 00:00:00 2001 From: ashrafchowdury Date: Thu, 3 Oct 2024 17:24:16 +0600 Subject: [PATCH 01/16] ui(frontend): implemented testset ui --- .../pages/testset/modals/CreateTestset.tsx | 68 ++++ .../testset/modals/CreateTestsetFromApi.tsx | 177 +++++++++++ .../modals/CreateTestsetFromScratch.tsx | 54 ++++ .../pages/testset/modals/UploadTestset.tsx | 163 ++++++++++ .../components/pages/testset/modals/index.tsx | 62 ++++ .../pages/apps/[app_id]/testsets/index.tsx | 290 ++++++++++++------ 6 files changed, 716 insertions(+), 98 deletions(-) create mode 100644 agenta-web/src/components/pages/testset/modals/CreateTestset.tsx create mode 100644 agenta-web/src/components/pages/testset/modals/CreateTestsetFromApi.tsx create mode 100644 agenta-web/src/components/pages/testset/modals/CreateTestsetFromScratch.tsx create mode 100644 agenta-web/src/components/pages/testset/modals/UploadTestset.tsx create mode 100644 agenta-web/src/components/pages/testset/modals/index.tsx diff --git a/agenta-web/src/components/pages/testset/modals/CreateTestset.tsx b/agenta-web/src/components/pages/testset/modals/CreateTestset.tsx new file mode 100644 index 0000000000..97d23c1dcb --- /dev/null +++ b/agenta-web/src/components/pages/testset/modals/CreateTestset.tsx @@ -0,0 +1,68 @@ +import {JSSTheme} from "@/lib/Types" +import {Typography} from "antd" +import React from "react" +import {createUseStyles} from "react-jss" + +const useStyles = createUseStyles((theme: JSSTheme) => ({ + headerText: { + lineHeight: theme.lineHeightLG, + fontSize: theme.fontSizeHeading4, + fontWeight: theme.fontWeightStrong, + }, + appTemplate: { + gap: 16, + display: "flex", + flexDirection: "column", + }, + template: { + border: "1px solid", + borderColor: theme.colorBorderSecondary, + borderRadius: theme.borderRadiusLG, + paddingTop: theme.paddingSM, + paddingBottom: theme.paddingSM, + paddingInline: theme.padding, + boxShadow: + "0px 2px 4px 0px #00000005, 0px 1px 6px -1px #00000005, 0px 1px 2px 0px #00000008", + gap: 2, + cursor: "pointer", + "& > span": { + fontSize: theme.fontSizeLG, + lineHeight: theme.lineHeightLG, + fontWeight: theme.fontWeightMedium, + }, + "& > div": { + marginBottom: 0, + }, + }, +})) + +type Props = {setCurrent: React.Dispatch>} + +const CreateTestset: React.FC = ({setCurrent}) => { + const classes = useStyles() + return ( +
+ Create new test set +
+
setCurrent(1)}> + Create from scratch + + Create a new test set directly from the webUI + +
+
setCurrent(2)}> + Upload a test set + Upload your test set as CSV or JSON +
+
setCurrent(3)}> + Create with API + + Create a test set programmatically using our API endpoints + +
+
+
+ ) +} + +export default CreateTestset diff --git a/agenta-web/src/components/pages/testset/modals/CreateTestsetFromApi.tsx b/agenta-web/src/components/pages/testset/modals/CreateTestsetFromApi.tsx new file mode 100644 index 0000000000..947cdf55f1 --- /dev/null +++ b/agenta-web/src/components/pages/testset/modals/CreateTestsetFromApi.tsx @@ -0,0 +1,177 @@ +import CopyButton from "@/components/CopyButton/CopyButton" +import {getAgentaApiUrl} from "@/lib/helpers/utils" +import {JSSTheme} from "@/lib/Types" +import {PythonOutlined} from "@ant-design/icons" +import {ArrowLeft, FileCode, FileTs} from "@phosphor-icons/react" +import {Button, Radio, Tabs, Typography} from "antd" +import {useRouter} from "next/router" +import React, {useState} from "react" +import {createUseStyles} from "react-jss" +import pythonCode from "@/code_snippets/testsets/create_with_json/python" +import cURLCode from "@/code_snippets/testsets/create_with_json/curl" +import tsCode from "@/code_snippets/testsets/create_with_json/typescript" +import CodeBlock from "@/components/DynamicCodeBlock/CodeBlock" +import pythonCodeUpload from "@/code_snippets/testsets/create_with_upload/python" +import cURLCodeUpload from "@/code_snippets/testsets/create_with_upload/curl" +import tsCodeUpload from "@/code_snippets/testsets/create_with_upload/typescript" + +const useStyles = createUseStyles((theme: JSSTheme) => ({ + headerText: { + lineHeight: theme.lineHeightLG, + fontSize: theme.fontSizeHeading4, + fontWeight: theme.fontWeightStrong, + }, + label: { + fontWeight: theme.fontWeightMedium, + }, + uploadContainer: { + padding: theme.paddingXS, + display: "flex", + alignItems: "center", + justifyContent: "space-between", + border: "1px solid", + borderColor: theme.colorBorder, + borderRadius: theme.borderRadiusLG, + }, + subText: { + color: theme.colorTextSecondary, + }, +})) + +type Props = { + setCurrent: React.Dispatch> + onCancel: () => void +} +type LanguageCodeBlockProps = { + selectedLang: string + codeSnippets: Record +} + +const LanguageCodeBlock = ({selectedLang, codeSnippets}: LanguageCodeBlockProps) => { + return ( +
+
+ +
+ +
+ +
+
+ ) +} + +const CreateTestsetFromApi: React.FC = ({setCurrent, onCancel}) => { + const classes = useStyles() + const router = useRouter() + const [uploadType, setUploadType] = useState<"csv" | "json">("csv") + const [selectedLang, setSelectedLang] = useState("python") + + const appId = router.query.app_id as string + + const uploadURI = `${getAgentaApiUrl()}/api/testsets/upload` + const jsonURI = `${getAgentaApiUrl()}/api/testsets/${appId}` + + const params = `{ + "name": "testset_name",}` + + const jsonCodeSnippets: Record = { + python: pythonCode(jsonURI, params), + bash: cURLCode(jsonURI, params), + typescript: tsCode(jsonURI, params), + } + + const csvCodeSnippets: Record = { + python: pythonCodeUpload(uploadURI, appId), + bash: cURLCodeUpload(uploadURI, appId), + typescript: tsCodeUpload(uploadURI, appId), + } + + const codeSnippets = uploadType === "csv" ? csvCodeSnippets : jsonCodeSnippets + + return ( +
+
+
+ +
+ Create a new test set directly from the webUI + +
+ Select type + setUploadType(e.target.value)}> + CSV + JSON + +
+ + + Use this endpoint to create a new Test set for your App using JSON + + +
+ + ), + icon: , + }, + { + key: "typescript", + label: "TypeScript", + children: ( + + ), + icon: , + }, + { + key: "bash", + label: "cURL", + children: ( + + ), + icon: , + }, + ]} + /> +
+
+ +
+ + +
+
+ ) +} + +export default CreateTestsetFromApi diff --git a/agenta-web/src/components/pages/testset/modals/CreateTestsetFromScratch.tsx b/agenta-web/src/components/pages/testset/modals/CreateTestsetFromScratch.tsx new file mode 100644 index 0000000000..3400595fba --- /dev/null +++ b/agenta-web/src/components/pages/testset/modals/CreateTestsetFromScratch.tsx @@ -0,0 +1,54 @@ +import React from "react" +import {JSSTheme} from "@/lib/Types" +import {ArrowLeft} from "@phosphor-icons/react" +import {Button, Input, Typography} from "antd" +import {createUseStyles} from "react-jss" + +const useStyles = createUseStyles((theme: JSSTheme) => ({ + headerText: { + lineHeight: theme.lineHeightLG, + fontSize: theme.fontSizeHeading4, + fontWeight: theme.fontWeightStrong, + }, + label: { + fontWeight: theme.fontWeightMedium, + }, +})) + +type Props = { + setCurrent: React.Dispatch> + onCancel: () => void +} + +const CreateTestsetFromScratch: React.FC = ({setCurrent, onCancel}) => { + const classes = useStyles() + return ( +
+
+
+ + Create a new test set directly from the webUI + +
+ Name of testset + +
+ +
+ + +
+
+ ) +} + +export default CreateTestsetFromScratch diff --git a/agenta-web/src/components/pages/testset/modals/UploadTestset.tsx b/agenta-web/src/components/pages/testset/modals/UploadTestset.tsx new file mode 100644 index 0000000000..dbebff975d --- /dev/null +++ b/agenta-web/src/components/pages/testset/modals/UploadTestset.tsx @@ -0,0 +1,163 @@ +import React, {useState} from "react" +import {JSSTheme} from "@/lib/Types" +import {ArrowLeft, FileCsv, Trash} from "@phosphor-icons/react" +import {Button, Collapse, Input, Radio, Typography} from "antd" +import {createUseStyles} from "react-jss" +import {UploadOutlined} from "@ant-design/icons" + +const useStyles = createUseStyles((theme: JSSTheme) => ({ + headerText: { + lineHeight: theme.lineHeightLG, + fontSize: theme.fontSizeHeading4, + fontWeight: theme.fontWeightStrong, + }, + label: { + fontWeight: theme.fontWeightMedium, + }, + uploadContainer: { + padding: theme.paddingXS, + display: "flex", + alignItems: "center", + justifyContent: "space-between", + border: "1px solid", + borderColor: theme.colorBorder, + borderRadius: theme.borderRadiusLG, + }, + subText: { + color: theme.colorTextSecondary, + }, +})) + +type Props = { + setCurrent: React.Dispatch> + onCancel: () => void +} + +const UploadTestset: React.FC = ({setCurrent, onCancel}) => { + const classes = useStyles() + const [uploadType, setUploadType] = useState<"csv" | "json">("csv") + + return ( +
+
+
+ +
+ Create a new test set directly from the webUI + +
+ Select type + setUploadType(e.target.value)}> + CSV + JSON + +
+ +
+ Name of testset + +
+ +
+
+ + Upload CSV or JSON + + +
+ +
+
+ + File-name +
+ + +
+
+ +
+ + {uploadType === "csv" ? ( + <> + {" "} + + The test set should be in CSV format with the + following requirements: + +
+ + 1. Comma separated values + + + 2. The first row should contain the headers + +
+ + Here is an example of a valid CSV file:
+ recipe_name,correct_answer
+ ChickenParmesan,Chicken
"a, special, + recipe",Beef +
+ + ) : ( + <> + + The test set should be in JSON format with the + following requirements: + + +
+ + 1. A json file with an array of rows + + + 2. Each row in the array should be an object + + + of column header name as key and row data as + value. + +
+ + + Here is an example of a valid JSON file:
+ {`[{ "recipe_name": "Chicken Parmesan","correct_answer": "Chicken" }, +{ "recipe_name": "a, special, recipe","correct_answer": "Beef" }]`} +
+ + )} + + +
+ ), + }, + ]} + /> +
+ + +
+ + +
+
+ ) +} + +export default UploadTestset diff --git a/agenta-web/src/components/pages/testset/modals/index.tsx b/agenta-web/src/components/pages/testset/modals/index.tsx new file mode 100644 index 0000000000..5bb832edb2 --- /dev/null +++ b/agenta-web/src/components/pages/testset/modals/index.tsx @@ -0,0 +1,62 @@ +import React, {useState} from "react" +import {JSSTheme} from "@/lib/Types" +import {Modal} from "antd" +import {createUseStyles} from "react-jss" +import CreateTestset from "./CreateTestset" +import CreateTestsetFromScratch from "./CreateTestsetFromScratch" +import UploadTestset from "./UploadTestset" +import CreateTestsetFromApi from "./CreateTestsetFromApi" + +const useStyles = createUseStyles((theme: JSSTheme) => ({ + modal: { + transition: "width 0.3s ease", + "& .ant-modal-content": { + overflow: "hidden", + borderRadius: 16, + "& > .ant-modal-close": { + top: 16, + }, + }, + }, +})) + +type Props = React.ComponentProps & {} + +const TestsetModal: React.FC = ({...props}) => { + const classes = useStyles() + const [current, setCurrent] = useState(0) + + const onCancel = () => props.onCancel?.({} as any) + + const steps = [ + { + content: , + }, + { + content: , + }, + { + content: , + }, + { + content: , + }, + ] + + return ( + setCurrent(0)} + footer={null} + title={null} + className={classes.modal} + {...props} + width={480} + centered + destroyOnClose + > + {steps[current]?.content} + + ) +} + +export default TestsetModal diff --git a/agenta-web/src/pages/apps/[app_id]/testsets/index.tsx b/agenta-web/src/pages/apps/[app_id]/testsets/index.tsx index 455829ed73..b3e33041c7 100644 --- a/agenta-web/src/pages/apps/[app_id]/testsets/index.tsx +++ b/agenta-web/src/pages/apps/[app_id]/testsets/index.tsx @@ -1,68 +1,46 @@ -import {Button, Table, Space} from "antd" -import Link from "next/link" -import {useRouter} from "next/router" -import {ColumnsType} from "antd/es/table" -import {useState} from "react" +import TestsetModal from "@/components/pages/testset/modals" import {formatDate} from "@/lib/helpers/dateTimeHelper" -import {DeleteOutlined} from "@ant-design/icons" +import {checkIfResourceValidForDeletion} from "@/lib/helpers/evaluate" +import {JSSTheme, testset} from "@/lib/Types" import {deleteTestsets, useLoadTestsetsList} from "@/services/testsets/api" +import {MoreOutlined, PlusOutlined} from "@ant-design/icons" +import {Copy, GearSix, Note, PencilSimple, Trash} from "@phosphor-icons/react" +import {Avatar, Button, Dropdown, Input, Spin, Table, Tag, Typography} from "antd" +import {ColumnsType} from "antd/es/table/interface" +import {useRouter} from "next/router" +import React, {useMemo, useState} from "react" import {createUseStyles} from "react-jss" -import {testset} from "@/lib/Types" -import {isDemo} from "@/lib/helpers/utils" -import {checkIfResourceValidForDeletion} from "@/lib/helpers/evaluate" -const useStyles = createUseStyles({ - container: { - marginTop: 20, - marginBottom: 40, - }, - btnContainer: { - display: "flex", - justifyContent: "space-between", - marginTop: "20px", - }, - deleteBtn: { - marginTop: "30px", - "& svg": { - color: "red", +const useStyles = createUseStyles((theme: JSSTheme) => ({ + modal: { + transition: "width 0.3s ease", + "& .ant-modal-content": { + overflow: "hidden", + borderRadius: 16, + "& > .ant-modal-close": { + top: 16, + }, }, }, - linksContainer: { - display: "flex", - gap: "10px", - flexWrap: "wrap", + headingTest: { + fontSize: theme.fontSizeHeading4, + lineHeight: theme.lineHeightHeading4, + fontWeight: theme.fontWeightMedium, }, - startLink: { + button: { display: "flex", alignItems: "center", - gap: 8, }, -}) +})) -export default function Testsets() { +const Testset = () => { const classes = useStyles() const router = useRouter() const appId = router.query.app_id as string const [selectedRowKeys, setSelectedRowKeys] = useState([]) const {testsets, isTestsetsLoading, mutate} = useLoadTestsetsList(appId) - - const columns: ColumnsType = [ - { - title: "Name", - dataIndex: "name", - key: "name", - className: "testset-column", - }, - { - title: "Creation date", - dataIndex: "created_at", - key: "created_at", - render: (date: string) => { - return formatDate(date) - }, - className: "testset-column", - }, - ] + const [isCreateTestsetModalOpen, setIsCreateTestsetModalOpen] = useState(false) + const [searchTerm, setSearchTerm] = useState("") const rowSelection = { onChange: (selectedRowKeys: React.Key[]) => { @@ -86,79 +64,195 @@ export default function Testsets() { } catch {} } - return ( -
-
-
-
- - - - - - - { + return testsets + ? testsets.filter((item: any) => + item.name.toLowerCase().includes(searchTerm.toLowerCase()), + ) + : testsets + }, [searchTerm, testsets]) + + const columns: ColumnsType = [ + { + title: "Name", + dataIndex: "name", + key: "name", + onHeaderCell: () => ({ + style: {minWidth: 160}, + }), + }, + { + title: "Date Modified", + dataIndex: "date_modified", + key: "date_modified", + onHeaderCell: () => ({ + style: {minWidth: 160}, + }), + render: (date: string) => { + return formatDate(date) + }, + }, + { + title: "Modified By", + dataIndex: "modified_by", + key: "modified_by", + render: (date: string) => { + return ( +
+ - - - {!isDemo() && ( - - - - )} + A + + Username
+ ) + }, + }, + { + title: "Tags", + dataIndex: "tags", + key: "tags", + onHeaderCell: () => ({ + style: {minWidth: 144}, + }), + render: (date: string) => { + return [1].map((tag) => Defailt) + }, + }, + { + title: "Date created", + dataIndex: "date_created", + key: "date_created", + render: (date: string) => { + return formatDate(date) + }, + onHeaderCell: () => ({ + style: {minWidth: 160}, + }), + }, + { + title: , + key: "key", + width: 56, + fixed: "right", + align: "center", + render: (_, record) => { + return ( + , + onClick: (e) => { + e.domEvent.stopPropagation() + router.push( + `/apps/${appId}/evaluations/single_model_test/${record}`, + ) + }, + }, + { + key: "clone", + label: "Clone", + icon: , + }, + {type: "divider"}, + { + key: "rename", + label: "Rename", + icon: , + }, + { + key: "delete_eval", + label: "Delete", + icon: , + danger: true, + }, + ], + }} + > + - + return ( + <> +
+
+ + Test sets + - - - - - )} +
- - {selectedRowKeys.length > 0 && ( +
+ setSearchTerm(e.target.value)} + /> - )} -
+
+ -
+ { return { onClick: () => router.push(`/apps/${appId}/testsets/${record._id}`), } }} /> - - + + + { + setIsCreateTestsetModalOpen(false) + }} + /> + ) } + +export default Testset From a43c143308717229f8e9887bba994f1e64f64a36 Mon Sep 17 00:00:00 2001 From: ashrafchowdury Date: Fri, 4 Oct 2024 11:41:39 +0600 Subject: [PATCH 02/16] feat(frontend): added functionalities --- .../modals/CreateTestsetFromScratch.tsx | 147 +++++++++++++++- .../pages/testset/modals/UploadTestset.tsx | 166 ++++++++++++++++-- .../components/pages/testset/modals/index.tsx | 50 +++++- .../pages/apps/[app_id]/testsets/index.tsx | 46 ++++- 4 files changed, 372 insertions(+), 37 deletions(-) diff --git a/agenta-web/src/components/pages/testset/modals/CreateTestsetFromScratch.tsx b/agenta-web/src/components/pages/testset/modals/CreateTestsetFromScratch.tsx index 3400595fba..d744cff410 100644 --- a/agenta-web/src/components/pages/testset/modals/CreateTestsetFromScratch.tsx +++ b/agenta-web/src/components/pages/testset/modals/CreateTestsetFromScratch.tsx @@ -1,8 +1,17 @@ -import React from "react" -import {JSSTheme} from "@/lib/Types" +import React, {useState} from "react" +import {JSSTheme, KeyValuePair, testset} from "@/lib/Types" import {ArrowLeft} from "@phosphor-icons/react" -import {Button, Input, Typography} from "antd" +import {Button, Input, message, Typography} from "antd" import {createUseStyles} from "react-jss" +import {useRouter} from "next/router" +import { + createNewTestset, + fetchTestset, + updateTestset, + useLoadTestsetsList, +} from "@/services/testsets/api" +import {fetchVariants} from "@/services/api" +import {getVariantInputParameters} from "@/lib/helpers/variantHelper" const useStyles = createUseStyles((theme: JSSTheme) => ({ headerText: { @@ -16,19 +25,124 @@ const useStyles = createUseStyles((theme: JSSTheme) => ({ })) type Props = { + cloneConfig: boolean + setCloneConfig: React.Dispatch> + editTestsetValues: testset | null + setEditTestsetValues: React.Dispatch> setCurrent: React.Dispatch> + renameTestsetConfig: boolean + setRenameTestsetConfig: React.Dispatch> onCancel: () => void } -const CreateTestsetFromScratch: React.FC = ({setCurrent, onCancel}) => { +const CreateTestsetFromScratch: React.FC = ({ + cloneConfig, + setCloneConfig, + editTestsetValues, + setEditTestsetValues, + renameTestsetConfig, + setRenameTestsetConfig, + setCurrent, + onCancel, +}) => { const classes = useStyles() + const router = useRouter() + const appId = router.query.app_id as string + const [testsetName, setTestsetName] = useState( + renameTestsetConfig ? (editTestsetValues?.name as string) : "", + ) + const [isLoading, setIsLoading] = useState(false) + const {mutate} = useLoadTestsetsList(appId) + + const handleCreateTestset = async () => { + try { + setIsLoading(true) + + const backendVariants = await fetchVariants(appId) + const variant = backendVariants[0] + const inputParams = await getVariantInputParameters(appId, variant) + const colData = inputParams.map((param) => ({field: param.name})) + colData.push({field: "correct_answer"}) + + const initialRowData = Array(3).fill({}) + const separateRowData = initialRowData.map(() => { + return colData.reduce((acc, curr) => ({...acc, [curr.field]: ""}), {}) + }) + + const response = await createNewTestset(appId, testsetName, separateRowData) + message.success("Test set created successfully") + router.push(`/apps/${appId}/testsets/${response.data.id}`) + } catch (error) { + console.error("Error saving test set:", error) + message.success("Failed to create Test set. Please try again!") + } finally { + setIsLoading(false) + } + } + + const handleCloneTestset = async () => { + try { + setIsLoading(true) + + const fetchTestsetValues = await fetchTestset(editTestsetValues?._id as string) + + if (fetchTestsetValues.csvdata) { + const response = await createNewTestset( + appId, + testsetName, + fetchTestsetValues.csvdata, + ) + message.success("Test set cloned successfully") + router.push(`/apps/${appId}/testsets/${response.data.id}`) + } else { + message.error("Failed to load intances") + } + } catch (error) { + message.error("Something went wrong. Please tru again later!") + } finally { + setIsLoading(false) + } + } + + const handleRenameTestset = async () => { + try { + setIsLoading(true) + + const fetchTestsetValues = await fetchTestset(editTestsetValues?._id as string) + + if (fetchTestsetValues.csvdata) { + await updateTestset( + editTestsetValues?._id as string, + testsetName, + fetchTestsetValues.csvdata, + ) + message.success("Test set renamed successfully") + mutate() + onCancel() + } else { + message.error("Failed to load intances") + } + } catch (error) { + message.error("Something went wrong. Please tru again later!") + } finally { + setIsLoading(false) + } + } + + const backForward = () => { + setCloneConfig(false) + setEditTestsetValues(null) + setCurrent(0) + setRenameTestsetConfig(false) + } + return (
- + +
) diff --git a/agenta-web/src/components/pages/testset/modals/UploadTestset.tsx b/agenta-web/src/components/pages/testset/modals/UploadTestset.tsx index dbebff975d..ef03d5b615 100644 --- a/agenta-web/src/components/pages/testset/modals/UploadTestset.tsx +++ b/agenta-web/src/components/pages/testset/modals/UploadTestset.tsx @@ -1,9 +1,15 @@ import React, {useState} from "react" -import {JSSTheme} from "@/lib/Types" +import {GenericObject, JSSTheme} from "@/lib/Types" import {ArrowLeft, FileCsv, Trash} from "@phosphor-icons/react" -import {Button, Collapse, Input, Radio, Typography} from "antd" +import {Button, Collapse, Form, Input, message, Radio, Typography, Upload, UploadFile} from "antd" import {createUseStyles} from "react-jss" import {UploadOutlined} from "@ant-design/icons" +import {isValidCSVFile, isValidJSONFile} from "@/lib/helpers/fileManipulations" +import axios from "axios" +import {useRouter} from "next/router" +import {getAgentaApiUrl} from "@/lib/helpers/utils" +import {globalErrorHandler} from "@/lib/helpers/errorHandler" +import {useLoadTestsetsList} from "@/services/testsets/api" const useStyles = createUseStyles((theme: JSSTheme) => ({ headerText: { @@ -22,10 +28,21 @@ const useStyles = createUseStyles((theme: JSSTheme) => ({ border: "1px solid", borderColor: theme.colorBorder, borderRadius: theme.borderRadiusLG, + position: "relative", + overflow: "hidden", }, subText: { color: theme.colorTextSecondary, }, + progressBar: { + position: "absolute", + top: 0, + bottom: 0, + left: 0, + right: 0, + backgroundColor: theme["cyan5"], + opacity: 0.4, + }, })) type Props = { @@ -35,7 +52,64 @@ type Props = { const UploadTestset: React.FC = ({setCurrent, onCancel}) => { const classes = useStyles() - const [uploadType, setUploadType] = useState<"csv" | "json">("csv") + const router = useRouter() + const [form] = Form.useForm() + const appId = router.query.app_id as string + const [uploadType, setUploadType] = useState<"JSON" | "CSV" | undefined>("CSV") + const [testsetName, setTestsetName] = useState("") + const [uploadLoading, setUploadLoading] = useState(false) + const [fileProgress, setFileProgress] = useState({} as UploadFile) + const {mutate} = useLoadTestsetsList(appId) + + const onFinish = async (values: any) => { + const {file} = values + const fileObj = file[0].originFileObj + const malformedFileError = `The file you uploaded is either malformed or is not a valid ${uploadType} file` + + if (file && file.length > 0 && uploadType) { + const isValidFile = await (uploadType == "CSV" + ? isValidCSVFile(fileObj) + : isValidJSONFile(fileObj)) + if (!isValidFile) { + message.error(malformedFileError) + return + } + + const formData = new FormData() + formData.append("upload_type", uploadType) + formData.append("file", fileObj) + if (values.testsetName && values.testsetName.trim() !== "") { + formData.append("testset_name", values.testsetName) + } + formData.append("app_id", appId) + + try { + setUploadLoading(true) + // TODO: move to api.ts + await axios.post(`${getAgentaApiUrl()}/api/testsets/upload/`, formData, { + headers: { + "Content-Type": "multipart/form-data", + }, + //@ts-ignore + _ignoreError: true, + }) + form.resetFields() + setTestsetName("") + mutate() + onCancel() + } catch (e: any) { + if ( + e?.response?.data?.detail?.find((item: GenericObject) => + item?.loc?.includes("csvdata"), + ) + ) + message.error(malformedFileError) + else globalErrorHandler(e) + } finally { + setUploadLoading(false) + } + } + } return (
@@ -55,14 +129,18 @@ const UploadTestset: React.FC = ({setCurrent, onCancel}) => {
Select type setUploadType(e.target.value)}> - CSV - JSON + CSV + JSON
Name of testset - + setTestsetName(e.target.value)} + />
@@ -70,17 +148,63 @@ const UploadTestset: React.FC = ({setCurrent, onCancel}) => { Upload CSV or JSON - + +
+ e.fileList} + className="mb-0" + rules={[{required: true}]} + > + { + setFileProgress(e.fileList[0]) + !testsetName && + setTestsetName( + e.fileList[0].name.split(".")[0] as string, + ) + }} + > + + + +
-
-
- - File-name -
+ {fileProgress.name && ( +
+ {fileProgress.status == "uploading" && ( +
+ )} +
+ {uploadType === "CSV" ? ( + + ) : ( + + )} + {fileProgress.name} +
- -
+ { + form.resetFields() + setTestsetName("") + setFileProgress({} as UploadFile) + }} + /> +
+ )}
@@ -93,7 +217,7 @@ const UploadTestset: React.FC = ({setCurrent, onCancel}) => { label: "Instructions", children: (
- {uploadType === "csv" ? ( + {uploadType === "CSV" ? ( <> {" "} @@ -153,8 +277,16 @@ const UploadTestset: React.FC = ({setCurrent, onCancel}) => {
- - + +
) diff --git a/agenta-web/src/components/pages/testset/modals/index.tsx b/agenta-web/src/components/pages/testset/modals/index.tsx index 5bb832edb2..964ec6381f 100644 --- a/agenta-web/src/components/pages/testset/modals/index.tsx +++ b/agenta-web/src/components/pages/testset/modals/index.tsx @@ -1,5 +1,5 @@ -import React, {useState} from "react" -import {JSSTheme} from "@/lib/Types" +import React from "react" +import {JSSTheme, testset} from "@/lib/Types" import {Modal} from "antd" import {createUseStyles} from "react-jss" import CreateTestset from "./CreateTestset" @@ -20,20 +20,56 @@ const useStyles = createUseStyles((theme: JSSTheme) => ({ }, })) -type Props = React.ComponentProps & {} +type Props = { + cloneConfig: boolean + setCloneConfig: React.Dispatch> + editTestsetValues: testset | null + setEditTestsetValues: React.Dispatch> + current: number + setCurrent: React.Dispatch> + renameTestsetConfig: boolean + setRenameTestsetConfig: React.Dispatch> +} & React.ComponentProps -const TestsetModal: React.FC = ({...props}) => { +const TestsetModal: React.FC = ({ + cloneConfig, + setCloneConfig, + editTestsetValues, + setEditTestsetValues, + current, + setCurrent, + renameTestsetConfig, + setRenameTestsetConfig, + ...props +}) => { const classes = useStyles() - const [current, setCurrent] = useState(0) const onCancel = () => props.onCancel?.({} as any) + const onCloseModal = () => { + setCloneConfig(false) + setEditTestsetValues(null) + setRenameTestsetConfig(false) + setCurrent(0) + } + const steps = [ { content: , }, { - content: , + content: ( + + ), }, { content: , @@ -45,7 +81,7 @@ const TestsetModal: React.FC = ({...props}) => { return ( setCurrent(0)} + afterClose={onCloseModal} footer={null} title={null} className={classes.modal} diff --git a/agenta-web/src/pages/apps/[app_id]/testsets/index.tsx b/agenta-web/src/pages/apps/[app_id]/testsets/index.tsx index b3e33041c7..f863f4ba37 100644 --- a/agenta-web/src/pages/apps/[app_id]/testsets/index.tsx +++ b/agenta-web/src/pages/apps/[app_id]/testsets/index.tsx @@ -41,6 +41,10 @@ const Testset = () => { const {testsets, isTestsetsLoading, mutate} = useLoadTestsetsList(appId) const [isCreateTestsetModalOpen, setIsCreateTestsetModalOpen] = useState(false) const [searchTerm, setSearchTerm] = useState("") + const [cloneConfig, setCloneConfig] = useState(false) + const [renameTestsetConfig, setRenameTestsetConfig] = useState(false) + const [editTestsetValues, setEditTestsetValues] = useState(null) + const [current, setCurrent] = useState(0) const rowSelection = { onChange: (selectedRowKeys: React.Key[]) => { @@ -48,7 +52,7 @@ const Testset = () => { }, } - const onDelete = async () => { + const onDeleteMultipleTestset = async () => { const testsetsIds = selectedRowKeys.map((key) => key.toString()) try { if ( @@ -64,6 +68,14 @@ const Testset = () => { } catch {} } + const onDelete = async (testsetsId: string[]) => { + try { + await deleteTestsets(testsetsId) + mutate() + setSelectedRowKeys([]) + } catch {} + } + const filteredTestset = useMemo(() => { return testsets ? testsets.filter((item: any) => @@ -151,27 +163,43 @@ const Testset = () => { icon: , onClick: (e) => { e.domEvent.stopPropagation() - router.push( - `/apps/${appId}/evaluations/single_model_test/${record}`, - ) + router.push(`/apps/${appId}/testsets/${record._id}`) }, }, { key: "clone", label: "Clone", icon: , + onClick: (e) => { + e.domEvent.stopPropagation() + setCloneConfig(true) + setEditTestsetValues(record) + setCurrent(1) + setIsCreateTestsetModalOpen(true) + }, }, {type: "divider"}, { key: "rename", label: "Rename", icon: , + onClick: (e) => { + e.domEvent.stopPropagation() + setRenameTestsetConfig(true) + setEditTestsetValues(record) + setCurrent(1) + setIsCreateTestsetModalOpen(true) + }, }, { key: "delete_eval", label: "Delete", icon: , danger: true, + onClick: (e) => { + e.domEvent.stopPropagation() + onDelete([record._id]) + }, }, ], }} @@ -216,7 +244,7 @@ const Testset = () => { icon={} className={classes.button} disabled={selectedRowKeys.length == 0} - onClick={onDelete} + onClick={onDeleteMultipleTestset} > Delete @@ -246,6 +274,14 @@ const Testset = () => { { setIsCreateTestsetModalOpen(false) From 17fae0c1bc475d05dabc6bc7f0f8a4c8b26e95a9 Mon Sep 17 00:00:00 2001 From: ashrafchowdury Date: Fri, 4 Oct 2024 14:15:11 +0600 Subject: [PATCH 03/16] ui(frontend): added import testset from endpoint --- .../pages/testset/modals/CreateTestset.tsx | 9 + .../modals/CreateTestsetFromEndpoint.tsx | 179 ++++++++++++++++++ .../components/pages/testset/modals/index.tsx | 11 ++ 3 files changed, 199 insertions(+) create mode 100644 agenta-web/src/components/pages/testset/modals/CreateTestsetFromEndpoint.tsx diff --git a/agenta-web/src/components/pages/testset/modals/CreateTestset.tsx b/agenta-web/src/components/pages/testset/modals/CreateTestset.tsx index 97d23c1dcb..ff126e3c91 100644 --- a/agenta-web/src/components/pages/testset/modals/CreateTestset.tsx +++ b/agenta-web/src/components/pages/testset/modals/CreateTestset.tsx @@ -1,3 +1,4 @@ +import { isDemo } from "@/lib/helpers/utils" import {JSSTheme} from "@/lib/Types" import {Typography} from "antd" import React from "react" @@ -60,6 +61,14 @@ const CreateTestset: React.FC = ({setCurrent}) => { Create a test set programmatically using our API endpoints + {!isDemo() && ( +
setCurrent(4)}> + Import from endpoint + + Import test set using your own endpoint + +
+ )} ) diff --git a/agenta-web/src/components/pages/testset/modals/CreateTestsetFromEndpoint.tsx b/agenta-web/src/components/pages/testset/modals/CreateTestsetFromEndpoint.tsx new file mode 100644 index 0000000000..d84667b07c --- /dev/null +++ b/agenta-web/src/components/pages/testset/modals/CreateTestsetFromEndpoint.tsx @@ -0,0 +1,179 @@ +import React, {useState} from "react" +import {JSSTheme} from "@/lib/Types" +import {ArrowLeft} from "@phosphor-icons/react" +import {Button, Collapse, Form, Input, message, Typography} from "antd" +import {createUseStyles} from "react-jss" +import {useRouter} from "next/router" +import {useLoadTestsetsList} from "@/services/testsets/api" +import {getAgentaApiUrl} from "@/lib/helpers/utils" +import axios from "@/lib/helpers/axiosConfig" + +const useStyles = createUseStyles((theme: JSSTheme) => ({ + headerText: { + lineHeight: theme.lineHeightLG, + fontSize: theme.fontSizeHeading4, + fontWeight: theme.fontWeightStrong, + }, + label: { + fontWeight: theme.fontWeightMedium, + }, +})) + +type FieldType = { + name: string + endpoint: string +} + +type Props = { + setCurrent: React.Dispatch> + onCancel: () => void +} + +const CreateTestsetFromEndpoint: React.FC = ({setCurrent, onCancel}) => { + const classes = useStyles() + const router = useRouter() + const [form] = Form.useForm() + const testsetName = Form.useWatch("name", form) + const testsetEndpoint = Form.useWatch("endpoint", form) + const appId = router.query.app_id as string + const [uploadLoading, setUploadLoading] = useState(false) + const {mutate} = useLoadTestsetsList(appId) + + const onFinish = async (values: FieldType) => { + if (values.name.trim() === "" || values.endpoint.trim() === "") { + message.error("Please fill out all fields") + return + } + + setUploadLoading(true) + + const formData = new FormData() + formData.append("endpoint", values.endpoint) + formData.append("testset_name", values.name) + formData.append("app_id", appId) + + try { + // TODO: move to api.ts + await axios.post(`${getAgentaApiUrl()}/api/testsets/endpoint/`, formData, { + headers: {"Content-Type": "multipart/form-data"}, + }) + mutate() + onCancel() + } catch (_) { + // Errors will be handled by Axios interceptor + // Do nothing here + } finally { + setUploadLoading(false) + } + } + + return ( +
+
+
+ +
+ Currently, we only support the JSON format + +
+
+ Test Set Name + + name="name" + rules={[{required: true, type: "string", whitespace: true}]} + className="mb-0" + > + + +
+ +
+ + Test Set Endpoint + + + name="endpoint" + rules={[{required: true, type: "url"}]} + className="mb-0" + > + + +
+ + +
+ + + Currently, we only support the JSON format which must + meet the following requirements: + +
+ + 1. A JSON with an array of rows + + + 2. Each row in the array should be an object of + column header name as key and row data as value + +
+
+                                            {JSON.stringify(
+                                                [
+                                                    {
+                                                        recipe_name: "Chicken Parmesan",
+                                                        correct_answer: "Chicken",
+                                                    },
+                                                    {
+                                                        recipe_name: "a, special, recipe",
+                                                        correct_answer: "Beef",
+                                                    },
+                                                ],
+                                                null,
+                                                2,
+                                            )}
+                                        
+ + +
+ ), + }, + ]} + /> +
+ + +
+ + +
+
+ ) +} + +export default CreateTestsetFromEndpoint diff --git a/agenta-web/src/components/pages/testset/modals/index.tsx b/agenta-web/src/components/pages/testset/modals/index.tsx index 964ec6381f..26fe6672f4 100644 --- a/agenta-web/src/components/pages/testset/modals/index.tsx +++ b/agenta-web/src/components/pages/testset/modals/index.tsx @@ -6,6 +6,8 @@ import CreateTestset from "./CreateTestset" import CreateTestsetFromScratch from "./CreateTestsetFromScratch" import UploadTestset from "./UploadTestset" import CreateTestsetFromApi from "./CreateTestsetFromApi" +import CreateTestsetFromEndpoint from "./CreateTestsetFromEndpoint" +import {isDemo} from "@/lib/helpers/utils" const useStyles = createUseStyles((theme: JSSTheme) => ({ modal: { @@ -77,6 +79,15 @@ const TestsetModal: React.FC = ({ { content: , }, + ...(!isDemo() + ? [ + { + content: ( + + ), + }, + ] + : []), ] return ( From 28f39056b7b2ea08ce45b8273995b6c2d0fb100c Mon Sep 17 00:00:00 2001 From: ashrafchowdury Date: Fri, 4 Oct 2024 15:20:09 +0600 Subject: [PATCH 04/16] refactor(frontend): removed older codes --- .../components/TestSetTable/TestsetTable.tsx | 45 +--- .../pages/testset/modals/CreateTestset.tsx | 2 +- .../pages/apps/[app_id]/testsets/index.tsx | 2 +- .../apps/[app_id]/testsets/new/api/index.tsx | 62 ------ .../[app_id]/testsets/new/endpoint/index.tsx | 128 ----------- .../[app_id]/testsets/new/manual/index.tsx | 5 - .../[app_id]/testsets/new/upload/index.tsx | 205 ------------------ 7 files changed, 6 insertions(+), 443 deletions(-) delete mode 100644 agenta-web/src/pages/apps/[app_id]/testsets/new/api/index.tsx delete mode 100644 agenta-web/src/pages/apps/[app_id]/testsets/new/endpoint/index.tsx delete mode 100644 agenta-web/src/pages/apps/[app_id]/testsets/new/manual/index.tsx delete mode 100644 agenta-web/src/pages/apps/[app_id]/testsets/new/upload/index.tsx diff --git a/agenta-web/src/components/TestSetTable/TestsetTable.tsx b/agenta-web/src/components/TestSetTable/TestsetTable.tsx index 872076b7cc..738958a2ca 100644 --- a/agenta-web/src/components/TestSetTable/TestsetTable.tsx +++ b/agenta-web/src/components/TestSetTable/TestsetTable.tsx @@ -4,8 +4,7 @@ import {IHeaderParams} from "ag-grid-community" import {createUseStyles} from "react-jss" import {Button, Input, Typography, message} from "antd" import TestsetMusHaveNameModal from "./InsertTestsetNameModal" -import {fetchVariants} from "@/services/api" -import {createNewTestset, fetchTestset, updateTestset} from "@/services/testsets/api" +import {fetchTestset, updateTestset} from "@/services/testsets/api" import {useRouter} from "next/router" import {useAppTheme} from "../Layout/ThemeContextProvider" import useBlockNavigation from "@/hooks/useBlockNavigation" @@ -13,7 +12,6 @@ import {useUpdateEffect} from "usehooks-ts" import useStateCallback from "@/hooks/useStateCallback" import {AxiosResponse} from "axios" import EditRowModal from "./EditRowModal" -import {getVariantInputParameters} from "@/lib/helpers/variantHelper" import {convertToCsv, downloadCsv} from "@/lib/helpers/fileManipulations" import {NoticeType} from "antd/es/message/interface" import {GenericObject, KeyValuePair} from "@/lib/Types" @@ -21,7 +19,7 @@ import TableCellsRenderer from "./TableCellsRenderer" import TableHeaderComponent from "./TableHeaderComponent" type TestsetTableProps = { - mode: "create" | "edit" + mode: "edit" } export type ColumnDefsType = {field: string; [key: string]: any} @@ -85,7 +83,6 @@ const TestsetTable: React.FC = ({mode}) => { const [inputValues, setInputValues] = useStateCallback(columnDefs.map((col) => col.field)) const [focusedRowData, setFocusedRowData] = useState() const [writeMode, setWriteMode] = useState(mode) - const [testsetId, setTestsetId] = useState(undefined) const gridRef = useRef(null) const [selectedRow, setSelectedRow] = useState([]) @@ -119,14 +116,6 @@ const TestsetTable: React.FC = ({mode}) => { async function applyColData(colData: {field: string}[] = []) { const newColDefs = createNewColDefs(colData) setColumnDefs(newColDefs) - if (writeMode === "create") { - const initialRowData = Array(3).fill({}) - const separateRowData = initialRowData.map(() => { - return colData.reduce((acc, curr) => ({...acc, [curr.field]: ""}), {}) - }) - - setRowData(separateRowData) - } setInputValues(newColDefs.filter((col) => !!col.field).map((col) => col.field)) } @@ -141,19 +130,6 @@ const TestsetTable: React.FC = ({mode}) => { })), ) }) - } else if (writeMode === "create" && appId) { - setIsDataChanged(true) - ;(async () => { - const backendVariants = await fetchVariants(appId) - const variant = backendVariants[0] - const inputParams = await getVariantInputParameters(appId, variant) - const colData = inputParams.map((param) => ({field: param.name})) - colData.push({field: "correct_answer"}) - - applyColData(colData) - })().catch(() => { - applyColData([]) - }) } }, [writeMode, testset_id, appId]) @@ -233,24 +209,11 @@ const TestsetTable: React.FC = ({mode}) => { } } - if (writeMode === "create") { - if (!testsetName) { - setIsModalOpen(true) - setIsLoading(false) - } else { - const response = await createNewTestset(appId, testsetName, rowData) - afterSave(response) - setTestsetId(response.data.id) - } - } else if (writeMode === "edit") { + if (writeMode === "edit") { if (!testsetName) { setIsModalOpen(true) } else { - const response = await updateTestset( - (testsetId || testset_id) as string, - testsetName, - rowData, - ) + const response = await updateTestset(testset_id as string, testsetName, rowData) afterSave(response) } } diff --git a/agenta-web/src/components/pages/testset/modals/CreateTestset.tsx b/agenta-web/src/components/pages/testset/modals/CreateTestset.tsx index ff126e3c91..5b9cf18cb4 100644 --- a/agenta-web/src/components/pages/testset/modals/CreateTestset.tsx +++ b/agenta-web/src/components/pages/testset/modals/CreateTestset.tsx @@ -1,4 +1,4 @@ -import { isDemo } from "@/lib/helpers/utils" +import {isDemo} from "@/lib/helpers/utils" import {JSSTheme} from "@/lib/Types" import {Typography} from "antd" import React from "react" diff --git a/agenta-web/src/pages/apps/[app_id]/testsets/index.tsx b/agenta-web/src/pages/apps/[app_id]/testsets/index.tsx index f863f4ba37..d91e70e1ca 100644 --- a/agenta-web/src/pages/apps/[app_id]/testsets/index.tsx +++ b/agenta-web/src/pages/apps/[app_id]/testsets/index.tsx @@ -130,7 +130,7 @@ const Testset = () => { style: {minWidth: 144}, }), render: (date: string) => { - return [1].map((tag) => Defailt) + return [1].map((tag) => Defailt) }, }, { diff --git a/agenta-web/src/pages/apps/[app_id]/testsets/new/api/index.tsx b/agenta-web/src/pages/apps/[app_id]/testsets/new/api/index.tsx deleted file mode 100644 index 829788c3e1..0000000000 --- a/agenta-web/src/pages/apps/[app_id]/testsets/new/api/index.tsx +++ /dev/null @@ -1,62 +0,0 @@ -import DynamicCodeBlock from "@/components/DynamicCodeBlock/DynamicCodeBlock" - -import pythonCode from "@/code_snippets/testsets/create_with_json/python" -import cURLCode from "@/code_snippets/testsets/create_with_json/curl" -import tsCode from "@/code_snippets/testsets/create_with_json/typescript" - -import pythonCodeUpload from "@/code_snippets/testsets/create_with_upload/python" -import cURLCodeUpload from "@/code_snippets/testsets/create_with_upload/curl" -import tsCodeUpload from "@/code_snippets/testsets/create_with_upload/typescript" -import {Typography} from "antd" -import {useRouter} from "next/router" -import {createUseStyles} from "react-jss" -import {getAgentaApiUrl} from "@/lib/helpers/utils" - -const useStyles = createUseStyles({ - title: { - marginBottom: "20px !important", - }, -}) - -export default function NewTestsetWithAPI() { - const classes = useStyles() - const router = useRouter() - const appId = router.query.app_id as string - - const uploadURI = `${getAgentaApiUrl()}/api/testsets/upload` - const jsonURI = `${getAgentaApiUrl()}/api/testsets/${appId}` - - const params = `{ - "name": "testset_name",}` - - const codeSnippets: Record = { - Python: pythonCode(jsonURI, params), - cURL: cURLCode(jsonURI, params), - TypeScript: tsCode(jsonURI, params), - } - - const codeSnippetsUpload: Record = { - Python: pythonCodeUpload(uploadURI, appId), - cURL: cURLCodeUpload(uploadURI, appId), - TypeScript: tsCodeUpload(uploadURI, appId), - } - return ( -
- - Create a new Test Set with JSON - - - Use this endpoint to create a new Test Set for your App. - - - - - Create a new Test Set with uploading a CSV file - - - Use this endpoint to create a new Test Set for your App. - - -
- ) -} diff --git a/agenta-web/src/pages/apps/[app_id]/testsets/new/endpoint/index.tsx b/agenta-web/src/pages/apps/[app_id]/testsets/new/endpoint/index.tsx deleted file mode 100644 index 673706a4d6..0000000000 --- a/agenta-web/src/pages/apps/[app_id]/testsets/new/endpoint/index.tsx +++ /dev/null @@ -1,128 +0,0 @@ -import axios from "@/lib/helpers/axiosConfig" -import {getAgentaApiUrl} from "@/lib/helpers/utils" -import {Alert, Button, Form, Input, Spin, Typography, message} from "antd" -import {useRouter} from "next/router" -import {useState} from "react" -import {createUseStyles} from "react-jss" - -const useStyles = createUseStyles({ - container: { - display: "flex", - flexDirection: "column", - rowGap: 20, - maxWidth: 800, - }, - json: { - overflow: "auto", - }, - buttonContainer: { - display: "flex", - flexDirection: "row", - justifyContent: "flex-end", - }, -}) - -type FieldType = { - name: string - endpoint: string -} - -export default function ImportTestsetFromEndpoint() { - const classes = useStyles() - - const router = useRouter() - const appId = router.query.app_id as string - - const handleSubmit = async (values: FieldType) => { - if (values.name.trim() === "" || values.endpoint.trim() === "") { - message.error("Please fill out all fields") - return - } - - setUploadLoading(true) - - const formData = new FormData() - formData.append("endpoint", values.endpoint) - formData.append("testset_name", values.name) - formData.append("app_id", appId) - - try { - // TODO: move to api.ts - await axios.post(`${getAgentaApiUrl()}/api/testsets/endpoint/`, formData, { - headers: {"Content-Type": "multipart/form-data"}, - }) - router.push(`/apps/${appId}/testsets`) - } catch (_) { - // Errors will be handled by Axios interceptor - // Do nothing here - } finally { - setUploadLoading(false) - } - } - - const [uploadLoading, setUploadLoading] = useState(false) - - return ( -
- Import a new Test Set from an endpoint - - - Currently, we only support the JSON format which must meet the following - requirements: -
    -
  1. A JSON with an array of rows
  2. -
  3. - Each row in the array should be an object of column header name as - key and row data as value -
  4. -
- Here is an example of a valid JSON file: -
-                            {JSON.stringify(
-                                [
-                                    {
-                                        recipe_name: "Chicken Parmesan",
-                                        correct_answer: "Chicken",
-                                    },
-                                    {recipe_name: "a, special, recipe", correct_answer: "Beef"},
-                                ],
-                                null,
-                                2,
-                            )}
-                        
- - } - type="info" - /> - - -
- - label="Test Set Name" - name="name" - rules={[{required: true, type: "string", whitespace: true}]} - > - - - - - label="Test Set Endpoint" - name="endpoint" - rules={[{required: true, type: "url"}]} - > - - - -
- -
- -
-
- ) -} diff --git a/agenta-web/src/pages/apps/[app_id]/testsets/new/manual/index.tsx b/agenta-web/src/pages/apps/[app_id]/testsets/new/manual/index.tsx deleted file mode 100644 index f2b6411688..0000000000 --- a/agenta-web/src/pages/apps/[app_id]/testsets/new/manual/index.tsx +++ /dev/null @@ -1,5 +0,0 @@ -import TestsetTable from "@/components/TestSetTable/TestsetTable" - -export default function testsetCreatePage() { - return -} diff --git a/agenta-web/src/pages/apps/[app_id]/testsets/new/upload/index.tsx b/agenta-web/src/pages/apps/[app_id]/testsets/new/upload/index.tsx deleted file mode 100644 index 0b8ecb2f7b..0000000000 --- a/agenta-web/src/pages/apps/[app_id]/testsets/new/upload/index.tsx +++ /dev/null @@ -1,205 +0,0 @@ -import {UploadOutlined} from "@ant-design/icons" -import {Alert, Button, Form, Input, Space, Spin, Upload, message} from "antd" -import {useState} from "react" -import axios from "@/lib/helpers/axiosConfig" -import {useRouter} from "next/router" -import {createUseStyles} from "react-jss" -import {isValidCSVFile, isValidJSONFile} from "@/lib/helpers/fileManipulations" -import {GenericObject} from "@/lib/Types" -import {globalErrorHandler} from "@/lib/helpers/errorHandler" -import {getAgentaApiUrl} from "@/lib/helpers/utils" - -const useStyles = createUseStyles({ - fileFormatBtn: { - display: "flex", - gap: "25px", - }, - container: { - width: "50%", - }, - alert: { - marginTop: 20, - marginBottom: 40, - }, - form: { - maxWidth: 600, - }, -}) - -export default function AddANewTestset() { - const classes = useStyles() - const router = useRouter() - const appId = router.query.app_id as string - const [form] = Form.useForm() - const [uploadLoading, setUploadLoading] = useState(false) - const [uploadType, setUploadType] = useState<"JSON" | "CSV" | undefined>("CSV") - - const onFinish = async (values: any) => { - const {file} = values - const fileObj = file[0].originFileObj - const malformedFileError = `The file you uploaded is either malformed or is not a valid ${uploadType} file` - - if (file && file.length > 0 && uploadType) { - const isValidFile = await (uploadType == "CSV" - ? isValidCSVFile(fileObj) - : isValidJSONFile(fileObj)) - if (!isValidFile) { - message.error(malformedFileError) - return - } - - const formData = new FormData() - formData.append("upload_type", uploadType) - formData.append("file", fileObj) - if (values.testsetName && values.testsetName.trim() !== "") { - formData.append("testset_name", values.testsetName) - } - formData.append("app_id", appId) - - try { - setUploadLoading(true) - // TODO: move to api.ts - await axios.post(`${getAgentaApiUrl()}/api/testsets/upload/`, formData, { - headers: { - "Content-Type": "multipart/form-data", - }, - //@ts-ignore - _ignoreError: true, - }) - form.resetFields() - router.push(`/apps/${appId}/testsets`) - } catch (e: any) { - if ( - e?.response?.data?.detail?.find((item: GenericObject) => - item?.loc?.includes("csvdata"), - ) - ) - message.error(malformedFileError) - else globalErrorHandler(e) - } finally { - setUploadLoading(false) - } - } - } - - const layout = { - labelCol: {span: 8}, - wrapperCol: {span: 16}, - } - - const tailLayout = { - wrapperCol: {offset: 8, span: 16}, - } - - return ( -
-
- - -
- - - The test set should be in {uploadType} format with the following - requirements: -
- {uploadType == "CSV" && ( - <> - 1. Comma separated values -
- 2. The first row should contain the headers -
-
- Here is an example of a valid CSV file: -
-
- recipe_name,correct_answer -
- Chicken Parmesan,Chicken -
- "a, special, recipe",Beef -
- - )} - {uploadType == "JSON" && ( - <> - 1. A json file with an array of rows -
- 2. Each row in the array should be an object -
- of column header name as key and row data as value -
-
- Here is an example of a valid JSON file: -
-
- {`[{ "recipe_name": "Chicken Parmesan","correct_answer": "Chicken" },`} -
- {`{ "recipe_name": "a, special, recipe","correct_answer": "Beef" }]`} - - )} - - } - type="info" - className={classes.alert} - /> -
- - -
- - - - e.fileList} - label="Test set source" - rules={[{required: true}]} - > - -

- -

-

- Click or drag a {uploadType} file to this area to upload -

-
-
- - - - - -
-
- ) -} From 70405e299ddff6371a79a0f0df686f3422522ae2 Mon Sep 17 00:00:00 2001 From: ashrafchowdury Date: Fri, 4 Oct 2024 17:14:30 +0600 Subject: [PATCH 05/16] test(frontend): fixed ccypress test --- agenta-web/cypress/e2e/testset.cy.ts | 29 +++++++++---------- .../cypress/support/commands/evaluations.ts | 8 +++-- .../pages/testset/modals/CreateTestset.tsx | 12 ++++++-- .../modals/CreateTestsetFromScratch.tsx | 2 ++ .../pages/testset/modals/UploadTestset.tsx | 10 +++++-- .../pages/apps/[app_id]/testsets/index.tsx | 18 ++++++++---- 6 files changed, 50 insertions(+), 29 deletions(-) diff --git a/agenta-web/cypress/e2e/testset.cy.ts b/agenta-web/cypress/e2e/testset.cy.ts index 0fda57278e..2c725482ff 100644 --- a/agenta-web/cypress/e2e/testset.cy.ts +++ b/agenta-web/cypress/e2e/testset.cy.ts @@ -18,21 +18,19 @@ describe("Testsets crud and UI functionality", () => { context("Testing creation process of testset", () => { beforeEach(() => { // navigate to the new testset page - cy.visit(`/apps/${app_id}/testsets/new/manual`) - }) - - it("Should navigates successfully to the new testset page", () => { - cy.url().should("include", "/testsets/new/manual") - }) - - it("Should not allow creation of a testset without a name", () => { - cy.get('[data-cy="testset-save-button"]').click() - cy.get('[data-cy="testset-name-reqd-error"]').should("be.visible") + cy.visit(`/apps/${app_id}/testsets`) }) it("Should successfully creates the testset and navigates to the list", () => { + cy.url().should("include", "/testsets") + cy.get('[data-cy="create-testset-modal-button"]').click() + cy.get(".ant-modal-content").should("exist") + cy.get('[data-cy="create-testset-from-scratch"]').click() + const testsetName = randString(8) cy.get('[data-cy="testset-name-input"]').type(testsetName) + cy.clickLinkAndWait('[data-cy="create-new-testset-button"]') + cy.get(".ag-row").should("have.length", 3) countries.forEach((country, index) => { cy.get(`.ag-center-cols-container .ag-row[row-index="${index}"]`).within(() => { @@ -51,7 +49,6 @@ describe("Testsets crud and UI functionality", () => { // validate that the new testset is in the list cy.get('[data-cy="app-testset-list"]').as("table") - cy.get("@table").get(".ant-table-pagination li a").last().click() cy.get("@table").contains(testsetName).as("tempTestSet").should("be.visible") }) }) @@ -64,19 +61,21 @@ describe("Testsets crud and UI functionality", () => { it("Should successfully upload a testset", () => { cy.url().should("include", "/testsets") - cy.clickLinkAndWait('[data-cy="testset-new-upload-link"]') - cy.url().should("include", "/testsets/new/upload") + + cy.get('[data-cy="create-testset-modal-button"]').click() + cy.get(".ant-modal-content").should("exist") + cy.get('[data-cy="upload-testset"]').click() + cy.get('[data-cy="upload-testset-file-name"]').type(testset_name) cy.get('[type="file"]').selectFile("cypress/data/countries-genders.csv", {force: true}) cy.wait(1000) cy.contains("countries-genders.csv").should("be.visible") - cy.get('[data-cy="testset-upload-button"]').click() + cy.clickLinkAndWait('[data-cy="testset-upload-button"]') }) it("Should check the uploaded testset is present", () => { cy.url().should("include", "/testsets") cy.get('[data-cy="app-testset-list"]').as("table") - cy.get("@table").get(".ant-table-pagination li a").last().click() cy.get("@table").contains(testset_name).as("tempTestSet").should("be.visible") }) }) diff --git a/agenta-web/cypress/support/commands/evaluations.ts b/agenta-web/cypress/support/commands/evaluations.ts index a375cb6003..298e0a3c95 100644 --- a/agenta-web/cypress/support/commands/evaluations.ts +++ b/agenta-web/cypress/support/commands/evaluations.ts @@ -58,11 +58,13 @@ Cypress.Commands.add("createVariantsAndTestsets", () => { cy.createVariant() cy.clickLinkAndWait('[data-cy="app-testsets-link"]') - cy.get('[data-cy="app-testsets-link"]').trigger("mouseout") - cy.clickLinkAndWait('[data-cy="testset-new-manual-link"]') - const testsetName = randString(5) + cy.get('[data-cy="create-testset-modal-button"]').click() + cy.get(".ant-modal-content").should("exist") + cy.get('[data-cy="create-testset-from-scratch"]').click() + const testsetName = randString(5) cy.get('[data-cy="testset-name-input"]').type(testsetName) + cy.clickLinkAndWait('[data-cy="create-new-testset-button"]') cy.wrap(testsetName).as("testsetName") cy.get(".ag-row").should("have.length", 3) diff --git a/agenta-web/src/components/pages/testset/modals/CreateTestset.tsx b/agenta-web/src/components/pages/testset/modals/CreateTestset.tsx index 5b9cf18cb4..c831977fc6 100644 --- a/agenta-web/src/components/pages/testset/modals/CreateTestset.tsx +++ b/agenta-web/src/components/pages/testset/modals/CreateTestset.tsx @@ -45,13 +45,21 @@ const CreateTestset: React.FC = ({setCurrent}) => {
Create new test set
-
setCurrent(1)}> +
setCurrent(1)} + data-cy="create-testset-from-scratch" + > Create from scratch Create a new test set directly from the webUI
-
setCurrent(2)}> +
setCurrent(2)} + data-cy="upload-testset" + > Upload a test set Upload your test set as CSV or JSON
diff --git a/agenta-web/src/components/pages/testset/modals/CreateTestsetFromScratch.tsx b/agenta-web/src/components/pages/testset/modals/CreateTestsetFromScratch.tsx index d744cff410..53e60a296b 100644 --- a/agenta-web/src/components/pages/testset/modals/CreateTestsetFromScratch.tsx +++ b/agenta-web/src/components/pages/testset/modals/CreateTestsetFromScratch.tsx @@ -158,6 +158,7 @@ const CreateTestsetFromScratch: React.FC = ({ placeholder="Enter a name" value={testsetName} onChange={(e) => setTestsetName(e.target.value)} + data-cy="testset-name-input" />
@@ -174,6 +175,7 @@ const CreateTestsetFromScratch: React.FC = ({ !cloneConfig && !renameTestsetConfig ? handleCreateTestset() : null }} loading={isLoading} + data-cy="create-new-testset-button" > Create test set diff --git a/agenta-web/src/components/pages/testset/modals/UploadTestset.tsx b/agenta-web/src/components/pages/testset/modals/UploadTestset.tsx index ef03d5b615..e4bb4a2f62 100644 --- a/agenta-web/src/components/pages/testset/modals/UploadTestset.tsx +++ b/agenta-web/src/components/pages/testset/modals/UploadTestset.tsx @@ -54,6 +54,7 @@ const UploadTestset: React.FC = ({setCurrent, onCancel}) => { const classes = useStyles() const router = useRouter() const [form] = Form.useForm() + const testsetFile = Form.useWatch("file", form) const appId = router.query.app_id as string const [uploadType, setUploadType] = useState<"JSON" | "CSV" | undefined>("CSV") const [testsetName, setTestsetName] = useState("") @@ -78,8 +79,8 @@ const UploadTestset: React.FC = ({setCurrent, onCancel}) => { const formData = new FormData() formData.append("upload_type", uploadType) formData.append("file", fileObj) - if (values.testsetName && values.testsetName.trim() !== "") { - formData.append("testset_name", values.testsetName) + if (testsetName && testsetName.trim() !== "") { + formData.append("testset_name", testsetName) } formData.append("app_id", appId) @@ -140,6 +141,7 @@ const UploadTestset: React.FC = ({setCurrent, onCancel}) => { placeholder="Enter a name" value={testsetName} onChange={(e) => setTestsetName(e.target.value)} + data-cy="upload-testset-file-name" />
@@ -281,9 +283,11 @@ const UploadTestset: React.FC = ({setCurrent, onCancel}) => { Cancel diff --git a/agenta-web/src/pages/apps/[app_id]/testsets/index.tsx b/agenta-web/src/pages/apps/[app_id]/testsets/index.tsx index d91e70e1ca..a7a3954501 100644 --- a/agenta-web/src/pages/apps/[app_id]/testsets/index.tsx +++ b/agenta-web/src/pages/apps/[app_id]/testsets/index.tsx @@ -90,7 +90,7 @@ const Testset = () => { dataIndex: "name", key: "name", onHeaderCell: () => ({ - style: {minWidth: 160}, + style: {minWidth: 220}, }), }, { @@ -98,7 +98,7 @@ const Testset = () => { dataIndex: "date_modified", key: "date_modified", onHeaderCell: () => ({ - style: {minWidth: 160}, + style: {minWidth: 220}, }), render: (date: string) => { return formatDate(date) @@ -108,6 +108,9 @@ const Testset = () => { title: "Modified By", dataIndex: "modified_by", key: "modified_by", + onHeaderCell: () => ({ + style: {minWidth: 220}, + }), render: (date: string) => { return (
@@ -127,7 +130,7 @@ const Testset = () => { dataIndex: "tags", key: "tags", onHeaderCell: () => ({ - style: {minWidth: 144}, + style: {minWidth: 160}, }), render: (date: string) => { return [1].map((tag) => Defailt) @@ -135,13 +138,13 @@ const Testset = () => { }, { title: "Date created", - dataIndex: "date_created", - key: "date_created", + dataIndex: "created_at", + key: "created_at", render: (date: string) => { return formatDate(date) }, onHeaderCell: () => ({ - style: {minWidth: 160}, + style: {minWidth: 220}, }), }, { @@ -228,6 +231,7 @@ const Testset = () => { type="primary" icon={} onClick={() => setIsCreateTestsetModalOpen(true)} + data-cy="create-testset-modal-button" > Create new test set @@ -258,11 +262,13 @@ const Testset = () => { columnWidth: 48, ...rowSelection, }} + data-cy="app-testset-list" className="ph-no-capture" columns={columns} dataSource={filteredTestset} rowKey="_id" loading={isTestsetsLoading} + scroll={{x: true}} bordered pagination={false} onRow={(record) => { From a3cf416814df7e714aec37557c4d0b4f5127db66 Mon Sep 17 00:00:00 2001 From: ashrafchowdury Date: Fri, 4 Oct 2024 18:10:54 +0600 Subject: [PATCH 06/16] enhance(frontend): improved code structure --- .../modals/CreateTestsetFromEndpoint.tsx | 9 +--- .../modals/CreateTestsetFromScratch.tsx | 41 ++++++++----------- .../pages/testset/modals/UploadTestset.tsx | 13 +----- agenta-web/src/services/testsets/api/index.ts | 18 ++++++++ 4 files changed, 40 insertions(+), 41 deletions(-) diff --git a/agenta-web/src/components/pages/testset/modals/CreateTestsetFromEndpoint.tsx b/agenta-web/src/components/pages/testset/modals/CreateTestsetFromEndpoint.tsx index d84667b07c..1388ff7517 100644 --- a/agenta-web/src/components/pages/testset/modals/CreateTestsetFromEndpoint.tsx +++ b/agenta-web/src/components/pages/testset/modals/CreateTestsetFromEndpoint.tsx @@ -4,9 +4,7 @@ import {ArrowLeft} from "@phosphor-icons/react" import {Button, Collapse, Form, Input, message, Typography} from "antd" import {createUseStyles} from "react-jss" import {useRouter} from "next/router" -import {useLoadTestsetsList} from "@/services/testsets/api" -import {getAgentaApiUrl} from "@/lib/helpers/utils" -import axios from "@/lib/helpers/axiosConfig" +import {importTestsetsViaEndpoint, useLoadTestsetsList} from "@/services/testsets/api" const useStyles = createUseStyles((theme: JSSTheme) => ({ headerText: { @@ -53,10 +51,7 @@ const CreateTestsetFromEndpoint: React.FC = ({setCurrent, onCancel}) => { formData.append("app_id", appId) try { - // TODO: move to api.ts - await axios.post(`${getAgentaApiUrl()}/api/testsets/endpoint/`, formData, { - headers: {"Content-Type": "multipart/form-data"}, - }) + await importTestsetsViaEndpoint(formData) mutate() onCancel() } catch (_) { diff --git a/agenta-web/src/components/pages/testset/modals/CreateTestsetFromScratch.tsx b/agenta-web/src/components/pages/testset/modals/CreateTestsetFromScratch.tsx index 53e60a296b..700b5c4632 100644 --- a/agenta-web/src/components/pages/testset/modals/CreateTestsetFromScratch.tsx +++ b/agenta-web/src/components/pages/testset/modals/CreateTestsetFromScratch.tsx @@ -54,22 +54,25 @@ const CreateTestsetFromScratch: React.FC = ({ const [isLoading, setIsLoading] = useState(false) const {mutate} = useLoadTestsetsList(appId) - const handleCreateTestset = async () => { + const handleCreateTestset = async (data?: KeyValuePair[]) => { try { setIsLoading(true) + let rowData = data + + if (!rowData) { + const backendVariants = await fetchVariants(appId) + const variant = backendVariants[0] + const inputParams = await getVariantInputParameters(appId, variant) + const colData = inputParams.map((param) => ({field: param.name})) + colData.push({field: "correct_answer"}) + + const initialRowData = Array(3).fill({}) + rowData = initialRowData.map(() => { + return colData.reduce((acc, curr) => ({...acc, [curr.field]: ""}), {}) + }) + } - const backendVariants = await fetchVariants(appId) - const variant = backendVariants[0] - const inputParams = await getVariantInputParameters(appId, variant) - const colData = inputParams.map((param) => ({field: param.name})) - colData.push({field: "correct_answer"}) - - const initialRowData = Array(3).fill({}) - const separateRowData = initialRowData.map(() => { - return colData.reduce((acc, curr) => ({...acc, [curr.field]: ""}), {}) - }) - - const response = await createNewTestset(appId, testsetName, separateRowData) + const response = await createNewTestset(appId, testsetName, rowData) message.success("Test set created successfully") router.push(`/apps/${appId}/testsets/${response.data.id}`) } catch (error) { @@ -87,19 +90,11 @@ const CreateTestsetFromScratch: React.FC = ({ const fetchTestsetValues = await fetchTestset(editTestsetValues?._id as string) if (fetchTestsetValues.csvdata) { - const response = await createNewTestset( - appId, - testsetName, - fetchTestsetValues.csvdata, - ) - message.success("Test set cloned successfully") - router.push(`/apps/${appId}/testsets/${response.data.id}`) + await handleCreateTestset(fetchTestsetValues.csvdata) } else { message.error("Failed to load intances") } } catch (error) { - message.error("Something went wrong. Please tru again later!") - } finally { setIsLoading(false) } } @@ -123,7 +118,7 @@ const CreateTestsetFromScratch: React.FC = ({ message.error("Failed to load intances") } } catch (error) { - message.error("Something went wrong. Please tru again later!") + message.error("Something went wrong. Please try again later!") } finally { setIsLoading(false) } diff --git a/agenta-web/src/components/pages/testset/modals/UploadTestset.tsx b/agenta-web/src/components/pages/testset/modals/UploadTestset.tsx index e4bb4a2f62..9819b9ccaf 100644 --- a/agenta-web/src/components/pages/testset/modals/UploadTestset.tsx +++ b/agenta-web/src/components/pages/testset/modals/UploadTestset.tsx @@ -5,11 +5,9 @@ import {Button, Collapse, Form, Input, message, Radio, Typography, Upload, Uploa import {createUseStyles} from "react-jss" import {UploadOutlined} from "@ant-design/icons" import {isValidCSVFile, isValidJSONFile} from "@/lib/helpers/fileManipulations" -import axios from "axios" import {useRouter} from "next/router" -import {getAgentaApiUrl} from "@/lib/helpers/utils" import {globalErrorHandler} from "@/lib/helpers/errorHandler" -import {useLoadTestsetsList} from "@/services/testsets/api" +import {uploadTestsets, useLoadTestsetsList} from "@/services/testsets/api" const useStyles = createUseStyles((theme: JSSTheme) => ({ headerText: { @@ -86,14 +84,7 @@ const UploadTestset: React.FC = ({setCurrent, onCancel}) => { try { setUploadLoading(true) - // TODO: move to api.ts - await axios.post(`${getAgentaApiUrl()}/api/testsets/upload/`, formData, { - headers: { - "Content-Type": "multipart/form-data", - }, - //@ts-ignore - _ignoreError: true, - }) + await uploadTestsets(formData) form.resetFields() setTestsetName("") mutate() diff --git a/agenta-web/src/services/testsets/api/index.ts b/agenta-web/src/services/testsets/api/index.ts index b4806ccc1f..3e9a085719 100644 --- a/agenta-web/src/services/testsets/api/index.ts +++ b/agenta-web/src/services/testsets/api/index.ts @@ -60,6 +60,24 @@ export const fetchTestset = async (testsetId: string | null) => { return response.data } +export const uploadTestsets = async (formData: FormData) => { + const response = await axios.post(`${getAgentaApiUrl()}/api/testsets/upload/`, formData, { + headers: { + "Content-Type": "multipart/form-data", + }, + //@ts-ignore + _ignoreError: true, + }) + return response +} + +export const importTestsetsViaEndpoint = async (formData: FormData) => { + const response = await axios.post(`${getAgentaApiUrl()}/api/testsets/endpoint/`, formData, { + headers: {"Content-Type": "multipart/form-data"}, + }) + return response +} + export const deleteTestsets = async (ids: string[]) => { const response = await axios({ method: "delete", From 189cbdf912c0631276cb457f7af1819b6cc32022 Mon Sep 17 00:00:00 2001 From: ashrafchowdury Date: Fri, 4 Oct 2024 20:55:21 +0600 Subject: [PATCH 07/16] fix(backend): testset updated_at time update issue --- .../models/api/testset_model.py | 2 + .../agenta_backend/routers/testset_router.py | 4 +- agenta-web/src/lib/Types.ts | 1 + .../pages/apps/[app_id]/testsets/index.tsx | 68 +++++++++---------- 4 files changed, 40 insertions(+), 35 deletions(-) diff --git a/agenta-backend/agenta_backend/models/api/testset_model.py b/agenta-backend/agenta_backend/models/api/testset_model.py index a5c82b230c..d07045805e 100644 --- a/agenta-backend/agenta_backend/models/api/testset_model.py +++ b/agenta-backend/agenta_backend/models/api/testset_model.py @@ -24,6 +24,7 @@ class TestSetSimpleResponse(BaseModel): id: str name: str created_at: str + updated_at: str class DeleteTestsets(BaseModel): @@ -48,6 +49,7 @@ class TestSetOutputResponse(BaseModel): id: str = Field(..., alias="_id") name: str created_at: str + updated_at: str class Config: allow_population_by_field_name = True diff --git a/agenta-backend/agenta_backend/routers/testset_router.py b/agenta-backend/agenta_backend/routers/testset_router.py index ddd39bcc26..05268749cf 100644 --- a/agenta-backend/agenta_backend/routers/testset_router.py +++ b/agenta-backend/agenta_backend/routers/testset_router.py @@ -5,7 +5,7 @@ import logging import requests from typing import Optional, List - +from datetime import datetime, timezone from pydantic import ValidationError from fastapi.responses import JSONResponse @@ -298,6 +298,7 @@ async def update_testset( testset_update = { "name": csvdata.name, "csvdata": csvdata.csvdata, + "updated_at": datetime.now(timezone.utc), } await db_manager.update_testset( testset_id=str(testset.id), values_to_update=testset_update @@ -351,6 +352,7 @@ async def get_testsets( _id=str(testset.id), # type: ignore name=testset.name, created_at=str(testset.created_at), + updated_at=str(testset.updated_at), ) for testset in testsets ] diff --git a/agenta-web/src/lib/Types.ts b/agenta-web/src/lib/Types.ts index b592aebd67..3b827ef9c0 100644 --- a/agenta-web/src/lib/Types.ts +++ b/agenta-web/src/lib/Types.ts @@ -8,6 +8,7 @@ export interface testset { _id: string name: string created_at: string + updated_at: string } export interface TestSet { diff --git a/agenta-web/src/pages/apps/[app_id]/testsets/index.tsx b/agenta-web/src/pages/apps/[app_id]/testsets/index.tsx index a7a3954501..29f3e5d0a2 100644 --- a/agenta-web/src/pages/apps/[app_id]/testsets/index.tsx +++ b/agenta-web/src/pages/apps/[app_id]/testsets/index.tsx @@ -95,8 +95,8 @@ const Testset = () => { }, { title: "Date Modified", - dataIndex: "date_modified", - key: "date_modified", + dataIndex: "updated_at", + key: "updated_at", onHeaderCell: () => ({ style: {minWidth: 220}, }), @@ -104,38 +104,38 @@ const Testset = () => { return formatDate(date) }, }, - { - title: "Modified By", - dataIndex: "modified_by", - key: "modified_by", - onHeaderCell: () => ({ - style: {minWidth: 220}, - }), - render: (date: string) => { - return ( -
- - A - - Username -
- ) - }, - }, - { - title: "Tags", - dataIndex: "tags", - key: "tags", - onHeaderCell: () => ({ - style: {minWidth: 160}, - }), - render: (date: string) => { - return [1].map((tag) => Defailt) - }, - }, + // { + // title: "Modified By", + // dataIndex: "modified_by", + // key: "modified_by", + // onHeaderCell: () => ({ + // style: {minWidth: 220}, + // }), + // render: (date: string) => { + // return ( + //
+ // + // A + // + // Username + //
+ // ) + // }, + // }, + // { + // title: "Tags", + // dataIndex: "tags", + // key: "tags", + // onHeaderCell: () => ({ + // style: {minWidth: 160}, + // }), + // render: (date: string) => { + // return [1].map((tag) => Defailt) + // }, + // }, { title: "Date created", dataIndex: "created_at", From bb0dd9f82089219d0ced2759071479cf8e15160c Mon Sep 17 00:00:00 2001 From: ashrafchowdury Date: Fri, 4 Oct 2024 21:27:51 +0600 Subject: [PATCH 08/16] fix(frontend): minor alignment issues --- .../testset/modals/CreateTestsetFromApi.tsx | 4 +-- .../pages/apps/[app_id]/testsets/index.tsx | 35 ++++++++++++------- 2 files changed, 24 insertions(+), 15 deletions(-) diff --git a/agenta-web/src/components/pages/testset/modals/CreateTestsetFromApi.tsx b/agenta-web/src/components/pages/testset/modals/CreateTestsetFromApi.tsx index 947cdf55f1..ed411dc488 100644 --- a/agenta-web/src/components/pages/testset/modals/CreateTestsetFromApi.tsx +++ b/agenta-web/src/components/pages/testset/modals/CreateTestsetFromApi.tsx @@ -148,7 +148,7 @@ const CreateTestsetFromApi: React.FC = ({setCurrent, onCancel}) => { selectedLang={selectedLang} /> ), - icon: , + icon: , }, { key: "bash", @@ -159,7 +159,7 @@ const CreateTestsetFromApi: React.FC = ({setCurrent, onCancel}) => { selectedLang={selectedLang} /> ), - icon: , + icon: , }, ]} /> diff --git a/agenta-web/src/pages/apps/[app_id]/testsets/index.tsx b/agenta-web/src/pages/apps/[app_id]/testsets/index.tsx index 29f3e5d0a2..04d07c4c0f 100644 --- a/agenta-web/src/pages/apps/[app_id]/testsets/index.tsx +++ b/agenta-web/src/pages/apps/[app_id]/testsets/index.tsx @@ -22,15 +22,27 @@ const useStyles = createUseStyles((theme: JSSTheme) => ({ }, }, }, - headingTest: { - fontSize: theme.fontSizeHeading4, - lineHeight: theme.lineHeightHeading4, - fontWeight: theme.fontWeightMedium, + headerText: { + display: "flex", + alignItems: "center", + justifyContent: "space-between", + "& > .ant-typography": { + fontSize: theme.fontSizeHeading4, + lineHeight: theme.lineHeightHeading4, + fontWeight: theme.fontWeightMedium, + margin: 0, + }, }, button: { display: "flex", alignItems: "center", }, + table: { + "& table": { + border: "1px solid", + borderColor: theme.colorBorderSecondary, + }, + }, })) const Testset = () => { @@ -221,15 +233,13 @@ const Testset = () => { return ( <> -
-
- - Test sets - +
+
+ Test sets
- Create a new test set directly from the webUI + Create a new test set directly from the webUI
- Select type + Select type setUploadType(e.target.value)}> CSV JSON
- - Use this endpoint to create a new Test set for your App using JSON - + Use this endpoint to create a new Test set for your App using JSON
= ({setCurrent, onCancel}) => {
- + + + +
diff --git a/agenta-web/src/components/pages/testset/modals/CreateTestsetFromEndpoint.tsx b/agenta-web/src/components/pages/testset/modals/CreateTestsetFromEndpoint.tsx index 1388ff7517..4067574e53 100644 --- a/agenta-web/src/components/pages/testset/modals/CreateTestsetFromEndpoint.tsx +++ b/agenta-web/src/components/pages/testset/modals/CreateTestsetFromEndpoint.tsx @@ -6,6 +6,8 @@ import {createUseStyles} from "react-jss" import {useRouter} from "next/router" import {importTestsetsViaEndpoint, useLoadTestsetsList} from "@/services/testsets/api" +const {Text} = Typography + const useStyles = createUseStyles((theme: JSSTheme) => ({ headerText: { lineHeight: theme.lineHeightLG, @@ -71,17 +73,15 @@ const CreateTestsetFromEndpoint: React.FC = ({setCurrent, onCancel}) => { onClick={() => setCurrent(0)} /> - - Import from endpoint - + Import from endpoint
- Currently, we only support the JSON format + Currently, we only support the JSON format
- Test Set Name + Test Set Name name="name" rules={[{required: true, type: "string", whitespace: true}]} @@ -92,9 +92,7 @@ const CreateTestsetFromEndpoint: React.FC = ({setCurrent, onCancel}) => {
- - Test Set Endpoint - + Test Set Endpoint name="endpoint" rules={[{required: true, type: "url"}]} @@ -115,18 +113,16 @@ const CreateTestsetFromEndpoint: React.FC = ({setCurrent, onCancel}) => { label: "Instructions", children: (
- + Currently, we only support the JSON format which must meet the following requirements: - +
- - 1. A JSON with an array of rows - - + 1. A JSON with an array of rows + 2. Each row in the array should be an object of column header name as key and row data as value - +
                                             {JSON.stringify(
@@ -144,8 +140,12 @@ const CreateTestsetFromEndpoint: React.FC = ({setCurrent, onCancel}) => {
                                                 2,
                                             )}
                                         
- - + + +
), }, diff --git a/agenta-web/src/components/pages/testset/modals/CreateTestsetFromScratch.tsx b/agenta-web/src/components/pages/testset/modals/CreateTestsetFromScratch.tsx index 700b5c4632..f9c5c74274 100644 --- a/agenta-web/src/components/pages/testset/modals/CreateTestsetFromScratch.tsx +++ b/agenta-web/src/components/pages/testset/modals/CreateTestsetFromScratch.tsx @@ -13,6 +13,8 @@ import { import {fetchVariants} from "@/services/api" import {getVariantInputParameters} from "@/lib/helpers/variantHelper" +const {Text} = Typography + const useStyles = createUseStyles((theme: JSSTheme) => ({ headerText: { lineHeight: theme.lineHeightLG, @@ -140,15 +142,19 @@ const CreateTestsetFromScratch: React.FC = ({ onClick={backForward} /> - - Create from scratch - + + {cloneConfig + ? "Clone Test set" + : renameTestsetConfig + ? "Rename Test set" + : "Create from scratch"} +
- Create a new test set directly from the webUI + Create a new test set directly from the webUI
- Name of testset + Name of testset = ({ type="primary" disabled={!testsetName} onClick={() => { - cloneConfig && handleCloneTestset() - renameTestsetConfig && handleRenameTestset() - !cloneConfig && !renameTestsetConfig ? handleCreateTestset() : null + cloneConfig + ? handleCloneTestset() + : renameTestsetConfig + ? handleRenameTestset() + : handleCreateTestset() }} loading={isLoading} data-cy="create-new-testset-button" diff --git a/agenta-web/src/components/pages/testset/modals/UploadTestset.tsx b/agenta-web/src/components/pages/testset/modals/UploadTestset.tsx index 9819b9ccaf..26cf0be7da 100644 --- a/agenta-web/src/components/pages/testset/modals/UploadTestset.tsx +++ b/agenta-web/src/components/pages/testset/modals/UploadTestset.tsx @@ -1,6 +1,6 @@ import React, {useState} from "react" import {GenericObject, JSSTheme} from "@/lib/Types" -import {ArrowLeft, FileCsv, Trash} from "@phosphor-icons/react" +import {ArrowLeft, FileCode, FileCsv, Trash} from "@phosphor-icons/react" import {Button, Collapse, Form, Input, message, Radio, Typography, Upload, UploadFile} from "antd" import {createUseStyles} from "react-jss" import {UploadOutlined} from "@ant-design/icons" @@ -9,6 +9,8 @@ import {useRouter} from "next/router" import {globalErrorHandler} from "@/lib/helpers/errorHandler" import {uploadTestsets, useLoadTestsetsList} from "@/services/testsets/api" +const {Text} = Typography + const useStyles = createUseStyles((theme: JSSTheme) => ({ headerText: { lineHeight: theme.lineHeightLG, @@ -29,8 +31,9 @@ const useStyles = createUseStyles((theme: JSSTheme) => ({ position: "relative", overflow: "hidden", }, - subText: { + trashIcon: { color: theme.colorTextSecondary, + cursor: "pointer", }, progressBar: { position: "absolute", @@ -39,7 +42,7 @@ const useStyles = createUseStyles((theme: JSSTheme) => ({ left: 0, right: 0, backgroundColor: theme["cyan5"], - opacity: 0.4, + opacity: 0.3, }, })) @@ -112,14 +115,14 @@ const UploadTestset: React.FC = ({setCurrent, onCancel}) => { onClick={() => setCurrent(0)} /> - Upload a test set + Upload a test set
- Create a new test set directly from the webUI + Create a new test set directly from the webUI
- Select type + Select type setUploadType(e.target.value)}> CSV JSON @@ -127,7 +130,7 @@ const UploadTestset: React.FC = ({setCurrent, onCancel}) => {
- Name of testset + Name of testset = ({setCurrent, onCancel}) => {
- - Upload CSV or JSON - + Upload CSV or JSON = ({setCurrent, onCancel}) => { {uploadType === "CSV" ? ( ) : ( - + )} - {fileProgress.name} + {fileProgress.name}
{ form.resetFields() setTestsetName("") @@ -212,18 +213,15 @@ const UploadTestset: React.FC = ({setCurrent, onCancel}) => {
{uploadType === "CSV" ? ( <> - {" "} - + The test set should be in CSV format with the following requirements: - +
- - 1. Comma separated values - - + 1. Comma separated values + 2. The first row should contain the headers - +
Here is an example of a valid CSV file:
@@ -234,33 +232,50 @@ const UploadTestset: React.FC = ({setCurrent, onCancel}) => { ) : ( <> - + The test set should be in JSON format with the following requirements: - +
- + 1. A json file with an array of rows - - + + 2. Each row in the array should be an object - - + + of column header name as key and row data as value. - +
Here is an example of a valid JSON file:
- {`[{ "recipe_name": "Chicken Parmesan","correct_answer": "Chicken" }, -{ "recipe_name": "a, special, recipe","correct_answer": "Beef" }]`} + {JSON.stringify( + [ + { + recipe_name: "Chicken Parmesan", + correct_answer: "Chicken", + }, + { + recipe_name: "a, special, recipe", + correct_answer: "Beef", + }, + ], + null, + 2, + )}
)} - + + +
), }, diff --git a/agenta-web/src/pages/apps/[app_id]/testsets/index.tsx b/agenta-web/src/pages/apps/[app_id]/testsets/index.tsx index 04d07c4c0f..eade596944 100644 --- a/agenta-web/src/pages/apps/[app_id]/testsets/index.tsx +++ b/agenta-web/src/pages/apps/[app_id]/testsets/index.tsx @@ -1,3 +1,4 @@ +import React, {useMemo, useState} from "react" import TestsetModal from "@/components/pages/testset/modals" import {formatDate} from "@/lib/helpers/dateTimeHelper" import {checkIfResourceValidForDeletion} from "@/lib/helpers/evaluate" @@ -8,7 +9,6 @@ import {Copy, GearSix, Note, PencilSimple, Trash} from "@phosphor-icons/react" import {Avatar, Button, Dropdown, Input, Spin, Table, Tag, Typography} from "antd" import {ColumnsType} from "antd/es/table/interface" import {useRouter} from "next/router" -import React, {useMemo, useState} from "react" import {createUseStyles} from "react-jss" const useStyles = createUseStyles((theme: JSSTheme) => ({ @@ -64,8 +64,8 @@ const Testset = () => { }, } - const onDeleteMultipleTestset = async () => { - const testsetsIds = selectedRowKeys.map((key) => key.toString()) + const onDelete = async (testsetsId?: string[]) => { + const testsetsIds = !testsetsId ? selectedRowKeys.map((key) => key.toString()) : testsetsId try { if ( !(await checkIfResourceValidForDeletion({ @@ -80,14 +80,6 @@ const Testset = () => { } catch {} } - const onDelete = async (testsetsId: string[]) => { - try { - await deleteTestsets(testsetsId) - mutate() - setSelectedRowKeys([]) - } catch {} - } - const filteredTestset = useMemo(() => { return testsets ? testsets.filter((item: any) => @@ -116,38 +108,6 @@ const Testset = () => { return formatDate(date) }, }, - // { - // title: "Modified By", - // dataIndex: "modified_by", - // key: "modified_by", - // onHeaderCell: () => ({ - // style: {minWidth: 220}, - // }), - // render: (date: string) => { - // return ( - //
- // - // A - // - // Username - //
- // ) - // }, - // }, - // { - // title: "Tags", - // dataIndex: "tags", - // key: "tags", - // onHeaderCell: () => ({ - // style: {minWidth: 160}, - // }), - // render: (date: string) => { - // return [1].map((tag) => Defailt) - // }, - // }, { title: "Date created", dataIndex: "created_at", @@ -258,7 +218,7 @@ const Testset = () => { icon={} className={classes.button} disabled={selectedRowKeys.length == 0} - onClick={onDeleteMultipleTestset} + onClick={() => onDelete()} > Delete From b986fad240e650de7df034f26110f5bec18eaba3 Mon Sep 17 00:00:00 2001 From: ashrafchowdury Date: Sun, 6 Oct 2024 16:11:25 +0600 Subject: [PATCH 10/16] fix(backend): removed updated_at from TestSetSimpleResponse --- agenta-backend/agenta_backend/models/api/testset_model.py | 1 - 1 file changed, 1 deletion(-) diff --git a/agenta-backend/agenta_backend/models/api/testset_model.py b/agenta-backend/agenta_backend/models/api/testset_model.py index d07045805e..02ccbe62b9 100644 --- a/agenta-backend/agenta_backend/models/api/testset_model.py +++ b/agenta-backend/agenta_backend/models/api/testset_model.py @@ -24,7 +24,6 @@ class TestSetSimpleResponse(BaseModel): id: str name: str created_at: str - updated_at: str class DeleteTestsets(BaseModel): From 6ef2bd64213ef428b85705bcb0c6d31d080f2fa8 Mon Sep 17 00:00:00 2001 From: ashrafchowdury Date: Sun, 6 Oct 2024 16:21:54 +0600 Subject: [PATCH 11/16] enhance(frontend): create testset from scratch process --- .../e2e/single-model-test-evaluation.cy.ts | 1 - .../testset/modals/CreateTestsetFromApi.tsx | 4 +- .../modals/CreateTestsetFromEndpoint.tsx | 2 +- .../modals/CreateTestsetFromScratch.tsx | 138 +++++++++--------- .../pages/testset/modals/UploadTestset.tsx | 6 +- .../components/pages/testset/modals/index.tsx | 23 +-- agenta-web/src/lib/Types.ts | 2 + .../pages/apps/[app_id]/testsets/index.tsx | 17 +-- 8 files changed, 92 insertions(+), 101 deletions(-) diff --git a/agenta-web/cypress/e2e/single-model-test-evaluation.cy.ts b/agenta-web/cypress/e2e/single-model-test-evaluation.cy.ts index dc402fceca..68b3d048bd 100644 --- a/agenta-web/cypress/e2e/single-model-test-evaluation.cy.ts +++ b/agenta-web/cypress/e2e/single-model-test-evaluation.cy.ts @@ -67,7 +67,6 @@ describe("Single Model Test workflow", () => { cy.visit(`/apps/${app_id}/testsets`) cy.url().should("include", "/testsets") cy.get('[data-cy="app-testset-list"]').as("table") - cy.get("@table").get(".ant-table-pagination li a").last().click() cy.get("@table").contains(saved_testset_name).as("tempTestSet").should("be.visible") }) }) diff --git a/agenta-web/src/components/pages/testset/modals/CreateTestsetFromApi.tsx b/agenta-web/src/components/pages/testset/modals/CreateTestsetFromApi.tsx index 3ea6b771db..07a9be936d 100644 --- a/agenta-web/src/components/pages/testset/modals/CreateTestsetFromApi.tsx +++ b/agenta-web/src/components/pages/testset/modals/CreateTestsetFromApi.tsx @@ -97,7 +97,7 @@ const CreateTestsetFromApi: React.FC = ({setCurrent, onCancel}) => { return (
-
+
- Create a new test set directly from the webUI + Create a test set programmatically using our API endpoints
Select type diff --git a/agenta-web/src/components/pages/testset/modals/CreateTestsetFromEndpoint.tsx b/agenta-web/src/components/pages/testset/modals/CreateTestsetFromEndpoint.tsx index 4067574e53..c8cee5bba7 100644 --- a/agenta-web/src/components/pages/testset/modals/CreateTestsetFromEndpoint.tsx +++ b/agenta-web/src/components/pages/testset/modals/CreateTestsetFromEndpoint.tsx @@ -66,7 +66,7 @@ const CreateTestsetFromEndpoint: React.FC = ({setCurrent, onCancel}) => { return (
-
+
Create a new test set directly from the webUI
- Name of testset + Test Set Name = ({
diff --git a/agenta-web/src/components/pages/testset/modals/UploadTestset.tsx b/agenta-web/src/components/pages/testset/modals/UploadTestset.tsx index 26cf0be7da..950bd9ecd3 100644 --- a/agenta-web/src/components/pages/testset/modals/UploadTestset.tsx +++ b/agenta-web/src/components/pages/testset/modals/UploadTestset.tsx @@ -108,7 +108,7 @@ const UploadTestset: React.FC = ({setCurrent, onCancel}) => { return (
-
+
- Create a new test set directly from the webUI + Upload your test set as CSV or JSON
Select type @@ -130,7 +130,7 @@ const UploadTestset: React.FC = ({setCurrent, onCancel}) => {
- Name of testset + Test Set Name ({ })) type Props = { - cloneConfig: boolean - setCloneConfig: React.Dispatch> + testsetCreationMode: TestsetCreationMode + setTestsetCreationMode: React.Dispatch> editTestsetValues: testset | null setEditTestsetValues: React.Dispatch> current: number setCurrent: React.Dispatch> - renameTestsetConfig: boolean - setRenameTestsetConfig: React.Dispatch> } & React.ComponentProps const TestsetModal: React.FC = ({ - cloneConfig, - setCloneConfig, + testsetCreationMode, + setTestsetCreationMode, editTestsetValues, setEditTestsetValues, current, setCurrent, - renameTestsetConfig, - setRenameTestsetConfig, ...props }) => { const classes = useStyles() @@ -49,9 +45,8 @@ const TestsetModal: React.FC = ({ const onCancel = () => props.onCancel?.({} as any) const onCloseModal = () => { - setCloneConfig(false) + setTestsetCreationMode("create") setEditTestsetValues(null) - setRenameTestsetConfig(false) setCurrent(0) } @@ -62,14 +57,12 @@ const TestsetModal: React.FC = ({ { content: ( ), }, diff --git a/agenta-web/src/lib/Types.ts b/agenta-web/src/lib/Types.ts index 3b827ef9c0..df47fd87bf 100644 --- a/agenta-web/src/lib/Types.ts +++ b/agenta-web/src/lib/Types.ts @@ -19,6 +19,8 @@ export interface TestSet { csvdata: KeyValuePair[] } +export type TestsetCreationMode = "create" | "clone" | "rename" + export interface ListAppsItem { app_id: string app_name: string diff --git a/agenta-web/src/pages/apps/[app_id]/testsets/index.tsx b/agenta-web/src/pages/apps/[app_id]/testsets/index.tsx index eade596944..396cbdfb5f 100644 --- a/agenta-web/src/pages/apps/[app_id]/testsets/index.tsx +++ b/agenta-web/src/pages/apps/[app_id]/testsets/index.tsx @@ -2,11 +2,11 @@ import React, {useMemo, useState} from "react" import TestsetModal from "@/components/pages/testset/modals" import {formatDate} from "@/lib/helpers/dateTimeHelper" import {checkIfResourceValidForDeletion} from "@/lib/helpers/evaluate" -import {JSSTheme, testset} from "@/lib/Types" +import {JSSTheme, testset, TestsetCreationMode} from "@/lib/Types" import {deleteTestsets, useLoadTestsetsList} from "@/services/testsets/api" import {MoreOutlined, PlusOutlined} from "@ant-design/icons" import {Copy, GearSix, Note, PencilSimple, Trash} from "@phosphor-icons/react" -import {Avatar, Button, Dropdown, Input, Spin, Table, Tag, Typography} from "antd" +import {Button, Dropdown, Input, Spin, Table, Typography} from "antd" import {ColumnsType} from "antd/es/table/interface" import {useRouter} from "next/router" import {createUseStyles} from "react-jss" @@ -53,8 +53,7 @@ const Testset = () => { const {testsets, isTestsetsLoading, mutate} = useLoadTestsetsList(appId) const [isCreateTestsetModalOpen, setIsCreateTestsetModalOpen] = useState(false) const [searchTerm, setSearchTerm] = useState("") - const [cloneConfig, setCloneConfig] = useState(false) - const [renameTestsetConfig, setRenameTestsetConfig] = useState(false) + const [testsetCreationMode, setTestsetCreationMode] = useState("create") const [editTestsetValues, setEditTestsetValues] = useState(null) const [current, setCurrent] = useState(0) @@ -147,7 +146,7 @@ const Testset = () => { icon: , onClick: (e) => { e.domEvent.stopPropagation() - setCloneConfig(true) + setTestsetCreationMode("clone") setEditTestsetValues(record) setCurrent(1) setIsCreateTestsetModalOpen(true) @@ -160,7 +159,7 @@ const Testset = () => { icon: , onClick: (e) => { e.domEvent.stopPropagation() - setRenameTestsetConfig(true) + setTestsetCreationMode("rename") setEditTestsetValues(record) setCurrent(1) setIsCreateTestsetModalOpen(true) @@ -249,14 +248,12 @@ const Testset = () => { { setIsCreateTestsetModalOpen(false) From 22dee33c98795a9aeeb93596fa78034e11761872 Mon Sep 17 00:00:00 2001 From: ashrafchowdury Date: Mon, 7 Oct 2024 13:13:19 +0600 Subject: [PATCH 12/16] fix(frontend): small ui issues --- .../src/components/DynamicCodeBlock/CodeBlock.tsx | 2 +- .../src/components/TestSetTable/TestsetTable.tsx | 1 - .../pages/testset/modals/CreateTestsetFromApi.tsx | 5 +++-- .../src/pages/apps/[app_id]/testsets/index.tsx | 14 ++++++++++---- 4 files changed, 14 insertions(+), 8 deletions(-) diff --git a/agenta-web/src/components/DynamicCodeBlock/CodeBlock.tsx b/agenta-web/src/components/DynamicCodeBlock/CodeBlock.tsx index df6ebc8002..6a611b3fcc 100644 --- a/agenta-web/src/components/DynamicCodeBlock/CodeBlock.tsx +++ b/agenta-web/src/components/DynamicCodeBlock/CodeBlock.tsx @@ -29,7 +29,7 @@ const CodeBlock: FC = ({language, value}) => { language={language} style={appTheme === "dark" ? darcula : coy} showLineNumbers - wrapLongLines={true} + wrapLongLines={false} > {value} diff --git a/agenta-web/src/components/TestSetTable/TestsetTable.tsx b/agenta-web/src/components/TestSetTable/TestsetTable.tsx index 738958a2ca..2e833be067 100644 --- a/agenta-web/src/components/TestSetTable/TestsetTable.tsx +++ b/agenta-web/src/components/TestSetTable/TestsetTable.tsx @@ -120,7 +120,6 @@ const TestsetTable: React.FC = ({mode}) => { } if (writeMode === "edit" && testset_id) { - setIsDataChanged(true) fetchTestset(testset_id as string).then((data) => { setTestsetName(data.name) setRowData(data.csvdata) diff --git a/agenta-web/src/components/pages/testset/modals/CreateTestsetFromApi.tsx b/agenta-web/src/components/pages/testset/modals/CreateTestsetFromApi.tsx index 07a9be936d..89f77e4bb7 100644 --- a/agenta-web/src/components/pages/testset/modals/CreateTestsetFromApi.tsx +++ b/agenta-web/src/components/pages/testset/modals/CreateTestsetFromApi.tsx @@ -56,7 +56,7 @@ const LanguageCodeBlock = ({selectedLang, codeSnippets}: LanguageCodeBlockProps)
-
+
= ({setCurrent, onCancel}) => { - + Read the docs diff --git a/agenta-web/src/pages/apps/[app_id]/testsets/index.tsx b/agenta-web/src/pages/apps/[app_id]/testsets/index.tsx index 396cbdfb5f..a98ef7fb21 100644 --- a/agenta-web/src/pages/apps/[app_id]/testsets/index.tsx +++ b/agenta-web/src/pages/apps/[app_id]/testsets/index.tsx @@ -2,7 +2,7 @@ import React, {useMemo, useState} from "react" import TestsetModal from "@/components/pages/testset/modals" import {formatDate} from "@/lib/helpers/dateTimeHelper" import {checkIfResourceValidForDeletion} from "@/lib/helpers/evaluate" -import {JSSTheme, testset, TestsetCreationMode} from "@/lib/Types" +import {JSSTheme, TestSet, testset, TestsetCreationMode} from "@/lib/Types" import {deleteTestsets, useLoadTestsetsList} from "@/services/testsets/api" import {MoreOutlined, PlusOutlined} from "@ant-design/icons" import {Copy, GearSix, Note, PencilSimple, Trash} from "@phosphor-icons/react" @@ -10,6 +10,7 @@ import {Button, Dropdown, Input, Spin, Table, Typography} from "antd" import {ColumnsType} from "antd/es/table/interface" import {useRouter} from "next/router" import {createUseStyles} from "react-jss" +import dayjs from "dayjs" const useStyles = createUseStyles((theme: JSSTheme) => ({ modal: { @@ -81,9 +82,14 @@ const Testset = () => { const filteredTestset = useMemo(() => { return testsets - ? testsets.filter((item: any) => - item.name.toLowerCase().includes(searchTerm.toLowerCase()), - ) + ? testsets + .filter((item: TestSet) => + item.name.toLowerCase().includes(searchTerm.toLowerCase()), + ) + .sort( + (a: TestSet, b: TestSet) => + dayjs(b.created_at).valueOf() - dayjs(a.created_at).valueOf(), + ) : testsets }, [searchTerm, testsets]) From d7511917533e9c7b24a1755770fd5cfab52f87a5 Mon Sep 17 00:00:00 2001 From: ashrafchowdury Date: Mon, 7 Oct 2024 13:18:02 +0600 Subject: [PATCH 13/16] fix(frontend): removed import from endpoint option --- .../pages/testset/modals/CreateTestset.tsx | 7 - .../modals/CreateTestsetFromEndpoint.tsx | 174 ------------------ .../components/pages/testset/modals/index.tsx | 11 -- 3 files changed, 192 deletions(-) delete mode 100644 agenta-web/src/components/pages/testset/modals/CreateTestsetFromEndpoint.tsx diff --git a/agenta-web/src/components/pages/testset/modals/CreateTestset.tsx b/agenta-web/src/components/pages/testset/modals/CreateTestset.tsx index 5bd4c3093c..aa2c67d2cf 100644 --- a/agenta-web/src/components/pages/testset/modals/CreateTestset.tsx +++ b/agenta-web/src/components/pages/testset/modals/CreateTestset.tsx @@ -1,5 +1,4 @@ import React from "react" -import {isDemo} from "@/lib/helpers/utils" import {JSSTheme} from "@/lib/Types" import {Typography} from "antd" import {createUseStyles} from "react-jss" @@ -69,12 +68,6 @@ const CreateTestset: React.FC = ({setCurrent}) => { Create a test set programmatically using our API endpoints
- {!isDemo() && ( -
setCurrent(4)}> - Import from endpoint - Import test set using your own endpoint -
- )}
) diff --git a/agenta-web/src/components/pages/testset/modals/CreateTestsetFromEndpoint.tsx b/agenta-web/src/components/pages/testset/modals/CreateTestsetFromEndpoint.tsx deleted file mode 100644 index c8cee5bba7..0000000000 --- a/agenta-web/src/components/pages/testset/modals/CreateTestsetFromEndpoint.tsx +++ /dev/null @@ -1,174 +0,0 @@ -import React, {useState} from "react" -import {JSSTheme} from "@/lib/Types" -import {ArrowLeft} from "@phosphor-icons/react" -import {Button, Collapse, Form, Input, message, Typography} from "antd" -import {createUseStyles} from "react-jss" -import {useRouter} from "next/router" -import {importTestsetsViaEndpoint, useLoadTestsetsList} from "@/services/testsets/api" - -const {Text} = Typography - -const useStyles = createUseStyles((theme: JSSTheme) => ({ - headerText: { - lineHeight: theme.lineHeightLG, - fontSize: theme.fontSizeHeading4, - fontWeight: theme.fontWeightStrong, - }, - label: { - fontWeight: theme.fontWeightMedium, - }, -})) - -type FieldType = { - name: string - endpoint: string -} - -type Props = { - setCurrent: React.Dispatch> - onCancel: () => void -} - -const CreateTestsetFromEndpoint: React.FC = ({setCurrent, onCancel}) => { - const classes = useStyles() - const router = useRouter() - const [form] = Form.useForm() - const testsetName = Form.useWatch("name", form) - const testsetEndpoint = Form.useWatch("endpoint", form) - const appId = router.query.app_id as string - const [uploadLoading, setUploadLoading] = useState(false) - const {mutate} = useLoadTestsetsList(appId) - - const onFinish = async (values: FieldType) => { - if (values.name.trim() === "" || values.endpoint.trim() === "") { - message.error("Please fill out all fields") - return - } - - setUploadLoading(true) - - const formData = new FormData() - formData.append("endpoint", values.endpoint) - formData.append("testset_name", values.name) - formData.append("app_id", appId) - - try { - await importTestsetsViaEndpoint(formData) - mutate() - onCancel() - } catch (_) { - // Errors will be handled by Axios interceptor - // Do nothing here - } finally { - setUploadLoading(false) - } - } - - return ( -
-
-
- -
- Currently, we only support the JSON format - - -
- Test Set Name - - name="name" - rules={[{required: true, type: "string", whitespace: true}]} - className="mb-0" - > - - -
- -
- Test Set Endpoint - - name="endpoint" - rules={[{required: true, type: "url"}]} - className="mb-0" - > - - -
- - -
- - - Currently, we only support the JSON format which must - meet the following requirements: - -
- 1. A JSON with an array of rows - - 2. Each row in the array should be an object of - column header name as key and row data as value - -
-
-                                            {JSON.stringify(
-                                                [
-                                                    {
-                                                        recipe_name: "Chicken Parmesan",
-                                                        correct_answer: "Chicken",
-                                                    },
-                                                    {
-                                                        recipe_name: "a, special, recipe",
-                                                        correct_answer: "Beef",
-                                                    },
-                                                ],
-                                                null,
-                                                2,
-                                            )}
-                                        
- - - -
- ), - }, - ]} - /> -
-
- -
- - -
-
- ) -} - -export default CreateTestsetFromEndpoint diff --git a/agenta-web/src/components/pages/testset/modals/index.tsx b/agenta-web/src/components/pages/testset/modals/index.tsx index 88adf8a431..8ea035eafc 100644 --- a/agenta-web/src/components/pages/testset/modals/index.tsx +++ b/agenta-web/src/components/pages/testset/modals/index.tsx @@ -6,8 +6,6 @@ import CreateTestset from "./CreateTestset" import CreateTestsetFromScratch from "./CreateTestsetFromScratch" import UploadTestset from "./UploadTestset" import CreateTestsetFromApi from "./CreateTestsetFromApi" -import CreateTestsetFromEndpoint from "./CreateTestsetFromEndpoint" -import {isDemo} from "@/lib/helpers/utils" const useStyles = createUseStyles((theme: JSSTheme) => ({ modal: { @@ -72,15 +70,6 @@ const TestsetModal: React.FC = ({ { content: , }, - ...(!isDemo() - ? [ - { - content: ( - - ), - }, - ] - : []), ] return ( From d7339f48221595195f5441e3fc64dc755a71eaed Mon Sep 17 00:00:00 2001 From: ashrafchowdury Date: Mon, 7 Oct 2024 15:19:46 +0600 Subject: [PATCH 14/16] fix(frontend): test sets search logic --- .../pages/apps/[app_id]/testsets/index.tsx | 20 +++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) diff --git a/agenta-web/src/pages/apps/[app_id]/testsets/index.tsx b/agenta-web/src/pages/apps/[app_id]/testsets/index.tsx index a98ef7fb21..fd54c4dfe0 100644 --- a/agenta-web/src/pages/apps/[app_id]/testsets/index.tsx +++ b/agenta-web/src/pages/apps/[app_id]/testsets/index.tsx @@ -81,16 +81,16 @@ const Testset = () => { } const filteredTestset = useMemo(() => { - return testsets - ? testsets - .filter((item: TestSet) => - item.name.toLowerCase().includes(searchTerm.toLowerCase()), - ) - .sort( - (a: TestSet, b: TestSet) => - dayjs(b.created_at).valueOf() - dayjs(a.created_at).valueOf(), - ) - : testsets + let allTestsets = testsets.sort( + (a: TestSet, b: TestSet) => + dayjs(b.updated_at).valueOf() - dayjs(a.updated_at).valueOf(), + ) + if (searchTerm) { + allTestsets = testsets.filter((item: TestSet) => + item.name.toLowerCase().includes(searchTerm.toLowerCase()), + ) + } + return allTestsets }, [searchTerm, testsets]) const columns: ColumnsType = [ From 09ba83aac0ad9397d41a1e78bb55be254d48cb56 Mon Sep 17 00:00:00 2001 From: ashrafchowdury Date: Mon, 7 Oct 2024 16:18:23 +0600 Subject: [PATCH 15/16] test(frontend): fixed cypress test failure --- agenta-web/src/components/TestSetTable/TableHeaderComponent.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/agenta-web/src/components/TestSetTable/TableHeaderComponent.tsx b/agenta-web/src/components/TestSetTable/TableHeaderComponent.tsx index 857f6f2bc9..a69bb1f95d 100644 --- a/agenta-web/src/components/TestSetTable/TableHeaderComponent.tsx +++ b/agenta-web/src/components/TestSetTable/TableHeaderComponent.tsx @@ -105,6 +105,7 @@ const TableHeaderComponent = ({ setInputValues(scopedInputValues) updateTable(scopedInputValues) setIsEditInputOpen(false) + setIsDataChanged(true) } } @@ -112,7 +113,6 @@ const TableHeaderComponent = ({ const values = [...inputValues] values[index] = event.target.value setScopedInputValues(values) - setIsDataChanged(true) } const onAddColumn = () => { From fd2539570f8e429a9e3a5e0d452919f8606d4e1d Mon Sep 17 00:00:00 2001 From: ashrafchowdury Date: Wed, 9 Oct 2024 12:43:39 +0600 Subject: [PATCH 16/16] enhance(frontend): added custom no-results-found section in table --- agenta-web/public/assets/not-found.png | Bin 0 -> 8584 bytes .../NoResultsFound/NoResultsFound.tsx | 37 ++++++++++++++++++ .../pages/apps/[app_id]/testsets/index.tsx | 6 +++ 3 files changed, 43 insertions(+) create mode 100644 agenta-web/public/assets/not-found.png create mode 100644 agenta-web/src/components/NoResultsFound/NoResultsFound.tsx diff --git a/agenta-web/public/assets/not-found.png b/agenta-web/public/assets/not-found.png new file mode 100644 index 0000000000000000000000000000000000000000..f4048f657376799bc1880eb0ab1c54d994920f37 GIT binary patch literal 8584 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 B!M*?h literal 0 HcmV?d00001 diff --git a/agenta-web/src/components/NoResultsFound/NoResultsFound.tsx b/agenta-web/src/components/NoResultsFound/NoResultsFound.tsx new file mode 100644 index 0000000000..9b173ef301 --- /dev/null +++ b/agenta-web/src/components/NoResultsFound/NoResultsFound.tsx @@ -0,0 +1,37 @@ +import React from "react" +import {Typography} from "antd" +import Image from "next/image" +import {createUseStyles} from "react-jss" +import {JSSTheme} from "@/lib/Types" + +const useStyles = createUseStyles((theme: JSSTheme) => ({ + notFound: { + width: "100%", + display: "flex", + flexDirection: "column", + alignItems: "center", + justifyContent: "center", + padding: "80px 0px", + gap: 16, + "& > span": { + lineHeight: theme.lineHeightHeading4, + fontSize: theme.fontSizeHeading4, + fontWeight: theme.fontWeightMedium, + }, + }, +})) + +const NoResultsFound = ({className}: {className?: string}) => { + const classes = useStyles() + return ( +
+ + No Results found + + No results match the search criteria. + +
+ ) +} + +export default NoResultsFound diff --git a/agenta-web/src/pages/apps/[app_id]/testsets/index.tsx b/agenta-web/src/pages/apps/[app_id]/testsets/index.tsx index fd54c4dfe0..3dcc4eeee5 100644 --- a/agenta-web/src/pages/apps/[app_id]/testsets/index.tsx +++ b/agenta-web/src/pages/apps/[app_id]/testsets/index.tsx @@ -1,5 +1,6 @@ import React, {useMemo, useState} from "react" import TestsetModal from "@/components/pages/testset/modals" +import NoResultsFound from "@/components/NoResultsFound/NoResultsFound" import {formatDate} from "@/lib/helpers/dateTimeHelper" import {checkIfResourceValidForDeletion} from "@/lib/helpers/evaluate" import {JSSTheme, TestSet, testset, TestsetCreationMode} from "@/lib/Types" @@ -43,6 +44,9 @@ const useStyles = createUseStyles((theme: JSSTheme) => ({ border: "1px solid", borderColor: theme.colorBorderSecondary, }, + "& .ant-table-expanded-row-fixed": { + width: "100% !important", + }, }, })) @@ -213,6 +217,7 @@ const Testset = () => {
setSearchTerm(e.target.value)} @@ -250,6 +255,7 @@ const Testset = () => { onClick: () => router.push(`/apps/${appId}/testsets/${record._id}`), } }} + locale={{emptyText: }} />