mirror of https://github.com/usememos/memos.git
implement server side attachment filtering
This commit is contained in:
parent
4668c4714b
commit
0669e102d3
|
|
@ -159,6 +159,11 @@ func (s *APIV1Service) ListAttachments(ctx context.Context, request *v1pb.ListAt
|
||||||
Offset: &offset,
|
Offset: &offset,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if request.Filter != "" {
|
||||||
|
filter := strings.TrimSpace(request.Filter)
|
||||||
|
findAttachment.FilenameSearch = &filter
|
||||||
|
}
|
||||||
|
|
||||||
attachments, err := s.Store.ListAttachments(ctx, findAttachment)
|
attachments, err := s.Store.ListAttachments(ctx, findAttachment)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, status.Errorf(codes.Internal, "failed to list attachments: %v", err)
|
return nil, status.Errorf(codes.Internal, "failed to list attachments: %v", err)
|
||||||
|
|
|
||||||
|
|
@ -36,12 +36,6 @@ const groupAttachmentsByDate = (attachments: Attachment[]): Map<string, Attachme
|
||||||
return grouped;
|
return grouped;
|
||||||
};
|
};
|
||||||
|
|
||||||
const filterAttachments = (attachments: Attachment[], searchQuery: string): Attachment[] => {
|
|
||||||
if (!searchQuery.trim()) return attachments;
|
|
||||||
const query = searchQuery.toLowerCase();
|
|
||||||
return attachments.filter((attachment) => attachment.filename.toLowerCase().includes(query));
|
|
||||||
};
|
|
||||||
|
|
||||||
interface AttachmentItemProps {
|
interface AttachmentItemProps {
|
||||||
attachment: Attachment;
|
attachment: Attachment;
|
||||||
}
|
}
|
||||||
|
|
@ -74,20 +68,18 @@ const Attachments = observer(() => {
|
||||||
const [isLoadingMore, setIsLoadingMore] = useState(false);
|
const [isLoadingMore, setIsLoadingMore] = useState(false);
|
||||||
|
|
||||||
// Memoized computed values
|
// Memoized computed values
|
||||||
const filteredAttachments = useMemo(() => filterAttachments(attachments, searchQuery), [attachments, searchQuery]);
|
const usedAttachments = useMemo(() => attachments.filter((attachment) => attachment.memo), [attachments]);
|
||||||
|
const unusedAttachments = useMemo(() => attachments.filter((attachment) => !attachment.memo), [attachments]);
|
||||||
const usedAttachments = useMemo(() => filteredAttachments.filter((attachment) => attachment.memo), [filteredAttachments]);
|
|
||||||
|
|
||||||
const unusedAttachments = useMemo(() => filteredAttachments.filter((attachment) => !attachment.memo), [filteredAttachments]);
|
|
||||||
|
|
||||||
const groupedAttachments = useMemo(() => groupAttachmentsByDate(usedAttachments), [usedAttachments]);
|
const groupedAttachments = useMemo(() => groupAttachmentsByDate(usedAttachments), [usedAttachments]);
|
||||||
|
|
||||||
// Fetch initial attachments
|
// Fetch attachments with search filter
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
const fetchInitialAttachments = async () => {
|
const fetchAttachments = async () => {
|
||||||
|
loadingState.setLoading();
|
||||||
try {
|
try {
|
||||||
const { attachments: fetchedAttachments, nextPageToken } = await attachmentServiceClient.listAttachments({
|
const { attachments: fetchedAttachments, nextPageToken } = await attachmentServiceClient.listAttachments({
|
||||||
pageSize: PAGE_SIZE,
|
pageSize: PAGE_SIZE,
|
||||||
|
filter: searchQuery.trim(),
|
||||||
});
|
});
|
||||||
setAttachments(fetchedAttachments);
|
setAttachments(fetchedAttachments);
|
||||||
setNextPageToken(nextPageToken ?? "");
|
setNextPageToken(nextPageToken ?? "");
|
||||||
|
|
@ -99,9 +91,8 @@ const Attachments = observer(() => {
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
fetchInitialAttachments();
|
fetchAttachments();
|
||||||
// eslint-disable-next-line react-hooks/exhaustive-deps
|
}, [searchQuery]);
|
||||||
}, []);
|
|
||||||
|
|
||||||
// Load more attachments with pagination
|
// Load more attachments with pagination
|
||||||
const handleLoadMore = useCallback(async () => {
|
const handleLoadMore = useCallback(async () => {
|
||||||
|
|
@ -112,6 +103,7 @@ const Attachments = observer(() => {
|
||||||
const { attachments: fetchedAttachments, nextPageToken: newPageToken } = await attachmentServiceClient.listAttachments({
|
const { attachments: fetchedAttachments, nextPageToken: newPageToken } = await attachmentServiceClient.listAttachments({
|
||||||
pageSize: PAGE_SIZE,
|
pageSize: PAGE_SIZE,
|
||||||
pageToken: nextPageToken,
|
pageToken: nextPageToken,
|
||||||
|
filter: searchQuery.trim(),
|
||||||
});
|
});
|
||||||
setAttachments((prev) => [...prev, ...fetchedAttachments]);
|
setAttachments((prev) => [...prev, ...fetchedAttachments]);
|
||||||
setNextPageToken(newPageToken ?? "");
|
setNextPageToken(newPageToken ?? "");
|
||||||
|
|
@ -121,7 +113,7 @@ const Attachments = observer(() => {
|
||||||
} finally {
|
} finally {
|
||||||
setIsLoadingMore(false);
|
setIsLoadingMore(false);
|
||||||
}
|
}
|
||||||
}, [nextPageToken, isLoadingMore]);
|
}, [searchQuery, nextPageToken, isLoadingMore]);
|
||||||
|
|
||||||
// Refetch all attachments from the beginning
|
// Refetch all attachments from the beginning
|
||||||
const handleRefetch = useCallback(async () => {
|
const handleRefetch = useCallback(async () => {
|
||||||
|
|
@ -129,6 +121,7 @@ const Attachments = observer(() => {
|
||||||
loadingState.setLoading();
|
loadingState.setLoading();
|
||||||
const { attachments: fetchedAttachments, nextPageToken } = await attachmentServiceClient.listAttachments({
|
const { attachments: fetchedAttachments, nextPageToken } = await attachmentServiceClient.listAttachments({
|
||||||
pageSize: PAGE_SIZE,
|
pageSize: PAGE_SIZE,
|
||||||
|
filter: searchQuery.trim(),
|
||||||
});
|
});
|
||||||
setAttachments(fetchedAttachments);
|
setAttachments(fetchedAttachments);
|
||||||
setNextPageToken(nextPageToken ?? "");
|
setNextPageToken(nextPageToken ?? "");
|
||||||
|
|
@ -138,7 +131,7 @@ const Attachments = observer(() => {
|
||||||
loadingState.setError();
|
loadingState.setError();
|
||||||
toast.error("Failed to refresh attachments. Please try again.");
|
toast.error("Failed to refresh attachments. Please try again.");
|
||||||
}
|
}
|
||||||
}, [loadingState]);
|
}, [searchQuery, loadingState]);
|
||||||
|
|
||||||
// Delete all unused attachments
|
// Delete all unused attachments
|
||||||
const handleDeleteUnusedAttachments = useCallback(async () => {
|
const handleDeleteUnusedAttachments = useCallback(async () => {
|
||||||
|
|
@ -182,7 +175,7 @@ const Attachments = observer(() => {
|
||||||
</div>
|
</div>
|
||||||
) : (
|
) : (
|
||||||
<>
|
<>
|
||||||
{filteredAttachments.length === 0 ? (
|
{attachments.length === 0 ? (
|
||||||
<div className="w-full mt-8 mb-8 flex flex-col justify-center items-center italic">
|
<div className="w-full mt-8 mb-8 flex flex-col justify-center items-center italic">
|
||||||
<Empty />
|
<Empty />
|
||||||
<p className="mt-4 text-muted-foreground">{t("message.no-data")}</p>
|
<p className="mt-4 text-muted-foreground">{t("message.no-data")}</p>
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue