mirror of https://github.com/buster-so/buster.git
better handling for versions
This commit is contained in:
parent
0aad88d09f
commit
46c7e3ea67
|
@ -69,7 +69,10 @@ const useGetDashboardAndInitializeMetrics = () => {
|
|||
};
|
||||
|
||||
export const useGetDashboard = <TData = BusterDashboardResponse>(
|
||||
{ id, version_number: version_number_prop }: { id: string | undefined; version_number?: number },
|
||||
{
|
||||
id,
|
||||
version_number: version_number_prop
|
||||
}: { id: string | undefined; version_number?: number | null },
|
||||
select?: (data: BusterDashboardResponse) => TData
|
||||
) => {
|
||||
const searchParams = useSearchParams();
|
||||
|
@ -77,6 +80,7 @@ export const useGetDashboard = <TData = BusterDashboardResponse>(
|
|||
const queryVersionNumber = searchParams.get('dashboard_version_number');
|
||||
|
||||
const version_number = useMemo(() => {
|
||||
if (version_number_prop === null) return undefined;
|
||||
return version_number_prop || queryVersionNumber ? parseInt(queryVersionNumber!) : undefined;
|
||||
}, [version_number_prop, queryVersionNumber]);
|
||||
|
||||
|
|
|
@ -32,7 +32,13 @@ import { useSearchParams } from 'next/navigation';
|
|||
* This is a hook that will use the version number from the URL params if it exists.
|
||||
*/
|
||||
export const useGetMetric = <TData = IBusterMetric>(
|
||||
{ id, version_number: version_number_prop }: { id: string | undefined; version_number?: number },
|
||||
{
|
||||
id,
|
||||
version_number: version_number_prop
|
||||
}: {
|
||||
id: string | undefined;
|
||||
version_number?: number | null; //if null it will not use a params from the query params
|
||||
},
|
||||
select?: (data: IBusterMetric) => TData
|
||||
) => {
|
||||
const searchParams = useSearchParams();
|
||||
|
@ -44,6 +50,7 @@ export const useGetMetric = <TData = IBusterMetric>(
|
|||
const queryClient = useQueryClient();
|
||||
|
||||
const version_number = useMemo(() => {
|
||||
if (version_number_prop === null) return undefined;
|
||||
return version_number_prop || queryVersionNumber ? parseInt(queryVersionNumber!) : undefined;
|
||||
}, [version_number_prop, queryVersionNumber]);
|
||||
|
||||
|
|
|
@ -1,55 +1,57 @@
|
|||
import { useGetDashboard } from '@/api/buster_rest/dashboards';
|
||||
import { useGetMetric } from '@/api/buster_rest/metrics';
|
||||
import React from 'react';
|
||||
import last from 'lodash/last';
|
||||
import React, { useMemo } from 'react';
|
||||
import { Button } from '@/components/ui/buttons';
|
||||
import { Check3, Xmark } from '@/components/ui/icons';
|
||||
import { Text } from '@/components/ui/typography';
|
||||
import { useCloseVersionHistory } from '@/layouts/ChatLayout/FileContainer/FileContainerHeader/MetricContainerHeaderButtons/FileContainerVersionHistory';
|
||||
import { ScrollArea } from '@/components/ui/scroll-area';
|
||||
import { cn } from '@/lib/classMerge';
|
||||
import Link from 'next/link';
|
||||
import { useMemoizedFn } from '@/hooks';
|
||||
import { useAppLayoutContextSelector } from '@/context/BusterAppLayout';
|
||||
import { formatDate, timeFromNow } from '@/lib';
|
||||
import { timeFromNow } from '@/lib';
|
||||
import { AppPageLayout } from '@/components/ui/layouts';
|
||||
import { useSearchParams } from 'next/navigation';
|
||||
import last from 'lodash/last';
|
||||
|
||||
export const VersionHistoryPanel = React.memo(
|
||||
({ assetId, type }: { assetId: string; type: 'metric' | 'dashboard' }) => {
|
||||
const onChangeQueryParams = useAppLayoutContextSelector((x) => x.onChangeQueryParams);
|
||||
const { data: metricVersions, isFetched: isMetricFetched } = useGetMetric(
|
||||
{ id: type === 'metric' ? assetId : undefined },
|
||||
(x) => ({ versions: x.versions, latestVersion: last(x.versions) })
|
||||
);
|
||||
const { data: dashboardVersions, isFetched: isDashboardFetched } = useGetDashboard(
|
||||
{
|
||||
id: type === 'dashboard' ? assetId : undefined
|
||||
},
|
||||
(x) => ({ versions: x.dashboard.versions, latestVersion: last(x.dashboard.versions) })
|
||||
);
|
||||
const { dashboardVersions, selectedVersion: dashboardSelectedVersion } =
|
||||
useListDashboardVersions({
|
||||
assetId,
|
||||
type
|
||||
});
|
||||
const { metricVersions, selectedVersion: metricSelectedVersion } = useListMetricVersions({
|
||||
assetId,
|
||||
type
|
||||
});
|
||||
|
||||
const listItems = type === 'metric' ? metricVersions?.versions : dashboardVersions?.versions;
|
||||
const selectedVersion =
|
||||
type === 'metric' ? metricVersions?.latestVersion : dashboardVersions?.latestVersion;
|
||||
const listItems = useMemo(() => {
|
||||
const items = type === 'metric' ? metricVersions : dashboardVersions;
|
||||
return items ? [...items].reverse() : undefined;
|
||||
}, [type, dashboardVersions, metricVersions]);
|
||||
|
||||
const selectedVersion = useMemo(() => {
|
||||
return type === 'metric' ? metricSelectedVersion : dashboardSelectedVersion;
|
||||
}, [type, dashboardSelectedVersion, metricSelectedVersion]);
|
||||
|
||||
const onClickVersionHistory = useMemoizedFn((versionNumber: number) => {
|
||||
onChangeQueryParams({ metric_version_number: versionNumber.toString() });
|
||||
});
|
||||
|
||||
return (
|
||||
<div className="flex flex-col gap-y-2">
|
||||
<PanelHeader />
|
||||
|
||||
<ScrollArea className="h-[calc(100vh-10rem)]">
|
||||
<AppPageLayout header={<PanelHeader />} scrollable>
|
||||
<div className="my-2 flex flex-col px-1">
|
||||
{listItems?.map((item) => (
|
||||
<ListItem
|
||||
key={item.version_number}
|
||||
{...item}
|
||||
selected={item.version_number === selectedVersion?.version_number}
|
||||
selected={item.version_number === selectedVersion}
|
||||
onClickVersionHistory={onClickVersionHistory}
|
||||
/>
|
||||
))}
|
||||
</ScrollArea>
|
||||
</div>
|
||||
</div>
|
||||
</AppPageLayout>
|
||||
);
|
||||
}
|
||||
);
|
||||
|
@ -70,12 +72,14 @@ const ListItem = React.memo(
|
|||
<div
|
||||
onClick={() => onClickVersionHistory(version_number)}
|
||||
className={cn(
|
||||
'hover:bg-item-hover flex cursor-pointer items-center justify-between space-x-2 px-2.5 py-1.5',
|
||||
'hover:bg-item-hover flex cursor-pointer items-center justify-between space-x-2 rounded px-2.5 py-1.5',
|
||||
selected && 'bg-item-select hover:bg-item-select'
|
||||
)}>
|
||||
<div className="flex items-center gap-x-2">
|
||||
<div className="flex flex-col justify-center space-y-0.5">
|
||||
<Text>{`Version ${version_number}`}</Text>
|
||||
<Text variant={'secondary'}>{timeFromNow(updated_at)}</Text>
|
||||
<Text size={'xs'} variant={'secondary'}>
|
||||
{timeFromNow(updated_at, false)}
|
||||
</Text>
|
||||
</div>
|
||||
{selected && (
|
||||
<div className="text-icon-color flex items-center">
|
||||
|
@ -92,7 +96,7 @@ const PanelHeader = React.memo(() => {
|
|||
const removeVersionHistoryQueryParams = useCloseVersionHistory();
|
||||
|
||||
return (
|
||||
<div className="flex items-center justify-between px-4 py-2.5">
|
||||
<div className="flex items-center justify-between">
|
||||
<Text>Version History</Text>
|
||||
<Button variant="ghost" prefix={<Xmark />} onClick={removeVersionHistoryQueryParams} />
|
||||
</div>
|
||||
|
@ -101,3 +105,61 @@ const PanelHeader = React.memo(() => {
|
|||
PanelHeader.displayName = 'PanelHeader';
|
||||
|
||||
VersionHistoryPanel.displayName = 'VersionHistoryPanel';
|
||||
|
||||
const useListDashboardVersions = ({
|
||||
assetId,
|
||||
type
|
||||
}: {
|
||||
assetId: string;
|
||||
type: 'metric' | 'dashboard';
|
||||
}) => {
|
||||
const selectedVersionParam = useSearchParams().get('dashboard_version_number');
|
||||
const { data: dashboardVersions } = useGetDashboard(
|
||||
{
|
||||
id: type === 'dashboard' ? assetId : undefined,
|
||||
version_number: null
|
||||
},
|
||||
(x) => x.dashboard.versions
|
||||
);
|
||||
|
||||
const selectedVersion = useMemo(() => {
|
||||
if (selectedVersionParam) return parseInt(selectedVersionParam);
|
||||
return last(dashboardVersions)?.version_number;
|
||||
}, [dashboardVersions, selectedVersionParam]);
|
||||
|
||||
return useMemo(() => {
|
||||
return {
|
||||
dashboardVersions,
|
||||
selectedVersion
|
||||
};
|
||||
}, [dashboardVersions, selectedVersion]);
|
||||
};
|
||||
|
||||
const useListMetricVersions = ({
|
||||
assetId,
|
||||
type
|
||||
}: {
|
||||
assetId: string;
|
||||
type: 'metric' | 'dashboard';
|
||||
}) => {
|
||||
const selectedVersionParam = useSearchParams().get('metric_version_number');
|
||||
const { data: metricVersions } = useGetMetric(
|
||||
{
|
||||
id: type === 'metric' ? assetId : undefined,
|
||||
version_number: null
|
||||
},
|
||||
(x) => x.versions
|
||||
);
|
||||
|
||||
const selectedVersion = useMemo(() => {
|
||||
if (selectedVersionParam) return parseInt(selectedVersionParam);
|
||||
return last(metricVersions)?.version_number;
|
||||
}, [metricVersions, selectedVersionParam]);
|
||||
|
||||
return useMemo(() => {
|
||||
return {
|
||||
metricVersions,
|
||||
selectedVersion
|
||||
};
|
||||
}, [metricVersions, selectedVersion]);
|
||||
};
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
'use client';
|
||||
|
||||
import React, { useMemo, useRef } from 'react';
|
||||
import React, { useLayoutEffect, useMemo, useRef } from 'react';
|
||||
import { FileContainerHeader } from './FileContainerHeader';
|
||||
import { AppPageLayout, AppSplitter, AppSplitterRef } from '@/components/ui/layouts';
|
||||
import { useChatLayoutContextSelector } from '../ChatLayoutContext';
|
||||
|
@ -58,7 +58,7 @@ export const FileContainer: React.FC<FileContainerProps> = ({ children }) => {
|
|||
return defaulClosedLayout;
|
||||
}, []);
|
||||
|
||||
const animateOpenSplitter = useMemoizedFn((side: 'open' | 'closed') => {
|
||||
const animateOpenSplitter = useMemoizedFn(async (side: 'open' | 'closed') => {
|
||||
if (side === 'open') {
|
||||
appSplitterRef.current?.animateWidth(defaultOpenLayout[1], 'right');
|
||||
} else {
|
||||
|
@ -75,8 +75,10 @@ export const FileContainer: React.FC<FileContainerProps> = ({ children }) => {
|
|||
);
|
||||
}, [debouncedSelectedFileViewSecondary, selectedFile?.id, selectedFile?.type]);
|
||||
|
||||
useUpdateLayoutEffect(() => {
|
||||
animateOpenSplitter(isOpenSecondary ? 'open' : 'closed');
|
||||
useLayoutEffect(() => {
|
||||
setTimeout(() => {
|
||||
animateOpenSplitter(isOpenSecondary ? 'open' : 'closed');
|
||||
}, 25);
|
||||
}, [isOpenSecondary]);
|
||||
|
||||
return (
|
||||
|
|
|
@ -207,7 +207,7 @@ export const isDateAfter = ({
|
|||
return dayjs(date).isAfter(compareDate, interval);
|
||||
};
|
||||
|
||||
export const timeFromNow = (date: string | Date, relative = true) => {
|
||||
export const timeFromNow = (date: string | Date, relative = false) => {
|
||||
return dayjs(new Date(date)).fromNow(relative);
|
||||
};
|
||||
|
||||
|
|
Loading…
Reference in New Issue