Skip to content

Commit

Permalink
fix: coverage color scheme
Browse files Browse the repository at this point in the history
  • Loading branch information
AKharytonchyk committed Apr 21, 2024
1 parent e7122b8 commit 1cca4b0
Show file tree
Hide file tree
Showing 10 changed files with 174 additions and 121 deletions.
4 changes: 2 additions & 2 deletions src/App.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ export const ConfigContext = React.createContext<{
octokit: GitService | null;
repositorySettings: Record<string, boolean>;
handleRepositorySelect: (repository: string, selected: boolean) => void;
}>({ octokit: null, repositorySettings: {}, handleRepositorySelect: () => {} });
}>({ octokit: null, repositorySettings: {}, handleRepositorySelect: () => {}});


function App() {
Expand Down Expand Up @@ -94,7 +94,7 @@ function App() {
return (
<>
<ConfigContext.Provider
value={{ octokit, repositorySettings, handleRepositorySelect }}
value={{ octokit, repositorySettings, handleRepositorySelect,}}
>
<AppBar
position="static"
Expand Down
17 changes: 17 additions & 0 deletions src/components/CoverageCell.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
import React from "react";
import { TableCell } from "@mui/material";
import RYGGradient from "../utils/RYGGradient";
import { CoverageDiffIcon } from "./CoverageDiffIcon";

export const CoverageCell: React.FC<{ coverage: number; previous: number; }> = ({
coverage, previous,
}) => {
const icon = React.useMemo(
() => CoverageDiffIcon(coverage - (previous), previous),
[coverage, previous]
);
const styles = React.useMemo(() => RYGGradient(coverage), [coverage]);
return (
<TableCell sx={styles}>{Math.round(coverage)}% {icon}</TableCell>
);
};
21 changes: 21 additions & 0 deletions src/components/CoverageDiffIcon.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
import React from "react";
import { Tooltip } from "@mui/material";
import { ArrowDownward, ArrowUpward } from "@mui/icons-material";

export const CoverageDiffIcon = (diff: number, prev: number) => {
if (prev === 0) return;
if (diff > 0) {
return (
<Tooltip title={`+${diff.toFixed(2)}%`}>
<ArrowUpward color="success" />
</Tooltip>
);
}
if (diff < 0) {
return (
<Tooltip title={`-${diff.toFixed(2)}%`}>
<ArrowDownward color="error" />
</Tooltip>
);
}
};
26 changes: 26 additions & 0 deletions src/components/CoverageRow.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
import React from "react";
import { TableCell, TableRow } from "@mui/material";
import { CoverageDetails } from "../models/CoverageDetails";
import { CoverageCell } from "./CoverageCell";

export const CoverageRow: React.FC<{ data: CoverageDetails; name: string; }> = ({
name, data,
}) => {
return (
<TableRow key={name}>
<TableCell>{name}</TableCell>
<CoverageCell
coverage={data.current.lines}
previous={data.previous.lines} />
<CoverageCell
coverage={data.current.statements}
previous={data.previous.statements} />
<CoverageCell
coverage={data.current.functions}
previous={data.previous.functions} />
<CoverageCell
coverage={data.current.branches}
previous={data.previous.branches} />
</TableRow>
);
};
28 changes: 28 additions & 0 deletions src/components/SummaryRow.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
import React from "react";
import { TableCell, TableRow } from "@mui/material";
import { CoverageDetails } from "../models/CoverageDetails";
import { CoverageCell } from "./CoverageCell";

export const SummaryRow: React.FC<{ data: CoverageDetails[]; }> = ({ data }) => {
const summaryData = React.useMemo(() => {
return {
lines: data.reduce((acc, curr) => acc + curr.current.lines, 0) / data.length,
statements: data.reduce((acc, curr) => acc + curr.current.statements, 0) /
data.length,
functions: data.reduce((acc, curr) => acc + curr.current.functions, 0) /
data.length,
branches: data.reduce((acc, curr) => acc + curr.current.branches, 0) /
data.length,
};
}, [data]);

return (
<TableRow key="Summary" sx={{ borderTopWidth: "2px" }}>
<TableCell sx={{ fontWeight: "bold" }}>Summary</TableCell>
<CoverageCell coverage={summaryData.lines} previous={0} />
<CoverageCell coverage={summaryData.statements} previous={0} />
<CoverageCell coverage={summaryData.functions} previous={0} />
<CoverageCell coverage={summaryData.branches} previous={0} />
</TableRow>
);
};
8 changes: 8 additions & 0 deletions src/models/CoverageDetails.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
import { CoverageValues } from "./CoverageValues";

export interface CoverageDetails {
current: CoverageValues;
previous: CoverageValues;
diff: CoverageValues;
changed: string;
}
5 changes: 5 additions & 0 deletions src/models/CoverageResponse.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
import { CoverageDetails } from "./CoverageDetails";

export interface CoverageResponse {
[key: string]: CoverageDetails;
}
6 changes: 6 additions & 0 deletions src/models/CoverageValues.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
export interface CoverageValues {
lines: number;
statements: number;
functions: number;
branches: number;
}
135 changes: 16 additions & 119 deletions src/pages/Coverage.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -10,128 +10,15 @@ import {
TableContainer,
TableHead,
TableRow,
Tooltip,
Typography,
} from "@mui/material";
import { Navigate } from "react-router-dom";
import { ConfigContext } from "../App";
import ErrorMessage from "../components/MissingCoverageErrorMessage";
import lz from "lz-string";
import { ArrowDownward, ArrowUpward } from "@mui/icons-material";

interface CoverageDetails {
current: CoverageValues;
previous: CoverageValues;
diff: CoverageValues;
changed: string;
}

interface CoverageValues {
lines: number;
statements: number;
functions: number;
branches: number;
}

interface CoverageResponse {
[key: string]: CoverageDetails;
}

const coverageStyles = (coverage: number) => {
console.log(coverage, coverage < 60);
if (coverage < 60) return { color: "#f44336", fontWeight: "bolder" };
if (coverage < 80) return { color: "#ed6c02", fontWeight: "bold" };
return { color: "#4caf50", fontWeight: "normal" };
};

const coverageDiffIcon = (diff: number, prev: number) => {
if (prev === 0) return;
if (diff > 0) {
return (
<Tooltip title={`+${diff.toFixed(2)}%`}>
<ArrowUpward color="success" />
</Tooltip>
);
}
if (diff < 0) {
return (
<Tooltip title={`-${diff.toFixed(2)}%`}>
<ArrowDownward color="error" />
</Tooltip>
);
}
};

const CoverageCell: React.FC<{ coverage: number; previous: number }> = ({
coverage,
previous,
}) => {
const icon = React.useMemo(
() => coverageDiffIcon(coverage - previous, previous),
[coverage, previous]
);
const styles = React.useMemo(() => coverageStyles(coverage), [coverage]);
return (
<TableCell sx={styles}>
{coverage.toFixed(2)} {icon}
</TableCell>
);
};

const CoverageRow: React.FC<{ data: CoverageDetails; name: string }> = ({
name,
data,
}) => {
return (
<TableRow key={name}>
<TableCell>{name}</TableCell>
<CoverageCell
coverage={data.current.lines}
previous={data.previous.lines}
/>
<CoverageCell
coverage={data.current.statements}
previous={data.previous.statements}
/>
<CoverageCell
coverage={data.current.functions}
previous={data.previous.functions}
/>
<CoverageCell
coverage={data.current.branches}
previous={data.previous.branches}
/>
</TableRow>
);
};

const SummaryRow: React.FC<{ data: CoverageDetails[] }> = ({ data }) => {
const summaryData = React.useMemo(() => {
return {
lines:
data.reduce((acc, curr) => acc + curr.current.lines, 0) / data.length,
statements:
data.reduce((acc, curr) => acc + curr.current.statements, 0) /
data.length,
functions:
data.reduce((acc, curr) => acc + curr.current.functions, 0) /
data.length,
branches:
data.reduce((acc, curr) => acc + curr.current.branches, 0) /
data.length,
};
}, [data]);

return (
<TableRow key="Summary">
<TableCell sx={{ fontWeight: "bold" }}>Summary</TableCell>
<CoverageCell coverage={summaryData.lines} previous={0} />
<CoverageCell coverage={summaryData.statements} previous={0} />
<CoverageCell coverage={summaryData.functions} previous={0} />
<CoverageCell coverage={summaryData.branches} previous={0} />
</TableRow>
);
};
import { CoverageResponse } from "../models/CoverageResponse";
import { CoverageRow } from "../components/CoverageRow";
import { SummaryRow } from "../components/SummaryRow";

export const Coverage: React.FC = () => {
const { data, isLoading, isError } = useQuery({
Expand All @@ -150,7 +37,10 @@ export const Coverage: React.FC = () => {
retry: false,
});

const dataLength = React.useMemo(() => Object.keys(data || {}).length, [data]);
const dataLength = React.useMemo(
() => Object.keys(data || {}).length,
[data]
);

const { repositorySettings } = React.useContext(ConfigContext);

Expand Down Expand Up @@ -178,10 +68,17 @@ export const Coverage: React.FC = () => {
if (!localStorage.getItem("token")) {
return <Navigate to="/login" />;
}

return (
<Box padding={2} width={"calc(100vw - 2em)"}>
<h1>Coverage</h1>
<Box
display="flex"
flexDirection="row"
justifyContent="space-between"
alignItems="baseline"
>
<h1>Coverage</h1>
</Box>
{isLoading && <CircularProgress color="inherit" />}
{isError && <ErrorMessage showError={true} />}
{data && dataLength === 0 && (
Expand Down
45 changes: 45 additions & 0 deletions src/utils/RYGGradient.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
interface StyleProps {
color: string;
fontWeight: string;
textShadow?: string;
backgroundColor?: string;
}

const RYGGradient = (coverage: number): StyleProps => {
let r: number = 0;
let g: number = 0;
let b: number = 0;

const red = { r: 185, g: 28, b: 28 };
const yellow = { r: 234, g: 179, b: 8 };
const green = { r: 101, g: 163, b: 13 };

if (coverage <= 45) {
r = red.r;
g = red.g;
b = red.b;
} else if (coverage <= 60) {
const ratio = (coverage - 45) / 15;
r = red.r + (yellow.r - red.r) * ratio;
g = red.g + (yellow.g - red.g) * ratio;
b = red.b + (yellow.b - red.b) * ratio;
} else if (coverage <= 85) {
const ratio = (coverage - 60) / 25;
r = yellow.r + (green.r - yellow.r) * ratio;
g = yellow.g + (green.g - yellow.g) * ratio;
b = yellow.b + (green.b - yellow.b) * ratio;
} else {
r = green.r;
g = green.g;
b = green.b;
}

const fontWeight = coverage < 45 ? "bolder" : "bold";
const color = `rgb(${Math.round(r)}, ${Math.round(g)}, ${Math.round(b)})`;

return { color, fontWeight };
};

export default RYGGradient;


0 comments on commit 1cca4b0

Please sign in to comment.