mirror of https://github.com/buster-so/buster.git
create dataset endpoints
This commit is contained in:
parent
3104cace3c
commit
2812df14a1
|
@ -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<BusterDatasetListItem[]>(['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
|
||||
});
|
||||
};
|
||||
|
||||
|
|
|
@ -30,8 +30,11 @@ export const getDatasetDataSample = async (datasetId: string): Promise<BusterDat
|
|||
.then((res) => res.data);
|
||||
};
|
||||
|
||||
export const createDataset = async (): Promise<BusterDataset> => {
|
||||
return await mainApi.post<BusterDataset>(`/datasets`).then((res) => res.data);
|
||||
export const createDataset = async (params: {
|
||||
name: string;
|
||||
data_source_id: string;
|
||||
}): Promise<BusterDataset> => {
|
||||
return await mainApi.post<BusterDataset>(`/datasets`, params).then((res) => res.data);
|
||||
};
|
||||
|
||||
export const deleteDataset = async (datasetId: string): Promise<void> => {
|
||||
|
|
|
@ -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<string | null>(
|
||||
datasourceId || null
|
||||
);
|
||||
const [datasetName, setDatasetName] = React.useState<string>('');
|
||||
|
||||
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();
|
||||
setTimeout(() => {
|
||||
router.push(createBusterRoute({ route: BusterRoutes.SETTINGS_DATASOURCES_ADD }));
|
||||
}, 350);
|
||||
setTimeout(() => {
|
||||
onClose();
|
||||
}, 450);
|
||||
});
|
||||
|
||||
useLayoutEffect(() => {
|
||||
|
@ -98,14 +86,18 @@ export const NewDatasetModal: React.FC<{
|
|||
return (
|
||||
<AppModal open={open} onClose={onClose} header={headerConfig} footer={footerConfig}>
|
||||
{open && (
|
||||
<div className="mt-2 flex flex-col gap-3">
|
||||
<FormWrapper title="Dataset name">
|
||||
<DatasetNameInput setDatasetName={setDatasetName} datasetName={datasetName} />
|
||||
</FormWrapper>
|
||||
|
||||
<FormWrapper title="Datasource">
|
||||
<SelectDataSourceDropdown
|
||||
setSelectedDatasource={setSelectedDatasource}
|
||||
selectedDatasource={selectedDatasource}
|
||||
/>
|
||||
)}
|
||||
|
||||
{open && selectedDatasource && (
|
||||
<SelectFromExistingDataset selectedDatasource={selectedDatasource} />
|
||||
</FormWrapper>
|
||||
</div>
|
||||
)}
|
||||
</AppModal>
|
||||
);
|
||||
|
@ -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<string | null>(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) => (
|
||||
<div className="flex items-center justify-end">
|
||||
<Button
|
||||
loading={submittingId === record.id}
|
||||
type="default"
|
||||
onClick={() => onSelectDataset(record.id)}>
|
||||
Use dataset
|
||||
</Button>
|
||||
</div>
|
||||
)
|
||||
}
|
||||
];
|
||||
}, [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 (
|
||||
<div
|
||||
className="mt-3 flex h-[250px] w-full flex-col"
|
||||
style={{
|
||||
border: `0.5px solid ${token.colorBorder}`,
|
||||
borderRadius: token.borderRadius
|
||||
}}>
|
||||
<div
|
||||
className="flex"
|
||||
style={{
|
||||
padding: 12,
|
||||
background: token.controlItemBgActive,
|
||||
borderBottom: `0.5px solid ${token.colorBorder}`
|
||||
}}>
|
||||
<Text size="sm">Use an existing table or view as a dataset</Text>
|
||||
</div>
|
||||
<div className="h-full w-full">
|
||||
<BusterList
|
||||
columns={columns}
|
||||
rows={rows}
|
||||
showHeader={false}
|
||||
emptyState={
|
||||
!isFetchedDatasets ? (
|
||||
<div className="flex h-full w-full items-center justify-center">
|
||||
<Text>No datasets found</Text>
|
||||
</div>
|
||||
) : (
|
||||
<></>
|
||||
)
|
||||
}
|
||||
<Input
|
||||
autoFocus
|
||||
defaultValue={datasetName}
|
||||
placeholder="Enter a name for your dataset"
|
||||
onChange={(e) => setDatasetName(e.target.value)}
|
||||
/>
|
||||
);
|
||||
},
|
||||
() => true
|
||||
);
|
||||
DatasetNameInput.displayName = 'DatasetNameInput';
|
||||
|
||||
const FormWrapper: React.FC<{
|
||||
title: string;
|
||||
children: React.ReactNode;
|
||||
}> = React.memo(({ title, children }) => {
|
||||
return (
|
||||
<div className="grid grid-cols-[minmax(150px,auto)_1fr] gap-4">
|
||||
<div>
|
||||
<Text>{title}</Text>
|
||||
</div>
|
||||
<div>{children}</div>
|
||||
</div>
|
||||
);
|
||||
});
|
||||
SelectFromExistingDataset.displayName = 'SelectFromExistingDataset';
|
||||
FormWrapper.displayName = 'FormWrapper';
|
||||
|
|
|
@ -125,9 +125,7 @@ export const AppCodeEditor = forwardRef<AppCodeEditorHandle, AppCodeEditorProps>
|
|||
]);
|
||||
|
||||
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<AppCodeEditorHandle, AppCodeEditorProps>
|
|||
|
||||
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'));
|
||||
}
|
||||
});
|
||||
}
|
||||
);
|
||||
|
||||
|
|
Loading…
Reference in New Issue