buster/web/src/components/features/versionHistory/VersionHistoryPanel.tsx

137 lines
4.4 KiB
TypeScript
Raw Normal View History

2025-03-27 00:40:26 +08:00
import React, { useMemo, useRef } from 'react';
2025-03-26 14:17:01 +08:00
import { Button } from '@/components/ui/buttons';
2025-03-29 05:15:49 +08:00
import { Xmark, History } from '@/components/ui/icons';
2025-03-27 00:13:37 +08:00
import { Check3 } from '@/components/ui/icons/NucleoIconFilled';
2025-03-26 14:17:01 +08:00
import { Text } from '@/components/ui/typography';
2025-03-27 00:40:26 +08:00
import { useCloseVersionHistory } from '@/layouts/ChatLayout/FileContainer/FileContainerHeader/FileContainerHeaderVersionHistory';
2025-03-26 14:17:01 +08:00
import { cn } from '@/lib/classMerge';
2025-03-27 00:40:26 +08:00
import { timeFromNow, timeout } from '@/lib';
2025-03-26 23:57:12 +08:00
import { AppPageLayout } from '@/components/ui/layouts';
2025-03-27 00:40:26 +08:00
import { useListVersionHistories } from './useListVersionHistories';
import { useMount } from '@/hooks';
2025-03-29 05:15:49 +08:00
import { AppTooltip } from '@/components/ui/tooltip';
2025-03-26 13:14:36 +08:00
export const VersionHistoryPanel = React.memo(
({ assetId, type }: { assetId: string; type: 'metric' | 'dashboard' }) => {
2025-03-29 05:15:49 +08:00
const removeVersionHistoryQueryParams = useCloseVersionHistory();
const {
listItems,
selectedVersion,
selectedQueryVersion,
onClickRestoreVersion,
onClickVersionHistory
} = useListVersionHistories({
2025-03-26 23:57:12 +08:00
assetId,
type
});
2025-03-27 00:40:26 +08:00
const bodyRef = useRef<HTMLDivElement>(null);
2025-03-26 14:17:01 +08:00
2025-03-27 00:40:26 +08:00
useMount(async () => {
if (bodyRef.current) {
2025-03-29 05:15:49 +08:00
await timeout(250);
2025-03-27 00:40:26 +08:00
const selectedNode = bodyRef.current.querySelector('.selected-version');
if (selectedNode) {
selectedNode.scrollIntoView({ behavior: 'smooth', block: 'start' });
}
}
2025-03-26 14:17:01 +08:00
});
return (
2025-03-26 23:59:56 +08:00
<AppPageLayout
2025-03-29 05:15:49 +08:00
headerClassName="border-l"
2025-03-26 23:59:56 +08:00
header={useMemo(
() => (
2025-03-29 05:15:49 +08:00
<PanelHeader removeVersionHistoryQueryParams={removeVersionHistoryQueryParams} />
2025-03-26 23:59:56 +08:00
),
[]
)}
scrollable
2025-03-29 05:15:49 +08:00
headerBorderVariant="ghost">
2025-03-27 00:40:26 +08:00
<div ref={bodyRef} className="mx-1.5 mb-1.5 flex flex-col">
2025-03-26 14:17:01 +08:00
{listItems?.map((item) => (
<ListItem
key={item.version_number}
{...item}
2025-03-29 05:15:49 +08:00
selected={item.version_number === selectedQueryVersion}
showRestoreButton={item.version_number !== selectedVersion}
2025-03-26 14:17:01 +08:00
onClickVersionHistory={onClickVersionHistory}
2025-03-29 05:15:49 +08:00
onClickRestoreVersion={onClickRestoreVersion}
2025-03-26 14:17:01 +08:00
/>
))}
2025-03-26 23:57:12 +08:00
</div>
</AppPageLayout>
2025-03-26 14:17:01 +08:00
);
2025-03-26 13:14:36 +08:00
}
);
2025-03-26 14:17:01 +08:00
const ListItem = React.memo(
({
version_number,
updated_at,
selected,
2025-03-29 05:15:49 +08:00
showRestoreButton,
onClickVersionHistory,
onClickRestoreVersion
2025-03-26 14:17:01 +08:00
}: {
version_number: number;
updated_at: string;
selected: boolean;
2025-03-29 05:15:49 +08:00
showRestoreButton: boolean;
2025-03-26 14:17:01 +08:00
onClickVersionHistory: (versionNumber: number) => void;
2025-03-29 05:15:49 +08:00
onClickRestoreVersion: (versionNumber: number) => void;
2025-03-26 14:17:01 +08:00
}) => {
return (
<div
onClick={() => onClickVersionHistory(version_number)}
className={cn(
2025-03-29 05:15:49 +08:00
'group hover:bg-item-hover flex cursor-pointer items-center justify-between space-x-2 rounded px-2.5 py-1.5',
2025-03-27 00:40:26 +08:00
selected && 'bg-item-select hover:bg-item-select selected-version'
2025-03-26 14:17:01 +08:00
)}>
2025-03-26 23:57:12 +08:00
<div className="flex flex-col justify-center space-y-0.5">
2025-03-26 14:17:01 +08:00
<Text>{`Version ${version_number}`}</Text>
2025-03-26 23:57:12 +08:00
<Text size={'xs'} variant={'secondary'}>
{timeFromNow(updated_at, false)}
</Text>
2025-03-26 14:17:01 +08:00
</div>
2025-03-29 05:15:49 +08:00
<div className="text-icon-color animate-in fade-in-0 flex items-center space-x-2 duration-200">
{showRestoreButton && (
<AppTooltip title="Restore version">
<div
onClick={(e) => {
e.stopPropagation();
e.preventDefault();
onClickRestoreVersion(version_number);
}}
className="hover:bg-item-select -mr-1 rounded p-1 opacity-0 group-hover:block group-hover:opacity-100">
<History />
</div>
</AppTooltip>
)}
{selected && (
<div className="group-hover:opacity-100">
<Check3 />
</div>
)}
</div>
2025-03-26 14:17:01 +08:00
</div>
);
}
);
ListItem.displayName = 'ListItem';
2025-03-29 05:15:49 +08:00
const PanelHeader = React.memo(
({ removeVersionHistoryQueryParams }: { removeVersionHistoryQueryParams: () => void }) => {
return (
<div className="flex w-full items-center justify-between">
<Text>Version History</Text>
<Button variant="ghost" prefix={<Xmark />} onClick={removeVersionHistoryQueryParams} />
</div>
);
}
);
2025-03-26 14:17:01 +08:00
PanelHeader.displayName = 'PanelHeader';
2025-03-26 13:14:36 +08:00
VersionHistoryPanel.displayName = 'VersionHistoryPanel';