diff --git a/airflow-core/src/airflow/ui/public/i18n/locales/en/admin.json b/airflow-core/src/airflow/ui/public/i18n/locales/en/admin.json
index e8735ea2713c0..06b9e773419f7 100644
--- a/airflow-core/src/airflow/ui/public/i18n/locales/en/admin.json
+++ b/airflow-core/src/airflow/ui/public/i18n/locales/en/admin.json
@@ -30,6 +30,7 @@
"firstConfirmMessage_other": "You are about to delete the following connections:",
"title": "Delete $t(connections.connection_one)"
},
+ "duplicate": "Duplicate",
"edit": "Edit $t(connections.connection_one)",
"form": {
"connectionIdRequired": "Connection ID is required",
diff --git a/airflow-core/src/airflow/ui/src/pages/Connections/Connections.tsx b/airflow-core/src/airflow/ui/src/pages/Connections/Connections.tsx
index 6279938f5747d..da4bb91ade634 100644
--- a/airflow-core/src/airflow/ui/src/pages/Connections/Connections.tsx
+++ b/airflow-core/src/airflow/ui/src/pages/Connections/Connections.tsx
@@ -52,6 +52,7 @@ import { formatNumber, useDocumentTitle } from "src/utils";
import AddConnectionButton from "./AddConnectionButton";
import DeleteConnectionButton from "./DeleteConnectionButton";
import DeleteConnectionsButton from "./DeleteConnectionsButton";
+import DuplicateConnectionButton from "./DuplicateConnectionButton";
import EditConnectionButton from "./EditConnectionButton";
import { NothingFoundInfo } from "./NothingFoundInfo";
import TestConnectionButton from "./TestConnectionButton";
@@ -125,6 +126,7 @@ const getColumns = ({
+
),
diff --git a/airflow-core/src/airflow/ui/src/pages/Connections/DuplicateConnectionButton.tsx b/airflow-core/src/airflow/ui/src/pages/Connections/DuplicateConnectionButton.tsx
new file mode 100644
index 0000000000000..f5c5d234565b5
--- /dev/null
+++ b/airflow-core/src/airflow/ui/src/pages/Connections/DuplicateConnectionButton.tsx
@@ -0,0 +1,82 @@
+/*!
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+import { useDisclosure } from "@chakra-ui/react";
+import { useTranslation } from "react-i18next";
+import { FiCopy } from "react-icons/fi";
+
+import type { ConnectionResponse } from "openapi/requests/types.gen";
+
+import { IconButton, Modal } from "src/system-components";
+
+import { useAddConnection } from "src/queries/useAddConnection";
+
+import ConnectionForm from "./ConnectionForm";
+import type { ConnectionBody } from "./Connections";
+
+type Props = {
+ readonly connection: ConnectionResponse;
+ readonly disabled: boolean;
+};
+
+const DuplicateConnectionButton = ({ connection, disabled }: Props) => {
+ const { t: translate } = useTranslation("admin");
+ const { onClose, onOpen, open } = useDisclosure();
+
+ const initialConnection: ConnectionBody = {
+ conn_type: connection.conn_type,
+ connection_id: "",
+ description: connection.description ?? "",
+ extra: connection.extra === "" || connection.extra === null ? "{}" : connection.extra,
+ host: connection.host ?? "",
+ login: connection.login ?? "",
+ password: "",
+ port: connection.port?.toString() ?? "",
+ schema: connection.schema ?? "",
+ team_name: connection.team_name ?? "",
+ };
+
+ const { addConnection, error, isPending } = useAddConnection({
+ onSuccessConfirm: onClose,
+ });
+
+ return (
+ <>
+
+
+
+
+
+
+
+ >
+ );
+};
+
+export default DuplicateConnectionButton;