mirror of
https://github.com/MHSanaei/3x-ui.git
synced 2026-08-17 16:50:58 +00:00
feat(sub): auto-detect subscription format by User-Agent (Updated) (#5826)
* feat(settings): add subscription format controls
* feat(sub): auto-detect subscription formats
* fix(xray): validate balancer regexes before save
* Revert "fix(xray): validate balancer regexes before save"
This reverts commit 8a208ce71b.
* doc(endpoints): align indent spaces
* doc(settings): improve error message formatting in validateSubUserAgentRegex
- Use NewErrorf with proper formatting instead of NewError with string concatenation
- Add comment explaining the rationale for returning original pattern value
- This preserves the intentional design where empty input is stored as empty
in the DB and inherited as the runtime default at read time
---------
Co-authored-by: Tomilla <5007859+Tomilla@users.noreply.github.com>
Co-authored-by: Sanaei <ho3ein.sanaei@gmail.com>
This commit is contained in:
@@ -0,0 +1,63 @@
|
||||
import { useRef, useState } from 'react';
|
||||
import { Input, Typography } from 'antd';
|
||||
|
||||
import { HttpUtil } from '@/utils';
|
||||
|
||||
interface GoRegexInputProps {
|
||||
value: string;
|
||||
ariaLabel?: string;
|
||||
placeholder?: string;
|
||||
maxLength?: number;
|
||||
onChange: (value: string) => void;
|
||||
externalError?: string;
|
||||
}
|
||||
|
||||
export async function validateGoRegex(value: string): Promise<string> {
|
||||
const result = await HttpUtil.post(
|
||||
'/panel/api/setting/validateRegex',
|
||||
{ regex: value },
|
||||
{ silent: true },
|
||||
);
|
||||
return result.success ? '' : result.msg || 'Invalid Go RE2 regular expression';
|
||||
}
|
||||
|
||||
export default function GoRegexInput({
|
||||
value,
|
||||
ariaLabel,
|
||||
placeholder,
|
||||
maxLength = 2048,
|
||||
onChange,
|
||||
externalError,
|
||||
}: GoRegexInputProps) {
|
||||
const [error, setError] = useState('');
|
||||
const validationSequence = useRef(0);
|
||||
|
||||
async function validate() {
|
||||
const sequence = ++validationSequence.current;
|
||||
const nextError = await validateGoRegex(value);
|
||||
if (sequence === validationSequence.current) {
|
||||
setError(nextError);
|
||||
}
|
||||
}
|
||||
|
||||
const displayError = externalError ?? error;
|
||||
|
||||
return (
|
||||
<div style={{ width: '100%' }}>
|
||||
<Input
|
||||
value={value}
|
||||
aria-label={ariaLabel}
|
||||
placeholder={placeholder}
|
||||
maxLength={maxLength}
|
||||
status={displayError ? 'error' : undefined}
|
||||
onChange={(event) => {
|
||||
validationSequence.current += 1;
|
||||
setError('');
|
||||
onChange(event.target.value);
|
||||
}}
|
||||
onBlur={() => void validate()}
|
||||
/>
|
||||
{displayError && <Typography.Text type="danger">{displayError}</Typography.Text>}
|
||||
</div>
|
||||
);
|
||||
}
|
||||
@@ -1,6 +1,7 @@
|
||||
export { default as DateTimePicker } from './DateTimePicker';
|
||||
export { default as JsonEditor } from './JsonEditor';
|
||||
export { default as HeaderMapEditor } from './HeaderMapEditor';
|
||||
export { default as GoRegexInput, validateGoRegex } from './GoRegexInput';
|
||||
export { default as SelectAllClearButtons } from './SelectAllClearButtons';
|
||||
export { default as RemarkTemplateField } from './RemarkTemplateField';
|
||||
export { default as RemarkVarPicker } from './RemarkVarPicker';
|
||||
|
||||
Reference in New Issue
Block a user