refactor(frontend): reorganize components & pages into feature folders

No behavior change; pure file relocation + import path updates.
This commit is contained in:
MHSanaei 2026-05-30 14:59:56 +02:00
parent 84a689cf10
commit 06d0ae947d
No known key found for this signature in database
GPG key ID: 7E4060F2FBE5AB7A
89 changed files with 97 additions and 66 deletions

View file

@ -0,0 +1,2 @@
export { default as PromptModal } from './PromptModal';
export { default as TextModal } from './TextModal';

View file

@ -2,7 +2,7 @@ import { useEffect, useRef, useState } from 'react';
import { Button, Input, Space } from 'antd';
import { MinusOutlined, PlusOutlined } from '@ant-design/icons';
import InputAddon from '@/components/InputAddon';
import { InputAddon } from '@/components/ui';
// Reusable header-map editor. Handles the two wire shapes Xray uses for
// HTTP-style header maps:

View file

@ -0,0 +1,3 @@
export { default as DateTimePicker } from './DateTimePicker';
export { default as JsonEditor } from './JsonEditor';
export { default as HeaderMapEditor } from './HeaderMapEditor';

View file

@ -0,0 +1,3 @@
export { default as InputAddon } from './InputAddon';
export { default as InfinityIcon } from './InfinityIcon';
export { default as SettingListItem } from './SettingListItem';

View file

@ -0,0 +1 @@
export { default as LazyMount } from './LazyMount';

View file

@ -0,0 +1 @@
export { default as Sparkline } from './Sparkline';

View file

@ -2,7 +2,7 @@ import { useTranslation } from 'react-i18next';
import { Form, Input, InputNumber, Select, Switch } from 'antd';
import type { FormInstance } from 'antd';
import HeaderMapEditor from '@/components/HeaderMapEditor';
import { HeaderMapEditor } from '@/components/form';
const MASQ_PATH = ['streamSettings', 'hysteriaSettings', 'masquerade'];

View file

@ -0,0 +1 @@
export { default as HysteriaMasqueradeForm } from './HysteriaMasqueradeForm';

View file

@ -0,0 +1 @@
export { default as FinalMaskForm } from './FinalMaskForm';

View file

@ -4,7 +4,7 @@ import SwaggerUI from 'swagger-ui-react';
import 'swagger-ui-react/swagger-ui.css';
import { useTheme } from '@/hooks/useTheme';
import AppSidebar from '@/components/AppSidebar';
import AppSidebar from '@/layouts/AppSidebar';
import './ApiDocsPage.css';
const basePath = window.X_UI_BASE_PATH || '';

View file

@ -7,7 +7,7 @@ import type { Dayjs } from 'dayjs';
import { RandomUtil, SizeFormatter } from '@/utils';
import { TLS_FLOW_CONTROL } from '@/schemas/primitives';
import DateTimePicker from '@/components/DateTimePicker';
import { DateTimePicker } from '@/components/form';
import { useClients, type InboundOption } from '@/hooks/useClients';
import { ClientBulkAddFormSchema, type ClientBulkAddFormValues } from '@/schemas/client';

View file

@ -20,7 +20,7 @@ import dayjs from 'dayjs';
import type { Dayjs } from 'dayjs';
import { HttpUtil, RandomUtil } from '@/utils';
import DateTimePicker from '@/components/DateTimePicker';
import { DateTimePicker } from '@/components/form';
import { TLS_FLOW_CONTROL } from '@/schemas/primitives';
import type { ClientRecord, InboundOption } from '@/hooks/useClients';
import { ClientFormSchema, ClientCreateFormSchema } from '@/schemas/client';

View file

