Skip to content
This repository has been archived by the owner on Jul 2, 2024. It is now read-only.

Commit

Permalink
Merge branch 'main' into EVG-20987
Browse files Browse the repository at this point in the history
  • Loading branch information
hadjri committed Oct 17, 2023
2 parents e997c62 + 4616497 commit 7143738
Show file tree
Hide file tree
Showing 14 changed files with 282 additions and 551 deletions.
6 changes: 3 additions & 3 deletions package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "spruce",
"version": "3.0.155",
"version": "3.0.158",
"private": true,
"scripts": {
"bootstrap-logkeeper": "./scripts/bootstrap-logkeeper.sh",
Expand Down Expand Up @@ -80,7 +80,7 @@
"@leafygreen-ui/loading-indicator": "2.0.6",
"@leafygreen-ui/menu": "20.0.1",
"@leafygreen-ui/modal": "16.0.1",
"@leafygreen-ui/number-input": "1.0.4",
"@leafygreen-ui/number-input": "1.0.17",
"@leafygreen-ui/pagination": "1.0.12",
"@leafygreen-ui/palette": "4.0.7",
"@leafygreen-ui/popover": "11.0.17",
Expand Down Expand Up @@ -162,7 +162,7 @@
"@types/new-relic-browser": "0.1212.2",
"@types/node": "^16.11.47",
"@types/pluralize": "0.0.29",
"@types/prompts": "2.4.5",
"@types/prompts": "2.4.6",
"@types/react": "18.2.0",
"@types/react-dom": "18.2.0",
"@typescript-eslint/eslint-plugin": "5.57.1",
Expand Down
13 changes: 12 additions & 1 deletion src/components/ErrorHandling/Sentry.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ import {
ErrorBoundary as SentryErrorBoundary,
getCurrentHub,
init,
Replay,
withScope,
} from "@sentry/react";
import type { Scope, SeverityLevel } from "@sentry/react";
Expand All @@ -13,12 +14,22 @@ const { getReleaseStage, getSentryDSN, isProduction } = environmentVariables;

const initializeSentry = () => {
const releaseStage = getReleaseStage() || "development";
const productionEnv = isProduction();
try {
init({
dsn: getSentryDSN(),
debug: !isProduction(),
debug: !productionEnv,
normalizeDepth: 5,
environment: releaseStage,
replaysSessionSampleRate: 0,
replaysOnErrorSampleRate: productionEnv ? 0.6 : 1.0,
integrations: [
new Replay({
blockAllMedia: productionEnv,
maskAllInputs: productionEnv,
maskAllText: productionEnv,
}),
],
});
} catch (e) {
console.error("Failed to initialize Sentry", e);
Expand Down
12 changes: 12 additions & 0 deletions src/components/ErrorHandling/initialize.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,9 @@ describe("should initialize error handlers according to release stage", () => {
jest.spyOn(Bugsnag, "start").mockImplementation(jest.fn());
jest.spyOn(Bugsnag, "isStarted").mockImplementation(jest.fn(() => false));
jest.spyOn(Sentry, "init").mockImplementation(jest.fn());
jest
.spyOn(Sentry, "Replay")
.mockImplementation(() => ({} as Sentry.Replay));
});

afterEach(() => {
Expand Down Expand Up @@ -48,6 +51,9 @@ describe("should initialize error handlers according to release stage", () => {
debug: false,
normalizeDepth: 5,
environment: "production",
integrations: [{}],
replaysOnErrorSampleRate: 0.6,
replaysSessionSampleRate: 0,
});
});

Expand All @@ -71,6 +77,9 @@ describe("should initialize error handlers according to release stage", () => {
debug: true,
normalizeDepth: 5,
environment: "beta",
integrations: [{}],
replaysOnErrorSampleRate: 1,
replaysSessionSampleRate: 0,
});
});

Expand All @@ -94,6 +103,9 @@ describe("should initialize error handlers according to release stage", () => {
debug: true,
normalizeDepth: 5,
environment: "staging",
integrations: [{}],
replaysOnErrorSampleRate: 1,
replaysSessionSampleRate: 0,
});
});
});
Expand Down
11 changes: 6 additions & 5 deletions src/components/SpruceForm/customFormats.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ const {
validateEmail,
validateJira,
validateJiraURL,
validateNoSpecialCharacters,
validatePercentage,
validateRegexp,
validateSlack,
Expand All @@ -13,16 +14,16 @@ const {
} = validators;

export const customFormats = (jiraHost: string) => ({
noSpecialCharacters: validateNoSpecialCharacters,
// Permit empty string but disallow whitespace
noSpaces: /^$|^\S+$/,
// Permit url
validURL: validateURL,
validURLTemplate: validateURLTemplate,
validDuration: validateDuration,
validPercentage: validatePercentage,
validEmail: validateEmail,
validJiraTicket: validateJira,
validJiraURL: (url: string) => validateJiraURL(jiraHost, url),
validPercentage: validatePercentage,
validRegex: validateRegexp,
validSlack: validateSlack,
validEmail: validateEmail,
validURL: validateURL,
validURLTemplate: validateURLTemplate,
});
6 changes: 6 additions & 0 deletions src/components/SpruceForm/errors.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
import { AjvError } from "@rjsf/core";
import { allowedSymbols } from "utils/validators";

export enum Errors {
Invisible = "invisible",
Expand Down Expand Up @@ -51,6 +52,11 @@ export const transformErrors = (errors: AjvError[]) =>
};
case "format":
switch (error.params.format) {
case "noSpecialCharacters":
return {
...error,
message: `Value can only contain numbers, letters and these symbols: ${allowedSymbols}.`,
};
case "noSpaces":
return {
...error,
Expand Down
11 changes: 6 additions & 5 deletions src/constants/routes.ts
Original file line number Diff line number Diff line change
Expand Up @@ -229,11 +229,12 @@ export const getProjectSettingsRoute = (
projectId: string,
tab?: ProjectSettingsTabRoutes
) => {
if (!tab) {
return `${paths.project}/${projectId}/${PageNames.Settings}`;
}

return `${paths.project}/${projectId}/${PageNames.Settings}/${tab}`;
// Encode projectId for backwards compatibilty.
// Encoding can be removed when all projectIDs
// are URL friendly withou encoding
const encodedProjectId = encodeURIComponent(projectId);
const root = `${paths.project}/${encodedProjectId}/${PageNames.Settings}`;
return tab ? `${root}/${tab}` : root;
};

export const getDistroSettingsRoute = (
Expand Down
7 changes: 4 additions & 3 deletions src/hooks/useSpruceConfig.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,11 +5,12 @@ import {
} from "gql/generated/types";
import { SPRUCE_CONFIG } from "gql/queries";

export const useSpruceConfig = () => {
export const useSpruceConfig = ():
| SpruceConfigQuery["spruceConfig"]
| undefined => {
const { data } = useQuery<SpruceConfigQuery, SpruceConfigQueryVariables>(
SPRUCE_CONFIG
);

const { spruceConfig } = data || {};
return spruceConfig;
return data?.spruceConfig;
};
4 changes: 2 additions & 2 deletions src/pages/distroSettings/tabs/GeneralTab/GeneralTab.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -12,9 +12,9 @@ export const GeneralTab: React.FC<TabProps> = ({
minimumHosts,
}) => {
const { distroId } = useParams();
const { containerPools } = useSpruceConfig();
const spruceConfig = useSpruceConfig();
const containerPoolDistros =
containerPools?.pools?.map(({ distro }) => distro) ?? [];
spruceConfig?.containerPools?.pools?.map(({ distro }) => distro) ?? [];

const isContainerDistro = containerPoolDistros.includes(distroId);

Expand Down
4 changes: 2 additions & 2 deletions src/pages/distroSettings/tabs/ProviderTab/ProviderTab.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -32,8 +32,8 @@ export const ProviderTab: React.FC<TabProps> = ({ distro, distroData }) => {
);
const { awsRegions } = awsData || {};

const { containerPools } = useSpruceConfig();
const { pools } = containerPools || {};
const spruceConfig = useSpruceConfig();
const { pools } = spruceConfig?.containerPools || {};

const selectedPoolId = formData?.dockerProviderSettings?.containerPoolId;
const selectedPool = pools?.find((p) => p.id === selectedPoolId) ?? null;
Expand Down
4 changes: 2 additions & 2 deletions src/pages/projectSettings/sharedFormSchema.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ export const projectName = {
type: "string" as "string",
title: "Project Name",
minLength: 1,
format: "noSpaces",
format: "noSpecialCharacters",
},
uiSchema: {
"ui:data-cy": "project-name-input",
Expand All @@ -14,7 +14,7 @@ export const projectId = {
schema: {
type: "string" as "string",
title: "Project ID",
format: "noSpaces",
format: "noSpecialCharacters",
},
uiSchema: {
"ui:data-cy": "project-id-input",
Expand Down
4 changes: 4 additions & 0 deletions src/pages/projectSettings/tabs/GeneralTab/getFormSchema.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -82,6 +82,10 @@ export const getFormSchema = (
title: "Identifier",
default: "",
minLength: 1,
// Don't invalidate form based on initial data
format: identifierHasChanges
? "noSpecialCharacters"
: "noSpaces",
},
}),
batchTime: {
Expand Down
16 changes: 15 additions & 1 deletion src/utils/validators/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -132,16 +132,30 @@ const validateRegexp = (regexp: string): boolean => {
}
};

const allowedSymbols = "-._~()";

/**
* `validateNoSpecialCharacters` tests if a provided string contains no special characters
* @param str - The string to test.
* @returns - true if the string has no special characters and false otherwise
*/
const validateNoSpecialCharacters = (str: string): boolean => {
const noSpecialCharacters = new RegExp(`^[0-9a-zA-Z${allowedSymbols}]*$`);
return noSpecialCharacters.test(str);
};

export {
allowedSymbols,
validateDuration,
validateEmail,
validateJira,
validateJiraURL,
validateNoSpecialCharacters,
validateObjectId,
validatePercentage,
validateRegexp,
validateSSHPublicKey,
validateSlack,
validateSSHPublicKey,
validateURL,
validateURLTemplate,
};
24 changes: 20 additions & 4 deletions src/utils/validators/validators.test.ts
Original file line number Diff line number Diff line change
@@ -1,13 +1,29 @@
import {
validateRegexp,
validateJira,
validateJiraURL,
validateNoSpecialCharacters,
validateObjectId,
validateRegexp,
validateSlack,
validateSSHPublicKey,
validateJiraURL,
validateJira,
validateURL,
validateSlack,
} from ".";

describe("validateNoSpecialCharacters", () => {
it("returns true if string has no special characters", () => {
expect(validateNoSpecialCharacters("")).toBe(true);
expect(validateNoSpecialCharacters("helloworld-_~)(")).toBe(true);
expect(validateNoSpecialCharacters("hello-world123")).toBe(true);
expect(validateNoSpecialCharacters("helloworld.123")).toBe(true);
expect(validateNoSpecialCharacters("hellowo~rld.123")).toBe(true);
expect(validateNoSpecialCharacters("helloWorld123")).toBe(true);

expect(validateNoSpecialCharacters(" ")).toBe(false);
expect(validateNoSpecialCharacters("he/lloworld")).toBe(false);
expect(validateNoSpecialCharacters("hello%world")).toBe(false);
});
});

describe("validateObjectId", () => {
it("validates object ids", () => {
expect(validateObjectId("5f74d99ab2373627c047c5e5")).toBeTruthy();
Expand Down
Loading

0 comments on commit 7143738

Please sign in to comment.