Compare commits

...

4 Commits

Author SHA1 Message Date
sagit d9f28f53c7 style: move advanced settings to bottom and optimize UI (#466) 2026-04-24 19:10:36 +08:00
sagit 1d08a1ccfc fix: ensure page refresh to login page upon logout (#465) 2026-04-23 20:43:27 +08:00
sagit db25ba2cbe style: move maxConn and speed limit inputs to advanced settings accordion (#464) 2026-04-23 20:29:52 +08:00
sagit a498067261 fix: properly initialize maxConn in forward rules (#463)
* fix: initialize maxConn in forward creation and edit forms

* fix: add maxConn to Forward interface
2026-04-23 20:23:18 +08:00
2 changed files with 61 additions and 47 deletions
+59 -46
View File
@@ -54,6 +54,7 @@ import { Switch } from "@/shadcn-bridge/heroui/switch";
import { Alert } from "@/shadcn-bridge/heroui/alert";
import { Progress } from "@/shadcn-bridge/heroui/progress";
import { Checkbox } from "@/shadcn-bridge/heroui/checkbox";
import { Accordion, AccordionItem } from "@/shadcn-bridge/heroui/accordion";
import {
createForward,
getForwardList,
@@ -118,6 +119,7 @@ interface Forward {
outFlow: number;
serviceRunning: boolean;
federationShareFlow?: number;
maxConn?: number;
createdTime: string;
userName?: string;
userId?: number;
@@ -2115,6 +2117,7 @@ export default function ForwardPage() {
interfaceName: forward.interfaceName || "",
strategy: forward.strategy || "fifo",
speedId: normalizeSpeedId(forward.speedId),
maxConn: forward.maxConn || 0,
});
setErrors({});
setModalOpen(true);
@@ -4727,20 +4730,6 @@ export default function ForwardPage() {
</ModalHeader>
<ModalBody>
<div className="space-y-4 pb-4">
<Input
label="最大连接数"
placeholder="0 或空表示不限制"
type="number"
min="0"
value={form.maxConn === 0 ? "" : String(form.maxConn || "")}
onChange={(e) => {
const value = Math.max(Number(e.target.value) || 0, 0);
setForm((prev) => ({ ...prev, maxConn: value }));
}}
description="此设置优先于用户的全局连接数限制。0 表示不限制。"
variant="bordered"
/>
<Input
errorMessage={errors.name}
isInvalid={!!errors.name}
@@ -4753,37 +4742,7 @@ export default function ForwardPage() {
}
/>
{isAdmin && (
<Select
label="规则限速"
placeholder="不限速"
selectedKeys={
selectedSpeedId !== null
? [selectedSpeedId.toString()]
: []
}
variant="bordered"
onSelectionChange={(keys) => {
const selectedKey = Array.from(keys)[0] as
| string
| undefined;
setForm((prev) => ({
...prev,
speedId: selectedKey ? Number(selectedKey) : null,
}));
}}
>
{availableSpeedLimits.map((speedLimit) => (
<SelectItem
key={speedLimit.id.toString()}
textValue={speedLimit.name}
>
{speedLimit.name}
</SelectItem>
))}
</Select>
)}
<Select
description={
@@ -4912,7 +4871,61 @@ export default function ForwardPage() {
<SelectItem key="hash">哈希模式 - IP哈希</SelectItem>
</Select>
)}
</div>
<Accordion className="px-0" variant="light">
<AccordionItem
key="advanced"
aria-label="高级设置"
title={<span className="text-small text-default-500 font-medium">高级设置</span>}
>
<div className="space-y-4 pb-2">
<Input
label="最大连接数"
placeholder="0 或空表示不限制"
type="number"
min="0"
value={form.maxConn === 0 ? "" : String(form.maxConn || "")}
onChange={(e) => {
const value = Math.max(Number(e.target.value) || 0, 0);
setForm((prev) => ({ ...prev, maxConn: value }));
}}
description="此设置优先于用户的全局连接数限制。0 表示不限制。"
variant="bordered"
/>
{isAdmin && (
<Select
label="规则限速"
placeholder="不限速"
selectedKeys={
selectedSpeedId !== null
? [selectedSpeedId.toString()]
: []
}
variant="bordered"
onSelectionChange={(keys) => {
const selectedKey = Array.from(keys)[0] as
| string
| undefined;
setForm((prev) => ({
...prev,
speedId: selectedKey ? Number(selectedKey) : null,
}));
}}
>
{availableSpeedLimits.map((speedLimit) => (
<SelectItem
key={speedLimit.id.toString()}
textValue={speedLimit.name}
>
{speedLimit.name}
</SelectItem>
))}
</Select>
)}
</div>
</AccordionItem>
</Accordion>
</div>
</ModalBody>
<ModalFooter>
<Button variant="light" onPress={onClose}>
+2 -1
View File
@@ -2,8 +2,9 @@ import { clearSession } from "@/utils/session";
/**
* 安全退出登录函数
* 清除登录相关数据,但保留用户偏好设置(如主题)
* 清除登录相关数据,并强制刷新跳转到首页
*/
export const safeLogout = () => {
clearSession();
window.location.href = "/";
};