fix: improve ID parsing logic in AccessListSelector and ProxyHostForm to ensure valid numeric IDs

This commit is contained in:
GitHub Actions
2026-02-28 04:45:26 +00:00
parent 6ed8d8054f
commit bf583927c1
4 changed files with 52 additions and 10 deletions

View File

@@ -31,8 +31,8 @@ function resolveAccessListToken(value: number | string | null | undefined): stri
return trimmed;
}
const parsed = Number.parseInt(trimmed, 10);
if (!Number.isNaN(parsed)) {
if (/^\d+$/.test(trimmed)) {
const parsed = Number.parseInt(trimmed, 10);
return `id:${parsed}`;
}
@@ -46,7 +46,7 @@ function getOptionToken(acl: { id?: number | string; uuid?: string }): string |
if (typeof acl.id === 'string') {
const trimmed = acl.id.trim();
if (trimmed !== '') {
if (trimmed !== '' && /^\d+$/.test(trimmed)) {
const parsed = Number.parseInt(trimmed, 10);
if (!Number.isNaN(parsed)) {
return `id:${parsed}`;
@@ -89,8 +89,8 @@ export default function AccessListSelector({ value, onChange }: AccessListSelect
return;
}
const numericId = Number.parseInt(newValue, 10);
if (!Number.isNaN(numericId)) {
if (/^\d+$/.test(newValue)) {
const numericId = Number.parseInt(newValue, 10);
onChange(numericId);
return;
}

View File

@@ -148,6 +148,10 @@ function normalizeNullableID(value: unknown): number | null | undefined {
return null
}
if (!/^\d+$/.test(trimmed)) {
return undefined
}
const parsed = Number.parseInt(trimmed, 10)
return Number.isNaN(parsed) ? undefined : parsed
}
@@ -173,8 +177,8 @@ function resolveSelectToken(value: number | string | null | undefined): string {
return trimmed
}
const parsed = Number.parseInt(trimmed, 10)
if (!Number.isNaN(parsed)) {
if (/^\d+$/.test(trimmed)) {
const parsed = Number.parseInt(trimmed, 10)
return `id:${parsed}`
}
@@ -195,8 +199,12 @@ function resolveTokenToFormValue(value: string): number | string | null {
return value.slice(5)
}
const parsed = Number.parseInt(value, 10)
return Number.isNaN(parsed) ? value : parsed
if (/^\d+$/.test(value)) {
const parsed = Number.parseInt(value, 10)
return Number.isNaN(parsed) ? value : parsed
}
return value
}
function getEntityToken(entity: { id?: number; uuid?: string }): string | null {

View File

@@ -163,4 +163,38 @@ describe('AccessListSelector', () => {
expect(mockOnChange).toHaveBeenCalledWith(7);
});
it('keeps a UUID-leading-digit selection stable in the trigger', () => {
const uuid = '9f63b8c9-1d26-4b2f-a2c8-001122334455';
const mockLists = [
{
id: undefined,
uuid,
name: 'UUID Digit Prefix ACL',
description: 'UUID-only ACL payload',
type: 'whitelist',
ip_rules: '[]',
country_codes: '',
local_network_only: false,
enabled: true,
created_at: '2024-01-01',
updated_at: '2024-01-01',
},
];
vi.mocked(useAccessListsHook.useAccessLists).mockReturnValue({
data: mockLists as unknown as AccessList[],
} as unknown as ReturnType<typeof useAccessListsHook.useAccessLists>);
const mockOnChange = vi.fn();
const Wrapper = createWrapper();
render(
<Wrapper>
<AccessListSelector value={uuid} onChange={mockOnChange} />
</Wrapper>
);
expect(screen.getByRole('combobox', { name: /Access Control List/i })).toHaveTextContent('UUID Digit Prefix ACL');
});
});

View File

@@ -559,7 +559,7 @@ describe('ProxyHostForm Dropdown Change Bug Fix', () => {
{
...mockAccessLists[0],
id: undefined,
uuid: 'acl-uuid-only',
uuid: '9f63b8c9-1d26-4b2f-a2c8-001122334455',
name: 'UUID Office Network',
},
]