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' of github.com:evergreen-ci/spruce into EVG-19921
Browse files Browse the repository at this point in the history
  • Loading branch information
SupaJoon committed Oct 16, 2023
2 parents 0f7877a + a797ba9 commit 37eadf7
Show file tree
Hide file tree
Showing 47 changed files with 527 additions and 236 deletions.
16 changes: 9 additions & 7 deletions cypress/integration/nav_bar.ts
Original file line number Diff line number Diff line change
Expand Up @@ -43,20 +43,22 @@ describe("Nav Bar", () => {
cy.visit(SPRUCE_URLS.cli);
cy.dataCy("legacy-ui-link").should("not.exist");
});
it("Nav Dropdown should provide links to legacy pages", () => {
cy.visit(SPRUCE_URLS.version);
cy.dataCy("legacy_route").should("not.exist");
cy.dataCy("auxiliary-dropdown-link").click();
cy.dataCy("legacy_route").should("exist");
cy.dataCy("legacy_route").should("have.attr", "href", LEGACY_URLS.distros);
});
it("Nav Dropdown should link to patches page of most recent project if cookie exists", () => {
cy.setCookie(projectCookie, "spruce");
cy.visit(SPRUCE_URLS.userPatches);
cy.dataCy("auxiliary-dropdown-link").click();
cy.dataCy("auxiliary-dropdown-project-patches").click();
cy.location("pathname").should("eq", "/project/spruce/patches");
});
it("Nav Dropdown should link to the first distro returned by the distros resolver", () => {
cy.visit(SPRUCE_URLS.version);
cy.dataCy("auxiliary-dropdown-link").click();
cy.dataCy("auxiliary-dropdown-distro-settings").should(
"have.attr",
"href",
"/distro/localhost/settings/general"
);
});
it("Nav Dropdown should link to patches page of default project in SpruceConfig if cookie does not exist", () => {
cy.clearCookie(projectCookie);
cy.visit(SPRUCE_URLS.userPatches);
Expand Down
27 changes: 23 additions & 4 deletions cypress/integration/version/banners.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,11 +2,11 @@ describe("banners", () => {
const versionWithBanners =
"/version/logkeeper_e864cf934194c161aa044e4599c8c81cee7b6237/tasks?sorts=STATUS%3AASC%3BBASE_STATUS%3ADESC";

beforeEach(() => {
cy.visit(versionWithBanners);
});

describe("errors", () => {
beforeEach(() => {
cy.visit(versionWithBanners);
});

it("should display the number of configuration errors", () => {
cy.dataCy("configuration-errors-banner").should("be.visible");
cy.contains("4 errors in configuration file").should("be.visible");
Expand All @@ -19,6 +19,10 @@ describe("banners", () => {
});

describe("warnings", () => {
beforeEach(() => {
cy.visit(versionWithBanners);
});

it("should display the number of configuration warnings", () => {
cy.dataCy("configuration-warnings-banner").should("be.visible");
cy.contains("3 warnings in configuration file").should("be.visible");
Expand All @@ -29,4 +33,19 @@ describe("banners", () => {
cy.get("ol").find("li").should("have.length", 3);
});
});

describe("ignored", () => {
it("should display a banner", () => {
cy.visit("/version/spruce_e695f654c8b4b959d3e12e71696c3e318bcd4c33");
cy.dataCy("ignored-banner").should("be.visible");
});

it("should indicate if a version is ignored in the inactive commits tooltip", () => {
cy.visit("/commits/spruce");
cy.dataCy("ignored-icon").should("not.exist");
cy.dataCy("inactive-commits-button").click();
cy.dataCy("inactive-commits-tooltip").should("be.visible");
cy.dataCy("ignored-icon").should("be.visible");
});
});
});
9 changes: 6 additions & 3 deletions lint-staged.config.js
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,10 @@ module.exports = {
"src/gql/**/*.{graphql,gql}": [
"yarn eslint:staged",
"yarn prettier --parser graphql",
], // For GraphQL files, run eslint and prettier
"*.{ts,tsx}": () => "tsc -p tsconfig.json --noEmit", // For TypeScript files, run tsc
"*": () => "yarn check-schema-and-codegen",
"yarn check-schema-and-codegen",
], // For GraphQL files, run eslint and prettier, and gql schema check
"*.{ts,tsx}": () => [
"tsc -p tsconfig.json --noEmit",
"yarn check-schema-and-codegen",
], // For TypeScript files, run tsc, and gql schema check
};
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.152",
"version": "3.0.157",
"private": true,
"scripts": {
"bootstrap-logkeeper": "./scripts/bootstrap-logkeeper.sh",
Expand Down Expand Up @@ -125,7 +125,7 @@
"query-string": "8.1.0",
"react": "18.2.0",
"react-dom": "18.2.0",
"react-router-dom": "6.14.2",
"react-router-dom": "6.16.0",
"react-string-replace": "1.1.1",
"react-virtuoso": "^4.3.11"
},
Expand Down Expand Up @@ -169,7 +169,7 @@
"@typescript-eslint/parser": "5.57.1",
"@vitejs/plugin-react": "4.0.0",
"babel-jest": "29.5.0",
"babel-loader": "^8.2.5",
"babel-loader": "^9.1.3",
"babel-plugin-import": "^1.13.6",
"babel-plugin-import-graphql": "^2.8.1",
"babel-preset-react-app": "^10.0.1",
Expand Down
2 changes: 1 addition & 1 deletion src/components/Content/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -42,7 +42,7 @@ export const Content: React.FC = () => (
<Route path={routes.configurePatch} element={<ConfigurePatch />}>
<Route path={tab} element={null} />
</Route>
<Route path={`${routes.distro}/*`} element={<Distro />}>
<Route path={`${routes.distroSettings}/*`} element={<Distro />}>
<Route path={tab} element={null} />
</Route>
<Route path={routes.host} element={<Host />} />
Expand Down
20 changes: 5 additions & 15 deletions src/components/DisplayModal.tsx
Original file line number Diff line number Diff line change
@@ -1,30 +1,20 @@
import styled from "@emotion/styled";
import Modal, { ModalSize } from "@leafygreen-ui/modal";
import Modal, { ModalProps } from "@leafygreen-ui/modal";
import { Body, BodyProps, H3 } from "@leafygreen-ui/typography";
import { size as tokenSize, zIndex } from "constants/tokens";

export interface DisplayModalProps {
"data-cy"?: string;
open?: boolean;
setOpen?: (
open: boolean
) => void | React.Dispatch<React.SetStateAction<boolean>>;
size?: ModalSize;
type DisplayModalProps = Omit<ModalProps, "title"> & {
title?: React.ReactNode | string;
children: React.ReactNode;
subtitle?: string;
}
};

export const DisplayModal: React.FC<DisplayModalProps> = ({
children,
"data-cy": dataCy,
open,
setOpen,
size,
subtitle,
title,
...rest
}) => (
<StyledModal data-cy={dataCy} open={open} setOpen={setOpen} size={size}>
<StyledModal {...rest}>
{title && <H3 data-cy="modal-title">{title}</H3>}
{subtitle && (
<StyledSubtitle data-cy="modal-subtitle">{subtitle}</StyledSubtitle>
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
14 changes: 6 additions & 8 deletions src/components/Header/AuxiliaryDropdown.tsx
Original file line number Diff line number Diff line change
@@ -1,26 +1,24 @@
import { useNavbarAnalytics } from "analytics";
import { legacyRoutes } from "constants/externalResources";
import {
routes,
getDistroSettingsRoute,
getProjectPatchesRoute,
getProjectSettingsRoute,
getTaskQueueRoute,
getCommitQueueRoute,
} from "constants/routes";
import { environmentVariables } from "utils";
import { useFirstDistro } from "hooks";
import { NavDropdown } from "./NavDropdown";

const { getUiUrl } = environmentVariables;

interface AuxiliaryDropdownProps {
projectIdentifier: string;
}

export const AuxiliaryDropdown: React.FC<AuxiliaryDropdownProps> = ({
projectIdentifier,
}) => {
const uiURL = getUiUrl();
const { sendEvent } = useNavbarAnalytics();
const distro = useFirstDistro();

const menuItems = [
{
Expand All @@ -39,9 +37,9 @@ export const AuxiliaryDropdown: React.FC<AuxiliaryDropdownProps> = ({
onClick: () => sendEvent({ name: "Click Task Queue Link" }),
},
{
"data-cy": "legacy_route",
href: `${uiURL}${legacyRoutes.distros}`,
text: "Distros",
"data-cy": "auxiliary-dropdown-distro-settings",
to: getDistroSettingsRoute(distro),
text: "Distro Settings",
onClick: () => sendEvent({ name: "Click Distros Link" }),
},

Expand Down
25 changes: 25 additions & 0 deletions src/components/Icon/icons/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ const { green } = palette;
interface LeafygreenIconProps extends React.SVGProps<SVGSVGElement> {
size?: number;
role?: "presentation" | "img";
["data-cy"]?: string;
}

export const EvergreenLogo: React.ComponentType<LeafygreenIconProps> = ({
Expand Down Expand Up @@ -241,3 +242,27 @@ export const Loading: React.ComponentType<LeafygreenIconProps> = ({
</g>
</svg>
);

export const Ignored: React.ComponentType<LeafygreenIconProps> = ({
className,
"data-cy": dataCy,
fill,
size = 16,
}) => (
<svg
aria-label="Ignored Icon"
data-cy={dataCy}
className={className}
fill="currentColor"
height={size}
width={size}
xmlns="http://www.w3.org/2000/svg"
>
<path
fill={fill}
fillRule="evenodd"
d="M8 14A6 6 0 1 0 8 2a6 6 0 0 0 0 12ZM5 7a1 1 0 0 0 0 2h6a1 1 0 1 0 0-2H5Z"
clipRule="evenodd"
/>
</svg>
);
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
12 changes: 11 additions & 1 deletion src/components/Table/BaseTable.tsx
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
import { css } from "@leafygreen-ui/emotion";
import {
Cell,
ExpandedContent,
Expand Down Expand Up @@ -43,7 +44,16 @@ export const BaseTable = <T extends LGRowData>({
</TableHead>
<TableBody>
{table.getRowModel().rows.map((row) => (
<Row key={row.id} row={row} data-cy={dataCyRow}>
<Row
key={row.id}
row={row}
data-cy={dataCyRow}
className={css`
&[aria-hidden="false"] td > div {
max-height: unset;
}
`}
>
{row.getVisibleCells().map((cell) => (
<Cell key={cell.id}>
{flexRender(cell.column.columnDef.cell, cell.getContext())}
Expand Down
Loading

0 comments on commit 37eadf7

Please sign in to comment.