🐛 fix: Fix file search error and support debounced search.(#27)
This commit is contained in:
parent
488f167e13
commit
a48a62c3d6
4 changed files with 49 additions and 15 deletions
|
|
@ -5,6 +5,7 @@ import cn.hutool.core.convert.Convert;
|
||||||
import cn.hutool.core.io.FileUtil;
|
import cn.hutool.core.io.FileUtil;
|
||||||
import cn.hutool.core.util.NumberUtil;
|
import cn.hutool.core.util.NumberUtil;
|
||||||
import cn.hutool.core.util.StrUtil;
|
import cn.hutool.core.util.StrUtil;
|
||||||
|
import cn.hutool.core.util.URLUtil;
|
||||||
import cn.hutool.log.Log;
|
import cn.hutool.log.Log;
|
||||||
import cn.hutool.log.LogFactory;
|
import cn.hutool.log.LogFactory;
|
||||||
import io.vertx.core.*;
|
import io.vertx.core.*;
|
||||||
|
|
@ -413,10 +414,14 @@ public class HttpVerticle extends AbstractVerticle {
|
||||||
ctx.fail(400);
|
ctx.fail(400);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
Map<String, String> filter = new HashMap<>();
|
||||||
|
ctx.request().params().forEach(filter::put);
|
||||||
|
filter.put("search", URLUtil.decode(filter.get("search")));
|
||||||
|
|
||||||
long chatId = Convert.toLong(chatIdStr);
|
long chatId = Convert.toLong(chatIdStr);
|
||||||
getTelegramVerticle(telegramId)
|
getTelegramVerticle(telegramId)
|
||||||
.ifPresentOrElse(telegramVerticle ->
|
.ifPresentOrElse(telegramVerticle ->
|
||||||
telegramVerticle.getChatFiles(chatId, ctx.request().params())
|
telegramVerticle.getChatFiles(chatId, filter)
|
||||||
.onSuccess(ctx::json)
|
.onSuccess(ctx::json)
|
||||||
.onFailure(ctx::fail),
|
.onFailure(ctx::fail),
|
||||||
() -> ctx.fail(404));
|
() -> ctx.fail(404));
|
||||||
|
|
|
||||||
|
|
@ -175,12 +175,10 @@ public class TelegramVerticle extends AbstractVerticle {
|
||||||
return this.convertChat(telegramChats.getChatList(activatedChatId, query, 100, archived));
|
return this.convertChat(telegramChats.getChatList(activatedChatId, query, 100, archived));
|
||||||
}
|
}
|
||||||
|
|
||||||
public Future<JsonObject> getChatFiles(long chatId, MultiMap filter) {
|
public Future<JsonObject> getChatFiles(long chatId, Map<String, String> filter) {
|
||||||
String status = filter.get("status");
|
String status = filter.get("status");
|
||||||
if (Arrays.asList("downloading", "paused", "completed", "error").contains(status)) {
|
if (Arrays.asList("downloading", "paused", "completed", "error").contains(status)) {
|
||||||
Map<String, String> filterMap = new HashMap<>();
|
return DataVerticle.fileRepository.getFiles(chatId, filter)
|
||||||
filter.forEach(filterMap::put);
|
|
||||||
return DataVerticle.fileRepository.getFiles(chatId, filterMap)
|
|
||||||
.compose(r -> {
|
.compose(r -> {
|
||||||
long[] messageIds = r.v1.stream().mapToLong(FileRecord::messageId).toArray();
|
long[] messageIds = r.v1.stream().mapToLong(FileRecord::messageId).toArray();
|
||||||
return client.execute(new TdApi.GetMessages(chatId, messageIds))
|
return client.execute(new TdApi.GetMessages(chatId, messageIds))
|
||||||
|
|
|
||||||
|
|
@ -13,6 +13,10 @@ import TableColumnFilter, {
|
||||||
import { type RowHeight } from "@/components/table-row-height-switch";
|
import { type RowHeight } from "@/components/table-row-height-switch";
|
||||||
import FileTypeFilter from "@/components/file-type-filter";
|
import FileTypeFilter from "@/components/file-type-filter";
|
||||||
import dynamic from "next/dynamic";
|
import dynamic from "next/dynamic";
|
||||||
|
import { useDebouncedCallback } from "use-debounce";
|
||||||
|
import { useEffect, useState } from "react";
|
||||||
|
import { X } from "lucide-react";
|
||||||
|
import { Button } from "./ui/button";
|
||||||
|
|
||||||
interface FileFiltersProps {
|
interface FileFiltersProps {
|
||||||
telegramId: string;
|
telegramId: string;
|
||||||
|
|
@ -43,17 +47,37 @@ export function FileFilters({
|
||||||
rowHeight,
|
rowHeight,
|
||||||
setRowHeight,
|
setRowHeight,
|
||||||
}: FileFiltersProps) {
|
}: FileFiltersProps) {
|
||||||
|
const [search, setSearch] = useState(filters.search);
|
||||||
|
|
||||||
|
const handleSearchChange = useDebouncedCallback((search: string) => {
|
||||||
|
onFiltersChange({ ...filters, search });
|
||||||
|
}, 500);
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
handleSearchChange(search);
|
||||||
|
}, [search, handleSearchChange]);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className="mb-6 flex flex-col justify-between md:flex-row">
|
<div className="mb-6 flex flex-col justify-between md:flex-row">
|
||||||
<div className="grid grid-cols-2 gap-4 md:flex md:flex-row">
|
<div className="grid grid-cols-2 gap-4 md:flex md:flex-row">
|
||||||
<Input
|
<div className="relative">
|
||||||
placeholder="Search files..."
|
<Input
|
||||||
value={filters.search}
|
placeholder="Search files..."
|
||||||
onChange={(e) =>
|
value={search}
|
||||||
onFiltersChange({ ...filters, search: e.target.value })
|
onChange={(e) => setSearch(e.target.value)}
|
||||||
}
|
className="relative col-span-2 md:w-[300px]"
|
||||||
className="col-span-2 md:w-[300px]"
|
/>
|
||||||
/>
|
{search && (
|
||||||
|
<Button
|
||||||
|
variant="ghost"
|
||||||
|
size="icon"
|
||||||
|
className="absolute right-2 top-1/2 h-6 w-6 -translate-y-1/2 rounded-full text-gray-500 transition-all duration-200 hover:scale-110 hover:bg-gray-100 hover:text-gray-800"
|
||||||
|
onClick={() => setSearch("")}
|
||||||
|
>
|
||||||
|
<X className="h-4 w-4" />
|
||||||
|
</Button>
|
||||||
|
)}
|
||||||
|
</div>
|
||||||
|
|
||||||
<FileTypeFilter
|
<FileTypeFilter
|
||||||
telegramId={telegramId}
|
telegramId={telegramId}
|
||||||
|
|
|
||||||
|
|
@ -42,15 +42,22 @@ export function useFiles(accountId: string, chatId: string) {
|
||||||
DEFAULT_FILTERS,
|
DEFAULT_FILTERS,
|
||||||
);
|
);
|
||||||
const getKey = (page: number, previousPageData: FileResponse) => {
|
const getKey = (page: number, previousPageData: FileResponse) => {
|
||||||
|
const params = new URLSearchParams({
|
||||||
|
...(filters.search && { search: window.encodeURIComponent(filters.search) }),
|
||||||
|
...(filters.type && { type: filters.type }),
|
||||||
|
...(filters.status && { status: filters.status })
|
||||||
|
});
|
||||||
|
|
||||||
if (page === 0) {
|
if (page === 0) {
|
||||||
return `/telegram/${accountId}/chat/${chatId}/files?search=${filters.search}&type=${filters.type}&status=${filters.status}`;
|
return `/telegram/${accountId}/chat/${chatId}/files?${params.toString()}`;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!previousPageData) {
|
if (!previousPageData) {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
return `/telegram/${accountId}/chat/${chatId}/files?search=${filters.search}&type=${filters.type}&status=${filters.status}&fromMessageId=${previousPageData.nextFromMessageId}`;
|
params.set("fromMessageId", previousPageData.nextFromMessageId.toString());
|
||||||
|
return `/telegram/${accountId}/chat/${chatId}/files?${params.toString()}`;
|
||||||
};
|
};
|
||||||
|
|
||||||
const {
|
const {
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue