feat(sub): per-inbound sort order for subscription links

Add a subSortIndex field to inbounds that controls the order of links
in subscription output only: the raw sub body, the HTML sub page, and
the JSON/Clash formats (all served from the same query). Lower values
come first; ties keep id order. The panel inbound list is unaffected.

The value is editable in the inbound form next to the share-address
fields, propagates to nodes via wireInbound, and follows the usual
node-sync rules (copied on import, mirrored while not dirty, never a
structural change).

Rescoped from #5214 by @Ponywka.
This commit is contained in:
MHSanaei
2026-06-12 12:03:22 +02:00
parent 7ae3ea66d1
commit f1a4286e2f
36 changed files with 367 additions and 4 deletions
@@ -39,6 +39,7 @@ export interface RawInboundRow {
nodeId?: number | null;
shareAddrStrategy?: string;
shareAddr?: string;
subSortIndex?: number;
clientStats?: unknown;
}
@@ -65,6 +66,7 @@ export interface WireInboundPayload {
nodeId?: number;
shareAddrStrategy: ShareAddrStrategy;
shareAddr: string;
subSortIndex: number;
}
function coerceJsonObject(value: unknown): Record<string, unknown> {
@@ -175,6 +177,7 @@ export function rawInboundToFormValues(row: RawInboundRow): InboundFormValues {
nodeId: row.nodeId ?? null,
shareAddrStrategy: coerceShareAddrStrategy(row.shareAddrStrategy),
shareAddr: row.shareAddr ?? '',
subSortIndex: Math.max(1, row.subSortIndex ?? 1),
protocol,
settings,
} as InboundFormValues;
@@ -322,6 +325,7 @@ export function formValuesToWirePayload(values: InboundFormValues): WireInboundP
tag: values.tag,
shareAddrStrategy: values.shareAddrStrategy,
shareAddr: values.shareAddr,
subSortIndex: values.subSortIndex,
};
if (values.nodeId != null) payload.nodeId = values.nodeId;
return payload;