mirror of
https://github.com/MHSanaei/3x-ui.git
synced 2026-07-22 12:36:07 +00:00
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:
@@ -575,6 +575,14 @@ export default function InboundFormModal({
|
||||
</Form.Item>
|
||||
)}
|
||||
|
||||
<Form.Item
|
||||
name="subSortIndex"
|
||||
label={t('pages.inbounds.form.subSortIndex')}
|
||||
extra={t('pages.inbounds.form.subSortIndexHelp')}
|
||||
>
|
||||
<InputNumber min={1} />
|
||||
</Form.Item>
|
||||
|
||||
<Form.Item
|
||||
name="port"
|
||||
label={t('pages.inbounds.port')}
|
||||
|
||||
@@ -93,6 +93,11 @@ export default function InboundList({
|
||||
[dbInbounds],
|
||||
);
|
||||
|
||||
const hasAnySubSortIndex = useMemo(
|
||||
() => dbInbounds.some((i) => (i.subSortIndex ?? 1) > 1),
|
||||
[dbInbounds],
|
||||
);
|
||||
|
||||
const toggleSelect = useCallback((id: number, checked: boolean) => {
|
||||
setSelectedRowKeys((prev) => {
|
||||
const next = new Set(prev);
|
||||
@@ -115,6 +120,7 @@ export default function InboundList({
|
||||
|
||||
const columns = useInboundColumns({
|
||||
hasAnyRemark,
|
||||
hasAnySubSortIndex,
|
||||
hasActiveNode,
|
||||
nodesById,
|
||||
clientCount,
|
||||
|
||||
@@ -22,6 +22,7 @@ export interface DBInboundRecord extends ProtocolFlags {
|
||||
id: number;
|
||||
enable: boolean;
|
||||
remark: string;
|
||||
subSortIndex: number;
|
||||
port: number;
|
||||
protocol: string;
|
||||
up: number;
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
import { useMemo, type ReactElement } from 'react';
|
||||
import { useTranslation } from 'react-i18next';
|
||||
import { Popover, Switch, Tag, type TableColumnType } from 'antd';
|
||||
import { Popover, Switch, Tag, Tooltip, type TableColumnType } from 'antd';
|
||||
import { TeamOutlined } from '@ant-design/icons';
|
||||
|
||||
import { SizeFormatter, IntlUtil, ColorUtils } from '@/utils';
|
||||
@@ -21,6 +21,7 @@ import type { ClientCountEntry, DBInboundRecord, RowAction } from './types';
|
||||
|
||||
interface UseInboundColumnsParams {
|
||||
hasAnyRemark: boolean;
|
||||
hasAnySubSortIndex: boolean;
|
||||
hasActiveNode: boolean;
|
||||
nodesById: Map<number, NodeRecord>;
|
||||
clientCount: Record<number, ClientCountEntry>;
|
||||
@@ -33,6 +34,7 @@ interface UseInboundColumnsParams {
|
||||
|
||||
export function useInboundColumns({
|
||||
hasAnyRemark,
|
||||
hasAnySubSortIndex,
|
||||
hasActiveNode,
|
||||
nodesById,
|
||||
clientCount,
|
||||
@@ -113,6 +115,20 @@ export function useInboundColumns({
|
||||
});
|
||||
}
|
||||
|
||||
if (hasAnySubSortIndex) {
|
||||
cols.push({
|
||||
title: (
|
||||
<Tooltip title={t('pages.inbounds.form.subSortIndex')}>
|
||||
{t('pages.inbounds.subSortIndex')}
|
||||
</Tooltip>
|
||||
),
|
||||
dataIndex: 'subSortIndex',
|
||||
key: 'subSortIndex',
|
||||
align: 'right',
|
||||
width: 70,
|
||||
});
|
||||
}
|
||||
|
||||
cols.push(
|
||||
{
|
||||
title: t('pages.inbounds.port'),
|
||||
@@ -267,5 +283,5 @@ export function useInboundColumns({
|
||||
);
|
||||
|
||||
return cols;
|
||||
}, [t, hasAnyRemark, hasActiveNode, nodesById, clientCount, subEnable, expireDiff, trafficDiff, datepicker, onRowAction, onSwitchEnable]);
|
||||
}, [t, hasAnyRemark, hasAnySubSortIndex, hasActiveNode, nodesById, clientCount, subEnable, expireDiff, trafficDiff, datepicker, onRowAction, onSwitchEnable]);
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user