diff --git a/frontend/src/locale/src/de.json b/frontend/src/locale/src/de.json index d36b259d46..d1fa581dcd 100644 --- a/frontend/src/locale/src/de.json +++ b/frontend/src/locale/src/de.json @@ -38,6 +38,9 @@ "action.add-location": { "defaultMessage": "Pfad Hinzufügen" }, + "action.clone": { + "defaultMessage": "Klonen" + }, "action.close": { "defaultMessage": "Schließen" }, diff --git a/frontend/src/locale/src/en.json b/frontend/src/locale/src/en.json index 355d0db77b..2b3b975e8b 100644 --- a/frontend/src/locale/src/en.json +++ b/frontend/src/locale/src/en.json @@ -44,6 +44,9 @@ "action.allow": { "defaultMessage": "Allow" }, + "action.clone": { + "defaultMessage": "Clone" + }, "action.close": { "defaultMessage": "Close" }, diff --git a/frontend/src/locale/src/es.json b/frontend/src/locale/src/es.json index 2b1ebfa4e8..c253b0d5f6 100644 --- a/frontend/src/locale/src/es.json +++ b/frontend/src/locale/src/es.json @@ -44,6 +44,9 @@ "action.allow": { "defaultMessage": "Permitir" }, + "action.clone": { + "defaultMessage": "Clonar" + }, "action.close": { "defaultMessage": "Cerrar" }, diff --git a/frontend/src/locale/src/it.json b/frontend/src/locale/src/it.json index 3301218f9e..a3e12c4318 100644 --- a/frontend/src/locale/src/it.json +++ b/frontend/src/locale/src/it.json @@ -38,6 +38,9 @@ "action.add-location": { "defaultMessage": "Aggiungi Percorso" }, + "action.clone": { + "defaultMessage": "Clona" + }, "action.close": { "defaultMessage": "Chiudi" }, diff --git a/frontend/src/locale/src/ja.json b/frontend/src/locale/src/ja.json index 1ace1c642d..462f8cdc6b 100644 --- a/frontend/src/locale/src/ja.json +++ b/frontend/src/locale/src/ja.json @@ -38,6 +38,9 @@ "action.add-location": { "defaultMessage": "場所を追加" }, + "action.clone": { + "defaultMessage": "複製" + }, "action.close": { "defaultMessage": "閉じる" }, diff --git a/frontend/src/locale/src/nl.json b/frontend/src/locale/src/nl.json index 2732f5e4df..e3d3371e71 100644 --- a/frontend/src/locale/src/nl.json +++ b/frontend/src/locale/src/nl.json @@ -38,6 +38,9 @@ "action.add-location": { "defaultMessage": "Locatie Toevoegen" }, + "action.clone": { + "defaultMessage": "Klonen" + }, "action.close": { "defaultMessage": "Sluiten" }, @@ -644,4 +647,4 @@ "users": { "defaultMessage": "Gebruikers" } -} \ No newline at end of file +} diff --git a/frontend/src/locale/src/pl.json b/frontend/src/locale/src/pl.json index 9853c7bc49..8971fcaa32 100644 --- a/frontend/src/locale/src/pl.json +++ b/frontend/src/locale/src/pl.json @@ -38,6 +38,9 @@ "action.add-location": { "defaultMessage": "Dodaj lokalizację" }, + "action.clone": { + "defaultMessage": "Klonuj" + }, "action.close": { "defaultMessage": "Zamknij" }, diff --git a/frontend/src/locale/src/ru.json b/frontend/src/locale/src/ru.json index dedcd51397..1f2973836e 100644 --- a/frontend/src/locale/src/ru.json +++ b/frontend/src/locale/src/ru.json @@ -38,6 +38,9 @@ "action.add-location": { "defaultMessage": "Добавить маршрут" }, + "action.clone": { + "defaultMessage": "Клонировать" + }, "action.close": { "defaultMessage": "Закрыть" }, diff --git a/frontend/src/locale/src/sk.json b/frontend/src/locale/src/sk.json index d006e5556c..ba39096eff 100644 --- a/frontend/src/locale/src/sk.json +++ b/frontend/src/locale/src/sk.json @@ -38,6 +38,9 @@ "action.add-location": { "defaultMessage": "Pridať umiestnenie" }, + "action.clone": { + "defaultMessage": "Klonovať" + }, "action.close": { "defaultMessage": "Zavrieť" }, diff --git a/frontend/src/locale/src/vi.json b/frontend/src/locale/src/vi.json index fc1ed85b2b..32153937cf 100644 --- a/frontend/src/locale/src/vi.json +++ b/frontend/src/locale/src/vi.json @@ -38,6 +38,9 @@ "action.add-location": { "defaultMessage": "Thêm Vị trí" }, + "action.clone": { + "defaultMessage": "Nhân bản" + }, "action.close": { "defaultMessage": "Đóng" }, diff --git a/frontend/src/locale/src/zh.json b/frontend/src/locale/src/zh.json index 541093a660..9fd1076c12 100755 --- a/frontend/src/locale/src/zh.json +++ b/frontend/src/locale/src/zh.json @@ -38,6 +38,9 @@ "action.add-location": { "defaultMessage": "添加路径规则(Location)" }, + "action.clone": { + "defaultMessage": "克隆" + }, "action.close": { "defaultMessage": "关闭" }, diff --git a/frontend/src/modals/ProxyHostModal.tsx b/frontend/src/modals/ProxyHostModal.tsx index ca322849d8..0f9b89c1f4 100644 --- a/frontend/src/modals/ProxyHostModal.tsx +++ b/frontend/src/modals/ProxyHostModal.tsx @@ -22,14 +22,12 @@ import { MANAGE, PROXY_HOSTS } from "src/modules/Permissions"; import { validateNumber, validateString } from "src/modules/Validations"; import { showObjectSuccess } from "src/notifications"; -const showProxyHostModal = (id: number | "new") => { - EasyModal.show(ProxyHostModal, { id }); -}; - interface Props extends InnerModalProps { id: number | "new"; + isClone?: boolean; } -const ProxyHostModal = EasyModal.create(({ id, visible, remove }: Props) => { + +const ProxyHostModal = EasyModal.create(({ id, isClone = false, visible, remove }: Props) => { const { data: currentUser, isLoading: userIsLoading, error: userError } = useUser("me"); const { data, isLoading, error } = useProxyHost(id); const { mutate: setProxyHost } = useSetProxyHost(); @@ -42,7 +40,7 @@ const ProxyHostModal = EasyModal.create(({ id, visible, remove }: Props) => { setErrorMsg(null); const { ...payload } = { - id: id === "new" ? undefined : id, + id: id === "new" || isClone ? undefined : id, ...values, }; @@ -99,7 +97,7 @@ const ProxyHostModal = EasyModal.create(({ id, visible, remove }: Props) => {
- + @@ -373,4 +371,8 @@ const ProxyHostModal = EasyModal.create(({ id, visible, remove }: Props) => { ); }); +const showProxyHostModal = (id: number | "new", isClone = false) => { + EasyModal.show(ProxyHostModal, { id, isClone } as Omit); +}; + export { showProxyHostModal }; diff --git a/frontend/src/pages/Nginx/ProxyHosts/Table.tsx b/frontend/src/pages/Nginx/ProxyHosts/Table.tsx index 9d58b26acd..da247a85d6 100644 --- a/frontend/src/pages/Nginx/ProxyHosts/Table.tsx +++ b/frontend/src/pages/Nginx/ProxyHosts/Table.tsx @@ -1,4 +1,4 @@ -import { IconDotsVertical, IconEdit, IconPower, IconTrash } from "@tabler/icons-react"; +import { IconCopy, IconDotsVertical, IconEdit, IconPower, IconTrash } from "@tabler/icons-react"; import { createColumnHelper, getCoreRowModel, useReactTable } from "@tanstack/react-table"; import { useMemo } from "react"; import type { ProxyHost } from "src/api/backend"; @@ -20,11 +20,12 @@ interface Props { isFiltered?: boolean; isFetching?: boolean; onEdit?: (id: number) => void; + onClone?: (id: number) => void; onDelete?: (id: number) => void; onDisableToggle?: (id: number, enabled: boolean) => void; onNew?: () => void; } -export default function Table({ data, isFetching, onEdit, onDelete, onDisableToggle, onNew, isFiltered }: Props) { +export default function Table({ data, isFetching, onEdit, onClone, onDelete, onDisableToggle, onNew, isFiltered }: Props) { const columnHelper = createColumnHelper(); const columns = useMemo( () => [ @@ -107,6 +108,17 @@ export default function Table({ data, isFetching, onEdit, onDelete, onDisableTog + { + e.preventDefault(); + onClone?.(info.row.original.id); + }} + > + + + ({ diff --git a/frontend/src/pages/Nginx/ProxyHosts/TableWrapper.tsx b/frontend/src/pages/Nginx/ProxyHosts/TableWrapper.tsx index 68af43e10a..c00252001e 100644 --- a/frontend/src/pages/Nginx/ProxyHosts/TableWrapper.tsx +++ b/frontend/src/pages/Nginx/ProxyHosts/TableWrapper.tsx @@ -99,6 +99,7 @@ export default function TableWrapper() { isFiltered={!!search} isFetching={isFetching} onEdit={(id: number) => showProxyHostModal(id)} + onClone={(id: number) => showProxyHostModal(id, true)} onDelete={(id: number) => showDeleteConfirmModal({ title: ,