From 2812df14a1b1192f9b94bf8de38ea32bf9da4257 Mon Sep 17 00:00:00 2001 From: Nate Kelley Date: Tue, 14 Jan 2025 12:53:54 -0700 Subject: [PATCH] create dataset endpoints --- .../api/busterv2/datasets/queryRequests.ts | 24 +-- web/src/api/busterv2/datasets/requests.ts | 7 +- .../_NewDatasetModal/_NewDatasetModal.tsx | 186 +++++------------- .../inputs/AppCodeEditor/AppCodeEditor.tsx | 10 - 4 files changed, 64 insertions(+), 163 deletions(-) diff --git a/web/src/api/busterv2/datasets/queryRequests.ts b/web/src/api/busterv2/datasets/queryRequests.ts index 7192764c2..ed23e8d53 100644 --- a/web/src/api/busterv2/datasets/queryRequests.ts +++ b/web/src/api/busterv2/datasets/queryRequests.ts @@ -78,28 +78,14 @@ export const prefetchGetDatasetMetadata = async ( export const useCreateDataset = () => { const queryClient = useQueryClient(); - const mutationFn = useMemoizedFn(() => createDataset()); - const onSuccess = useMemoizedFn((newDataset: unknown) => { - queryClient.setQueryData(['datasets', {}], (oldData) => { - // const newListItem: BusterDatasetListItem = { - // ...newDataset, - // name: newDataset.name, - // created_at: newDataset.created_at, - // updated_at: newDataset.updated_at, - // definition: newDataset.definition, - // owner: '', - // }; - return oldData; - }); - }); - const onError = useMemoizedFn((error: any) => { - console.error('Failed to create dataset:', error); + + const onSuccess = useMemoizedFn(() => { + queryClient.invalidateQueries({ queryKey: ['datasets', {}] }); }); return useCreateReactMutation({ - mutationFn, - onSuccess, - onError + mutationFn: createDataset, + onSuccess }); }; diff --git a/web/src/api/busterv2/datasets/requests.ts b/web/src/api/busterv2/datasets/requests.ts index 068721147..3481f9f85 100644 --- a/web/src/api/busterv2/datasets/requests.ts +++ b/web/src/api/busterv2/datasets/requests.ts @@ -30,8 +30,11 @@ export const getDatasetDataSample = async (datasetId: string): Promise res.data); }; -export const createDataset = async (): Promise => { - return await mainApi.post(`/datasets`).then((res) => res.data); +export const createDataset = async (params: { + name: string; + data_source_id: string; +}): Promise => { + return await mainApi.post(`/datasets`, params).then((res) => res.data); }; export const deleteDataset = async (datasetId: string): Promise => { diff --git a/web/src/app/app/datasets/_NewDatasetModal/_NewDatasetModal.tsx b/web/src/app/app/datasets/_NewDatasetModal/_NewDatasetModal.tsx index 31c052baf..89f32ac8a 100644 --- a/web/src/app/app/datasets/_NewDatasetModal/_NewDatasetModal.tsx +++ b/web/src/app/app/datasets/_NewDatasetModal/_NewDatasetModal.tsx @@ -1,22 +1,12 @@ import React, { useLayoutEffect, useMemo, useState } from 'react'; -import { Button, Select, SelectProps } from 'antd'; +import { Input, Select, SelectProps } from 'antd'; import { useMemoizedFn, useMount } from 'ahooks'; -import { useDatasetContextSelector } from '@/context/Datasets'; import { useDataSourceContextSelector } from '@/context/DataSources'; -import { - BusterDatasetListItem, - useCreateDataset, - useGetDatasets, - useUpdateDataset -} from '@/api/busterv2/datasets'; +import { useCreateDataset } from '@/api/busterv2/datasets'; import { useAppLayoutContextSelector } from '@/context/BusterAppLayout'; import { BusterRoutes, createBusterRoute } from '@/routes'; import { useRouter } from 'next/navigation'; import { AppModal, Text } from '@/components'; -import { useAntToken } from '@/styles/useAntToken'; -import { BusterList, BusterListColumn, BusterListRow } from '@/components/list'; -import { formatDate } from '@/utils/date'; -import { timeout } from '@/utils'; const headerConfig = { title: 'Create a dataset', @@ -35,21 +25,22 @@ export const NewDatasetModal: React.FC<{ const forceInitDataSourceList = useDataSourceContextSelector( (state) => state.forceInitDataSourceList ); - const { mutateAsync: createDataset } = useCreateDataset(); - const [creatingDataset, setCreatingDataset] = React.useState(false); + const { mutateAsync: createDataset, isPending: creatingDataset } = useCreateDataset(); const [selectedDatasource, setSelectedDatasource] = React.useState( datasourceId || null ); + const [datasetName, setDatasetName] = React.useState(''); - const disableSubmit = !selectedDatasource; + const disableSubmit = !selectedDatasource || !datasetName; const createNewDatasetPreflight = useMemoizedFn(async () => { - if (creatingDataset || disableSubmit) return; - setCreatingDataset(true); + if (creatingDataset || disableSubmit || !selectedDatasource) return; + beforeCreate?.(); const res = await createDataset({ - data_source_id: selectedDatasource! + data_source_id: selectedDatasource, + name: datasetName }); if (res.id) { onChangePage({ @@ -62,16 +53,13 @@ export const NewDatasetModal: React.FC<{ afterCreate?.(); }, 150); } - setTimeout(() => { - setCreatingDataset(false); - }, 500); }); const onAddDataSourceClick = useMemoizedFn(() => { - onClose(); + router.push(createBusterRoute({ route: BusterRoutes.SETTINGS_DATASOURCES_ADD })); setTimeout(() => { - router.push(createBusterRoute({ route: BusterRoutes.SETTINGS_DATASOURCES_ADD })); - }, 350); + onClose(); + }, 450); }); useLayoutEffect(() => { @@ -98,14 +86,18 @@ export const NewDatasetModal: React.FC<{ return ( {open && ( - - )} +
+ + + - {open && selectedDatasource && ( - + + + +
)}
); @@ -132,6 +124,10 @@ const SelectDataSourceDropdown: React.FC<{ return selectOptions.find((option) => option.value === selectedDatasource); }, [selectOptions, selectedDatasource]); + const onSelect = useMemoizedFn((value: unknown) => { + setSelectedDatasource(value as string); + }); + useMount(() => { initDataSourceList(); router.prefetch( @@ -149,115 +145,41 @@ const SelectDataSourceDropdown: React.FC<{ value={selectedOption} placeholder="Select datasources that this term pertains to" popupMatchSelectWidth={true} - autoFocus={true} - onChange={(value) => { - setSelectedDatasource(value as unknown as string); - }} + onChange={onSelect} /> ); }); SelectDataSourceDropdown.displayName = 'SelectDataSourceDropdown'; -const SelectFromExistingDataset: React.FC<{ - selectedDatasource: string; -}> = React.memo(({ selectedDatasource }) => { - const token = useAntToken(); - const { data: importedDatasets, isFetched: isFetchedDatasets } = useGetDatasets({ - imported: true - }); - const { mutateAsync: onUpdateDataset } = useUpdateDataset(); - - const onChangePage = useAppLayoutContextSelector((s) => s.onChangePage); - - const [submittingId, setSubmittingId] = useState(null); - - const columns: BusterListColumn[] = useMemo(() => { - return [ - { - title: 'Name', - dataIndex: 'name' - }, - { - title: 'Updated at', - dataIndex: 'updated_at', - render: (v) => formatDate({ date: v, format: 'lll' }), - width: 130 - }, - { - title: 'Actions', - dataIndex: 'actions', - width: 100, - render: (_, record: BusterDatasetListItem) => ( -
- -
- ) - } - ]; - }, [submittingId]); - - const rows: BusterListRow[] = useMemo(() => { - return importedDatasets.map((dataset) => ({ - id: dataset.id, - data: dataset - })); - }, [importedDatasets]); - - const onSelectDataset = useMemoizedFn(async (datasetId: string) => { - setSubmittingId(datasetId); - // try { - // await onUpdateDataset({ - // id: datasetId, - // name: 'test' - // }); - // await timeout(500); - // onChangePage({ - // route: BusterRoutes.APP_DATASETS_ID, - // datasetId - // }); - // } catch (error) { - // setSubmittingId(null); - // } - }); +const DatasetNameInput: React.FC<{ + setDatasetName: (name: string) => void; + datasetName: string; +}> = React.memo( + ({ setDatasetName, datasetName }) => { + return ( + setDatasetName(e.target.value)} + /> + ); + }, + () => true +); +DatasetNameInput.displayName = 'DatasetNameInput'; +const FormWrapper: React.FC<{ + title: string; + children: React.ReactNode; +}> = React.memo(({ title, children }) => { return ( -
-
- Use an existing table or view as a dataset -
-
- - No datasets found -
- ) : ( - <> - ) - } - /> +
+
+ {title}
+
{children}
); }); -SelectFromExistingDataset.displayName = 'SelectFromExistingDataset'; +FormWrapper.displayName = 'FormWrapper'; diff --git a/web/src/components/inputs/AppCodeEditor/AppCodeEditor.tsx b/web/src/components/inputs/AppCodeEditor/AppCodeEditor.tsx index 5cac8596e..8eddc4a39 100644 --- a/web/src/components/inputs/AppCodeEditor/AppCodeEditor.tsx +++ b/web/src/components/inputs/AppCodeEditor/AppCodeEditor.tsx @@ -125,9 +125,7 @@ export const AppCodeEditor = forwardRef ]); if (language === 'yaml') { - console.log('loading yaml'); await configureMonacoToUseYaml(monaco); - console.log('yaml loaded'); } monaco.editor.defineTheme('github-light', GithubLightTheme); @@ -149,14 +147,6 @@ export const AppCodeEditor = forwardRef setIsLoading(false); hasLoadedDynamicEditor = true; - - // Add this to see how Monaco is tokenizing the text - editor.onDidChangeModelContent(() => { - const model = editor.getModel(); - if (model) { - console.log(monaco.editor.tokenize(model.getValue(), 'yaml')); - } - }); } );