diff --git a/frontend/src/components/feedback/PromptModal.tsx b/frontend/src/components/feedback/PromptModal.tsx
index e6bf9bd73..eda131dd4 100644
--- a/frontend/src/components/feedback/PromptModal.tsx
+++ b/frontend/src/components/feedback/PromptModal.tsx
@@ -3,6 +3,8 @@ import { Input, Modal } from 'antd';
import type { InputRef } from 'antd';
import { useTranslation } from 'react-i18next';
+import JsonEditor from '@/components/form/JsonEditor';
+
interface PromptModalProps {
open: boolean;
onClose: () => void;
@@ -11,6 +13,7 @@ interface PromptModalProps {
type?: 'input' | 'textarea';
initialValue?: string;
loading?: boolean;
+ json?: boolean;
onConfirm: (value: string) => void;
}
@@ -22,6 +25,7 @@ export default function PromptModal({
type = 'input',
initialValue = '',
loading = false,
+ json = false,
onConfirm,
}: PromptModalProps) {
const { t } = useTranslation();
@@ -63,7 +67,9 @@ export default function PromptModal({
onCancel={onClose}
destroyOnHidden
>
- {type === 'textarea' ? (
+ {json ? (
+
+ ) : type === 'textarea' ? (
{ textareaRef.current = (el as unknown as { resizableTextArea?: { textArea: HTMLTextAreaElement } })?.resizableTextArea?.textArea ?? null; }}
value={value}
diff --git a/frontend/src/components/feedback/TextModal.tsx b/frontend/src/components/feedback/TextModal.tsx
index 59653efdb..19586fb82 100644
--- a/frontend/src/components/feedback/TextModal.tsx
+++ b/frontend/src/components/feedback/TextModal.tsx
@@ -2,6 +2,7 @@ import { Button, Input, Modal, message } from 'antd';
import { CopyOutlined, DownloadOutlined } from '@ant-design/icons';
import { useTranslation } from 'react-i18next';
+import JsonEditor from '@/components/form/JsonEditor';
import { ClipboardManager, FileManager } from '@/utils';
interface TextModalProps {
@@ -10,9 +11,10 @@ interface TextModalProps {
title: string;
content: string;
fileName?: string;
+ json?: boolean;
}
-export default function TextModal({ open, onClose, title, content, fileName = '' }: TextModalProps) {
+export default function TextModal({ open, onClose, title, content, fileName = '', json = false }: TextModalProps) {
const { t } = useTranslation();
const [messageApi, messageContextHolder] = message.useMessage();
async function copy() {
@@ -45,16 +47,20 @@ export default function TextModal({ open, onClose, title, content, fileName = ''
>
)}
>
-
+ {json ? (
+
+ ) : (
+
+ )}
>
);
diff --git a/frontend/src/pages/inbounds/InboundsPage.tsx b/frontend/src/pages/inbounds/InboundsPage.tsx
index 9c385d173..5accac5c9 100644
--- a/frontend/src/pages/inbounds/InboundsPage.tsx
+++ b/frontend/src/pages/inbounds/InboundsPage.tsx
@@ -146,12 +146,14 @@ export default function InboundsPage() {
const [textTitle, setTextTitle] = useState('');
const [textContent, setTextContent] = useState('');
const [textFileName, setTextFileName] = useState('');
+ const [textJson, setTextJson] = useState(false);
const [promptOpen, setPromptOpen] = useState(false);
const [promptTitle, setPromptTitle] = useState('');
const [promptOkText, setPromptOkText] = useState('OK');
const [promptType, setPromptType] = useState<'textarea' | 'input'>('textarea');
const [promptInitial, setPromptInitial] = useState('');
+ const [promptJson, setPromptJson] = useState(false);
const [promptLoading, setPromptLoading] = useState(false);
const [promptHandler, setPromptHandler] = useState<((value: string) => Promise | boolean | void) | null>(null);
@@ -163,10 +165,11 @@ export default function InboundsPage() {
const infoNodeAddress = useMemo(() => hostOverrideFor(infoDbInbound), [infoDbInbound, hostOverrideFor]);
const qrNodeAddress = useMemo(() => hostOverrideFor(qrDbInbound), [qrDbInbound, hostOverrideFor]);
- const openText = useCallback((opts: { title: string; content: string; fileName?: string }) => {
+ const openText = useCallback((opts: { title: string; content: string; fileName?: string; json?: boolean }) => {
setTextTitle(opts.title);
setTextContent(opts.content);
setTextFileName(opts.fileName || '');
+ setTextJson(opts.json || false);
setTextOpen(true);
}, []);
@@ -175,12 +178,14 @@ export default function InboundsPage() {
okText?: string;
type?: 'textarea' | 'input';
value?: string;
+ json?: boolean;
confirm: (value: string) => Promise | boolean | void;
}) => {
setPromptTitle(opts.title);
setPromptOkText(opts.okText || t('confirm'));
setPromptType(opts.type || 'textarea');
setPromptInitial(opts.value || '');
+ setPromptJson(opts.json || false);
setPromptHandler(() => opts.confirm);
setPromptOpen(true);
}, [t]);
@@ -267,7 +272,7 @@ export default function InboundsPage() {
}, [checkFallback, remarkModel, hostOverrideFor, subSettings.publicHost, openText, t]);
const exportInboundClipboard = useCallback((dbInbound: DBInbound) => {
- openText({ title: t('pages.inbounds.inboundJsonTitle'), content: JSON.stringify(dbInbound, null, 2) });
+ openText({ title: t('pages.inbounds.inboundJsonTitle'), content: JSON.stringify(dbInbound, null, 2), json: true });
}, [openText, t]);
const exportInboundSubs = useCallback((dbInbound: DBInbound) => {
@@ -327,6 +332,7 @@ export default function InboundsPage() {
okText: t('pages.inbounds.import'),
type: 'textarea',
value: '',
+ json: true,
confirm: async (value) => {
const msg = await HttpUtil.post('/panel/api/inbounds/import', { data: value });
if (msg?.success) {
@@ -705,6 +711,7 @@ export default function InboundsPage() {
title={textTitle}
content={textContent}
fileName={textFileName}
+ json={textJson}
/>
@@ -716,6 +723,7 @@ export default function InboundsPage() {
type={promptType}
initialValue={promptInitial}
loading={promptLoading}
+ json={promptJson}
onConfirm={onPromptConfirm}
/>