|
@@ -1,11 +1,16 @@
|
|
|
import { useState } from 'react';
|
|
import { useState } from 'react';
|
|
|
|
|
+import { useFormContext } from 'react-hook-form';
|
|
|
import { useTranslation } from 'react-i18next';
|
|
import { useTranslation } from 'react-i18next';
|
|
|
import { Alert, Button, Collapse, Descriptions, Divider, Form, Input, InputNumber, Select, Space, Switch } from 'antd';
|
|
import { Alert, Button, Collapse, Descriptions, Divider, Form, Input, InputNumber, Select, Space, Switch } from 'antd';
|
|
|
import { RadarChartOutlined, ReloadOutlined, SearchOutlined } from '@ant-design/icons';
|
|
import { RadarChartOutlined, ReloadOutlined, SearchOutlined } from '@ant-design/icons';
|
|
|
|
|
|
|
|
import { FormField } from '@/components/form/rhf';
|
|
import { FormField } from '@/components/form/rhf';
|
|
|
import { UTLS_FINGERPRINT } from '@/schemas/primitives';
|
|
import { UTLS_FINGERPRINT } from '@/schemas/primitives';
|
|
|
-import { validateRealityTarget } from '@/lib/xray/stream-wire-normalize';
|
|
|
|
|
|
|
+import {
|
|
|
|
|
+ validateRealityClientVer,
|
|
|
|
|
+ validateRealityMaxClientVer,
|
|
|
|
|
+ validateRealityTarget,
|
|
|
|
|
+} from '@/lib/xray/stream-wire-normalize';
|
|
|
import type { RealityScanResult } from '@/generated/types';
|
|
import type { RealityScanResult } from '@/generated/types';
|
|
|
import RealityTargetScannerModal from './RealityTargetScannerModal';
|
|
import RealityTargetScannerModal from './RealityTargetScannerModal';
|
|
|
|
|
|
|
@@ -39,7 +44,14 @@ export default function RealityForm({
|
|
|
clearMldsa65,
|
|
clearMldsa65,
|
|
|
}: RealityFormProps) {
|
|
}: RealityFormProps) {
|
|
|
const { t } = useTranslation();
|
|
const { t } = useTranslation();
|
|
|
|
|
+ const { getFieldState, trigger } = useFormContext();
|
|
|
const [scannerOpen, setScannerOpen] = useState(false);
|
|
const [scannerOpen, setScannerOpen] = useState(false);
|
|
|
|
|
+ const maxClientVerPath = 'streamSettings.realitySettings.maxClientVer';
|
|
|
|
|
+ const revalidateMaxClientVer = () => {
|
|
|
|
|
+ if (getFieldState(maxClientVerPath).error) {
|
|
|
|
|
+ void trigger(maxClientVerPath);
|
|
|
|
|
+ }
|
|
|
|
|
+ };
|
|
|
return (
|
|
return (
|
|
|
<>
|
|
<>
|
|
|
<FormField
|
|
<FormField
|
|
@@ -128,6 +140,13 @@ export default function RealityForm({
|
|
|
name={['streamSettings', 'realitySettings', 'minClientVer']}
|
|
name={['streamSettings', 'realitySettings', 'minClientVer']}
|
|
|
label={t('pages.inbounds.form.minClientVer')}
|
|
label={t('pages.inbounds.form.minClientVer')}
|
|
|
tooltip={t('pages.inbounds.form.minClientVerHint')}
|
|
tooltip={t('pages.inbounds.form.minClientVerHint')}
|
|
|
|
|
+ onAfterChange={revalidateMaxClientVer}
|
|
|
|
|
+ rules={{
|
|
|
|
|
+ validate: (value) => {
|
|
|
|
|
+ const errKey = validateRealityClientVer(typeof value === 'string' ? value : '');
|
|
|
|
|
+ return errKey ? errKey : true;
|
|
|
|
|
+ },
|
|
|
|
|
+ }}
|
|
|
>
|
|
>
|
|
|
<Input placeholder="26.3.27" />
|
|
<Input placeholder="26.3.27" />
|
|
|
</FormField>
|
|
</FormField>
|
|
@@ -135,6 +154,14 @@ export default function RealityForm({
|
|
|
name={['streamSettings', 'realitySettings', 'maxClientVer']}
|
|
name={['streamSettings', 'realitySettings', 'maxClientVer']}
|
|
|
label={t('pages.inbounds.form.maxClientVer')}
|
|
label={t('pages.inbounds.form.maxClientVer')}
|
|
|
tooltip={t('pages.inbounds.form.maxClientVerHint')}
|
|
tooltip={t('pages.inbounds.form.maxClientVerHint')}
|
|
|
|
|
+ rules={{
|
|
|
|
|
+ validate: (value, formValues) => {
|
|
|
|
|
+ const max = typeof value === 'string' ? value : '';
|
|
|
|
|
+ const min = formValues?.streamSettings?.realitySettings?.minClientVer;
|
|
|
|
|
+ const errKey = validateRealityMaxClientVer(max, typeof min === 'string' ? min : '');
|
|
|
|
|
+ return errKey ? errKey : true;
|
|
|
|
|
+ },
|
|
|
|
|
+ }}
|
|
|
>
|
|
>
|
|
|
<Input placeholder="x.y.z" />
|
|
<Input placeholder="x.y.z" />
|
|
|
</FormField>
|
|
</FormField>
|