This is an automated email from the ASF dual-hosted git repository.

liuhongyu pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/shenyu-dashboard.git


The following commit(s) were added to refs/heads/master by this push:
     new eed34ea0 Add a universal browser copying method (#569)
eed34ea0 is described below

commit eed34ea062203d4f3732f02eba157cde6290bf06
Author: renlu <[email protected]>
AuthorDate: Thu Feb 5 13:09:05 2026 +0800

    Add a universal browser copying method (#569)
---
 src/routes/Plugin/AiProxy/ApiKeys/index.js    | 27 ++++++++-------------------
 src/routes/Plugin/McpServer/JsonEditModal.js  |  4 ++--
 src/routes/Plugin/McpServer/McpConfigModal.js |  7 +++----
 src/routes/Plugin/McpServer/ToolsModal.js     |  4 ++--
 src/utils/utils.js                            | 18 ++++++++++++++++++
 5 files changed, 33 insertions(+), 27 deletions(-)

diff --git a/src/routes/Plugin/AiProxy/ApiKeys/index.js 
b/src/routes/Plugin/AiProxy/ApiKeys/index.js
index d8812cca..2fe2b520 100644
--- a/src/routes/Plugin/AiProxy/ApiKeys/index.js
+++ b/src/routes/Plugin/AiProxy/ApiKeys/index.js
@@ -41,6 +41,7 @@ import {
   batchDeleteAiProxyApiKeys,
   batchEnableAiProxyApiKeys,
 } from "../../../../services/api";
+import { clipboardCopy } from "../../../../utils/utils";
 
 const { Search } = Input;
 const { Title } = Typography;
@@ -308,25 +309,13 @@ function ApiKeysPage({
     const newKey = res && res.data && res.data.proxyApiKey;
     if (newKey) {
       const copy = async (text) => {
-        try {
-          if (
-            navigator &&
-            navigator.clipboard &&
-            navigator.clipboard.writeText
-          ) {
-            await navigator.clipboard.writeText(text);
-          } else {
-            const ta = document.createElement("textarea");
-            ta.value = text;
-            document.body.appendChild(ta);
-            ta.select();
-            document.execCommand("copy");
-            document.body.removeChild(ta);
-          }
-          message.success(getIntlContent("SHENYU.COMMON.COPY") || "Copy");
-        } catch (e) {
-          message.warn("Copy failed");
-        }
+        clipboardCopy(text)
+          .then(() => {
+            message.success(getIntlContent("SHENYU.COMMON.COPY") || "Copy");
+          })
+          .catch(() => {
+            message.warn("Copy failed");
+          });
       };
       Modal.success({
         title: getIntlContent("APIPROXY.APIKEY.CREATE") || "Create API Key",
diff --git a/src/routes/Plugin/McpServer/JsonEditModal.js 
b/src/routes/Plugin/McpServer/JsonEditModal.js
index 487942ff..361d7bc2 100644
--- a/src/routes/Plugin/McpServer/JsonEditModal.js
+++ b/src/routes/Plugin/McpServer/JsonEditModal.js
@@ -19,6 +19,7 @@ import React, { Component } from "react";
 import { Button, Modal, message, Input, Tabs, Radio } from "antd";
 import ReactJson from "react-json-view";
 import { getIntlContent } from "../../../utils/IntlUtils";
+import { clipboardCopy } from "../../../utils/utils";
 
 const { TextArea } = Input;
 const { TabPane } = Tabs;
@@ -286,8 +287,7 @@ class JsonEditModal extends Component {
         ? this.state.flattenedText
         : this.state.unifiedText;
 
-    navigator.clipboard
-      .writeText(textToCopy)
+    clipboardCopy(textToCopy)
       .then(() => {
         message.success(getIntlContent("SHENYU.MCP.JSON.EDIT.COPY.SUCCESS"));
       })
diff --git a/src/routes/Plugin/McpServer/McpConfigModal.js 
b/src/routes/Plugin/McpServer/McpConfigModal.js
index a0866519..a4b2abb3 100644
--- a/src/routes/Plugin/McpServer/McpConfigModal.js
+++ b/src/routes/Plugin/McpServer/McpConfigModal.js
@@ -19,6 +19,7 @@ import React, { Component } from "react";
 import { Modal, Button, message, Typography, Divider, Input } from "antd";
 import ReactJson from "react-json-view";
 import { getIntlContent } from "../../../utils/IntlUtils";
+import { clipboardCopy } from "../../../utils/utils";
 
 const { Title, Text } = Typography;
 const { TextArea } = Input;
@@ -184,8 +185,7 @@ class McpConfigModal extends Component {
   // 复制配置到剪贴板
   handleCopyConfig = (config) => {
     const configText = JSON.stringify(config, null, 2);
-    navigator.clipboard
-      .writeText(configText)
+    clipboardCopy(configText)
       .then(() => {
         message.success(getIntlContent("SHENYU.MCP.CONFIG.COPY.SUCCESS"));
       })
@@ -196,8 +196,7 @@ class McpConfigModal extends Component {
 
   // 复制JSON文本
   copyJsonText = (text) => {
-    navigator.clipboard
-      .writeText(text)
+    clipboardCopy(text)
       .then(() => {
         message.success(getIntlContent("SHENYU.MCP.CONFIG.COPY.SUCCESS"));
       })
diff --git a/src/routes/Plugin/McpServer/ToolsModal.js 
b/src/routes/Plugin/McpServer/ToolsModal.js
index bc298598..421c9b2e 100644
--- a/src/routes/Plugin/McpServer/ToolsModal.js
+++ b/src/routes/Plugin/McpServer/ToolsModal.js
@@ -34,6 +34,7 @@ import TextArea from "antd/lib/input/TextArea";
 import ReactJson from "react-json-view";
 import styles from "../index.less";
 import { getIntlContent } from "../../../utils/IntlUtils";
+import { clipboardCopy } from "../../../utils/utils";
 
 const FormItem = Form.Item;
 const { Option } = Select;
@@ -338,8 +339,7 @@ class AddModal extends Component {
   };
 
   handleCopyToClipboard = () => {
-    navigator.clipboard
-      .writeText(this.state.jsonText)
+    clipboardCopy(this.state.jsonText)
       .then(() => {
         message.success(getIntlContent("SHENYU.MCP.JSON.EDIT.COPY.SUCCESS"));
       })
diff --git a/src/utils/utils.js b/src/utils/utils.js
index 7efb7153..75481a4b 100644
--- a/src/utils/utils.js
+++ b/src/utils/utils.js
@@ -243,3 +243,21 @@ export function formatTimeString(str) {
   const f = formatTime(str);
   return f ? f.format("HH:mm:ss") : "";
 }
+
+export async function clipboardCopy(text) {
+  try {
+    if (navigator && navigator.clipboard && navigator.clipboard.writeText) {
+      await navigator.clipboard.writeText(text);
+    } else {
+      const ta = document.createElement("textarea");
+      ta.value = text;
+      document.body.appendChild(ta);
+      ta.select();
+      document.execCommand("copy");
+      document.body.removeChild(ta);
+    }
+    return true;
+  } catch (e) {
+    return false;
+  }
+}

Reply via email to