-
Notifications
You must be signed in to change notification settings - Fork 13
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
DEVPROD-10188: Render waterfall (#412)
- Loading branch information
Showing
13 changed files
with
383 additions
and
37 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,41 @@ | ||
describe("waterfall page", () => { | ||
beforeEach(() => { | ||
cy.visit("/project/spruce/waterfall"); | ||
}); | ||
|
||
describe("version labels", () => { | ||
it("shows a git tag label", () => { | ||
cy.dataCy("version-labels") | ||
.children() | ||
.eq(4) | ||
.contains("Git Tags: v2.28.5"); | ||
}); | ||
}); | ||
|
||
describe("inactive commits", () => { | ||
it("renders an inactive version column", () => { | ||
cy.dataCy("version-labels") | ||
.children() | ||
.eq(2) | ||
.should("have.attr", "data-cy", "inactive-label"); | ||
cy.dataCy("build-group") | ||
.first() | ||
.children() | ||
.eq(2) | ||
.should("have.attr", "data-cy", "inactive-column"); | ||
}); | ||
}); | ||
|
||
describe("task grid", () => { | ||
it("correctly renders child tasks", () => { | ||
cy.dataCy("build-group").children().as("builds"); | ||
|
||
cy.get("@builds").eq(0).children().should("have.length", 1); | ||
cy.get("@builds").eq(1).children().should("have.length", 8); | ||
cy.get("@builds").eq(2).children().should("have.length", 0); | ||
cy.get("@builds").eq(3).children().should("have.length", 1); | ||
cy.get("@builds").eq(4).children().should("have.length", 8); | ||
cy.get("@builds").eq(5).children().should("have.length", 8); | ||
}); | ||
}); | ||
}); |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,173 @@ | ||
import { memo, useCallback } from "react"; | ||
import styled from "@emotion/styled"; | ||
import { palette } from "@leafygreen-ui/palette"; | ||
import { Link } from "react-router-dom"; | ||
import { TaskStatus } from "@evg-ui/lib/types/task"; | ||
import { useWaterfallAnalytics } from "analytics"; | ||
import { StyledLink } from "components/styles"; | ||
import { getTaskRoute, getVariantHistoryRoute } from "constants/routes"; | ||
import { size } from "constants/tokens"; | ||
import { | ||
WaterfallBuild, | ||
WaterfallBuildVariant, | ||
WaterfallQuery, | ||
} from "gql/generated/types"; | ||
import { | ||
BuildVariantTitle, | ||
columnBasis, | ||
gridGroupCss, | ||
InactiveVersion, | ||
Row, | ||
} from "./styles"; | ||
|
||
const { black, gray, green, white } = palette; | ||
|
||
export const BuildRow: React.FC<{ | ||
build: WaterfallBuildVariant; | ||
projectIdentifier: string; | ||
versions: WaterfallQuery["waterfall"]["versions"]; | ||
}> = ({ build, projectIdentifier, versions }) => { | ||
const { sendEvent } = useWaterfallAnalytics(); | ||
const handleVariantClick = useCallback( | ||
() => sendEvent({ name: "Clicked variant label" }), | ||
[sendEvent], | ||
); | ||
const handleTaskClick = useCallback( | ||
(status: string) => () => | ||
sendEvent({ | ||
name: "Clicked task box", | ||
"task.status": status, | ||
}), | ||
[sendEvent], | ||
); | ||
|
||
const { builds, displayName } = build; | ||
let buildIndex = 0; | ||
return ( | ||
<Row> | ||
<BuildVariantTitle> | ||
<StyledLink | ||
href={getVariantHistoryRoute(projectIdentifier, build.id)} | ||
onClick={handleVariantClick} | ||
> | ||
{displayName} | ||
</StyledLink> | ||
</BuildVariantTitle> | ||
<BuildGroup data-cy="build-group"> | ||
{versions.map(({ inactiveVersions, version }) => { | ||
if (inactiveVersions?.length) { | ||
return ( | ||
<InactiveVersion | ||
key={inactiveVersions[0].id} | ||
data-cy="inactive-column" | ||
/> | ||
); | ||
} | ||
/* The list of builds returned does not include a placeholder for inactive builds, so we need to check whether the build matches the version in the current column. | ||
Builds are sorted in descending revision order and so match the versions' sort order. */ | ||
if (version && version.id === builds?.[buildIndex]?.version) { | ||
const b = builds[buildIndex]; | ||
buildIndex += 1; | ||
return ( | ||
<BuildGrid | ||
key={b.id} | ||
build={b} | ||
handleTaskClick={handleTaskClick} | ||
/> | ||
); | ||
} | ||
return <Build key={version?.id} />; | ||
})} | ||
</BuildGroup> | ||
</Row> | ||
); | ||
}; | ||
|
||
const BuildGrid: React.FC<{ | ||
build: WaterfallBuild; | ||
handleTaskClick: (s: string) => () => void; | ||
}> = ({ build, handleTaskClick }) => ( | ||
<Build | ||
onClick={(event: React.MouseEvent) => { | ||
handleTaskClick( | ||
(event.target as HTMLDivElement)?.getAttribute("status") ?? "", | ||
); | ||
}} | ||
> | ||
{build.tasks.map(({ displayName, id, status }) => ( | ||
<SquareMemo | ||
key={id} | ||
data-tooltip={displayName} | ||
status={status} | ||
to={getTaskRoute(id)} // TODO DEVPROD-11734: use execution in task route | ||
/> | ||
))} | ||
</Build> | ||
); | ||
|
||
const BuildGroup = styled.div` | ||
${gridGroupCss} | ||
border: 1px solid ${gray.light2}; | ||
border-radius: ${size.xs}; | ||
padding-bottom: ${size.xs}; | ||
padding-top: ${size.xs}; | ||
`; | ||
|
||
const Build = styled.div` | ||
${columnBasis} | ||
`; | ||
|
||
const SQUARE_SIZE = 16; | ||
|
||
const Square = styled(Link)<{ status: string }>` | ||
width: ${SQUARE_SIZE}px; | ||
height: ${SQUARE_SIZE}px; | ||
border: 1px solid ${white}; | ||
box-sizing: content-box; | ||
float: left; | ||
cursor: pointer; | ||
position: relative; | ||
/* TODO DEVPROD-11368: Render colors for all statuses. Could use background-image property to render icons. */ | ||
${({ status }) => | ||
status === TaskStatus.Succeeded | ||
? `background-color: ${green.dark1};` | ||
: `background-color: ${gray.light2}; | ||
`} | ||
/* Tooltip */ | ||
:before { | ||
content: attr(data-tooltip); | ||
position: absolute; | ||
bottom: calc(100% + 5px); | ||
left: 50%; | ||
transform: translate(-50%); | ||
z-index: 1; | ||
width: max-content; | ||
max-width: 450px; | ||
overflow-wrap: break-word; | ||
padding: ${size.xs}; | ||
border-radius: 6px; | ||
background: ${black}; | ||
color: ${white}; | ||
text-align: center; | ||
display: none; | ||
} | ||
:hover:before { | ||
display: block; | ||
} | ||
/* Tooltip caret */ | ||
:hover:after { | ||
content: ""; | ||
position: absolute; | ||
bottom: calc(100% - 5px); | ||
left: 50%; | ||
margin-left: -5px; | ||
border-width: 5px; | ||
border-style: solid; | ||
border-color: ${black} transparent transparent transparent; | ||
} | ||
`; | ||
|
||
const SquareMemo = memo(Square); |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.