updated header to match new format

This commit is contained in:
Nate Kelley 2025-01-08 16:21:58 -07:00
parent 7378a7b115
commit 166afbea2b
No known key found for this signature in database
GPG Key ID: FD90372AB8D98B4F
9 changed files with 138 additions and 124 deletions

View File

@ -0,0 +1,36 @@
import { createBusterRoute, BusterRoutes } from '@/routes';
import { BreadcrumbSeperator } from '@/styles/context/useBreadcrumbStyles';
import { Breadcrumb } from 'antd';
import Link from 'next/link';
import React, { useMemo } from 'react';
export const DatasetBreadcrumb: React.FC<{
datasetName?: string;
}> = React.memo(({ datasetName }) => {
const breadcrumbItems = useMemo(
() =>
[
{
title: (
<Link prefetch href={createBusterRoute({ route: BusterRoutes.APP_DATASETS })}>
Datasets
</Link>
)
},
{
title: datasetName
}
].filter((item) => item.title),
[datasetName]
);
return (
<>
<Breadcrumb
className="flex items-center"
items={breadcrumbItems}
separator={<BreadcrumbSeperator />}
/>
</>
);
});

View File

@ -0,0 +1,63 @@
'use client';
import { AppSegmented } from '@/components';
import { SegmentedProps } from 'antd';
import Link from 'next/link';
import { useRouter } from 'next/navigation';
import React, { useMemo } from 'react';
import { DatasetApps, DataSetAppText } from '../_config';
import { createBusterRoute, BusterRoutes } from '@/routes';
export const DatasetsHeaderOptions: React.FC<{
selectedApp: DatasetApps;
isAdmin: boolean;
datasetId: string;
}> = React.memo(({ datasetId, isAdmin, selectedApp }) => {
const { push } = useRouter();
const optionsItems = isAdmin
? [DatasetApps.OVERVIEW, DatasetApps.PERMISSIONS, DatasetApps.EDITOR]
: [DatasetApps.OVERVIEW, DatasetApps.PERMISSIONS];
const options: SegmentedProps['options'] = useMemo(
() =>
optionsItems.map((key) => ({
label: (
<Link prefetch href={keyToRoute(datasetId, key)}>
{DataSetAppText[key as DatasetApps]}
</Link>
),
value: key
})),
[datasetId, optionsItems]
);
return (
<AppSegmented
options={options}
value={selectedApp}
onChange={(value) => {
push(keyToRoute(datasetId, value as DatasetApps));
}}
/>
);
});
DatasetsHeaderOptions.displayName = 'DatasetsHeaderOptions';
const keyToRoute = (datasetId: string, key: DatasetApps) => {
const record: Record<DatasetApps, string> = {
[DatasetApps.PERMISSIONS]: createBusterRoute({
route: BusterRoutes.APP_DATASETS_ID_DESCRIPTIONS,
datasetId
}),
[DatasetApps.OVERVIEW]: createBusterRoute({
route: BusterRoutes.APP_DATASETS_ID_OVERVIEW,
datasetId
}),
[DatasetApps.EDITOR]: createBusterRoute({
route: BusterRoutes.APP_DATASETS_ID_SQL,
datasetId
})
};
return record[key];
};

View File

@ -0,0 +1,8 @@
import { AppMaterialIcons } from '@/components';
import { Button } from 'antd';
import React from 'react';
export const DatasetIndividualThreeDotMenu: React.FC = React.memo(() => {
return <Button type="text" icon={<AppMaterialIcons icon="more_horiz" />} />;
});
DatasetIndividualThreeDotMenu.displayName = 'DatasetIndividualThreeDotMenu';

View File

