|
|
@@ -1,5 +1,5 @@
|
|
|
/* eslint-disable @typescript-eslint/no-explicit-any */
|
|
|
-import { useCallback, useEffect, useMemo, useState } from 'react';
|
|
|
+import { lazy, useCallback, useEffect, useMemo, useState } from 'react';
|
|
|
import { useTranslation } from 'react-i18next';
|
|
|
import {
|
|
|
Card,
|
|
|
@@ -28,14 +28,15 @@ import { useWebSocket } from '@/hooks/useWebSocket';
|
|
|
import { useNodes } from '@/hooks/useNodes';
|
|
|
import AppSidebar from '@/components/AppSidebar';
|
|
|
import CustomStatistic from '@/components/CustomStatistic';
|
|
|
-import TextModal from '@/components/TextModal';
|
|
|
-import PromptModal from '@/components/PromptModal';
|
|
|
+const TextModal = lazy(() => import('@/components/TextModal'));
|
|
|
+const PromptModal = lazy(() => import('@/components/PromptModal'));
|
|
|
|
|
|
import { useInbounds } from './useInbounds';
|
|
|
import InboundList from './InboundList';
|
|
|
-import InboundFormModal from './InboundFormModal';
|
|
|
-import InboundInfoModal from './InboundInfoModal';
|
|
|
-import QrCodeModal from './QrCodeModal';
|
|
|
+import LazyMount from '@/components/LazyMount';
|
|
|
+const InboundFormModal = lazy(() => import('./InboundFormModal'));
|
|
|
+const InboundInfoModal = lazy(() => import('./InboundInfoModal'));
|
|
|
+const QrCodeModal = lazy(() => import('./QrCodeModal'));
|
|
|
import '@/styles/page-cards.css';
|
|
|
import './InboundsPage.css';
|
|
|
|
|
|
@@ -234,15 +235,15 @@ export default function InboundsPage() {
|
|
|
const exportInboundLinks = useCallback((dbInbound: any) => {
|
|
|
const projected = checkFallback(dbInbound);
|
|
|
openText({
|
|
|
- title: 'Export inbound links',
|
|
|
+ title: t('pages.inbounds.exportLinksTitle'),
|
|
|
content: projected.genInboundLinks(remarkModel, hostOverrideFor(dbInbound)),
|
|
|
fileName: projected.remark || 'inbound',
|
|
|
});
|
|
|
- }, [checkFallback, remarkModel, hostOverrideFor, openText]);
|
|
|
+ }, [checkFallback, remarkModel, hostOverrideFor, openText, t]);
|
|
|
|
|
|
const exportInboundClipboard = useCallback((dbInbound: any) => {
|
|
|
- openText({ title: 'Inbound JSON', content: JSON.stringify(dbInbound, null, 2) });
|
|
|
- }, [openText]);
|
|
|
+ openText({ title: t('pages.inbounds.inboundJsonTitle'), content: JSON.stringify(dbInbound, null, 2) });
|
|
|
+ }, [openText, t]);
|
|
|
|
|
|
const exportInboundSubs = useCallback((dbInbound: any) => {
|
|
|
const inbound = dbInbound.toInbound();
|
|
|
@@ -254,11 +255,11 @@ export default function InboundsPage() {
|
|
|
}
|
|
|
}
|
|
|
openText({
|
|
|
- title: 'Export subscription links',
|
|
|
+ title: t('pages.inbounds.exportSubsTitle'),
|
|
|
content: [...new Set(subLinks)].join('\n'),
|
|
|
fileName: `${dbInbound.remark || 'inbound'}-Subs`,
|
|
|
});
|
|
|
- }, [subSettings, openText]);
|
|
|
+ }, [subSettings, openText, t]);
|
|
|
|
|
|
const exportAllLinks = useCallback(async () => {
|
|
|
const hydrated = await Promise.all(
|
|
|
@@ -269,8 +270,8 @@ export default function InboundsPage() {
|
|
|
const projected = checkFallback(ib);
|
|
|
out.push(projected.genInboundLinks(remarkModel, hostOverrideFor(ib)));
|
|
|
}
|
|
|
- openText({ title: 'Export all inbound links', content: out.join('\r\n'), fileName: 'All-Inbounds' });
|
|
|
- }, [dbInbounds, hydrateInbound, checkFallback, remarkModel, hostOverrideFor, openText]);
|
|
|
+ openText({ title: t('pages.inbounds.exportAllLinksTitle'), content: out.join('\r\n'), fileName: 'All-Inbounds' });
|
|
|
+ }, [dbInbounds, hydrateInbound, checkFallback, remarkModel, hostOverrideFor, openText, t]);
|
|
|
|
|
|
const exportAllSubs = useCallback(async () => {
|
|
|
const hydrated = await Promise.all(
|
|
|
@@ -286,8 +287,8 @@ export default function InboundsPage() {
|
|
|
}
|
|
|
}
|
|
|
}
|
|
|
- openText({ title: 'Export all subscription links', content: [...new Set(out)].join('\r\n'), fileName: 'All-Inbounds-Subs' });
|
|
|
- }, [dbInbounds, hydrateInbound, subSettings, openText]);
|
|
|
+ openText({ title: t('pages.inbounds.exportAllSubsTitle'), content: [...new Set(out)].join('\r\n'), fileName: 'All-Inbounds-Subs' });
|
|
|
+ }, [dbInbounds, hydrateInbound, subSettings, openText, t]);
|
|
|
|
|
|
const importInbound = useCallback(() => {
|
|
|
openPrompt({
|
|
|
@@ -320,37 +321,37 @@ export default function InboundsPage() {
|
|
|
|
|
|
const confirmDelete = useCallback((dbInbound: any) => {
|
|
|
modal.confirm({
|
|
|
- title: `Delete inbound "${dbInbound.remark}"?`,
|
|
|
- content: 'This removes the inbound and all its clients. This cannot be undone.',
|
|
|
- okText: 'Delete',
|
|
|
+ title: t('pages.inbounds.deleteConfirmTitle', { remark: dbInbound.remark }),
|
|
|
+ content: t('pages.inbounds.deleteConfirmContent'),
|
|
|
+ okText: t('delete'),
|
|
|
okType: 'danger',
|
|
|
- cancelText: 'Cancel',
|
|
|
+ cancelText: t('cancel'),
|
|
|
onOk: async () => {
|
|
|
const msg = await HttpUtil.post(`/panel/api/inbounds/del/${dbInbound.id}`);
|
|
|
if (msg?.success) await refresh();
|
|
|
},
|
|
|
});
|
|
|
- }, [modal, refresh]);
|
|
|
+ }, [modal, refresh, t]);
|
|
|
|
|
|
const confirmResetTraffic = useCallback((dbInbound: any) => {
|
|
|
modal.confirm({
|
|
|
- title: `Reset traffic for "${dbInbound.remark}"?`,
|
|
|
- content: 'Resets up/down counters to 0 for this inbound.',
|
|
|
- okText: 'Reset',
|
|
|
- cancelText: 'Cancel',
|
|
|
+ title: t('pages.inbounds.resetConfirmTitle', { remark: dbInbound.remark }),
|
|
|
+ content: t('pages.inbounds.resetConfirmContent'),
|
|
|
+ okText: t('reset'),
|
|
|
+ cancelText: t('cancel'),
|
|
|
onOk: async () => {
|
|
|
const msg = await HttpUtil.post(`/panel/api/inbounds/${dbInbound.id}/resetTraffic`);
|
|
|
if (msg?.success) await refresh();
|
|
|
},
|
|
|
});
|
|
|
- }, [modal, refresh]);
|
|
|
+ }, [modal, refresh, t]);
|
|
|
|
|
|
const confirmClone = useCallback((dbInbound: any) => {
|
|
|
modal.confirm({
|
|
|
- title: `Clone inbound "${dbInbound.remark}"?`,
|
|
|
- content: 'Creates a copy with a new port and an empty client list.',
|
|
|
- okText: 'Clone',
|
|
|
- cancelText: 'Cancel',
|
|
|
+ title: t('pages.inbounds.cloneConfirmTitle', { remark: dbInbound.remark }),
|
|
|
+ content: t('pages.inbounds.cloneConfirmContent'),
|
|
|
+ okText: t('pages.inbounds.clone'),
|
|
|
+ cancelText: t('cancel'),
|
|
|
onOk: async () => {
|
|
|
const baseInbound = dbInbound.toInbound();
|
|
|
let clonedSettings: string;
|
|
|
@@ -379,7 +380,7 @@ export default function InboundsPage() {
|
|
|
if (msg?.success) await refresh();
|
|
|
},
|
|
|
});
|
|
|
- }, [modal, refresh]);
|
|
|
+ }, [modal, refresh, t]);
|
|
|
|
|
|
const onGeneralAction = useCallback((key: GeneralAction) => {
|
|
|
switch (key) {
|
|
|
@@ -517,56 +518,66 @@ export default function InboundsPage() {
|
|
|
</Layout.Content>
|
|
|
</Layout>
|
|
|
|
|
|
- <InboundFormModal
|
|
|
- open={formOpen}
|
|
|
- onClose={() => setFormOpen(false)}
|
|
|
- onSaved={refresh}
|
|
|
- mode={formMode}
|
|
|
- dbInbound={formDbInbound}
|
|
|
- dbInbounds={dbInbounds as any[]}
|
|
|
- availableNodes={nodesList}
|
|
|
- />
|
|
|
- <InboundInfoModal
|
|
|
- open={infoOpen}
|
|
|
- onClose={() => setInfoOpen(false)}
|
|
|
- dbInbound={infoDbInbound}
|
|
|
- clientIndex={infoClientIndex}
|
|
|
- remarkModel={remarkModel}
|
|
|
- expireDiff={expireDiff}
|
|
|
- trafficDiff={trafficDiff}
|
|
|
- ipLimitEnable={ipLimitEnable}
|
|
|
- tgBotEnable={tgBotEnable}
|
|
|
- subSettings={subSettings}
|
|
|
- lastOnlineMap={lastOnlineMap}
|
|
|
- nodeAddress={infoNodeAddress}
|
|
|
- />
|
|
|
- <QrCodeModal
|
|
|
- open={qrOpen}
|
|
|
- onClose={() => setQrOpen(false)}
|
|
|
- dbInbound={qrDbInbound}
|
|
|
- client={null}
|
|
|
- remarkModel={remarkModel}
|
|
|
- nodeAddress={qrNodeAddress}
|
|
|
- subSettings={subSettings}
|
|
|
- />
|
|
|
-
|
|
|
- <TextModal
|
|
|
- open={textOpen}
|
|
|
- onClose={() => setTextOpen(false)}
|
|
|
- title={textTitle}
|
|
|
- content={textContent}
|
|
|
- fileName={textFileName}
|
|
|
- />
|
|
|
- <PromptModal
|
|
|
- open={promptOpen}
|
|
|
- onClose={() => setPromptOpen(false)}
|
|
|
- title={promptTitle}
|
|
|
- okText={promptOkText}
|
|
|
- type={promptType}
|
|
|
- initialValue={promptInitial}
|
|
|
- loading={promptLoading}
|
|
|
- onConfirm={onPromptConfirm}
|
|
|
- />
|
|
|
+ <LazyMount when={formOpen}>
|
|
|
+ <InboundFormModal
|
|
|
+ open={formOpen}
|
|
|
+ onClose={() => setFormOpen(false)}
|
|
|
+ onSaved={refresh}
|
|
|
+ mode={formMode}
|
|
|
+ dbInbound={formDbInbound}
|
|
|
+ dbInbounds={dbInbounds as any[]}
|
|
|
+ availableNodes={nodesList}
|
|
|
+ />
|
|
|
+ </LazyMount>
|
|
|
+ <LazyMount when={infoOpen}>
|
|
|
+ <InboundInfoModal
|
|
|
+ open={infoOpen}
|
|
|
+ onClose={() => setInfoOpen(false)}
|
|
|
+ dbInbound={infoDbInbound}
|
|
|
+ clientIndex={infoClientIndex}
|
|
|
+ remarkModel={remarkModel}
|
|
|
+ expireDiff={expireDiff}
|
|
|
+ trafficDiff={trafficDiff}
|
|
|
+ ipLimitEnable={ipLimitEnable}
|
|
|
+ tgBotEnable={tgBotEnable}
|
|
|
+ subSettings={subSettings}
|
|
|
+ lastOnlineMap={lastOnlineMap}
|
|
|
+ nodeAddress={infoNodeAddress}
|
|
|
+ />
|
|
|
+ </LazyMount>
|
|
|
+ <LazyMount when={qrOpen}>
|
|
|
+ <QrCodeModal
|
|
|
+ open={qrOpen}
|
|
|
+ onClose={() => setQrOpen(false)}
|
|
|
+ dbInbound={qrDbInbound}
|
|
|
+ client={null}
|
|
|
+ remarkModel={remarkModel}
|
|
|
+ nodeAddress={qrNodeAddress}
|
|
|
+ subSettings={subSettings}
|
|
|
+ />
|
|
|
+ </LazyMount>
|
|
|
+
|
|
|
+ <LazyMount when={textOpen}>
|
|
|
+ <TextModal
|
|
|
+ open={textOpen}
|
|
|
+ onClose={() => setTextOpen(false)}
|
|
|
+ title={textTitle}
|
|
|
+ content={textContent}
|
|
|
+ fileName={textFileName}
|
|
|
+ />
|
|
|
+ </LazyMount>
|
|
|
+ <LazyMount when={promptOpen}>
|
|
|
+ <PromptModal
|
|
|
+ open={promptOpen}
|
|
|
+ onClose={() => setPromptOpen(false)}
|
|
|
+ title={promptTitle}
|
|
|
+ okText={promptOkText}
|
|
|
+ type={promptType}
|
|
|
+ initialValue={promptInitial}
|
|
|
+ loading={promptLoading}
|
|
|
+ onConfirm={onPromptConfirm}
|
|
|
+ />
|
|
|
+ </LazyMount>
|
|
|
</Layout>
|
|
|
</ConfigProvider>
|
|
|
);
|