From 69ed014ee2cce1404a17454f1680632ac3fadfc0 Mon Sep 17 00:00:00 2001 From: Andrew Ballantyne Date: Mon, 16 Sep 2024 10:42:57 -0400 Subject: [PATCH] Handle special character cases --- .../src/concepts/k8s/__tests__/utils.spec.ts | 38 ++++++++++++++++--- frontend/src/concepts/k8s/utils.ts | 23 +++++++++-- 2 files changed, 51 insertions(+), 10 deletions(-) diff --git a/frontend/src/concepts/k8s/__tests__/utils.spec.ts b/frontend/src/concepts/k8s/__tests__/utils.spec.ts index bc4497d6af..080a711c9e 100644 --- a/frontend/src/concepts/k8s/__tests__/utils.spec.ts +++ b/frontend/src/concepts/k8s/__tests__/utils.spec.ts @@ -1,4 +1,5 @@ import { mockProjectK8sResource } from '~/__mocks__'; +import * as stringUtils from '~/utilities/string'; import { getDescriptionFromK8sResource, getDisplayNameFromK8sResource, @@ -45,27 +46,52 @@ describe('translateDisplayNameForK8s', () => { 'ymbols-capitals-and-spaces-these-are-invalid', ); expect(translateDisplayNameForK8s('1234', { safeK8sPrefix: 'wb-' })).toBe('wb-1234'); + expect(translateDisplayNameForK8s('-validcharacters')).toBe(`validcharacters`); }); }); describe('translateDisplayNameForK8sAndReport', () => { + type ReturnArrayType = ReturnType; + + it('should NOT generate name if provided nothing', () => { + expect(translateDisplayNameForK8sAndReport('')).toEqual([ + '', + { autoGenerated: false, safeK8sPrefix: false, maxLength: false }, + ] satisfies ReturnArrayType); + }); + it('should handle cases where it applied additional criteria', () => { expect(translateDisplayNameForK8sAndReport('1234', { safeK8sPrefix: 'wb-' })).toEqual([ 'wb-1234', - { safeK8sPrefix: true, maxLength: false }, - ] satisfies ReturnType); + { autoGenerated: false, safeK8sPrefix: true, maxLength: false }, + ] satisfies ReturnArrayType); expect(translateDisplayNameForK8sAndReport('foobarbaz', { maxLength: 3 })).toEqual([ 'foo', - { safeK8sPrefix: false, maxLength: true }, - ] satisfies ReturnType); + { autoGenerated: false, safeK8sPrefix: false, maxLength: true }, + ] satisfies ReturnArrayType); }); it('should report nothing happened if no criteria was provided', () => { expect(translateDisplayNameForK8sAndReport('foobarbaz')).toEqual([ 'foobarbaz', - { safeK8sPrefix: false, maxLength: false }, - ] satisfies ReturnType); + { autoGenerated: false, safeK8sPrefix: false, maxLength: false }, + ] satisfies ReturnArrayType); + }); + + it('should generate name if it trims it to nothing', () => { + const GENERATED_STRING = 'iamgenerated'; + jest.spyOn(stringUtils, 'genRandomChars').mockReturnValue(GENERATED_STRING); + + expect(translateDisplayNameForK8sAndReport('-')).toEqual([ + `gen-${GENERATED_STRING}`, + { autoGenerated: true, safeK8sPrefix: false, maxLength: false }, + ] satisfies ReturnArrayType); + + expect(translateDisplayNameForK8sAndReport('$%*($%()*')).toEqual([ + `gen-${GENERATED_STRING}`, + { autoGenerated: true, safeK8sPrefix: false, maxLength: false }, + ] satisfies ReturnArrayType); }); }); diff --git a/frontend/src/concepts/k8s/utils.ts b/frontend/src/concepts/k8s/utils.ts index 702f600ecc..d55fd6fe48 100644 --- a/frontend/src/concepts/k8s/utils.ts +++ b/frontend/src/concepts/k8s/utils.ts @@ -1,5 +1,6 @@ import { K8sResourceCommon } from '@openshift/dynamic-plugin-sdk-utils'; import { K8sDSGResource } from '~/k8sTypes'; +import { genRandomChars } from '~/utilities/string'; export const PreInstalledName = 'Pre-installed'; @@ -24,7 +25,10 @@ type AdditionalCriteriaForTranslation = { /** Cap the characters allowed */ maxLength?: number; }; -type AdditionalCriteriaApplied = Record; +type AdditionalCriteriaApplied = Record< + keyof AdditionalCriteriaForTranslation | 'autoGenerated', + boolean +>; /** * Converts a display name to a k8s safe variant. @@ -35,6 +39,7 @@ export const translateDisplayNameForK8sAndReport = ( { safeK8sPrefix, maxLength }: AdditionalCriteriaForTranslation = {}, ): [string, AdditionalCriteriaApplied] => { const appliedCriteria: AdditionalCriteriaApplied = { + autoGenerated: false, safeK8sPrefix: false, maxLength: false, }; @@ -54,12 +59,22 @@ export const translateDisplayNameForK8sAndReport = ( if (maxLength && translatedName.length > maxLength) { // Avoid too long - translatedName = translatedName - .slice(0, maxLength) // shorten to length - .replace(/[-]*$/, ''); // remove invalid trailing characters + translatedName = translatedName.slice(0, maxLength); // shorten to length appliedCriteria.maxLength = true; } + // Trim out extra dashes; the only special characters we allow but are invalid at the start/end + translatedName = translatedName.replace(/^[-]*/, '').replace(/[-]*$/, ''); + + if (name.trim().length > 0 && translatedName.trim().length === 0) { + // We trimmed it down to nothing, generate a new value + translatedName = `${safeK8sPrefix || 'gen-'}${genRandomChars()}`; + appliedCriteria.autoGenerated = true; + if (safeK8sPrefix) { + appliedCriteria.safeK8sPrefix = true; + } + } + return [translatedName, appliedCriteria]; };