mirror of https://github.com/buster-so/buster.git
add loading indicator for fetching temp data
This commit is contained in:
parent
adc0e4e57e
commit
ab3d205f6d
|
@ -54,11 +54,12 @@ export const useGetDatasetData = (datasetId: string) => {
|
|||
|
||||
export const useGetDatasetMetadata = (datasetId: string) => {
|
||||
const queryFn = useMemoizedFn(() => getDatasetMetadata(datasetId));
|
||||
return useCreateReactQuery<BusterDataset>({
|
||||
const res = useCreateReactQuery<BusterDataset>({
|
||||
queryKey: ['datasetMetadata', datasetId],
|
||||
queryFn,
|
||||
enabled: !!datasetId
|
||||
});
|
||||
return res;
|
||||
};
|
||||
|
||||
export const prefetchGetDatasetMetadata = async (
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
import { DataSource } from '../datasources';
|
||||
import { DataSource, DataSourceTypes } from '../datasources';
|
||||
|
||||
export interface BusterDatasetListItem {
|
||||
id: string;
|
||||
|
@ -28,6 +28,9 @@ export type BusterDataset = {
|
|||
name: string;
|
||||
sql: string;
|
||||
yml_file: string;
|
||||
data_source_id: string;
|
||||
data_source_name: string;
|
||||
data_source_type: DataSourceTypes;
|
||||
};
|
||||
|
||||
export interface BusterDatasetColumn {
|
||||
|
|
|
@ -2,7 +2,7 @@
|
|||
|
||||
import { useIndividualDataset } from '@/context/Datasets';
|
||||
import { useSelectedLayoutSegment } from 'next/navigation';
|
||||
import React, { PropsWithChildren, useEffect, useLayoutEffect, useState } from 'react';
|
||||
import React, { PropsWithChildren, useEffect, useState } from 'react';
|
||||
import { DatasetApps } from './_config';
|
||||
import {
|
||||
createContext,
|
||||
|
@ -13,8 +13,8 @@ import {
|
|||
export const useDatasetPageContext = ({ datasetId }: { datasetId: string }) => {
|
||||
const segments = useSelectedLayoutSegment() as DatasetApps;
|
||||
const { dataset, datasetData } = useIndividualDataset({ datasetId });
|
||||
const originalDatasetSQL = dataset.data?.sql;
|
||||
const datasetYmlFile = dataset.data?.yml_file;
|
||||
const originalDatasetSQL = dataset?.data?.sql;
|
||||
const datasetYmlFile = dataset?.data?.yml_file;
|
||||
|
||||
const [sql, setSQL] = useState<string>(originalDatasetSQL || '');
|
||||
const [ymlFile, setYmlFile] = useState<string>(datasetYmlFile || '');
|
||||
|
|
|
@ -3,6 +3,7 @@ import { createStyles } from 'antd-style';
|
|||
import React from 'react';
|
||||
import isEmpty from 'lodash/isEmpty';
|
||||
import AppDataGrid from '@/components/table/AppDataGrid';
|
||||
import { IndeterminateLinearLoader } from '@/components/loaders';
|
||||
|
||||
export const DataContainer: React.FC<{
|
||||
data: BusterDatasetData;
|
||||
|
@ -13,7 +14,14 @@ export const DataContainer: React.FC<{
|
|||
const hasData = !isEmpty(data);
|
||||
|
||||
return (
|
||||
<div className={cx(styles.container, 'h-full w-full overflow-hidden', className)}>
|
||||
<div className={cx(styles.container, 'relative h-full w-full overflow-hidden', className)}>
|
||||
<IndeterminateLinearLoader
|
||||
className={cx(
|
||||
'absolute left-0 top-0 z-10 w-full',
|
||||
fetchingData && hasData ? 'block' : '!hidden'
|
||||
)}
|
||||
/>
|
||||
|
||||
{hasData ? (
|
||||
<AppDataGrid rows={data} />
|
||||
) : (
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
'use client';
|
||||
|
||||
import React, { useRef, useState } from 'react';
|
||||
import React, { useMemo, useRef, useState } from 'react';
|
||||
import { useDatasetPageContextSelector } from '../_DatasetPageContext';
|
||||
import { AppSplitter, AppSplitterRef } from '@/components';
|
||||
import { SQLContainer } from './SQLContainer';
|
||||
|
@ -12,6 +12,9 @@ import { EditorApps, EditorContainerSubHeader } from './EditorContainerSubHeader
|
|||
import { createStyles } from 'antd-style';
|
||||
import { MetadataContainer } from './MetadataContainer';
|
||||
import { runSQL } from '@/api/busterv2';
|
||||
import { RustApiError } from '@/api/buster/errors';
|
||||
import isEmpty from 'lodash/isEmpty';
|
||||
|
||||
export const EditorContent: React.FC<{
|
||||
defaultLayout: [string, string];
|
||||
}> = ({ defaultLayout }) => {
|
||||
|
@ -20,35 +23,51 @@ export const EditorContent: React.FC<{
|
|||
const splitterRef = useRef<AppSplitterRef>(null);
|
||||
const [selectedApp, setSelectedApp] = useState<EditorApps>(EditorApps.PREVIEW);
|
||||
const datasetData = useDatasetPageContextSelector((state) => state.datasetData);
|
||||
const { data: dataset } = useDatasetPageContextSelector((state) => state.dataset);
|
||||
const sql = useDatasetPageContextSelector((state) => state.sql);
|
||||
const setSQL = useDatasetPageContextSelector((state) => state.setSQL);
|
||||
const ymlFile = useDatasetPageContextSelector((state) => state.ymlFile);
|
||||
const setYmlFile = useDatasetPageContextSelector((state) => state.setYmlFile);
|
||||
|
||||
const [tempData, setTempData] = useState<BusterDatasetData>(datasetData.data || []);
|
||||
const [fetchingTempData, setFetchingTempData] = useState(false);
|
||||
const [runSQLError, setRunSQLError] = useState<string>('');
|
||||
|
||||
const { runAsync: runQuery } = useRequest(
|
||||
const shownData = useMemo(() => {
|
||||
return isEmpty(tempData) ? datasetData.data || [] : tempData;
|
||||
}, [tempData, datasetData.data]);
|
||||
|
||||
const { runAsync: runQuery, loading: fetchingTempData } = useRequest(
|
||||
async () => {
|
||||
await timeout(1000);
|
||||
const res = await runSQL({ data_source_id: '123', sql });
|
||||
console.log(res);
|
||||
try {
|
||||
console.log('dataset', sql);
|
||||
const res = await runSQL({ data_source_id: dataset?.data_source_id!, sql });
|
||||
const data = res.data.data;
|
||||
setTempData(data);
|
||||
return data;
|
||||
} catch (error) {
|
||||
setRunSQLError((error as unknown as RustApiError)?.message || 'Something went wrong');
|
||||
}
|
||||
},
|
||||
{ manual: true }
|
||||
);
|
||||
|
||||
const fetchingData = fetchingTempData || datasetData.isFetching;
|
||||
|
||||
const error = '';
|
||||
const fetchingInitialData = datasetData.isFetching;
|
||||
|
||||
const onRunQuery = useMemoizedFn(async () => {
|
||||
await runQuery();
|
||||
const heightOfRow = 36;
|
||||
const heightOfDataContainer = heightOfRow * (datasetData.data?.length || 0);
|
||||
const containerHeight = ref.current?.clientHeight || 0;
|
||||
const maxHeight = Math.floor(containerHeight * 0.6);
|
||||
const finalHeight = Math.min(heightOfDataContainer, maxHeight);
|
||||
splitterRef.current?.setSplitSizes(['auto', `${finalHeight}px`]);
|
||||
try {
|
||||
const result = await runQuery();
|
||||
if (result && result.length > 0) {
|
||||
const headerHeight = 50;
|
||||
const heightOfRow = 36;
|
||||
const heightOfDataContainer = headerHeight + heightOfRow * (result.length || 0);
|
||||
const containerHeight = ref.current?.clientHeight || 0;
|
||||
const maxHeight = Math.floor(containerHeight * 0.6);
|
||||
const finalHeight = Math.min(heightOfDataContainer, maxHeight);
|
||||
splitterRef.current?.setSplitSizes(['auto', `${finalHeight}px`]);
|
||||
}
|
||||
} catch (error) {
|
||||
//
|
||||
}
|
||||
});
|
||||
|
||||
return (
|
||||
|
@ -63,15 +82,15 @@ export const EditorContent: React.FC<{
|
|||
className="mb-3"
|
||||
datasetSQL={sql}
|
||||
setDatasetSQL={setSQL}
|
||||
error={error}
|
||||
error={runSQLError}
|
||||
onRunQuery={onRunQuery}
|
||||
/>
|
||||
}
|
||||
rightChildren={
|
||||
<DataContainer
|
||||
className="mt-3"
|
||||
data={datasetData.data!}
|
||||
fetchingData={fetchingData}
|
||||
data={shownData}
|
||||
fetchingData={fetchingInitialData || fetchingTempData}
|
||||
/>
|
||||
}
|
||||
split="horizontal"
|
||||
|
|
|
@ -36,7 +36,12 @@ export const SQLContainer: React.FC<{
|
|||
|
||||
return (
|
||||
<div className={cx(styles.container, 'flex h-full w-full flex-col overflow-hidden', className)}>
|
||||
<AppCodeEditor className="overflow-hidden" value={datasetSQL} onChange={setDatasetSQL} />
|
||||
<AppCodeEditor
|
||||
className="overflow-hidden"
|
||||
value={datasetSQL}
|
||||
onChange={setDatasetSQL}
|
||||
onMetaEnter={onRunQueryPreflight}
|
||||
/>
|
||||
<Divider className="!my-0" />
|
||||
<div className="relative flex items-center justify-between px-4 py-2.5">
|
||||
<Button type="default" onClick={onCopySQL}>
|
||||
|
|
|
@ -1,3 +1,4 @@
|
|||
import { createStyles } from 'antd-style';
|
||||
import React from 'react';
|
||||
|
||||
export const IndeterminateLinearLoader: React.FC<{
|
||||
|
@ -7,15 +8,24 @@ export const IndeterminateLinearLoader: React.FC<{
|
|||
trackColor?: string;
|
||||
valueColor?: string;
|
||||
}> = ({ className = '', trackColor, valueColor, style, height = 2 }) => {
|
||||
const { styles, cx } = useStyles();
|
||||
|
||||
return (
|
||||
<div
|
||||
className={`indeterminate-progress-bar ${className}`}
|
||||
style={{ ...style, height, backgroundColor: trackColor }}>
|
||||
<div
|
||||
className="indeterminate-progress-bar-value bg-buster-purple"
|
||||
className={cx(styles.track, 'indeterminate-progress-bar-value')}
|
||||
style={{
|
||||
backgroundColor: valueColor
|
||||
}}></div>
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
const useStyles = createStyles(({ css, token }) => ({
|
||||
track: css`
|
||||
background: ${token.colorPrimary};
|
||||
opacity: 0.6;
|
||||
`
|
||||
}));
|
||||
|
|
|
@ -35,7 +35,7 @@ export const createBusterRoute = ({ route, ...args }: BusterRoutesWithArgsRoute)
|
|||
return Object.entries(args).reduce<string>((acc, [key, value]) => {
|
||||
acc.replace(`[${key}]`, value as string);
|
||||
return acc.replace(`:${key}`, value as string);
|
||||
}, route);
|
||||
}, route || '');
|
||||
};
|
||||
|
||||
const routeToRegex = (route: string): RegExp => {
|
||||
|
|
Loading…
Reference in New Issue