@ -7,15 +7,18 @@ import { BusterRoutes, createBusterRoute } from '@/routes';
import { AppSegmented, AppTooltip, PreventNavigation } from '@/components';
import { useDatasetContextSelector } from '@/context/Datasets';
import { useHotkeys } from 'react-hotkeys-hook';
import { AppContentHeader } from '../../_components/AppContentHeader';
import { AppContentHeader } from '../../../_components/AppContentHeader';
import { BreadcrumbSeperator } from '@/styles/context/useBreadcrumbStyles';
import { SegmentedProps } from 'antd/lib';
import { DataSetAppIcons, DatasetApps, DataSetAppText } from './_config';
import { DataSetAppIcons, DatasetApps, DataSetAppText } from '../_config';
import { BusterDataset } from '@/api/busterv2/datasets';
import { useMemoizedFn } from 'ahooks';
import { PublishDatasetModal } from './_PublishModal';
import { PublishDatasetModal } from '../_PublishModal';
import { useRouter } from 'next/navigation';
import { useUserConfigContextSelector } from '@/context/Users';
import { DatasetsHeaderOptions } from './DatasetHeaderOptions';
import { DatasetBreadcrumb } from './DatasetBreadcrumb';
import { DatasetIndividualThreeDotMenu } from './DatasetIndividualThreeDotMenu';
export const DatasetsIndividualHeader: React.FC<{
selectedApp: DatasetApps;
@ -28,28 +31,15 @@ export const DatasetsIndividualHeader: React.FC<{
const showSkeletonLoader = !selectedDataset?.id;
const [openPublishModal, setOpenPublishModal] = React.useState(false);
const isSQLApp = selectedApp === DatasetApps.SQL;
const isSQLApp = selectedApp === DatasetApps.EDITOR;
const disablePublish = useMemo(() => {
const originalSQL = selectedDataset?.definition || '';
return originalSQL === sql;
return !selectedDataset?.id || !sql || originalSQL === sql;
}, [selectedDataset?.definition, sql]);
const preventNavigation = !disablePublish;
const breadcrumbItems = [
{
title: (
<Link prefetch href={createBusterRoute({ route: BusterRoutes.APP_DATASETS })}>
Datasets
</Link>
)
},
{
title: selectedDataset?.name
}
].filter((item) => item.title);
const onReset = useMemoizedFn(() => {
setSQL(selectedDataset?.definition || '');
});
@ -68,6 +58,10 @@ export const DatasetsIndividualHeader: React.FC<{
}, 300);
});
const onOpenPublishModal = useMemoizedFn(() => {
setOpenPublishModal(true);
});
useHotkeys('d', () => {
setOpenNewDatasetModal(true);
});
@ -76,49 +70,33 @@ export const DatasetsIndividualHeader: React.FC<{
if (isSQLApp) setOpenPublishModal(true);
});
if (showSkeletonLoader) return <SkeletonLoader />;
if (showSkeletonLoader) return <></>;
return (
<>
<AppContentHeader className="items-center justify-between space-x-2">
<div className="flex space-x-1">
<Breadcrumb
className="flex items-center"
items={breadcrumbItems}
separator={<BreadcrumbSeperator />}
/>
{/* <DatasetFilters
activeFilters={dashboardListFilters}
onChangeFilter={onSetDatasetListFilters}
/> */}
</div>
<div className="flex items-center space-x-3">
<DatasetBreadcrumb datasetName={selectedDataset?.name} />
<div className="flex items-center">
<DatasetsHeaderOptions
isAdmin={isAdmin}
selectedApp={selectedApp}
datasetId={selectedDataset?.id || ''}
/>
</div>
<div
className="flex items-center"
style={{
display: isSQLApp ? 'flex' : 'none'
}}>
<Divider type="vertical" className="!h-5" />
<div className="flex items-center">
<div className="flex items-center">
<DatasetIndividualThreeDotMenu />
<Divider type="vertical" className="!h-4" />
<div className="flex items-center space-x-2">
<Button type="text" onClick={onReset} disabled={sql === selectedDataset?.definition}>
Reset
</Button>
<AppTooltip title={'Open publish dataset'} shortcuts={['p']}>
<Button
type="primary"
disabled={disablePublish}
onClick={() => {
setOpenPublishModal(true);
}}>
<Button type="primary" disabled={disablePublish} onClick={onOpenPublishModal}>
Publish
</Button>
</AppTooltip>
@ -147,75 +125,3 @@ export const DatasetsIndividualHeader: React.FC<{
</>
);
};
const keyToRoute = (datasetId: string, key: DatasetApps) => {
const record: Record<DatasetApps, string> = {
[DatasetApps.DESCRIPTIONS]: createBusterRoute({
route: BusterRoutes.APP_DATASETS_ID_DESCRIPTIONS,
datasetId
}),
[DatasetApps.OVERVIEW]: createBusterRoute({
route: BusterRoutes.APP_DATASETS_ID_OVERVIEW,
datasetId
}),
[DatasetApps.SQL]: createBusterRoute({
route: BusterRoutes.APP_DATASETS_ID_SQL,
datasetId
})
};
return record[key];
};
const DatasetsHeaderOptions: React.FC<{
selectedApp: DatasetApps;
isAdmin: boolean;
datasetId: string;
}> = ({ datasetId, isAdmin, selectedApp }) => {
const { push } = useRouter();
const optionsItems = isAdmin
? [DatasetApps.OVERVIEW, DatasetApps.DESCRIPTIONS, DatasetApps.SQL]
: [DatasetApps.OVERVIEW, DatasetApps.DESCRIPTIONS];
const options: SegmentedProps['options'] = optionsItems.map((key) => ({
label: (
<Link prefetch href={keyToRoute(datasetId, key)}>
{DataSetAppText[key as DatasetApps]}
</Link>
),
value: key,
icon: DataSetAppIcons[key as DatasetApps]
}));
return (
<AppSegmented
options={options}
value={selectedApp}
onChange={(value) => {
push(keyToRoute(datasetId, value as DatasetApps));
}}
/>
);
};
const SkeletonLoader: React.FC<{}> = () => {
const size = 'small';
const buttonShape = 'round';
return (
<AppContentHeader className="items-center justify-between space-x-2">
<div className="flex h-full w-3/4 items-center justify-center space-x-2">
<Skeleton.Button
className="!flex h-full min-w-12 !items-center"
size={size}
shape={buttonShape}
style={{ width: '100%' }}
/>
<Skeleton.Input
block
className="!flex h-full w-24 !items-center overflow-hidden rounded"
size={size}
/>
</div>
</AppContentHeader>
);
};

