feat(clients): hide disabled inbounds in the client form selector

The attach-inbounds select in the client add/edit modal listed every inbound, so panels with many disabled inbounds had to scroll past dead entries. InboundOption now carries the inbound's enable flag and the form drops disabled inbounds from the options, keeping ones the client is already attached to so edit mode still renders existing assignments.

Closes #5645
This commit is contained in:
MHSanaei 2026-07-03 09:26:06 +02:00
parent b2ceb854f5
commit 052dd85ad3
No known key found for this signature in database
GPG key ID: 7E4060F2FBE5AB7A
7 changed files with 20 additions and 2 deletions

View file

@ -1824,6 +1824,10 @@
},
"InboundOption": {
"properties": {
"enable": {
"example": true,
"type": "boolean"
},
"id": {
"example": 1,
"type": "integer"
@ -1880,6 +1884,7 @@
}
},
"required": [
"enable",
"id",
"port",
"protocol",
@ -2795,6 +2800,7 @@
"success": true,
"obj": [
{
"enable": true,
"id": 1,
"listen": "",
"nodeAddress": "",

View file

@ -399,6 +399,7 @@ export const EXAMPLES: Record<string, unknown> = {
"xver": 0
},
"InboundOption": {
"enable": true,
"id": 1,
"listen": "",
"nodeAddress": "",

View file

@ -1798,6 +1798,10 @@ export const SCHEMAS: Record<string, unknown> = {
},
"InboundOption": {
"properties": {
"enable": {
"example": true,
"type": "boolean"
},
"id": {
"example": 1,
"type": "integer"
@ -1854,6 +1858,7 @@ export const SCHEMAS: Record<string, unknown> = {
}
},
"required": [
"enable",
"id",
"port",
"protocol",

View file

@ -393,6 +393,7 @@ export interface InboundFallback {
}
export interface InboundOption {
enable: boolean;
id: number;
listen?: string;
nodeAddress?: string;

View file

@ -420,6 +420,7 @@ export const InboundFallbackSchema = z.object({
export type InboundFallback = z.infer<typeof InboundFallbackSchema>;
export const InboundOptionSchema = z.object({
enable: z.boolean(),
id: z.number().int(),
listen: z.string().optional(),
nodeAddress: z.string().optional(),

View file

@ -376,12 +376,13 @@ export default function ClientFormModal({
const inboundOptions = useMemo(
() => (inbounds || [])
.filter((ib) => MULTI_CLIENT_PROTOCOLS.has(ib.protocol || ''))
.filter((ib) => ib.enable || (form.inboundIds || []).includes(ib.id))
.map((ib) => ({
label: formatInboundLabel(ib.tag, ib.remark),
value: ib.id,
title: formatInboundLabel(ib.tag, ib.remark),
})),
[inbounds],
[inbounds, form.inboundIds],
);
const linkRows = useMemo(() => form.externalLinks.filter((r) => r.kind === 'link'), [form.externalLinks]);

View file

@ -297,6 +297,7 @@ type InboundOption struct {
Tag string `json:"tag" example:"in-443-tcp"`
Protocol string `json:"protocol" example:"vless"`
Port int `json:"port" example:"443"`
Enable bool `json:"enable" example:"true"`
TlsFlowCapable bool `json:"tlsFlowCapable" example:"true"`
SsMethod string `json:"ssMethod"`
WgPublicKey string `json:"wgPublicKey,omitempty"`
@ -325,6 +326,7 @@ func (s *InboundService) GetInboundOptions(userId int) ([]InboundOption, error)
Tag string `gorm:"column:tag"`
Protocol string `gorm:"column:protocol"`
Port int `gorm:"column:port"`
Enable bool `gorm:"column:enable"`
StreamSettings string `gorm:"column:stream_settings"`
Settings string `gorm:"column:settings"`
Listen string `gorm:"column:listen"`
@ -334,7 +336,7 @@ func (s *InboundService) GetInboundOptions(userId int) ([]InboundOption, error)
NodeAddress string `gorm:"column:node_address"`
}
err := db.Table("inbounds").
Select("inbounds.id, inbounds.remark, inbounds.tag, inbounds.protocol, inbounds.port, inbounds.stream_settings, inbounds.settings, inbounds.listen, inbounds.share_addr, inbounds.share_addr_strategy, inbounds.node_id, COALESCE(nodes.address, '') AS node_address").
Select("inbounds.id, inbounds.remark, inbounds.tag, inbounds.protocol, inbounds.port, inbounds.enable, inbounds.stream_settings, inbounds.settings, inbounds.listen, inbounds.share_addr, inbounds.share_addr_strategy, inbounds.node_id, COALESCE(nodes.address, '') AS node_address").
Joins("LEFT JOIN nodes ON nodes.id = inbounds.node_id").
Where("inbounds.user_id = ?", userId).
Order("inbounds.id ASC").
@ -355,6 +357,7 @@ func (s *InboundService) GetInboundOptions(userId int) ([]InboundOption, error)
Tag: r.Tag,
Protocol: r.Protocol,
Port: r.Port,
Enable: r.Enable,
TlsFlowCapable: inboundCanEnableTlsFlow(r.Protocol, r.StreamSettings, r.Settings),
SsMethod: inboundShadowsocksMethod(r.Protocol, r.Settings),
WgPublicKey: wgPublicKey,