refactor(frontend): move form-item hints from extra to tooltip

Switch reality target, node options, and WARP auto-update-IP hints from
inline extra text to label tooltips for a cleaner form layout.
This commit is contained in:
MHSanaei
2026-06-17 17:24:16 +02:00
parent d6cddaff12
commit 4915d6b18d
23 changed files with 218 additions and 223 deletions
@@ -47,7 +47,7 @@ export default function RealityForm({
</Form.Item>
<Form.Item
label={t('pages.inbounds.form.target')}
extra={t('pages.inbounds.form.realityTargetHint')}
tooltip={t('pages.inbounds.form.realityTargetHint')}
>
<Space.Compact block>
<Form.Item
+7 -7
View File
@@ -323,7 +323,7 @@ export default function NodeFormModal({
label={t('pages.nodes.allowPrivateAddress')}
name="allowPrivateAddress"
valuePropName="checked"
extra={t('pages.nodes.allowPrivateAddressHint')}
tooltip={t('pages.nodes.allowPrivateAddressHint')}
>
<Switch />
</Form.Item>
@@ -331,7 +331,7 @@ export default function NodeFormModal({
<Form.Item
label={t('pages.nodes.tlsVerifyMode')}
name="tlsVerifyMode"
extra={t('pages.nodes.tlsVerifyModeHint')}
tooltip={t('pages.nodes.tlsVerifyModeHint')}
>
<Select
disabled={scheme === 'http'}
@@ -366,7 +366,7 @@ export default function NodeFormModal({
<Form.Item
label={t('pages.nodes.pinnedCert')}
name="pinnedCertSha256"
extra={t('pages.nodes.pinnedCertHint')}
tooltip={t('pages.nodes.pinnedCertHint')}
>
<Input.Search
placeholder={t('pages.nodes.pinnedCertPlaceholder')}
@@ -381,7 +381,7 @@ export default function NodeFormModal({
label={t('pages.nodes.apiToken')}
name="apiToken"
rules={[antdRule(NodeFormSchema.shape.apiToken, t)]}
extra={t('pages.nodes.apiTokenHint')}
tooltip={t('pages.nodes.apiTokenHint')}
>
<Input.Password placeholder={t('pages.nodes.apiTokenPlaceholder')} />
</Form.Item>
@@ -389,7 +389,7 @@ export default function NodeFormModal({
<Form.Item
label={t('pages.nodes.outboundTag')}
name="outboundTag"
extra={t('pages.nodes.outboundTagHint')}
tooltip={t('pages.nodes.outboundTagHint')}
getValueProps={(v) => ({ value: (v as string) || undefined })}
>
<Select
@@ -403,7 +403,7 @@ export default function NodeFormModal({
<Form.Item
label={t('pages.nodes.inboundSyncMode')}
name="inboundSyncMode"
extra={t('pages.nodes.inboundSyncModeHint')}
tooltip={t('pages.nodes.inboundSyncModeHint')}
>
<Select
options={[
@@ -417,7 +417,7 @@ export default function NodeFormModal({
<Form.Item
label={t('pages.nodes.inboundTags')}
name="inboundTags"
extra={t('pages.nodes.inboundTagsHint')}
tooltip={t('pages.nodes.inboundTagsHint')}
>
<Select
mode="multiple"
+156 -155
View File
@@ -266,170 +266,171 @@ export default function WarpModal({
<>
{messageContextHolder}
<Modal open={open} title="Cloudflare WARP" footer={null} onCancel={onClose}>
{!hasWarp ? (
<Button type="primary" loading={loading} icon={<ApiOutlined />} onClick={register}>
{t('pages.xray.warp.createAccount')}
</Button>
) : (
<>
<table className="warp-data-table">
<tbody>
<tr className="row-odd">
<td>{t('pages.xray.warp.accessToken')}</td>
<td>{warpData?.access_token}</td>
</tr>
<tr>
<td>{t('pages.xray.warp.deviceId')}</td>
<td>{warpData?.device_id}</td>
</tr>
<tr className="row-odd">
<td>{t('pages.xray.warp.licenseKey')}</td>
<td>{warpData?.license_key}</td>
</tr>
<tr>
<td>{t('pages.xray.warp.privateKey')}</td>
<td>{warpData?.private_key}</td>
</tr>
</tbody>
</table>
<Button loading={loading} type="primary" danger className="mt-8" icon={<DeleteOutlined />} onClick={delConfig}>
{t('pages.xray.warp.deleteAccount')}
{!hasWarp ? (
<Button type="primary" loading={loading} icon={<ApiOutlined />} onClick={register}>
{t('pages.xray.warp.createAccount')}
</Button>
) : (
<>
<table className="warp-data-table">
<tbody>
<tr className="row-odd">
<td>{t('pages.xray.warp.accessToken')}</td>
<td>{warpData?.access_token}</td>
</tr>
<tr>
<td>{t('pages.xray.warp.deviceId')}</td>
<td>{warpData?.device_id}</td>
</tr>
<tr className="row-odd">
<td>{t('pages.xray.warp.licenseKey')}</td>
<td>{warpData?.license_key}</td>
</tr>
<tr>
<td>{t('pages.xray.warp.privateKey')}</td>
<td>{warpData?.private_key}</td>
</tr>
</tbody>
</table>
<Divider className="zero-margin">{t('pages.xray.warp.settings')}</Divider>
<Button loading={loading} type="primary" danger className="mt-8" icon={<DeleteOutlined />} onClick={delConfig}>
{t('pages.xray.warp.deleteAccount')}
</Button>
<Collapse
className="my-10"
items={[
{
key: '1',
label: t('pages.xray.warp.licenseKeyLabel'),
children: (
<Form colon={false} labelCol={{ md: { span: 6 } }} wrapperCol={{ md: { span: 14 } }}>
<Form.Item label={t('pages.xray.warp.key')}>
<Input
value={warpPlus}
placeholder={t('pages.xray.warp.keyPlaceholder')}
onChange={(e) => {
setWarpPlus(e.target.value);
setLicenseError('');
}}
/>
<div className="license-actions mt-8">
<Button
type="primary"
disabled={warpPlus.length < 26}
loading={loading}
onClick={updateLicense}
>
{t('update')}
<Divider className="zero-margin">{t('pages.xray.warp.settings')}</Divider>
<Collapse
className="my-10"
items={[
{
key: '1',
label: t('pages.xray.warp.licenseKeyLabel'),
children: (
<Form colon={false} labelCol={{ md: { span: 6 } }} wrapperCol={{ md: { span: 14 } }}>
<Form.Item label={t('pages.xray.warp.key')}>
<Input
value={warpPlus}
placeholder={t('pages.xray.warp.keyPlaceholder')}
onChange={(e) => {
setWarpPlus(e.target.value);
setLicenseError('');
}}
/>
<div className="license-actions mt-8">
<Button
type="primary"
disabled={warpPlus.length < 26}
loading={loading}
onClick={updateLicense}
>
{t('update')}
</Button>
{licenseError && (
<Alert title={licenseError} type="error" showIcon className="license-error" />
)}
</div>
</Form.Item>
</Form>
),
},
{
key: '2',
label: t('pages.xray.warp.autoUpdateIp', 'Auto Update IP Address'),
children: (
<Form colon={false} labelCol={{ md: { span: 8 } }} wrapperCol={{ md: { span: 12 } }}>
<Form.Item label={t('pages.xray.warp.intervalDays', 'Interval (Days)')}
tooltip={t('pages.xray.warp.intervalDesc', '0 to disable. Changes IP address automatically.')}>
<Input
type="number"
min={0}
value={updateInterval}
onChange={(e) => setUpdateInterval(Number(e.target.value))}
/>
<Button className="mt-8" type="primary" loading={loading} onClick={saveInterval}>
{t('save', 'Save')}
</Button>
{licenseError && (
<Alert title={licenseError} type="error" showIcon className="license-error" />
)}
</div>
</Form.Item>
</Form>
),
},
{
key: '2',
label: t('pages.xray.warp.autoUpdateIp', 'Auto Update IP Address'),
children: (
<Form colon={false} labelCol={{ md: { span: 8 } }} wrapperCol={{ md: { span: 12 } }}>
<Form.Item label={t('pages.xray.warp.intervalDays', 'Interval (Days)')} extra={t('pages.xray.warp.intervalDesc', '0 to disable. Changes IP address automatically.')}>
<Input
type="number"
min={0}
value={updateInterval}
onChange={(e) => setUpdateInterval(Number(e.target.value))}
/>
<Button className="mt-8" type="primary" loading={loading} onClick={saveInterval}>
{t('save', 'Save')}
</Button>
</Form.Item>
</Form>
),
},
]}
/>
</Form.Item>
</Form>
),
},
]}
/>
<Divider className="zero-margin">{t('pages.xray.warp.accountInfo')}</Divider>
<div className="my-8">
<Button loading={loading} type="primary" icon={<SyncOutlined />} onClick={getConfig}>
{t('refresh')}
</Button>
<Button loading={loading} type="primary" className="ml-8" icon={<SyncOutlined />} onClick={changeIp}>
{t('pages.xray.warp.changeIp', 'Change IP')}
</Button>
</div>
<Divider className="zero-margin">{t('pages.xray.warp.accountInfo')}</Divider>
<div className="my-8">
<Button loading={loading} type="primary" icon={<SyncOutlined />} onClick={getConfig}>
{t('refresh')}
</Button>
<Button loading={loading} type="primary" className="ml-8" icon={<SyncOutlined />} onClick={changeIp}>
{t('pages.xray.warp.changeIp', 'Change IP')}
</Button>
</div>
{hasConfig && (
<>
<table className="warp-data-table">
<tbody>
<tr className="row-odd">
<td>{t('pages.xray.warp.deviceName')}</td>
<td>{warpConfig?.name}</td>
</tr>
<tr>
<td>{t('pages.xray.warp.deviceModel')}</td>
<td>{warpConfig?.model}</td>
</tr>
<tr className="row-odd">
<td>{t('pages.xray.warp.deviceEnabled')}</td>
<td>{String(warpConfig?.enabled)}</td>
</tr>
{warpConfig?.account && (
<>
<tr>
<td>{t('pages.xray.warp.accountType')}</td>
<td>{warpConfig.account.account_type}</td>
</tr>
<tr className="row-odd">
<td>{t('pages.xray.warp.role')}</td>
<td>{warpConfig.account.role}</td>
</tr>
<tr>
<td>{t('pages.xray.warp.warpPlusData')}</td>
<td>{SizeFormatter.sizeFormat(warpConfig.account.premium_data)}</td>
</tr>
<tr className="row-odd">
<td>{t('pages.xray.warp.quota')}</td>
<td>{SizeFormatter.sizeFormat(warpConfig.account.quota)}</td>
</tr>
{warpConfig.account.usage != null && (
{hasConfig && (
<>
<table className="warp-data-table">
<tbody>
<tr className="row-odd">
<td>{t('pages.xray.warp.deviceName')}</td>
<td>{warpConfig?.name}</td>
</tr>
<tr>
<td>{t('pages.xray.warp.deviceModel')}</td>
<td>{warpConfig?.model}</td>
</tr>
<tr className="row-odd">
<td>{t('pages.xray.warp.deviceEnabled')}</td>
<td>{String(warpConfig?.enabled)}</td>
</tr>
{warpConfig?.account && (
<>
<tr>
<td>{t('pages.xray.warp.usage')}</td>
<td>{SizeFormatter.sizeFormat(warpConfig.account.usage)}</td>
<td>{t('pages.xray.warp.accountType')}</td>
<td>{warpConfig.account.account_type}</td>
</tr>
)}
</>
)}
</tbody>
</table>
<tr className="row-odd">
<td>{t('pages.xray.warp.role')}</td>
<td>{warpConfig.account.role}</td>
</tr>
<tr>
<td>{t('pages.xray.warp.warpPlusData')}</td>
<td>{SizeFormatter.sizeFormat(warpConfig.account.premium_data)}</td>
</tr>
<tr className="row-odd">
<td>{t('pages.xray.warp.quota')}</td>
<td>{SizeFormatter.sizeFormat(warpConfig.account.quota)}</td>
</tr>
{warpConfig.account.usage != null && (
<tr>
<td>{t('pages.xray.warp.usage')}</td>
<td>{SizeFormatter.sizeFormat(warpConfig.account.usage)}</td>
</tr>
)}
</>
)}
</tbody>
</table>
<Divider className="my-10">{t('pages.xray.outbound.outboundStatus')}</Divider>
{warpOutboundIndex >= 0 ? (
<>
<Tag color="green">{t('enabled')}</Tag>
<Button type="primary" danger loading={loading} className="ml-8" onClick={resetOutbound}>
{t('reset')}
</Button>
</>
) : (
<>
<Tag color="orange">{t('disabled')}</Tag>
<Button type="primary" loading={loading} className="ml-8" icon={<PlusOutlined />} onClick={addOutbound}>
{t('pages.xray.warp.addOutbound')}
</Button>
</>
)}
</>
)}
</>
)}
<Divider className="my-10">{t('pages.xray.outbound.outboundStatus')}</Divider>
{warpOutboundIndex >= 0 ? (
<>
<Tag color="green">{t('enabled')}</Tag>
<Button type="primary" danger loading={loading} className="ml-8" onClick={resetOutbound}>
{t('reset')}
</Button>
</>
) : (
<>
<Tag color="orange">{t('disabled')}</Tag>
<Button type="primary" loading={loading} className="ml-8" icon={<PlusOutlined />} onClick={addOutbound}>
{t('pages.xray.warp.addOutbound')}
</Button>
</>
)}
</>
)}
</>
)}
</Modal>
</>
);