From 588a9a70068591f092e8ba1193715598e653ea86 Mon Sep 17 00:00:00 2001 From: Mohamed Khelif Date: Wed, 28 Feb 2024 12:16:41 -0500 Subject: [PATCH] DEVPROD-933 Trim trailing and ending whitespace for project settings fields (#2267) --- src/components/SpruceForm/customFormats.ts | 2 ++ src/components/SpruceForm/errors.ts | 5 +++++ src/gql/generated/types.ts | 2 ++ src/pages/projectSettings/index.tsx | 2 +- .../tabs/AccessTab/getFormSchema.ts | 1 + .../tabs/GeneralTab/getFormSchema.tsx | 4 ++++ .../tabs/GithubCommitQueueTab/getFormSchema.tsx | 2 ++ .../tabs/PatchAliasesTab/getFormSchema.tsx | 3 +++ .../tabs/PeriodicBuildsTab/getFormSchema.ts | 1 + .../tabs/PluginsTab/getFormSchema.tsx | 2 ++ .../tabs/ProjectTriggersTab/getFormSchema.tsx | 2 ++ .../tabs/VariablesTab/getFormSchema.ts | 1 + src/utils/validators/index.ts | 11 +++++++++++ src/utils/validators/validators.test.ts | 15 +++++++++++++++ 14 files changed, 52 insertions(+), 1 deletion(-) diff --git a/src/components/SpruceForm/customFormats.ts b/src/components/SpruceForm/customFormats.ts index 38e92f383e..a69ba68c83 100644 --- a/src/components/SpruceForm/customFormats.ts +++ b/src/components/SpruceForm/customFormats.ts @@ -6,6 +6,7 @@ const { validateJira, validateJiraURL, validateNoSpecialCharacters, + validateNoStartingOrTrailingWhitespace, validatePercentage, validateRegexp, validateSlack, @@ -17,6 +18,7 @@ export const customFormats = (jiraHost: string) => ({ noSpecialCharacters: validateNoSpecialCharacters, // Permit empty string but disallow whitespace noSpaces: /^$|^\S+$/, + noStartingOrTrailingWhitespace: validateNoStartingOrTrailingWhitespace, validDuration: validateDuration, validEmail: validateEmail, validJiraTicket: validateJira, diff --git a/src/components/SpruceForm/errors.ts b/src/components/SpruceForm/errors.ts index 3776466e6c..081f547c8d 100644 --- a/src/components/SpruceForm/errors.ts +++ b/src/components/SpruceForm/errors.ts @@ -62,6 +62,11 @@ export const transformErrors = (errors: AjvError[]) => ...error, message: "Value should not contain spaces.", }; + case "noStartingOrTrailingWhitespace": + return { + ...error, + message: "Value should not start or end with whitespace.", + }; case "validDuration": return { ...error, diff --git a/src/gql/generated/types.ts b/src/gql/generated/types.ts index ab69ebc38e..1da6c84f44 100644 --- a/src/gql/generated/types.ts +++ b/src/gql/generated/types.ts @@ -2949,6 +2949,7 @@ export type UserSettings = { region?: Maybe; slackMemberId?: Maybe; slackUsername?: Maybe; + timeFormat?: Maybe; timezone?: Maybe; useSpruceOptions?: Maybe; }; @@ -2964,6 +2965,7 @@ export type UserSettingsInput = { region?: InputMaybe; slackMemberId?: InputMaybe; slackUsername?: InputMaybe; + timeFormat?: InputMaybe; timezone?: InputMaybe; useSpruceOptions?: InputMaybe; }; diff --git a/src/pages/projectSettings/index.tsx b/src/pages/projectSettings/index.tsx index e788ab6e73..8770f50060 100644 --- a/src/pages/projectSettings/index.tsx +++ b/src/pages/projectSettings/index.tsx @@ -60,7 +60,7 @@ const ProjectSettings: React.FC = () => { projectData?.projectSettings?.projectRef?.repoRefId || identifier; // Assign project type in order to show/hide elements that should only appear for repos, attached projects, etc. - let projectType; + let projectType: ProjectType; if (isRepo) { projectType = ProjectType.Repo; } else if (projectData?.projectSettings?.projectRef?.repoRefId) { diff --git a/src/pages/projectSettings/tabs/AccessTab/getFormSchema.ts b/src/pages/projectSettings/tabs/AccessTab/getFormSchema.ts index c2adf28009..cf31f22a8b 100644 --- a/src/pages/projectSettings/tabs/AccessTab/getFormSchema.ts +++ b/src/pages/projectSettings/tabs/AccessTab/getFormSchema.ts @@ -38,6 +38,7 @@ export const getFormSchema = ( title: "Username", default: "", minLength: 1, + format: "noStartingOrTrailingWhitespace", }, }, }, diff --git a/src/pages/projectSettings/tabs/GeneralTab/getFormSchema.tsx b/src/pages/projectSettings/tabs/GeneralTab/getFormSchema.tsx index 78f2d550d9..c2a205432f 100644 --- a/src/pages/projectSettings/tabs/GeneralTab/getFormSchema.tsx +++ b/src/pages/projectSettings/tabs/GeneralTab/getFormSchema.tsx @@ -66,6 +66,7 @@ export const getFormSchema = ( branch: { type: "string" as "string", title: "Branch Name", + format: "noStartingOrTrailingWhitespace", }, }), other: { @@ -75,6 +76,7 @@ export const getFormSchema = ( displayName: { type: "string" as "string", title: "Display Name", + format: "noStartingOrTrailingWhitespace", }, ...(projectType !== ProjectType.Repo && { identifier: { @@ -96,10 +98,12 @@ export const getFormSchema = ( remotePath: { type: "string" as "string", title: "Config File", + format: "noStartingOrTrailingWhitespace", }, spawnHostScriptPath: { type: "string" as "string", title: "Spawn Host Script Path", + format: "noStartingOrTrailingWhitespace", }, versionControlEnabled: { type: ["boolean", "null"], diff --git a/src/pages/projectSettings/tabs/GithubCommitQueueTab/getFormSchema.tsx b/src/pages/projectSettings/tabs/GithubCommitQueueTab/getFormSchema.tsx index 47a10d42ea..339383628e 100644 --- a/src/pages/projectSettings/tabs/GithubCommitQueueTab/getFormSchema.tsx +++ b/src/pages/projectSettings/tabs/GithubCommitQueueTab/getFormSchema.tsx @@ -150,6 +150,7 @@ export const getFormSchema = ( title: "Username", default: "", minLength: 1, + format: "noStartingOrTrailingWhitespace", }, }, ), @@ -168,6 +169,7 @@ export const getFormSchema = ( title: "Team", default: "", minLength: 1, + format: "noStartingOrTrailingWhitespace", }, }, ), diff --git a/src/pages/projectSettings/tabs/PatchAliasesTab/getFormSchema.tsx b/src/pages/projectSettings/tabs/PatchAliasesTab/getFormSchema.tsx index a1ccbee974..24438dc0ab 100644 --- a/src/pages/projectSettings/tabs/PatchAliasesTab/getFormSchema.tsx +++ b/src/pages/projectSettings/tabs/PatchAliasesTab/getFormSchema.tsx @@ -46,16 +46,19 @@ export const getFormSchema = ( title: "Alias", default: "", minLength: 1, + format: "noStartingOrTrailingWhitespace", }, childProjectIdentifier: { type: "string" as "string", title: "Project", default: "", minLength: 1, + format: "noStartingOrTrailingWhitespace", }, parentAsModule: { type: "string" as "string", title: "Module", + format: "noStartingOrTrailingWhitespace", }, status: { type: "string" as "string", diff --git a/src/pages/projectSettings/tabs/PeriodicBuildsTab/getFormSchema.ts b/src/pages/projectSettings/tabs/PeriodicBuildsTab/getFormSchema.ts index 63fbdf2449..59eab08636 100644 --- a/src/pages/projectSettings/tabs/PeriodicBuildsTab/getFormSchema.ts +++ b/src/pages/projectSettings/tabs/PeriodicBuildsTab/getFormSchema.ts @@ -85,6 +85,7 @@ export const getFormSchema = ( title: "Config File", minLength: 1, default: "", + format: "noStartingOrTrailingWhitespace", }, alias: { type: "string" as "string", diff --git a/src/pages/projectSettings/tabs/PluginsTab/getFormSchema.tsx b/src/pages/projectSettings/tabs/PluginsTab/getFormSchema.tsx index d1bc7c337f..61417d3d51 100644 --- a/src/pages/projectSettings/tabs/PluginsTab/getFormSchema.tsx +++ b/src/pages/projectSettings/tabs/PluginsTab/getFormSchema.tsx @@ -126,6 +126,7 @@ export const getFormSchema = ( createProject: { type: "string" as "string", title: "", + format: "noStartingOrTrailingWhitespace", }, }, }, @@ -204,6 +205,7 @@ export const getFormSchema = ( default: "", minLength: 1, maxLength: 40, + format: "noStartingOrTrailingWhitespace", }, urlTemplate: { type: "string" as "string", diff --git a/src/pages/projectSettings/tabs/ProjectTriggersTab/getFormSchema.tsx b/src/pages/projectSettings/tabs/ProjectTriggersTab/getFormSchema.tsx index 9630b53ed3..c5307287b6 100644 --- a/src/pages/projectSettings/tabs/ProjectTriggersTab/getFormSchema.tsx +++ b/src/pages/projectSettings/tabs/ProjectTriggersTab/getFormSchema.tsx @@ -28,12 +28,14 @@ export const getFormSchema = ( title: "Project", default: "", minLength: 1, + format: "noStartingOrTrailingWhitespace", }, configFile: { type: "string" as "string", title: "Config File", default: "", minLength: 1, + format: "noStartingOrTrailingWhitespace", }, level: { type: "string" as "string", diff --git a/src/pages/projectSettings/tabs/VariablesTab/getFormSchema.ts b/src/pages/projectSettings/tabs/VariablesTab/getFormSchema.ts index 58f983cf66..fb4d89a821 100644 --- a/src/pages/projectSettings/tabs/VariablesTab/getFormSchema.ts +++ b/src/pages/projectSettings/tabs/VariablesTab/getFormSchema.ts @@ -24,6 +24,7 @@ export const getFormSchema = ( title: "Variable Name", default: "", minLength: 1, + format: "noStartingOrTrailingWhitespace", }, varValue: { type: "string" as "string", diff --git a/src/utils/validators/index.ts b/src/utils/validators/index.ts index 9def5f64c9..b426234186 100644 --- a/src/utils/validators/index.ts +++ b/src/utils/validators/index.ts @@ -144,6 +144,16 @@ const validateNoSpecialCharacters = (str: string): boolean => { return noSpecialCharacters.test(str); }; +/** + * `validateNoStartingOrTrailingWhitespace` tests if a provided string contains no starting or trailing whitespace + * @param str - The string to test. + * @returns - true if the string has no starting or trailing whitespace and false otherwise + */ +const validateNoStartingOrTrailingWhitespace = (str: string): boolean => { + const noStartingOrTrailingWhitespaceRegex = /^(?! ).*(? { }); }); +describe("validateNoStartingOrTrailingWhitespace", () => { + it("returns true if string has no starting or trailing whitespace", () => { + expect(validateNoStartingOrTrailingWhitespace("")).toBe(true); + expect(validateNoStartingOrTrailingWhitespace("a")).toBe(true); + expect(validateNoStartingOrTrailingWhitespace("helloworld")).toBe(true); + expect(validateNoStartingOrTrailingWhitespace(" helloWorld123")).toBe( + false, + ); + expect(validateNoStartingOrTrailingWhitespace("helloWorld123 ")).toBe( + false, + ); + }); +}); + describe("validateObjectId", () => { it("validates object ids", () => { expect(validateObjectId("5f74d99ab2373627c047c5e5")).toBeTruthy();