fix(catalog-model): add support for icons containing colons

Signed-off-by: Benjamin Janssens <benji.janssens@gmail.com>
This commit is contained in:
Benjamin Janssens
2025-05-15 12:51:51 +02:00
parent da2a66eac6
commit ed4e62561f
5 changed files with 54 additions and 8 deletions
+5
View File
@@ -0,0 +1,5 @@
---
'@backstage/catalog-model': patch
---
Added support for icons containing colons
@@ -189,13 +189,15 @@ describe('FieldFormatEntityPolicy', () => {
await expect(policy.enforce(data)).rejects.toThrow(/links.0.icon.*""/i);
});
it.each([['dashboard'], ['admin-dashboard'], ['foo_dashboard']])(
'accepts valid link icon',
async icon => {
data.metadata.links = [{ url: 'http://foo', icon }];
await expect(policy.enforce(data)).resolves.toBe(data);
},
);
it.each([
['dashboard'],
['admin-dashboard'],
['foo_dashboard'],
['kind:api'],
])('accepts valid link icon', async icon => {
data.metadata.links = [{ url: 'http://foo', icon }];
await expect(policy.enforce(data)).resolves.toBe(data);
});
it.each([[123], [{}], [[]], ['abc xyz']])(
'rejects bad link icon value %s',
@@ -97,6 +97,10 @@ export class FieldFormatEntityPolicy implements EntityPolicy {
case 'isNonEmptyString':
expectation = 'a non empty string';
break;
case 'isValidIcon':
expectation =
'a string that is sequences of [a-zA-Z0-9] separated by any of [-_.:], at most 63 characters in total';
break;
default:
expectation = undefined;
break;
@@ -161,7 +165,7 @@ export class FieldFormatEntityPolicy implements EntityPolicy {
optional(
`links.${i}.icon`,
links[i]?.icon,
KubernetesValidatorFunctions.isValidObjectName,
CommonValidatorFunctions.isValidIcon,
);
}
@@ -243,4 +243,25 @@ describe('CommonValidatorFunctions', () => {
])(`isNonEmptyString %p ? %p`, (value, result) => {
expect(CommonValidatorFunctions.isNonEmptyString(value)).toBe(result);
});
it.each([
[7, false],
[null, false],
['', false],
['a', true],
['AZ09', true],
['a'.repeat(63), true],
['a'.repeat(64), false],
['a/b', false],
['a-b', true],
['-a-b', false],
['a-b-', false],
['a--b', true],
['a_b', true],
['a.b', true],
['a..b', true],
['a:b', true],
])(`isValidIcon %p ? %p`, (value, matches) => {
expect(CommonValidatorFunctions.isValidIcon(value)).toBe(matches);
});
});
@@ -147,4 +147,18 @@ export class CommonValidatorFunctions {
static isNonEmptyString(value: unknown): value is string {
return typeof value === 'string' && value?.trim()?.length >= 1;
}
/**
* Checks that the value is a valid icon.
*
* @param value - The value to check
*/
static isValidIcon(value: unknown): boolean {
return (
typeof value === 'string' &&
value.length >= 1 &&
value.length <= 63 &&
/^([A-Za-z0-9][-A-Za-z0-9_.:]*)?[A-Za-z0-9]$/.test(value)
);
}
}