Skip to content

Commit

Permalink
feat: Working Nivo chart (#22)
Browse files Browse the repository at this point in the history
* use v2 pr/search

* fix build

* wip data

* data is fetched and structured

* remove async functions

* add nivo/line and prep data

* o.filter is not a function

* dirty fix for rendering the chart

* fix type error

* adds meta data

* npm run format

* swap Datum

* npm run format

* chore: add required packages

* chore: disable comma dangle rule

* chore: update chart styles and data

* feat: fix all type errors and refactor implementation

* chore: show stats data

* chore: more updates to charts data

* chore: update formating and color of chart lines

* misc: minor refactor

* fix: build now goes through

* Update components/CIResponsiveLine.tsx

* type errors

* lock files

* build fix?

* build fix

---------

Co-authored-by: Sunday Ogbonna <[email protected]>
Co-authored-by: OGBONNA SUNDAY <[email protected]>
  • Loading branch information
3 people authored Jan 5, 2024
1 parent cecd9ed commit 22c07a9
Show file tree
Hide file tree
Showing 10 changed files with 324 additions and 208 deletions.
2 changes: 1 addition & 1 deletion .eslintrc.json
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
{
"extends": "next/core-web-vitals",
"rules": {
"comma-dangle": "error",
// "comma-dangle": "error",
"quotes": "error",
"camelcase": "error",
"jsx-quotes": "error",
Expand Down
50 changes: 50 additions & 0 deletions components/CIResponsiveLine.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
import { ResponsiveLine, Datum } from "@nivo/line";
import { format, parse } from "date-fns";

const CIResponsiveLine = ({ data }: Datum) => {
return (
<>
<div style={{ height: 400, width: "100%" }}>
<ResponsiveLine
data={data}
margin={{ top: 50, right: 150, bottom: 50, left: 60 }}
yScale={{
type: "linear",
}}
motionConfig="stiff"
curve="catmullRom"
enableSlices="x"
axisTop={null}
isInteractive={true}
axisRight={null}
axisLeft={{
tickValues: 5,
tickSize: 0,
tickPadding: 5,
tickRotation: 0,
legend: "Pull Requests Merged per Day",
legendOffset: -40,
legendPosition: "middle",
}}
axisBottom={{
tickSize: 0,
format: (value) => {
return format(parse(value, "MM/dd/yyyy", new Date()), "MMM d");
},
}}
pointSize={0}
pointColor={{ theme: "background" }}
enableGridX={false}
enableGridY={false}
useMesh={true}
enableArea={false}
enableCrosshair={true}
enablePointLabel={false}
colors={(d) => d.color}
/>
</div>
</>
);
};

export default CIResponsiveLine;
62 changes: 27 additions & 35 deletions hooks/useContributorData.ts
Original file line number Diff line number Diff line change
@@ -1,46 +1,38 @@
import useSWR from "swr";
import { useCallback } from "react";
interface PaginatedDataResponse {
readonly data: DBContributors[];
readonly data: DBContributorsPR[];
readonly meta: Meta;
}

type Response =
| { type: "loading" }
| { type: "error"; error: Error }
// Todo: figure out meta
| { type: "result"; data: DBContributors[]; meta: { itemCount: number } };

// We're not currently using this, we're just using useSWR directly inside ChildWithSWR
// this needs useCallback wrap if we want to use it in the other component
const useContributorData = () => {
useCallback(async (owner: string, repo: string): Promise<Response> => {
// useSWR is probably going to be a sticking point
// eslint-disable-next-line react-hooks/rules-of-hooks
const { data, error, mutate } = useSWR<PaginatedDataResponse, Error>(
`repos/${owner}/${repo}/contributions`
);

if (!error && !data) {
return { type: "loading" };
}

if (error) {
return {
type: "error",
error: error
};
}

return {
type: "result",
data: data?.data ?? [],
meta: data?.meta ?? { itemCount: 0 }
// commenting for now to appease build
// mutate
};
}, []);
const useContributorData = (repo: string, startDate?: number, status?: "closed" | "open") => {
const query = new URLSearchParams();

if (startDate) {
query.set("prev_days_start_date", `${startDate}`);
}
if (status) {
query.set("status", `${status}`);
}
query.set("repo", `${repo}`);

query.set("limit", "100");

const baseEndpoint = "prs/search";

const endpointString = `${baseEndpoint}?${query.toString()}`;

const { data, error, mutate } = useSWR<PaginatedDataResponse, Error>(repo ? endpointString : null);

return {
data: data?.data ?? [],
isLoading: !data && !error,
isError: Object.keys(error ?? {}).length > 0,
meta: data?.meta ?? { itemCount: 0 },
mutate,
};
};
// good catch []

export { useContributorData };
89 changes: 89 additions & 0 deletions lib/prCounts.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,89 @@
const count = (prData: DBContributorsPR[]): { mergedCount: number; closedCount: number; totalCount: number } => {
const mergedCount = prData.filter((item) => item.pr_is_merged).length; // Merged PRs
const closedCount = prData.filter((item) => item.pr_state === "closed").length; // Closed PRs

const totalCount = prData.length; // Total number of PRs

return {
mergedCount,
closedCount,
totalCount,
};
};

const prPerDay = (open: DBContributorsPR[], closed: DBContributorsPR[]) => {
const sortedMergedPRs = closed.sort((a, b) => {
const aDate = new Date(a.pr_created_at);
const bDate = new Date(b.pr_created_at);

return aDate.getTime() - bDate.getTime();
});

const sortedOpenedPRs = open.sort((a, b) => {
const aDate = new Date(a.pr_created_at);
const bDate = new Date(b.pr_created_at);

return aDate.getTime() - bDate.getTime();
});
const mergedPRsPerDay = sortedMergedPRs.reduce<Record<string, number>>((acc, item) => {
const mergedDate = new Date(item.pr_merged_at).toLocaleDateString();

if (item.pr_is_merged) {
if (!acc[mergedDate]) {
acc[mergedDate] = 0;
}
acc[mergedDate]++;
}

return acc;
}, {});

const closedPRsPerDay = sortedMergedPRs.reduce<Record<string, number>>((acc, item) => {
const closedDate = new Date(item.pr_updated_at).toLocaleDateString();

if (item.pr_is_merged === false) {
if (!acc[closedDate]) {
acc[closedDate] = 0;
}
acc[closedDate]++;
}

return acc;
}, {});

const openedPRsPerDay = sortedOpenedPRs.reduce<Record<string, number>>((acc, item) => {
const openedDate = new Date(item.pr_created_at).toLocaleDateString();

if (!acc[openedDate]) {
acc[openedDate] = 0;
}
acc[openedDate]++;

return acc;
}, {});

const openedPRs = Object.entries(openedPRsPerDay).map(([x, y]) => ({ x, y }));
const closedPRs = Object.entries(closedPRsPerDay).map(([x, y]) => ({ x, y }));

const mergedPrs = Object.entries(mergedPRsPerDay).map(([x, y]) => ({ x, y }));

return [
{
id: "Opened PRs",
color: "#10b981",
data: openedPRs,
},
{
id: "Merged PRs",
color: "#3b38f1",
data: mergedPrs,
},
{
id: "Closed PRs",
color: "#ef4444",
data: closedPRs,
},
];
};

export default prPerDay;
31 changes: 23 additions & 8 deletions next-types.d.ts
Original file line number Diff line number Diff line change
@@ -1,12 +1,27 @@
// User defined type definitions. Please add type definitions for global types here

interface DBContributors {
readonly id: string
readonly commits: number,
readonly first_commit_time: string
readonly last_commit_time: string
interface Meta {
readonly itemCount: number;
}

interface Meta {
readonly itemCount: number,
}
interface DBContributorsPR {
readonly event_id: string;
readonly pr_additions: number;
readonly pr_author_login: string;
readonly pr_base_label: string;
readonly pr_changed_files: number;
readonly pr_comments: number;
readonly pr_commits: number;
readonly pr_created_at: string;
readonly pr_deletions: number;
readonly pr_head_label: string;
readonly pr_is_draft: boolean;
readonly pr_is_merged: boolean;
readonly pr_head_ref: string;
readonly pr_merged_at: string;
readonly pr_number: number;
readonly pr_state: string;
readonly pr_title: string;
readonly pr_updated_at: string;
readonly repo_name: string;
}
29 changes: 26 additions & 3 deletions npm-shrinkwrap.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 2 additions & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -34,9 +34,11 @@
"dependencies": {
"@nivo/core": "^0.84.0",
"@nivo/line": "^0.84.0",
"date-fns": "^3.0.6",
"next": "12.2.5",
"react": "18.2.0",
"react-dom": "18.2.0",
"react-icons": "^4.12.0",
"rooks": "^7.2.1",
"swr": "^1.3.0",
"tailwindcss": "^3.1.8",
Expand Down
Loading

0 comments on commit 22c07a9

Please sign in to comment.