mirror of
https://github.com/docmost/docmost.git
synced 2026-05-20 00:14:10 +08:00
prefetch history
This commit is contained in:
@@ -3,18 +3,40 @@ import { CustomAvatar } from "@/components/ui/custom-avatar.tsx";
|
|||||||
import { formattedDate } from "@/lib/time";
|
import { formattedDate } from "@/lib/time";
|
||||||
import classes from "./history.module.css";
|
import classes from "./history.module.css";
|
||||||
import clsx from "clsx";
|
import clsx from "clsx";
|
||||||
|
import { IPageHistory } from "@/features/page-history/types/page.types";
|
||||||
|
import { memo, useCallback } from "react";
|
||||||
|
|
||||||
interface HistoryItemProps {
|
interface HistoryItemProps {
|
||||||
historyItem: any;
|
historyItem: IPageHistory;
|
||||||
onSelect: (id: string) => void;
|
index: number;
|
||||||
|
onSelect: (id: string, index: number) => void;
|
||||||
|
onHover?: (id: string) => void;
|
||||||
|
onHoverEnd?: () => void;
|
||||||
isActive: boolean;
|
isActive: boolean;
|
||||||
}
|
}
|
||||||
|
|
||||||
function HistoryItem({ historyItem, onSelect, isActive }: HistoryItemProps) {
|
const HistoryItem = memo(function HistoryItem({
|
||||||
|
historyItem,
|
||||||
|
index,
|
||||||
|
onSelect,
|
||||||
|
onHover,
|
||||||
|
onHoverEnd,
|
||||||
|
isActive,
|
||||||
|
}: HistoryItemProps) {
|
||||||
|
const handleClick = useCallback(() => {
|
||||||
|
onSelect(historyItem.id, index);
|
||||||
|
}, [onSelect, historyItem.id, index]);
|
||||||
|
|
||||||
|
const handleMouseEnter = useCallback(() => {
|
||||||
|
onHover?.(historyItem.id);
|
||||||
|
}, [onHover, historyItem.id]);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<UnstyledButton
|
<UnstyledButton
|
||||||
p="xs"
|
p="xs"
|
||||||
onClick={() => onSelect(historyItem.id)}
|
onClick={handleClick}
|
||||||
|
onMouseEnter={handleMouseEnter}
|
||||||
|
onMouseLeave={onHoverEnd}
|
||||||
className={clsx(classes.history, { [classes.active]: isActive })}
|
className={clsx(classes.history, { [classes.active]: isActive })}
|
||||||
>
|
>
|
||||||
<Group wrap="nowrap">
|
<Group wrap="nowrap">
|
||||||
@@ -27,11 +49,11 @@ function HistoryItem({ historyItem, onSelect, isActive }: HistoryItemProps) {
|
|||||||
<Group gap={4} wrap="nowrap">
|
<Group gap={4} wrap="nowrap">
|
||||||
<CustomAvatar
|
<CustomAvatar
|
||||||
size="sm"
|
size="sm"
|
||||||
avatarUrl={historyItem.lastUpdatedBy.avatarUrl}
|
avatarUrl={historyItem.lastUpdatedBy?.avatarUrl}
|
||||||
name={historyItem.lastUpdatedBy.name}
|
name={historyItem.lastUpdatedBy?.name}
|
||||||
/>
|
/>
|
||||||
<Text size="sm" c="dimmed" lineClamp={1}>
|
<Text size="sm" c="dimmed" lineClamp={1}>
|
||||||
{historyItem.lastUpdatedBy.name}
|
{historyItem.lastUpdatedBy?.name}
|
||||||
</Text>
|
</Text>
|
||||||
</Group>
|
</Group>
|
||||||
</div>
|
</div>
|
||||||
@@ -39,6 +61,6 @@ function HistoryItem({ historyItem, onSelect, isActive }: HistoryItemProps) {
|
|||||||
</Group>
|
</Group>
|
||||||
</UnstyledButton>
|
</UnstyledButton>
|
||||||
);
|
);
|
||||||
}
|
});
|
||||||
|
|
||||||
export default HistoryItem;
|
export default HistoryItem;
|
||||||
|
|||||||
@@ -2,6 +2,8 @@ import {
|
|||||||
usePageHistoryListQuery,
|
usePageHistoryListQuery,
|
||||||
usePageHistoryQuery,
|
usePageHistoryQuery,
|
||||||
} from "@/features/page-history/queries/page-history-query";
|
} from "@/features/page-history/queries/page-history-query";
|
||||||
|
import { getPageHistoryById } from "@/features/page-history/services/page-history-service";
|
||||||
|
import { queryClient } from "@/main";
|
||||||
import HistoryItem from "@/features/page-history/components/history-item";
|
import HistoryItem from "@/features/page-history/components/history-item";
|
||||||
import {
|
import {
|
||||||
activeHistoryIdAtom,
|
activeHistoryIdAtom,
|
||||||
@@ -34,6 +36,8 @@ import {
|
|||||||
SpaceCaslSubject,
|
SpaceCaslSubject,
|
||||||
} from "@/features/space/permissions/permissions.type.ts";
|
} from "@/features/space/permissions/permissions.type.ts";
|
||||||
|
|
||||||
|
const PREFETCH_DELAY_MS = 300;
|
||||||
|
|
||||||
interface Props {
|
interface Props {
|
||||||
pageId: string;
|
pageId: string;
|
||||||
}
|
}
|
||||||
@@ -58,6 +62,7 @@ function HistoryList({ pageId }: Props) {
|
|||||||
);
|
);
|
||||||
|
|
||||||
const loadMoreRef = useRef<HTMLDivElement>(null);
|
const loadMoreRef = useRef<HTMLDivElement>(null);
|
||||||
|
const prefetchTimeoutRef = useRef<ReturnType<typeof setTimeout> | null>(null);
|
||||||
|
|
||||||
const [mainEditor] = useAtom(pageEditorAtom);
|
const [mainEditor] = useAtom(pageEditorAtom);
|
||||||
const [mainEditorTitle] = useAtom(titleEditorAtom);
|
const [mainEditorTitle] = useAtom(titleEditorAtom);
|
||||||
@@ -99,6 +104,35 @@ function HistoryList({ pageId }: Props) {
|
|||||||
}
|
}
|
||||||
}, [activeHistoryData]);
|
}, [activeHistoryData]);
|
||||||
|
|
||||||
|
const clearPrefetchTimeout = useCallback(() => {
|
||||||
|
if (prefetchTimeoutRef.current) {
|
||||||
|
clearTimeout(prefetchTimeoutRef.current);
|
||||||
|
prefetchTimeoutRef.current = null;
|
||||||
|
}
|
||||||
|
}, []);
|
||||||
|
|
||||||
|
const handleHover = useCallback((historyId: string) => {
|
||||||
|
clearPrefetchTimeout();
|
||||||
|
prefetchTimeoutRef.current = setTimeout(() => {
|
||||||
|
queryClient.prefetchQuery({
|
||||||
|
queryKey: ["page-history", historyId],
|
||||||
|
queryFn: () => getPageHistoryById(historyId),
|
||||||
|
});
|
||||||
|
}, PREFETCH_DELAY_MS);
|
||||||
|
}, [clearPrefetchTimeout]);
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
return clearPrefetchTimeout;
|
||||||
|
}, [clearPrefetchTimeout]);
|
||||||
|
|
||||||
|
const handleSelect = useCallback(
|
||||||
|
(id: string, index: number) => {
|
||||||
|
setActiveHistoryId(id);
|
||||||
|
setActiveHistoryPrevId(historyItems[index + 1]?.id ?? "");
|
||||||
|
},
|
||||||
|
[historyItems, setActiveHistoryId, setActiveHistoryPrevId],
|
||||||
|
);
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
if (historyItems.length > 0 && !activeHistoryId) {
|
if (historyItems.length > 0 && !activeHistoryId) {
|
||||||
setActiveHistoryId(historyItems[0].id);
|
setActiveHistoryId(historyItems[0].id);
|
||||||
@@ -142,10 +176,10 @@ function HistoryList({ pageId }: Props) {
|
|||||||
<HistoryItem
|
<HistoryItem
|
||||||
key={historyItem.id}
|
key={historyItem.id}
|
||||||
historyItem={historyItem}
|
historyItem={historyItem}
|
||||||
onSelect={(id) => {
|
index={index}
|
||||||
setActiveHistoryId(id);
|
onSelect={handleSelect}
|
||||||
setActiveHistoryPrevId(historyItems[index + 1]?.id ?? "");
|
onHover={handleHover}
|
||||||
}}
|
onHoverEnd={clearPrefetchTimeout}
|
||||||
isActive={historyItem.id === activeHistoryId}
|
isActive={historyItem.id === activeHistoryId}
|
||||||
/>
|
/>
|
||||||
))}
|
))}
|
||||||
|
|||||||
Reference in New Issue
Block a user