fix: tolerate offline nodes when controlling forward services and editing tunnels

- controlForwardServices: skip offline nodes instead of failing entire operation,
  so forward pause/resume/delete works when some entry nodes are offline
- onNodeOnline: always sync forward state on node reconnect (not just post-upgrade),
  so forwards that changed status while a node was offline get synced
- add ListForwardIDsByNode repo method to sync all forwards (including paused)
- tunnel edit UI: allow deselecting already-selected offline nodes in
  entry/chain/exit selectors, matching the backend's existing tolerance
This commit is contained in:
sagitchu
2026-04-21 16:53:47 +08:00
parent 431613cb6a
commit 5107f59d94
4 changed files with 66 additions and 16 deletions
+45 -12
View File
@@ -2184,16 +2184,27 @@ export default function TunnelPage() {
<h3 className="text-lg font-semibold">入口配置</h3>
<div className="space-y-2">
<Select
disabledKeys={[
...nodes
.filter((node) => node.status !== 1)
.map((node) => node.id.toString()),
...(form.outNodeId || []).map((ct) =>
ct.nodeId.toString(),
),
...getSelectedChainNodeIds().map((id) => id.toString()),
]}
<Select
disabledKeys={[
...nodes
.filter(
(node) =>
node.status !== 1 &&
!(
isEdit &&
form.inNodeId.some(
(ct) => ct.nodeId === node.id,
)
),
)
.map((node) => node.id.toString()),
...(form.outNodeId || []).map((ct) =>
ct.nodeId.toString(),
),
...getSelectedChainNodeIds().map((id) =>
id.toString(),
),
]}
errorMessage={errors.inNodeId}
isInvalid={!!errors.inNodeId}
label="入口节点"
@@ -2365,7 +2376,18 @@ export default function TunnelPage() {
}}
disabledKeys={[
...nodes
.filter((node) => node.status !== 1)
.filter(
(node) =>
node.status !== 1 &&
!(
isEdit &&
groupNodes.some(
(ct) =>
ct.nodeId === node.id &&
ct.nodeId !== -1,
)
),
)
.map((node) => node.id.toString()),
...form.inNodeId.map((ct) =>
ct.nodeId.toString(),
@@ -2626,7 +2648,18 @@ export default function TunnelPage() {
}}
disabledKeys={[
...nodes
.filter((node) => node.status !== 1)
.filter(
(node) =>
node.status !== 1 &&
!(
isEdit &&
(form.outNodeId || []).some(
(ct) =>
ct.nodeId === node.id &&
ct.nodeId !== -1,
)
),
)
.map((node) => node.id.toString()),
...form.inNodeId.map((ct) =>
ct.nodeId.toString(),