@ -7,7 +7,7 @@ import { ClipboardManager, HttpUtil, IntlUtil, SizeFormatter } from '@/utils';
import { useDatepicker } from '@/hooks/useDatepicker';
import type { ClientRecord, InboundOption } from '@/hooks/useClients';
import { isPostQuantumLink } from '@/lib/xray/inbound-link';
import QrPanel from '@/pages/inbounds/QrPanel';
import { QrPanel } from '@/pages/inbounds/qr';
import './ClientInfoModal.css';
const PROTOCOL_COLORS: Record<string, string> = {

View file

@ -3,7 +3,7 @@ import { useTranslation } from 'react-i18next';
import { Collapse, Modal, Spin } from 'antd';
import { HttpUtil } from '@/utils';
import { isPostQuantumLink } from '@/lib/xray/inbound-link';
import QrPanel from '@/pages/inbounds/QrPanel';
import { QrPanel } from '@/pages/inbounds/qr';
import type { ClientRecord } from '@/hooks/useClients';
interface SubSettings {

View file

@ -51,10 +51,10 @@ import { useWebSocket } from '@/hooks/useWebSocket';
import { useClients } from '@/hooks/useClients';
import { useDatepicker } from '@/hooks/useDatepicker';
import type { ClientRecord, InboundOption } from '@/hooks/useClients';
import AppSidebar from '@/components/AppSidebar';
import AppSidebar from '@/layouts/AppSidebar';
import { IntlUtil, SizeFormatter } from '@/utils';
import { setMessageInstance } from '@/utils/messageBus';
import LazyMount from '@/components/LazyMount';
import { LazyMount } from '@/components/utility';
const ClientFormModal = lazy(() => import('./ClientFormModal'));
const ClientInfoModal = lazy(() => import('./ClientInfoModal'));
const ClientQrModal = lazy(() => import('./ClientQrModal'));

View file

@ -42,8 +42,8 @@ import { usePageTitle } from '@/hooks/usePageTitle';
import { useClients } from '@/hooks/useClients';
import { HttpUtil } from '@/utils';
import { setMessageInstance } from '@/utils/messageBus';
import AppSidebar from '@/components/AppSidebar';
import LazyMount from '@/components/LazyMount';
import AppSidebar from '@/layouts/AppSidebar';
import { LazyMount } from '@/components/utility';
import { keys } from '@/api/queryKeys';
import {
ClientRecordSchema,

View file

@ -28,19 +28,19 @@ import { useTheme } from '@/hooks/useTheme';
import { useMediaQuery } from '@/hooks/useMediaQuery';
import { useWebSocket } from '@/hooks/useWebSocket';
import { useNodesQuery } from '@/api/queries/useNodesQuery';
import AppSidebar from '@/components/AppSidebar';
const TextModal = lazy(() => import('@/components/TextModal'));
const PromptModal = lazy(() => import('@/components/PromptModal'));
import AppSidebar from '@/layouts/AppSidebar';
const TextModal = lazy(() => import('@/components/feedback/TextModal'));
const PromptModal = lazy(() => import('@/components/feedback/PromptModal'));
import { useInbounds } from './useInbounds';
import InboundList from './InboundList';
import LazyMount from '@/components/LazyMount';
const InboundFormModal = lazy(() => import('./InboundFormModal'));
const InboundInfoModal = lazy(() => import('./InboundInfoModal'));
const QrCodeModal = lazy(() => import('./QrCodeModal'));
const AttachClientsModal = lazy(() => import('./AttachClientsModal'));
const DetachClientsModal = lazy(() => import('./DetachClientsModal'));
const AddClientsToGroupModal = lazy(() => import('./AddClientsToGroupModal'));
import { InboundList } from './list';
import { LazyMount } from '@/components/utility';
const InboundFormModal = lazy(() => import('./form/InboundFormModal'));
const InboundInfoModal = lazy(() => import('./info/InboundInfoModal'));
const QrCodeModal = lazy(() => import('./qr/QrCodeModal'));
const AttachClientsModal = lazy(() => import('./clients/AttachClientsModal'));
const DetachClientsModal = lazy(() => import('./clients/DetachClientsModal'));
const AddClientsToGroupModal = lazy(() => import('./clients/AddClientsToGroupModal'));
type RowAction =
| 'edit'

View file

@ -5,7 +5,7 @@ import type { ColumnsType } from 'antd/es/table';
import { HttpUtil } from '@/utils';
import { coerceInboundJsonField, type DBInbound } from '@/models/dbinbound';
import { isInboundMultiUser } from './InboundList';
import { isInboundMultiUser } from '../list';
interface AttachClientsModalProps {
open: boolean;

View file

@ -0,0 +1,3 @@
export { default as AttachClientsModal } from './AttachClientsModal';
export { default as DetachClientsModal } from './DetachClientsModal';
export { default as AddClientsToGroupModal } from './AddClientsToGroupModal';

View file

@ -80,12 +80,12 @@ import { WsStreamSettingsSchema } from '@/schemas/protocols/stream/ws';
import { GrpcStreamSettingsSchema } from '@/schemas/protocols/stream/grpc';
import { HttpUpgradeStreamSettingsSchema } from '@/schemas/protocols/stream/httpupgrade';
import { XHttpStreamSettingsSchema } from '@/schemas/protocols/stream/xhttp';
import DateTimePicker from '@/components/DateTimePicker';
import FinalMaskForm from '@/components/FinalMaskForm';
import HeaderMapEditor from '@/components/HeaderMapEditor';
import HysteriaMasqueradeForm from '@/components/HysteriaMasqueradeForm';
import InputAddon from '@/components/InputAddon';
import JsonEditor from '@/components/JsonEditor';
import { DateTimePicker } from '@/components/form';
import { FinalMaskForm } from '@/lib/xray/forms/transport';
import { HeaderMapEditor } from '@/components/form';
import { HysteriaMasqueradeForm } from '@/lib/xray/forms/protocols/shared';
import { InputAddon } from '@/components/ui';
import { JsonEditor } from '@/components/form';
import './InboundFormModal.css';
import type { FormInstance } from 'antd';
import type { NamePath } from 'antd/es/form/interface';

View file

@ -0,0 +1 @@
export { default as InboundFormModal } from './InboundFormModal';

View file

@ -13,7 +13,7 @@ import {
FileManager,
} from '@/utils';
import { Protocols } from '@/schemas/primitives';
import InfinityIcon from '@/components/InfinityIcon';
import { InfinityIcon } from '@/components/ui';
import { useDatepicker } from '@/hooks/useDatepicker';
import { coerceInboundJsonField } from '@/models/dbinbound';
import {
@ -27,7 +27,7 @@ import {
genWireguardLinks,
} from '@/lib/xray/inbound-link';
import { inboundFromDb } from '@/lib/xray/inbound-from-db';
import type { SubSettings } from './useInbounds';
import type { SubSettings } from '../useInbounds';
import './InboundInfoModal.css';
const LINK_PROTOCOLS: ReadonlySet<string> = new Set([

View file

@ -0,0 +1 @@
export { default as InboundInfoModal } from './InboundInfoModal';

View file

@ -34,7 +34,7 @@ import {
} from '@ant-design/icons';
import { HttpUtil, SizeFormatter, IntlUtil, ColorUtils } from '@/utils';
import InfinityIcon from '@/components/InfinityIcon';
import { InfinityIcon } from '@/components/ui';
import { useDatepicker } from '@/hooks/useDatepicker';
import type { NodeRecord } from '@/api/queries/useNodesQuery';
import { isSSMultiUser } from '@/lib/xray/protocol-capabilities';

View file

@ -0,0 +1 @@
export { default as InboundList, isInboundMultiUser } from './InboundList';

View file

@ -12,7 +12,7 @@ import {
} from '@/lib/xray/inbound-link';
import { inboundFromDb, type DbInboundLike } from '@/lib/xray/inbound-from-db';
import QrPanel from './QrPanel';
import type { SubSettings } from './useInbounds';
import type { SubSettings } from '../useInbounds';
interface ClientSetting {
email?: string;

View file

@ -0,0 +1,2 @@
export { default as QrPanel } from './QrPanel';
export { default as QrCodeModal } from './QrCodeModal';

View file

@ -39,13 +39,13 @@ import { HttpUtil, SizeFormatter, TimeFormatter, ClipboardManager, FileManager }
import { useTheme } from '@/hooks/useTheme';
import { useStatusQuery } from '@/api/queries/useStatusQuery';
import { useMediaQuery } from '@/hooks/useMediaQuery';
import AppSidebar from '@/components/AppSidebar';
import LazyMount from '@/components/LazyMount';
import AppSidebar from '@/layouts/AppSidebar';
import { LazyMount } from '@/components/utility';
import { setMessageInstance } from '@/utils/messageBus';
import StatusCard from './StatusCard';
import XrayStatusCard from './XrayStatusCard';
import type { PanelUpdateInfo } from './PanelUpdateModal';
const JsonEditor = lazy(() => import('@/components/JsonEditor'));
const JsonEditor = lazy(() => import('@/components/form/JsonEditor'));
const PanelUpdateModal = lazy(() => import('./PanelUpdateModal'));
const LogModal = lazy(() => import('./LogModal'));
const BackupModal = lazy(() => import('./BackupModal'));

View file

@ -3,7 +3,7 @@ import { useTranslation } from 'react-i18next';
import { Modal, Select, Tabs } from 'antd';
import { HttpUtil, SizeFormatter } from '@/utils';
import Sparkline from '@/components/Sparkline';
import { Sparkline } from '@/components/viz';
import { useMediaQuery } from '@/hooks/useMediaQuery';
import type { Status } from '@/models/status';
import './SystemHistoryModal.css';

View file

@ -3,7 +3,7 @@ import { useTranslation } from 'react-i18next';
import { Alert, Modal, Select, Tabs, Tag } from 'antd';
import { HttpUtil, Msg, SizeFormatter } from '@/utils';
import Sparkline from '@/components/Sparkline';
import { Sparkline } from '@/components/viz';
import { useMediaQuery } from '@/hooks/useMediaQuery';
import './XrayMetricsModal.css';

View file

@ -1,7 +1,7 @@
import { useEffect, useRef, useState } from 'react';
import { useTranslation } from 'react-i18next';
import { HttpUtil } from '@/utils';
import Sparkline from '@/components/Sparkline';
import { Sparkline } from '@/components/viz';
import './NodeHistoryPanel.css';
interface NodeRef {

View file

@ -13,7 +13,7 @@ import { useMediaQuery } from '@/hooks/useMediaQuery';
import { useNodesQuery } from '@/api/queries/useNodesQuery';
import type { NodeRecord } from '@/api/queries/useNodesQuery';
import { useNodeMutations } from '@/api/queries/useNodeMutations';
import AppSidebar from '@/components/AppSidebar';
import AppSidebar from '@/layouts/AppSidebar';
import NodeList from './NodeList';
import NodeFormModal from './NodeFormModal';
import { setMessageInstance } from '@/utils/messageBus';

View file

@ -10,7 +10,7 @@ import {
} from 'antd';
import type { AllSetting } from '@/models/setting';
import { HttpUtil, LanguageManager } from '@/utils';
import SettingListItem from '@/components/SettingListItem';
import { SettingListItem } from '@/components/ui';
interface ApiMsg<T = unknown> {
success?: boolean;

View file

@ -14,7 +14,7 @@ import {
} from 'antd';
import { ClipboardManager, HttpUtil, RandomUtil } from '@/utils';
import type { AllSetting } from '@/models/setting';
import SettingListItem from '@/components/SettingListItem';
import { SettingListItem } from '@/components/ui';
import TwoFactorModal from './TwoFactorModal';
import './SecurityTab.css';

View file

@ -30,7 +30,7 @@ import { useTheme } from '@/hooks/useTheme';
import { useMediaQuery } from '@/hooks/useMediaQuery';
import { useAllSettings } from '@/api/queries/useAllSettings';
import { AllSettingSchema } from '@/schemas/setting';
import AppSidebar from '@/components/AppSidebar';
import AppSidebar from '@/layouts/AppSidebar';
import GeneralTab from './GeneralTab';
import SecurityTab from './SecurityTab';
import TelegramTab from './TelegramTab';

View file

@ -10,7 +10,7 @@ import {
Switch,
} from 'antd';
import type { AllSetting } from '@/models/setting';
import SettingListItem from '@/components/SettingListItem';
import { SettingListItem } from '@/components/ui';
import './SubscriptionFormatsTab.css';
interface SubscriptionFormatsTabProps {

View file

@ -1,7 +1,7 @@
import { Collapse, Divider, Input, InputNumber, Switch } from 'antd';
import { useTranslation } from 'react-i18next';
import type { AllSetting } from '@/models/setting';
import SettingListItem from '@/components/SettingListItem';
import { SettingListItem } from '@/components/ui';
interface SubscriptionGeneralTabProps {
allSetting: AllSetting;

View file

@ -3,7 +3,7 @@ import { useTranslation } from 'react-i18next';
import { Collapse, Input, InputNumber, Select, Switch } from 'antd';
import { LanguageManager } from '@/utils';
import type { AllSetting } from '@/models/setting';
import SettingListItem from '@/components/SettingListItem';
import { SettingListItem } from '@/components/ui';
interface TelegramTabProps {
allSetting: AllSetting;

View file

@ -33,17 +33,16 @@ import { useTheme } from '@/hooks/useTheme';
import { useMediaQuery } from '@/hooks/useMediaQuery';
import { useXraySetting } from '@/hooks/useXraySetting';
import type { XraySettingsValue } from '@/hooks/useXraySetting';
import AppSidebar from '@/components/AppSidebar';
import JsonEditor from '@/components/JsonEditor';
import AppSidebar from '@/layouts/AppSidebar';
import { JsonEditor } from '@/components/form';
import { setMessageInstance } from '@/utils/messageBus';
import BasicsTab from './BasicsTab';
import RoutingTab from './RoutingTab';
import OutboundsTab from './OutboundsTab';
import BalancersTab from './BalancersTab';
import DnsTab from './DnsTab';
import WarpModal from './WarpModal';
import NordModal from './NordModal';
import { BasicsTab } from './basics';
import { RoutingTab } from './routing';
import { OutboundsTab } from './outbounds';
import { BalancersTab } from './balancers';
import { DnsTab } from './dns';
import { WarpModal, NordModal } from './overrides';
import './XrayPage.css';
const TAB_KEYS = ['tpl-basic', 'tpl-routing', 'tpl-outbound', 'tpl-balancer', 'tpl-dns', 'tpl-advanced'];

View file

@ -3,7 +3,7 @@ import { useTranslation } from 'react-i18next';
import { Button, Form, Input, InputNumber, Modal, Select, Space, Switch } from 'antd';
import { MinusOutlined, PlusOutlined } from '@ant-design/icons';
import InputAddon from '@/components/InputAddon';
import { InputAddon } from '@/components/ui';
import {
BalancerFormSchema,
type BalancerFormValues,

View file

@ -6,7 +6,7 @@ import type { ColumnsType } from 'antd/es/table';
import BalancerFormModal from './BalancerFormModal';
import type { BalancerFormValue } from './BalancerFormModal';
import JsonEditor from '@/components/JsonEditor';
import { JsonEditor } from '@/components/form';
import type { XraySettingsValue, SetTemplate } from '@/hooks/useXraySetting';
import type {
BalancerObject,

View file

@ -0,0 +1,2 @@
export { default as BalancersTab } from './BalancersTab';
export { default as BalancerFormModal } from './BalancerFormModal';

View file

@ -4,7 +4,7 @@ import { Alert, Button, Collapse, Input, Modal, Select, Space, Switch } from 'an
import { CloudOutlined, ApiOutlined } from '@ant-design/icons';
import { OutboundDomainStrategies } from '@/schemas/primitives';
import SettingListItem from '@/components/SettingListItem';
import { SettingListItem } from '@/components/ui';
import type { XraySettingsValue, SetTemplate } from '@/hooks/useXraySetting';
import './BasicsTab.css';

View file

@ -0,0 +1 @@
export { default as BasicsTab } from './BasicsTab';

View file

@ -3,7 +3,7 @@ import { useTranslation } from 'react-i18next';
import { Button, Divider, Form, Input, InputNumber, Modal, Select, Space, Switch } from 'antd';
import { MinusOutlined, PlusOutlined } from '@ant-design/icons';
import InputAddon from '@/components/InputAddon';
import { InputAddon } from '@/components/ui';
import {
DnsQueryStrategySchema,
DnsServerObjectInnerSchema,

View file

@ -4,7 +4,7 @@ import { Button, Collapse, Dropdown, Empty, Input, InputNumber, Modal, Select, S
import { PlusOutlined, MoreOutlined, EditOutlined, DeleteOutlined, MenuOutlined } from '@ant-design/icons';
import type { ColumnsType } from 'antd/es/table';
import SettingListItem from '@/components/SettingListItem';
import { SettingListItem } from '@/components/ui';
import DnsServerModal from './DnsServerModal';
import type { DnsServerValue } from './DnsServerModal';
import DnsPresetsModal from './DnsPresetsModal';

View file

@ -0,0 +1,3 @@
export { default as DnsTab } from './DnsTab';
export { default as DnsServerModal } from './DnsServerModal';
export { default as DnsPresetsModal } from './DnsPresetsModal';

View file

@ -15,11 +15,11 @@ import {
} from 'antd';
import { DeleteOutlined, MinusOutlined, PlusOutlined, ReloadOutlined } from '@ant-design/icons';
import FinalMaskForm from '@/components/FinalMaskForm';
import HeaderMapEditor from '@/components/HeaderMapEditor';
import HysteriaMasqueradeForm from '@/components/HysteriaMasqueradeForm';
import InputAddon from '@/components/InputAddon';
import JsonEditor from '@/components/JsonEditor';
import { FinalMaskForm } from '@/lib/xray/forms/transport';
import { HeaderMapEditor } from '@/components/form';
import { HysteriaMasqueradeForm } from '@/lib/xray/forms/protocols/shared';
import { InputAddon } from '@/components/ui';
import { JsonEditor } from '@/components/form';
import { Wireguard } from '@/utils';
import {
XMUX_DEFAULTS,

View file

@ -0,0 +1,2 @@
export { default as OutboundsTab } from './OutboundsTab';
export { default as OutboundFormModal } from './OutboundFormModal';

View file

@ -0,0 +1,2 @@
export { default as WarpModal } from './WarpModal';
export { default as NordModal } from './NordModal';

View file

@ -2,7 +2,7 @@ import { useEffect, useState } from 'react';
import { useTranslation } from 'react-i18next';
import { Button, Form, Input, Modal, Select, Space, Tooltip } from 'antd';
import { PlusOutlined, MinusOutlined, QuestionCircleOutlined } from '@ant-design/icons';
import InputAddon from '@/components/InputAddon';
import { InputAddon } from '@/components/ui';
import { RuleFormSchema, type RuleFormValues } from '@/schemas/xray';
export interface RoutingRule {

View file

@ -0,0 +1,2 @@
export { default as RoutingTab } from './RoutingTab';
export { default as RuleFormModal } from './RuleFormModal';