diff --git a/public/locales/en-US/application.json b/public/locales/en-US/application.json index 073239c..122cf9a 100644 --- a/public/locales/en-US/application.json +++ b/public/locales/en-US/application.json @@ -622,7 +622,12 @@ "copyLinkToClipboard": "Copy link to clipboard" }, "download": { + "noFilesFound": "No files found", + "filterByName": "Filter by name", + "selectAll": "Select all", + "reverseSelect": "Reverse select", "cancelTaskConfirm": "Are you sure to cancel this download task?", + "saveChanges": "Save changes", "failedToLoad": "Failed to load.", "active": "Active", "finished": "Finished", diff --git a/public/locales/zh-CN/application.json b/public/locales/zh-CN/application.json index c8506a4..3469508 100644 --- a/public/locales/zh-CN/application.json +++ b/public/locales/zh-CN/application.json @@ -622,6 +622,10 @@ "copyLinkToClipboard": "复制链接到剪切板" }, "download": { + "noFilesFound": "没有找到任何文件", + "filterByName": "按名称过滤", + "selectAll": "全选", + "reverseSelect": "反选", "cancelTaskConfirm": "确定要取消此任务吗?", "saveChanges": "保存更改", "failedToLoad": "加载失败", diff --git a/public/locales/zh-TW/application.json b/public/locales/zh-TW/application.json index f5959b1..c7739f9 100644 --- a/public/locales/zh-TW/application.json +++ b/public/locales/zh-TW/application.json @@ -622,6 +622,10 @@ "copyLinkToClipboard": "復制連結到剪下板" }, "download": { + "noFilesFound": "沒有找到任何檔案", + "filterByName": "按名稱過濾", + "selectAll": "全選", + "reverseSelect": "反選", "cancelTaskConfirm": "確定要取消此任務嗎?", "saveChanges": "儲存更改", "failedToLoad": "載入失敗", diff --git a/src/component/Pages/Tasks/DownloadFileList.tsx b/src/component/Pages/Tasks/DownloadFileList.tsx index 3241498..c3bab09 100644 --- a/src/component/Pages/Tasks/DownloadFileList.tsx +++ b/src/component/Pages/Tasks/DownloadFileList.tsx @@ -2,10 +2,12 @@ import { Box, Button, Grow, + Stack, Table, TableCell, TableContainer, TableRow, + TextField, Typography, useTheme, } from "@mui/material"; @@ -19,10 +21,7 @@ import { DownloadTaskFile, TaskSummary } from "../../../api/workflow.ts"; import { useAppDispatch } from "../../../redux/hooks.ts"; import { confirmOperation } from "../../../redux/thunks/dialog.ts"; import { fileBase, sizeToString } from "../../../util"; -import { - StyledCheckbox, - StyledTableContainerPaper, -} from "../../Common/StyledComponents.tsx"; +import { StyledCheckbox, StyledTableContainerPaper } from "../../Common/StyledComponents.tsx"; import FileIcon from "../../FileManager/Explorer/FileIcon.tsx"; import Dismiss from "../../Icons/Dismiss.tsx"; import { getProgressColor } from "./TaskCard.tsx"; @@ -41,6 +40,7 @@ const DownloadFileList = ({ taskId, summary, downloading, readonly }: DownloadFi const [changeApplied, setChangeApplied] = useState(true); const [loading, setLoading] = useState(false); const [height, setHeight] = useState(33); + const [filterText, setFilterText] = useState(""); const files = summary?.props?.download?.files; const { t } = useTranslation(); const theme = useTheme(); @@ -51,6 +51,16 @@ const DownloadFileList = ({ taskId, summary, downloading, readonly }: DownloadFi return getProgressColor(theme); }, [theme]); + const filteredFiles = useMemo(() => { + if (!files) { + return []; + } + if (!filterText) { + return files; + } + return files.filter((file) => file.name.toLowerCase().includes(filterText.toLowerCase())); + }, [files, filterText]); + const setFileSelected = (value: DownloadTaskFile, selected: boolean) => { setSelectedMask((prev) => { return { @@ -83,6 +93,25 @@ const DownloadFileList = ({ taskId, summary, downloading, readonly }: DownloadFi }); }; + const selectAll = () => { + const newMask = { ...selectedMask }; + filteredFiles.forEach((file) => { + newMask[file.index] = true; + }); + setSelectedMask(newMask); + setChangeApplied(false); + }; + + const reverseSelect = () => { + const newMask = { ...selectedMask }; + filteredFiles.forEach((file) => { + const currentSelection = newMask[file.index] ?? file.selected; + newMask[file.index] = !currentSelection; + }); + setSelectedMask(newMask); + setChangeApplied(false); + }; + const cancelTask = () => { dispatch(confirmOperation(t("download.cancelTaskConfirm"))).then(() => { setLoading(true); @@ -102,79 +131,104 @@ const DownloadFileList = ({ taskId, summary, downloading, readonly }: DownloadFi return ( {files && ( - - { - setHeight(h + 0.5); - }} - components={{ - // eslint-disable-next-line react/display-name - Table: (props) => , - // eslint-disable-next-line react/display-name - TableRow: (props) => { - const index = props["data-index"]; - const percentage = (files[index]?.progress ?? 0) * 100; - const progressBgColor = theme.palette.background.default; - return ( - - ); - }, - }} - data={files} - itemContent={(_index, value) => ( - <> - - { - setFileSelected(value, e.target.checked); - }} - disabled={!downloading || readonly} - disableRipple - checked={selectedMask[value.index] ?? value.selected} - size="small" - /> - - - - + {!readonly && files.length > 20 && ( + + setFilterText(e.target.value)} + sx={{ flexGrow: 1 }} + /> + + + + )} + + { + setHeight(h + 0.5); + }} + components={{ + // eslint-disable-next-line react/display-name + Table: (props) =>
, + // eslint-disable-next-line react/display-name + TableRow: (props) => { + const index = props["data-index"]; + const percentage = (files[index]?.progress ?? 0) * 100; + const progressBgColor = theme.palette.background.default; + return ( + - {fileBase(value.name)} - - - - - {sizeToString(value.size)} - - - - - {((value.progress ?? 0) * 100).toFixed(2)} % - - - + ); + }, + }} + data={filteredFiles} + itemContent={(_index, value) => ( + <> + + { + setFileSelected(value, e.target.checked); + }} + disabled={!downloading || readonly} + disableRipple + checked={selectedMask[value.index] ?? value.selected} + size="small" + /> + + + + + {fileBase(value.name)} + + + + + {sizeToString(value.size)} + + + + + {((value.progress ?? 0) * 100).toFixed(2)} % + + + + )} + /> + {filteredFiles.length === 0 && ( + + {t("download.noFilesFound")} + )} - /> - + + )} {downloading && !readonly && summary?.phase == "monitor" && (