diff --git a/src/locales/ach-UG/translation.json b/src/locales/ach-UG/translation.json index 25b2dbed3..f224754a8 100644 --- a/src/locales/ach-UG/translation.json +++ b/src/locales/ach-UG/translation.json @@ -150,6 +150,7 @@ "starting_script": "crwdns8176:0crwdne8176:0", "starting_updates": "crwdns8178:0crwdne8178:0", "script_started": "crwdns8180:0crwdne8180:0", + "operation_failed": "Operation failed", "batch_operations": "crwdns8182:0crwdne8182:0", "export": "crwdns8184:0crwdne8184:0", "delete": "crwdns8186:0crwdne8186:0", diff --git a/src/locales/de-DE/translation.json b/src/locales/de-DE/translation.json index d18264195..8006372b7 100644 --- a/src/locales/de-DE/translation.json +++ b/src/locales/de-DE/translation.json @@ -151,6 +151,7 @@ "starting_script": "Skript wird gestartet...", "starting_updates": "Batch-Update wird gestartet...", "script_started": "Skript gestartet", + "operation_failed": "Vorgang fehlgeschlagen", "batch_operations": "Batch-Operationen", "export": "Exportieren", "delete": "Löschen", diff --git a/src/locales/en-US/translation.json b/src/locales/en-US/translation.json index a5df027f6..27c9fc645 100644 --- a/src/locales/en-US/translation.json +++ b/src/locales/en-US/translation.json @@ -151,6 +151,7 @@ "starting_script": "Starting Script...", "starting_updates": "Starting Batch Updates...", "script_started": "Script Started", + "operation_failed": "Operation failed", "batch_operations": "Batch Operations", "export": "Export", "delete": "Delete", diff --git a/src/locales/ja-JP/translation.json b/src/locales/ja-JP/translation.json index 1b7a04b01..48ee896ef 100644 --- a/src/locales/ja-JP/translation.json +++ b/src/locales/ja-JP/translation.json @@ -151,6 +151,7 @@ "starting_script": "スクリプトを開始中...", "starting_updates": "一括更新を開始中...", "script_started": "スクリプトが開始しました", + "operation_failed": "操作に失敗しました", "batch_operations": "一括操作", "export": "エクスポート", "delete": "削除", diff --git a/src/locales/ru-RU/translation.json b/src/locales/ru-RU/translation.json index b41776979..64eadc9d4 100644 --- a/src/locales/ru-RU/translation.json +++ b/src/locales/ru-RU/translation.json @@ -151,6 +151,7 @@ "starting_script": "Запуск скрипта...", "starting_updates": "Массовое обновление...", "script_started": "Скрипт запущен", + "operation_failed": "Операция не выполнена", "batch_operations": "Пакетные операции", "export": "Экспорт", "delete": "Удалить", diff --git a/src/locales/vi-VN/translation.json b/src/locales/vi-VN/translation.json index 9b35e23ec..626f28cad 100644 --- a/src/locales/vi-VN/translation.json +++ b/src/locales/vi-VN/translation.json @@ -151,6 +151,7 @@ "starting_script": "Đang khởi động script...", "starting_updates": "Đang khởi động cập nhật hàng loạt...", "script_started": "Script đã khởi động", + "operation_failed": "Thao tác thất bại", "batch_operations": "Thao tác hàng loạt", "export": "Xuất", "delete": "Xóa", diff --git a/src/locales/zh-CN/translation.json b/src/locales/zh-CN/translation.json index 2409e2e52..08b6c99b9 100644 --- a/src/locales/zh-CN/translation.json +++ b/src/locales/zh-CN/translation.json @@ -151,6 +151,7 @@ "starting_script": "正在启动脚本...", "starting_updates": "正在批量更新...", "script_started": "脚本已启动", + "operation_failed": "操作失败", "batch_operations": "批量操作", "export": "导出", "delete": "删除", diff --git a/src/locales/zh-TW/translation.json b/src/locales/zh-TW/translation.json index fa6b99483..0e6e4754b 100644 --- a/src/locales/zh-TW/translation.json +++ b/src/locales/zh-TW/translation.json @@ -151,6 +151,7 @@ "starting_script": "正在啟動腳本...", "starting_updates": "正在批次更新...", "script_started": "腳本已啟動", + "operation_failed": "操作失敗", "batch_operations": "批次操作", "export": "匯出", "delete": "刪除", diff --git a/src/pages/options/routes/ScriptList/ScriptCard.tsx b/src/pages/options/routes/ScriptList/ScriptCard.tsx index 65d7a54f6..89b0aade7 100644 --- a/src/pages/options/routes/ScriptList/ScriptCard.tsx +++ b/src/pages/options/routes/ScriptList/ScriptCard.tsx @@ -1,4 +1,4 @@ -import React, { useMemo } from "react"; +import React, { createContext, useCallback, useContext, useMemo } from "react"; import { Avatar, Button, Card, Divider, Popconfirm, Space, Tag, Tooltip, Typography } from "@arco-design/web-react"; import { Link, useNavigate } from "react-router-dom"; import { IconClockCircle, IconDragDotVertical } from "@arco-design/web-react/icon"; @@ -24,14 +24,73 @@ import { useTranslation } from "react-i18next"; import { VscLayoutSidebarLeft, VscLayoutSidebarLeftOff } from "react-icons/vsc"; import { FaThList } from "react-icons/fa"; import type { DragEndEvent } from "@dnd-kit/core"; -import { DndContext, KeyboardSensor, PointerSensor, useSensor, useSensors } from "@dnd-kit/core"; +import { closestCenter, DndContext, KeyboardSensor, PointerSensor, useSensor, useSensors } from "@dnd-kit/core"; import { rectSortingStrategy, SortableContext, sortableKeyboardCoordinates, useSortable } from "@dnd-kit/sortable"; import { CSS } from "@dnd-kit/utilities"; import { useAppContext } from "@App/pages/store/AppContext"; -import type { SetSearchRequest } from "./hooks"; +import { type SearchFilterRequest } from "./SearchFilter"; import type { SearchType } from "@App/app/service/service_worker/types"; -const { Text } = Typography; +type DragCtx = Pick, "listeners" | "setActivatorNodeRef"> | null; +const SortableDragCtx = createContext(null); + +function composeRefs(...refs: React.Ref[]): (node: T | null) => void { + return (node) => { + for (const ref of refs) { + if (typeof ref === "function") { + ref(node); + } else if (ref) { + (ref as React.MutableRefObject).current = node; + } + } + }; +} + +const DraggableEntry = React.forwardRef>( + ({ record, ...rest }, ref) => { + const sortable = useSortable({ id: record.uuid }); + const { setNodeRef, transform, transition, listeners, setActivatorNodeRef } = sortable; + + const style = { + transform: CSS.Transform.toString(transform), + transition, + }; + + const mergedRef = React.useMemo(() => composeRefs(setNodeRef, ref), [setNodeRef, ref]); + + const ctxValue = useMemo( + () => ({ + listeners: listeners, + setActivatorNodeRef: setActivatorNodeRef, + }), + [listeners, setActivatorNodeRef] + ); + + return ( + +
+ + ); + } +); +DraggableEntry.displayName = "DraggableEntry"; + +const DragHandle = () => { + const sortable = useContext(SortableDragCtx); + + const { listeners, setActivatorNodeRef } = sortable || {}; + const style = { cursor: "move", padding: 6 }; + + return !setActivatorNodeRef ? ( + + + + ) : ( + + + + ); +}; interface ScriptCardItemProps { item: ScriptLoading; @@ -56,15 +115,6 @@ export const ScriptCardItem = React.memo( handleConfig, handleRunStop, }: ScriptCardItemProps) => { - const { attributes, listeners, setNodeRef, transform, transition } = useSortable({ - id: item.uuid, - }); - - const style = { - transform: CSS.Transform.toString(transform), - transition, - }; - const { t } = useTranslation(); const navigate = useNavigate(); @@ -106,210 +156,210 @@ export const ScriptCardItem = React.memo( }), }; + // console.log("Rendered - " + item.name); // 用于检查垃圾React有否过度更新 + return ( - -
-
-
-
- -
- - +
+ +
+
+
+
+ - {i18nName(item)} - +
+ + + {i18nName(item)} + +
+ + {tags.length > 0 && ( + + {tags.map((tag) => ( + + {tag} + + ))} + + )} +
+
+ { + updateScripts([item.uuid], { enableLoading: true }); + requestEnableScript({ uuid: item.uuid, enable: checked }); + }} + /> +
+ +
- - {tags.length > 0 && ( - - {tags.map((tag) => ( - - {tag} - - ))} - - )} -
-
- { - updateScripts([item.uuid], { enableLoading: true }); - requestEnableScript({ uuid: item.uuid, enable: checked }); - }} - /> -
- -
-
-
- - {/* 版本和更新时间 */} -
- {item.metadata.version && ( -
- - {t("version")} - {": "} - - {item.metadata.version[0]}
- )} -
- - {t("last_updated")} - {": "} - - -
-
- {/* 运行状态 */} -
- {item.type !== SCRIPT_TYPE_NORMAL && ( -
- - } - color="blue" - bordered - style={{ cursor: "pointer" }} - onClick={toLogger} - > - {item.runStatus === SCRIPT_RUN_STATUS_RUNNING ? t("running") : t("completed")} - - + {/* 版本和更新时间 */} +
+ {item.metadata.version && ( +
+ + {t("version")} + {": "} + + {item.metadata.version[0]} +
+ )} +
+ + {t("last_updated")} + {": "} + + +
- )} - -
-
- {item.type === SCRIPT_TYPE_NORMAL && ( - - {favoriteMemo.trimmed.map((fav) => ( - { - if (fav.website) { - window.open(fav.website, "_blank"); + {/* 运行状态 */} +
+ {item.type !== SCRIPT_TYPE_NORMAL && ( +
+ - ))} - {favoriteMemo.originalLen > 8 && {"..."}} - - )} - -
-
- {/* 操作按钮 */} -
- -
-
- {item.type !== SCRIPT_TYPE_NORMAL && ( - - )} -
-
- - - - - {item.config && ( - + > + } + color="blue" + bordered + style={{ cursor: "pointer" }} + onClick={toLogger} + > + {item.runStatus === SCRIPT_RUN_STATUS_RUNNING ? t("running") : t("completed")} + + +
)} - {item.metadata.cloudcat && ( - + +
+ +
+ {item.type === SCRIPT_TYPE_NORMAL && ( + + {favoriteMemo.trimmed.map((fav) => ( + { + if (fav.website) { + window.open(fav.website, "_blank"); + } + }} + /> + ))} + {favoriteMemo.originalLen > 8 && {"..."}} + )} - } - onOk={() => handleDelete(item)} - > - - - + +
+
+ {/* 操作按钮 */} +
+ +
+
+ {item.type !== SCRIPT_TYPE_NORMAL && ( + + )} +
+
+ + + + + {item.config && ( + + )} + {item.metadata.cloudcat && ( + + )} + } + onOk={() => handleDelete(item)} + > + + + +
+
-
+
-
+ ); }, (prevProps, nextProps) => { @@ -323,13 +373,13 @@ interface ScriptCardProps { scriptList: ScriptLoading[]; scriptListSortOrder: (params: { active: string; over: string }) => void; sidebarOpen: boolean; - setSidebarOpen: React.Dispatch>; + setSidebarOpen: ReactStateSetter; setViewMode: (mode: "card" | "table") => void; updateScripts: (uuids: string[], data: Partial