View File

@ -0,0 +1 @@
export * from './DatasetsIndividualHeader';

View File

@ -2,19 +2,19 @@ import { AppMaterialIcons } from '@/components';
import React from 'react';
export enum DatasetApps {
SQL = 'sql',
DESCRIPTIONS = 'descriptions',
OVERVIEW = 'overview'
OVERVIEW = 'overview',
PERMISSIONS = 'PERMISSIONS',
EDITOR = 'editor'
}
export const DataSetAppText: Record<DatasetApps, string> = {
[DatasetApps.OVERVIEW]: 'Overview',
[DatasetApps.DESCRIPTIONS]: 'Metadata',
[DatasetApps.SQL]: 'SQL Editor'
[DatasetApps.PERMISSIONS]: 'Permissions',
[DatasetApps.EDITOR]: 'Editor'
};
export const DataSetAppIcons: Record<DatasetApps, React.ReactNode> = {
[DatasetApps.OVERVIEW]: <AppMaterialIcons icon="info" />,
[DatasetApps.DESCRIPTIONS]: <AppMaterialIcons icon="menu_book" />,
[DatasetApps.SQL]: <AppMaterialIcons icon="data_object" />
[DatasetApps.PERMISSIONS]: <AppMaterialIcons icon="menu_book" />,
[DatasetApps.EDITOR]: <AppMaterialIcons icon="data_object" />
};

View File

@ -1,6 +1,6 @@
'use client';
import React, { useContext } from 'react';
import React from 'react';
import { DatasetIndividualContent } from '../_DatasetContent';
import { useDatasetPageContextSelector } from '../_DatasetPageContext';