Skip to content

Commit

Permalink
chore: release 2.44.0 (#3713)
Browse files Browse the repository at this point in the history
  • Loading branch information
brandonroberts authored Jul 11, 2024
2 parents b94c5ac + 505556b commit 6cf35b1
Show file tree
Hide file tree
Showing 20 changed files with 642 additions and 102 deletions.
47 changes: 47 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,53 @@

> All notable changes to this project will be documented in this file

## [2.44.0-beta.6](https://github.com/open-sauced/app/compare/v2.44.0-beta.5...v2.44.0-beta.6) (2024-07-11)


### 🍕 Features

* filter `RossChart` by contributor type ([#3698](https://github.com/open-sauced/app/issues/3698)) ([d48e8ac](https://github.com/open-sauced/app/commit/d48e8ac55e34136540277c1f7bb9dac2881d984c))


### 🐛 Bug Fixes

* allow repos and contributors to be added to workspaces from explore page ([#3700](https://github.com/open-sauced/app/issues/3700)) ([3271dd4](https://github.com/open-sauced/app/commit/3271dd4f086df90b79a8ad5a704ea49a1f528602))

## [2.44.0-beta.5](https://github.com/open-sauced/app/compare/v2.44.0-beta.4...v2.44.0-beta.5) (2024-07-11)


### 🍕 Features

* add Contributor Distribution to repo page ([#3712](https://github.com/open-sauced/app/issues/3712)) ([a53c7cd](https://github.com/open-sauced/app/commit/a53c7cd57652c75ecc52a9650a8aed9dbc9ac9c7))

## [2.44.0-beta.4](https://github.com/open-sauced/app/compare/v2.44.0-beta.3...v2.44.0-beta.4) (2024-07-11)


### 🍕 Features

* allow input and display of GitHub releases as highlights ([#3705](https://github.com/open-sauced/app/issues/3705)) ([8aa0177](https://github.com/open-sauced/app/commit/8aa01775eb4f93491459bbcd571293bf207e66e4))

## [2.44.0-beta.3](https://github.com/open-sauced/app/compare/v2.44.0-beta.2...v2.44.0-beta.3) (2024-07-10)


### 🐛 Bug Fixes

* now a contributor insight can be deleted if one was deleted in the same page session ([#3246](https://github.com/open-sauced/app/issues/3246)) ([8dd1ee2](https://github.com/open-sauced/app/commit/8dd1ee25d4bfbee7d78191609e205e0cb62f7213))

## [2.44.0-beta.2](https://github.com/open-sauced/app/compare/v2.44.0-beta.1...v2.44.0-beta.2) (2024-07-10)


### 🐛 Bug Fixes

* now the contributions tab is the first tab on the user profile page ([#3709](https://github.com/open-sauced/app/issues/3709)) ([87d0ee9](https://github.com/open-sauced/app/commit/87d0ee9f72a002de2cffb0df1d335add01303330))

## [2.44.0-beta.1](https://github.com/open-sauced/app/compare/v2.43.0...v2.44.0-beta.1) (2024-07-10)


### 🍕 Features

* implemented the Radar chart component ([#3704](https://github.com/open-sauced/app/issues/3704)) ([8579f41](https://github.com/open-sauced/app/commit/8579f416f3077108631d04d88833a47d43896e17))

## [2.43.0](https://github.com/open-sauced/app/compare/v2.42.0...v2.43.0) (2024-07-09)


Expand Down
45 changes: 45 additions & 0 deletions components/Graphs/RadarChart.stories.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
import { Meta, StoryObj } from "@storybook/react";
import { ChartTooltipContent } from "components/primitives/chart-primitives";
import { RadarChart } from "./RadarChart";

type Story = StoryObj<typeof RadarChart>;

const meta: Meta<typeof RadarChart> = {
title: "Components/Graphs/RadarChart",
component: RadarChart,
args: {
radarDataKey: "percentage",
polarAngleAxisDataKey: "type",
data: [
{ type: "Code review", percentage: 30 },
{ type: "Issues", percentage: 11 },
{ type: "Pull requests", percentage: 11 },
{ type: "Commits", percentage: 48 },
],
fill: "#ff5100",
},
};

export default meta;

export const Default: Story = {};
export const WithDot: Story = {
args: {
dot: {
r: 4,
fillOpacity: 1,
},
},
};
export const WithCustomTooltip: Story = {
args: {
chartTooltipContent: (
<ChartTooltipContent
className="bg-white"
formatter={(value, name, item, index, payload) => {
return `${value}%`;
}}
/>
),
},
};
57 changes: 57 additions & 0 deletions components/Graphs/RadarChart.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,57 @@
"use client";

// If you want to make improvements to the chart or extend it, see the examples at https://ui.shadcn.com/charts#radar-chart

import { PolarAngleAxis, PolarGrid, Radar, RadarChart as RawRadarChart } from "recharts";
import { ComponentProps } from "react";
import { ChartConfig, ChartContainer, ChartTooltip, ChartTooltipContent } from "components/primitives/chart-primitives";

const chartConfig = {
desktop: {
label: "Desktop",
color: "hsl(var(--chart-1))",
},
} satisfies ChartConfig;

interface RadarChartProps {
data: ComponentProps<typeof RawRadarChart>["data"];
cursor?: boolean;
radarDataKey: ComponentProps<typeof Radar>["dataKey"];
polarAngleAxisDataKey: ComponentProps<typeof PolarAngleAxis>["dataKey"];
children?: React.ReactNode;
opacity?: number;
// create an optional prop for the type that is the type of the RawRadarChart dot prop, but infer it from it's existing type
dot?: ComponentProps<typeof Radar>["dot"];
fill: ComponentProps<typeof Radar>["fill"];
// If you need a diffent unit, you can add it here
maxHeight?: `${number}${"px" | "rem"}` | "auto";
labelFormatter?: ComponentProps<typeof ChartTooltipContent>["labelFormatter"];
formatter?: ComponentProps<typeof ChartTooltipContent>["formatter"];
chartTooltipContent?: ComponentProps<typeof ChartTooltip>["content"];
}

export function RadarChart({
data,
radarDataKey,
polarAngleAxisDataKey,
dot,
fill,
cursor = false,
opacity = 0.6,
maxHeight = "250px",
chartTooltipContent,
}: RadarChartProps) {
return (
<ChartContainer config={chartConfig} className={`mx-auto aspect-square max-h-[${maxHeight}]`}>
<RawRadarChart data={data}>
<ChartTooltip
cursor={cursor}
content={chartTooltipContent ? chartTooltipContent : <ChartTooltipContent className="bg-white" />}
/>
<PolarAngleAxis dataKey={polarAngleAxisDataKey} />
<PolarGrid />
<Radar dataKey={radarDataKey} fill={fill} fillOpacity={opacity} dot={dot} />
</RawRadarChart>
</ChartContainer>
);
}
157 changes: 98 additions & 59 deletions components/Repositories/RossChart.tsx
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import { FaUsers } from "react-icons/fa6";
import { Bar, BarChart, CartesianGrid, ResponsiveContainer, Tooltip, TooltipProps, XAxis, YAxis } from "recharts";
import { NameType, ValueType } from "recharts/types/component/DefaultTooltipContent";
import { useMemo } from "react";
import { useMemo, useState } from "react";
import Card from "components/atoms/Card/card";
import SkeletonWrapper from "components/atoms/SkeletonLoader/skeleton-wrapper";
import humanizeNumber from "lib/utils/humanizeNumber";
Expand All @@ -11,34 +11,82 @@ type RossChartProps = {
isLoading: boolean;
error: Error | undefined;
range: number;
rangedTotal: number;
className?: string;
};

export default function RossChart({ stats, rangedTotal, isLoading, error, range, className }: RossChartProps) {
const rangedAverage = useMemo(() => (rangedTotal / range).toPrecision(2), [rangedTotal, range]);
export default function RossChart({ stats, isLoading, error, range, className }: RossChartProps) {
const [filterOutside, setFilterOutside] = useState(true);
const [filterRecurring, setFilterRecurring] = useState(true);
const [filterInternal, setFilterInternal] = useState(true);

const filteredTotal = useMemo(() => {
return (
stats?.contributors.reduce((prev, curr) => {
return (prev +=
(filterOutside ? curr.new : 0) +
(filterRecurring ? curr.recurring : 0) +
(filterInternal ? curr.internal : 0));
}, 0) || 0
);
}, [stats, filterOutside, filterRecurring, filterInternal]);

const rangedAverage = useMemo(
() => (filteredTotal / (stats ? stats.contributors.length : 1)).toPrecision(2),
[filteredTotal, stats]
);

const weeklyData = useMemo(() => {
const result = stats?.contributors.reverse().map((week) => {
return stats?.contributors.reverse().map((week) => {
return {
...week,
new: filterOutside ? week.new : 0,
recurring: filterRecurring ? week.recurring : 0,
internal: filterInternal ? week.internal : 0,
bucket: new Date(week.bucket).toLocaleDateString(undefined, { month: "numeric", day: "numeric" }),
};
});

return result;
}, [stats]);
}, [stats, filterOutside, filterRecurring, filterInternal]);

const bucketTicks = useMemo(() => {
const result = stats?.contributors.reverse().map((week) => {
return stats?.contributors.reverse().map((week) => {
return new Date(week.bucket).toLocaleDateString(undefined, { month: "numeric", day: "numeric" });
});

return result;
}, [stats]);

const CONTRIBUTOR_COLORS: Record<string, string> = {
internal: "#1E3A8A",
recurring: "#2563EB",
new: "#60A5FA",
};

function CustomTooltip({ active, payload }: TooltipProps<ValueType, NameType>) {
if (active && payload) {
const legend = payload.reverse();
return (
<figcaption className="flex flex-col gap-1 text-sm bg-white px-4 py-3 rounded-lg border w-fit">
<section className="flex gap-2 font-medium text-slate-500 items-center text-xs w-fit">
<FaUsers className="fill-slate-500" />
<p>Contributors</p>
<p>{payload[0]?.payload.bucket}</p>
</section>

{legend.map((data) => (
<section key={`${data.payload.bucket}_${data.name}`} className="flex justify-between">
<p className="flex gap-2 items-center px-1 text-slate-500 capitalize">
<span
className={`w-2 h-2 rounded-full bg-[${CONTRIBUTOR_COLORS[data.name || "new"]}] inline-block`}
></span>
{data.name === "new" ? "Outside" : data.name}:
</p>
<p className="font-medium pl-2">{data.value}</p>
</section>
))}
</figcaption>
);
}
}

return (
<Card className={`${className ?? ""} flex flex-col gap-8 w-full h-full items-center !px-6 !py-8`}>
<Card className={`${className ?? ""} flex flex-col gap-6 w-full h-full items-center !px-6 !py-8`}>
<section className="flex flex-col lg:flex-row w-full items-start lg:items-start gap-4 lg:justify-between px-2">
{isLoading ? (
<SkeletonWrapper width={100} height={24} />
Expand All @@ -54,10 +102,10 @@ export default function RossChart({ stats, rangedTotal, isLoading, error, range,
<aside className="flex gap-8">
<div>
<h3 className="text-xs xl:text-sm text-slate-500">Total {range} days</h3>
<p className="font-semibold text-xl xl:text-3xl">{rangedTotal}</p>
<p className="font-semibold text-xl xl:text-3xl">{filteredTotal}</p>
</div>
<div>
<h3 className="text-xs xl:text-sm text-slate-500">Average per day</h3>
<h3 className="text-xs xl:text-sm text-slate-500">Average per week</h3>
<p className="font-semibold text-xl xl:text-3xl">{humanizeNumber(rangedAverage)}</p>
</div>
</aside>
Expand All @@ -79,57 +127,48 @@ export default function RossChart({ stats, rangedTotal, isLoading, error, range,
/>
<Tooltip content={CustomTooltip} filterNull={false} />
<CartesianGrid vertical={false} strokeDasharray="4" stroke="#E2E8F0" />
<Bar dataKey="internal" stackId="a" fill="#1E3A8A" />
<Bar dataKey="recurring" stackId="a" fill="#2563EB" />
<Bar dataKey="new" stackId="a" fill="#60A5FA" />
{filterInternal && <Bar dataKey="internal" stackId="a" fill={CONTRIBUTOR_COLORS["internal"]} />}
{filterRecurring && <Bar dataKey="recurring" stackId="a" fill={CONTRIBUTOR_COLORS["recurring"]} />}
{filterOutside && <Bar dataKey="new" stackId="a" fill={CONTRIBUTOR_COLORS["new"]} />}
</BarChart>
)}
</ResponsiveContainer>

<fieldset className="flex flex-row gap-4 w-fit text-sm mx-auto p-0">
<button
onClick={() => setFilterOutside(!filterOutside)}
className={`flex gap-2 h-full items-center text-slate-700 ${
!filterOutside && "opacity-60"
} transition-all duration-300 hover:bg-slate-100 rounded-lg px-2 py-1`}
>
<span className={`w-4 h-4 rounded-sm bg-[#60A5FA] inline-block`} />
Outside
</button>

<button
onClick={() => setFilterRecurring(!filterRecurring)}
className={`flex gap-2 h-full items-center text-slate-700 ${
!filterRecurring && "opacity-60"
} transition-all duration-300 hover:bg-slate-100 rounded-lg px-2 py-1`}
>
<span className={`w-4 h-4 rounded-sm bg-[#2563EB] inline-block`} />
Recurring
</button>

<button
onClick={() => setFilterInternal(!filterInternal)}
className={`flex gap-2 h-full items-center text-slate-700 ${
!filterInternal && "opacity-60"
} transition-all duration-300 hover:bg-slate-100 rounded-lg px-2 py-1`}
>
<span className={`w-4 h-4 rounded-sm bg-[#1E3A8A] inline-block`} />
Internal
</button>
</fieldset>
</Card>
);
}

function CustomTooltip({ active, payload }: TooltipProps<ValueType, NameType>) {
if (active && payload) {
return (
<figcaption className="flex flex-col gap-1 text-sm bg-white px-4 py-3 rounded-lg border w-fit">
<section className="flex gap-2 font-medium text-slate-500 items-center text-xs w-fit">
<FaUsers className="fill-slate-500" />
<p>Contributors</p>
<p>{payload[0]?.payload.bucket}</p>
</section>
{payload[2]?.value && (
<section className="flex justify-between">
<p className="flex gap-2 items-center px-1 text-slate-500">
<span className={`w-2 h-2 rounded-full bg-[#60A5FA] inline-block`}></span>
New:
</p>
<p className="font-medium pl-2">{payload[2]?.value}</p>
</section>
)}
{payload[1]?.value && (
<section className="flex justify-between">
<p className="flex gap-2 items-center px-1 text-slate-500">
<span className={`w-2 h-2 rounded-full bg-[#2563EB] inline-block`}></span>
Recurring:
</p>
<p className="font-medium pl-2">{payload[1]?.value}</p>
</section>
)}
{payload[0]?.value && (
<section className="flex justify-between">
<p className="flex gap-2 items-center px-1 text-slate-500">
<span className={`w-2 h-2 rounded-full bg-[#1E3A8A] inline-block`}></span>
Internal:
</p>
<p className="font-medium pl-2">{payload[0]?.value}</p>
</section>
)}
</figcaption>
);
}
}

function CustomTick({ x, y, payload }: { x: number; y: number; payload: { value: string } }) {
return (
<g transform={`translate(${x},${y})`}>
Expand Down
4 changes: 3 additions & 1 deletion components/atoms/TextInput/text-input.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -32,8 +32,10 @@ const TextInput = ({

const handleResetInput = () => {
handleChange?.("");
if (fieldRef) {
if (fieldRef?.current) {
fieldRef.current!.value = "";
} else if (inputRef.current) {
inputRef.current.value = "";
}
};

Expand Down
Loading

0 comments on commit 6cf35b1

Please sign in to comment.