From ffe35e210e6d4115480a0c44478998c73fade875 Mon Sep 17 00:00:00 2001 From: Brandon Roberts Date: Tue, 18 Apr 2023 13:57:17 -0500 Subject: [PATCH 01/11] feat: add page to accept insight member invitation (#1102) --- pages/hub/insights/[insightId]/accept.tsx | 85 +++++++++++++++++++++++ 1 file changed, 85 insertions(+) create mode 100644 pages/hub/insights/[insightId]/accept.tsx diff --git a/pages/hub/insights/[insightId]/accept.tsx b/pages/hub/insights/[insightId]/accept.tsx new file mode 100644 index 0000000000..2b9f0f2fbd --- /dev/null +++ b/pages/hub/insights/[insightId]/accept.tsx @@ -0,0 +1,85 @@ +import { useRouter } from "next/router"; + +import GitHubIcon from "img/icons/github-icon.svg"; + +import HubLayout from "layouts/hub"; +import Button from "components/atoms/Button/button"; +import Title from "components/atoms/Typography/title"; +import Text from "components/atoms/Typography/text"; + +import useSupabaseAuth from "lib/hooks/useSupabaseAuth"; +import useInsight from "lib/hooks/useInsight"; +import { useToast } from "lib/hooks/useToast"; +import Icon from "components/atoms/Icon/icon"; + +const AcceptMemberInvitePage = () => { + const { user, sessionToken, signIn } = useSupabaseAuth(); + const router = useRouter(); + const { toast } = useToast(); + const { insightId, id: inviteId } = router.query; + const id = insightId as string; + const { data: insight, isLoading: insightLoading, isError: insightError } = useInsight(id); + + async function acceptInvite() { + const response = await fetch(`${process.env.NEXT_PUBLIC_API_URL}/user/insights/${insightId}/members/${inviteId}`, { + method: "PATCH", + headers: { + "Content-Type": "application/json", + Authorization: `Bearer ${sessionToken}` + }, + body: JSON.stringify({ access: "view" }) + }); + + if (response.ok) { + router.push(`/pages/${user?.user_metadata.user_name}/${insightId}/dashboard`); + } else { + toast({ description: "An error occurred!", variant: "danger" }); + } + } + + if (insightLoading) { + return <>Loading; + } + + if (insightError) { + return <>An error occurred while loading this page; + } + + return ( +
+
+
+ + Insight Member Invitation - {insight?.name} + + + + An insight is a dashboard containing selected repositories that you and your team can get insights from. + +
+ +
+
+ {user ? ( + + ) : ( + + )} +
+
+
+
+ ); +}; + +AcceptMemberInvitePage.PageLayout = HubLayout; +AcceptMemberInvitePage.SEO = { + title: "Accept Insight Member Invitation | Open Sauced Insights", + noindex: true +}; + +export default AcceptMemberInvitePage; From 08e652c3e07d3fcd25ae811f2b5871869b31c0f5 Mon Sep 17 00:00:00 2001 From: Brandon Roberts Date: Tue, 18 Apr 2023 19:01:15 +0000 Subject: [PATCH 02/11] chore(minor): release 1.43.0-beta.1 on beta channel [skip ci] MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit ## [1.43.0-beta.1](https://github.com/open-sauced/insights/compare/v1.42.0...v1.43.0-beta.1) (2023-04-18) ### πŸ• Features * add page to accept insight member invitation ([#1102](https://github.com/open-sauced/insights/issues/1102)) ([ffe35e2](https://github.com/open-sauced/insights/commit/ffe35e210e6d4115480a0c44478998c73fade875)) --- CHANGELOG.md | 7 +++++++ npm-shrinkwrap.json | 4 ++-- package.json | 2 +- 3 files changed, 10 insertions(+), 3 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index db81c1031f..dd8128d3f4 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -5,6 +5,13 @@ > All notable changes to this project will be documented in this file +## [1.43.0-beta.1](https://github.com/open-sauced/insights/compare/v1.42.0...v1.43.0-beta.1) (2023-04-18) + + +### πŸ• Features + +* add page to accept insight member invitation ([#1102](https://github.com/open-sauced/insights/issues/1102)) ([ffe35e2](https://github.com/open-sauced/insights/commit/ffe35e210e6d4115480a0c44478998c73fade875)) + ## [1.42.0](https://github.com/open-sauced/insights/compare/v1.41.1...v1.42.0) (2023-04-18) diff --git a/npm-shrinkwrap.json b/npm-shrinkwrap.json index 6ca77a83db..c7f689d291 100644 --- a/npm-shrinkwrap.json +++ b/npm-shrinkwrap.json @@ -1,12 +1,12 @@ { "name": "@open-sauced/insights", - "version": "1.42.0", + "version": "1.43.0-beta.1", "lockfileVersion": 3, "requires": true, "packages": { "": { "name": "@open-sauced/insights", - "version": "1.42.0", + "version": "1.43.0-beta.1", "hasInstallScript": true, "license": "MIT", "dependencies": { diff --git a/package.json b/package.json index 2e8d6a2b14..69cbf1cd0b 100644 --- a/package.json +++ b/package.json @@ -2,7 +2,7 @@ "name": "@open-sauced/insights", "description": "πŸ•The dashboard for open source discovery.", "keywords": [], - "version": "1.42.0", + "version": "1.43.0-beta.1", "author": "TED Vortex ", "private": true, "license": "MIT", From 5186a6089c7dd5f306b7854f5a7706015e33e0f0 Mon Sep 17 00:00:00 2001 From: OGBONNA SUNDAY <62995161+OgDev-01@users.noreply.github.com> Date: Tue, 18 Apr 2023 21:59:06 +0100 Subject: [PATCH 03/11] feat: implement insights team feature (#1080) * intial commit for this PR * chore: update db types * feat: create insight members hook * chore: copy text updates and fix insights data error * chore: validate email * feat: setup team invite * feat: add teams hook * feat: update member role implementation * chore: minor changes * refactor: improve search component * refactor: improve select filter for teams role * feat: add toast for visual feedback * chore: update teams crud * refactor: minor adjustments * fix: linting errors * fix: select tick visibility * refactor: minor adjustments * fix: build error * fix: update teams story * refactor: update toast message * chore: review changes * chore: review changes * fix: update story props * chore: review changes --- components/atoms/Search/search.tsx | 6 +- components/atoms/Selector/selector.tsx | 61 ++++++-------- .../FilterCardSelect/filter-card-select.tsx | 46 ++++++----- .../TeamMemberRow/team-member-row.tsx | 63 ++++++++++---- .../TeamMembersConfig/team-members-config.tsx | 78 ++++++++++++++++-- .../organisms/InsightPage/InsightPage.tsx | 36 +++++++- lib/hooks/useInsightMembers.ts | 82 +++++++++++++++++++ next-types.d.ts | 12 +++ pages/hub/insights/[insightId]/edit.tsx | 10 +-- stories/atoms/selector.stories.tsx | 11 ++- stories/atoms/team-member-row.stories.tsx | 8 +- stories/atoms/team-members-config.stories.tsx | 12 ++- 12 files changed, 328 insertions(+), 97 deletions(-) create mode 100644 lib/hooks/useInsightMembers.ts diff --git a/components/atoms/Search/search.tsx b/components/atoms/Search/search.tsx index 33f4203f24..3d42188c6b 100644 --- a/components/atoms/Search/search.tsx +++ b/components/atoms/Search/search.tsx @@ -1,4 +1,4 @@ -import React, { useState } from "react"; +import React, { useEffect, useState } from "react"; import { GrClose } from "react-icons/gr"; import { FaSearch } from "react-icons/fa"; import { Spinner } from "../SpinLoader/spin-loader"; @@ -44,6 +44,10 @@ const Search = ({ onChange?.(""); }; + useEffect(() => { + setSearch(value); + }, [value]); + const handleOnSelect = (suggestion: string) => { setSearch(suggestion); onSearch?.(suggestion); diff --git a/components/atoms/Selector/selector.tsx b/components/atoms/Selector/selector.tsx index 427d35e29f..13a36af095 100644 --- a/components/atoms/Selector/selector.tsx +++ b/components/atoms/Selector/selector.tsx @@ -2,46 +2,39 @@ import Radio from "components/atoms/Radio/radio"; import RadioCheck from "../RadioCheck/radio-check"; interface SelectorProps { - filterOptions: string[]; + filterOptions: { name: string; value: string }[]; handleFilterClick: (filter: string) => void; selected?: string; - variation?: "circle" | "check" + variation?: "circle" | "check"; } -const Selector = ({ - filterOptions, - handleFilterClick, - selected, - variation = "circle" -}: SelectorProps) => { +const Selector = ({ filterOptions, handleFilterClick, selected, variation = "circle" }: SelectorProps) => { return ( -
+
{filterOptions.length > 0 && - filterOptions.map((option, index) => { - return ( - variation === "circle" ? ( - { - handleFilterClick(option); - }} - className="!w-full" - checked={selected === option ? true : false} - > - {option} - - ) : ( - { - handleFilterClick(option); - }} - className="!w-full" - checked={selected === option ? true : false} - > - {option} - - ) + filterOptions.map(({ name, value }, index) => { + return variation === "circle" ? ( + { + handleFilterClick(value); + }} + className="!w-full" + checked={selected === value ? true : false} + > + {name} + + ) : ( + { + handleFilterClick(value); + }} + className="!w-full" + checked={selected === value ? true : false} + > + {name} + ); })}
diff --git a/components/molecules/FilterCardSelect/filter-card-select.tsx b/components/molecules/FilterCardSelect/filter-card-select.tsx index d8eb969867..c928d9afee 100644 --- a/components/molecules/FilterCardSelect/filter-card-select.tsx +++ b/components/molecules/FilterCardSelect/filter-card-select.tsx @@ -8,10 +8,10 @@ import repoIcon from "../../../img/icons/repo.svg"; import Selector from "../../atoms/Selector/selector"; interface FilterCardSelectProps { - selected: string; - icon?: "topic" | "repo" | "org" | "contributor"; - options: string[]; - handleFilterClick: (filter: string) => void; + selected: string; + icon?: "topic" | "repo" | "org" | "contributor"; + options: string[]; + handleFilterClick: (filter: string) => void; } const icons = { @@ -33,8 +33,12 @@ const icons = { } }; -const FilterCardSelect: React.FC = ({ selected: filterName, icon = "topic", options, handleFilterClick }) => { - +const FilterCardSelect: React.FC = ({ + selected: filterName, + icon = "topic", + options, + handleFilterClick +}) => { const ref = useRef(null); const [isOpen, setIsOpen] = useState(false); const toggleFilter = () => { @@ -62,22 +66,26 @@ const FilterCardSelect: React.FC = ({ selected: filterNam
+ className={ + "inline-block py-1 border border-slate-300 outline-none hover:bg-slate-50 focus:ring-2 bg-slate-100 focus:ring-slate-300 rounded-lg cursor-pointer" + } + > - { isOpen && - } + {isOpen && ( + ({ name: option, value: option }))} + handleFilterClick={handleFilterClick} + selected={filterName} + /> + )}
); diff --git a/components/molecules/TeamMemberRow/team-member-row.tsx b/components/molecules/TeamMemberRow/team-member-row.tsx index 76593ace33..fdb0c84789 100644 --- a/components/molecules/TeamMemberRow/team-member-row.tsx +++ b/components/molecules/TeamMemberRow/team-member-row.tsx @@ -3,43 +3,76 @@ import { AiOutlineCaretDown } from "react-icons/ai"; import pendingImg from "img/icons/fallback-image-disabled-square.svg"; import { useState } from "react"; import Selector from "components/atoms/Selector/selector"; -import { TeamMemberData } from "../TeamMembersConfig/team-members-config"; +import { MemberAccess, TeamMemberData } from "../TeamMembersConfig/team-members-config"; interface TeamMemberRowProps extends TeamMemberData { className?: string; + onDelete: (memberId: string) => void; + onUpdate: (memberId: string, access: MemberAccess) => Promise | undefined; } -const mapRoleToText: Record = { +const mapRoleToText: Record = { + owner: "Owner", admin: "Admin", - editor: "can edit", - viewer: "can view", + edit: "can edit", + view: "can view", pending: "Pending" }; -const TeamMemberRow = ({ className, name, avatarUrl, role }: TeamMemberRowProps) => { - +const TeamMemberRow = ({ className, name, avatarUrl, access, email, onDelete, onUpdate, id }: TeamMemberRowProps) => { const [isMenuOpen, setIsMenuOpen] = useState(false); - const pending = role == "pending"; + const pending = access == "pending"; + const isOwner = access == "owner"; - const handleRoleChange = (role: string) => {}; + const handleRoleChange = async (role: string) => { + setIsMenuOpen(false); + if (role === "remove") { + onDelete(id); + } else { + onUpdate(id, role as MemberAccess); + } + }; - return( + return (
-
+
-

{name}

+

{name || email}

- {mapRoleToText[role]} {!pending && {setIsMenuOpen(!isMenuOpen);}} />} + {mapRoleToText[access]} + {!pending && ( + <> + {isOwner ? ( + + ) : ( + { + setIsMenuOpen(!isMenuOpen); + }} + /> + )} + + )}
- { !pending && isMenuOpen && ( - + {!pending && isMenuOpen && ( + )}
); - }; export default TeamMemberRow; diff --git a/components/molecules/TeamMembersConfig/team-members-config.tsx b/components/molecules/TeamMembersConfig/team-members-config.tsx index 6804b4ad7b..a54c358e2c 100644 --- a/components/molecules/TeamMembersConfig/team-members-config.tsx +++ b/components/molecules/TeamMembersConfig/team-members-config.tsx @@ -1,30 +1,90 @@ import Button from "components/atoms/Button/button"; import Search from "components/atoms/Search/search"; import TeamMemberRow from "../TeamMemberRow/team-member-row"; +import { useState } from "react"; +import { validateEmail } from "lib/utils/validate-email"; +import { useToast } from "lib/hooks/useToast"; interface TeamMembersConfigProps { className?: string; members: TeamMemberData[]; + onAddMember: (email: string) => Promise | undefined; + onDeleteMember: (memberId: string) => void; + onUpdateMember: (memberId: string, access: MemberAccess) => Promise; } +export type MemberAccess = "owner" | "pending" | "admin" | "edit" | "view"; export interface TeamMemberData { + id: string; + insight_id: number; + user_id?: number; name: string; + access: MemberAccess; avatarUrl: string; - role: "admin" | "editor" | "viewer" | "pending"; + email?: string; } -const TeamMembersConfig = ({ className, members }: TeamMembersConfigProps) => { +const TeamMembersConfig = ({ + className, + members, + onAddMember, + onDeleteMember, + onUpdateMember +}: TeamMembersConfigProps) => { + const [validInput, setValidInput] = useState(false); + const [email, setEmail] = useState(""); + const [loading, setLoading] = useState(false); + const { toast } = useToast(); + + const handleChange = async (value: string) => { + setEmail(value); + + setValidInput(!!validateEmail(value)); + }; + + const handleAddMember = async () => { + const memberExists = members.find((member) => member.email?.toLowerCase() === email.toLowerCase()); + + if (memberExists) { + toast({ description: "Member already exists", variant: "danger" }); + return; + } + setLoading(true); + const res = await onAddMember(email); + setLoading(false); + setEmail(""); + if (res) { + toast({ description: "Member invite sent successfully", variant: "success" }); + } else { + toast({ description: "An error occurred!", variant: "danger" }); + } + }; return ( -
-

Add Team Members

-
- - +
+

Add Team Members

+
+ handleChange(value)} + placeholder="Enter email address" + name="search" + className="flex-1 text-base" + /> +
- {members.map(member => ( - + {members.map((member) => ( + ))}
diff --git a/components/organisms/InsightPage/InsightPage.tsx b/components/organisms/InsightPage/InsightPage.tsx index fb095e8e60..66a117481d 100644 --- a/components/organisms/InsightPage/InsightPage.tsx +++ b/components/organisms/InsightPage/InsightPage.tsx @@ -13,7 +13,7 @@ import RepoNotIndexed from "components/organisms/Repositories/repository-not-ind import DeleteInsightPageModal from "./DeleteInsightPageModal"; import useSupabaseAuth from "lib/hooks/useSupabaseAuth"; -import { getAvatarByUsername } from "lib/utils/github"; +import { getAvatarById, getAvatarByUsername } from "lib/utils/github"; import useStore from "lib/store"; import Error from "components/atoms/Error/Error"; import Search from "components/atoms/Search/search"; @@ -21,6 +21,8 @@ import { useDebounce } from "rooks"; import SuggestedRepositoriesList from "../SuggestedRepoList/suggested-repo-list"; import { RepoCardProfileProps } from "components/molecules/RepoCardProfile/repo-card-profile"; import { useToast } from "lib/hooks/useToast"; +import TeamMembersConfig, { TeamMemberData } from "components/molecules/TeamMembersConfig/team-members-config"; +import useInsightMembers from "lib/hooks/useInsightMembers"; enum RepoLookupError { Initial = 0, @@ -44,6 +46,25 @@ const InsightPage = ({ edit, insight, pageRepos }: InsightPageProps) => { receivedData = JSON.parse(router.query.selectedRepos as string); } + const { data, addMember, deleteMember, updateMember } = useInsightMembers(insight?.id || 0); + + const members = + data && + data.map((member) => ({ + ...member, + email: member.invitation_email, + avatarUrl: !!member.user_id ? getAvatarById(String(member.user_id)) : "" + })); + + const insightOwner: TeamMemberData = { + insight_id: Number(insight?.id), + email: String(insight?.user.email), + id: String(insight?.user.id), + name: String(insight?.user.name || insight?.user.login), + avatarUrl: getAvatarByUsername(String(insight?.user.login)), + access: "owner" + }; + // Loading States const [deleteLoading, setDeleteLoading] = useState(false); const [createLoading, setCreateLoading] = useState(false); @@ -350,7 +371,7 @@ const InsightPage = ({ edit, insight, pageRepos }: InsightPageProps) => { {/* insights.opensauced.pizza/pages/{username}/{`{pageId}`}/dashboard */}
-
+
Add Repositories @@ -400,6 +421,17 @@ const InsightPage = ({ edit, insight, pageRepos }: InsightPageProps) => {
+ {edit && ( +
+ updateMember(id, access)} + onDeleteMember={deleteMember} + onAddMember={addMember} + members={[insightOwner, ...members]} + /> +
+ )} + {edit && (
diff --git a/lib/hooks/useInsightMembers.ts b/lib/hooks/useInsightMembers.ts new file mode 100644 index 0000000000..66126acab3 --- /dev/null +++ b/lib/hooks/useInsightMembers.ts @@ -0,0 +1,82 @@ +import useSWR, { Fetcher } from "swr"; +import useSupabaseAuth from "./useSupabaseAuth"; +import publicApiFetcher from "lib/utils/public-api-fetcher"; +import { MemberAccess } from "components/molecules/TeamMembersConfig/team-members-config"; +interface PaginatedInsightMembers { + data: DbInsightMember[]; + meta: Meta; +} + +const useInsightMembers = (insightId: number) => { + const { sessionToken } = useSupabaseAuth(); + + const { data, error, mutate } = useSWR<PaginatedInsightMembers, Error>( + `user/insights/${insightId}/members`, + publicApiFetcher as Fetcher<PaginatedInsightMembers, Error> + ); + + const addMember = async (email: string) => { + const req = await fetch(`${process.env.NEXT_PUBLIC_API_URL}/user/insights/${insightId}/members`, { + method: "POST", + headers: { + "Content-type": "application/json", + Authorization: `Bearer ${sessionToken}` + }, + body: JSON.stringify({ email }) + }); + + if (!req.ok) { + console.log(req.status, req.statusText); + return undefined; + } else { + mutate(); + return req.json(); + } + }; + + const updateMember = async (memberId: string, access: MemberAccess) => { + const req = await fetch(`${process.env.NEXT_PUBLIC_API_URL}/user/insights/${insightId}/members/${memberId}`, { + method: "PATCH", + headers: { + "Content-type": "application/json", + Authorization: `Bearer ${sessionToken}` + }, + body: JSON.stringify({ access }) + }); + + if (!req.ok) { + console.log(req.status, req.statusText); + + return undefined; + } else { + mutate(); + return req.json(); + } + }; + + const deleteMember = async (memberId: string) => { + const req = await fetch(`${process.env.NEXT_PUBLIC_API_URL}/user/insights/${insightId}/members/${memberId}`, { + method: "DELETE", + headers: { + "Content-type": "application/json", + Authorization: `Bearer ${sessionToken}` + } + }); + + if (req.ok) { + mutate(); + } + }; + + return { + data: data?.data ?? [], + isLoading: !error && !data, + isError: !!error, + mutate, + addMember, + updateMember, + deleteMember + }; +}; + +export default useInsightMembers; diff --git a/next-types.d.ts b/next-types.d.ts index 3edb74d72b..2bdbd20c63 100644 --- a/next-types.d.ts +++ b/next-types.d.ts @@ -98,6 +98,18 @@ interface DbInsight { readonly accepted_repo_total: number; } +interface DbInsightMember { + readonly id: string; + readonly insight_id: number; + readonly user_id: number; + readonly name: string; + readonly access: "pending" | "admin" | "edit" | "view"; + readonly created_at: string; + readonly updated_at: string; + readonly deleted_at: string; + readonly invitation_emailed_at: string; + readonly invitation_email: string; +} interface DbUserInsight { readonly id: number; readonly user_id: number; diff --git a/pages/hub/insights/[insightId]/edit.tsx b/pages/hub/insights/[insightId]/edit.tsx index f3ab7388ef..7fa3db4c29 100644 --- a/pages/hub/insights/[insightId]/edit.tsx +++ b/pages/hub/insights/[insightId]/edit.tsx @@ -14,7 +14,7 @@ const EditInsightPage: WithPageLayout = () => { const { insightId } = router.query; const id = insightId as string; const { data: insight, isLoading: insightLoading, isError: insightError } = useInsight(id); - const insightRepos = insight?.repos.map(repo => repo.repo_id); + const insightRepos = insight?.repos.map((repo) => repo.repo_id); const { data: repos } = useRepositories(insightRepos); if (insightLoading) { @@ -29,13 +29,7 @@ const EditInsightPage: WithPageLayout = () => { return <>Unauthorized</>; } - return ( - <InsightPage - edit={true} - insight={insight} - pageRepos={repos} - /> - ); + return <InsightPage edit={true} insight={insight} pageRepos={repos} />; }; EditInsightPage.PageLayout = HubLayout; diff --git a/stories/atoms/selector.stories.tsx b/stories/atoms/selector.stories.tsx index c0e80237cc..c5ca9c70c9 100644 --- a/stories/atoms/selector.stories.tsx +++ b/stories/atoms/selector.stories.tsx @@ -8,6 +8,13 @@ const storyConfig = { export default storyConfig; +const options = [ + { name: "option1", value: "option1" }, + { name: "option2", value: "option2" }, + { name: "option3", value: "option3" }, + { name: "option4", value: "option4" } +]; + //Select Template const SelectTemplate: ComponentStory<typeof Selector> = (args) => <Selector {...args} />; @@ -15,12 +22,12 @@ export const Default = SelectTemplate.bind({}); export const CheckMarks = SelectTemplate.bind({}); Default.args = { - filterOptions: ["option1", "option2", "option3"], + filterOptions: options, selected: "option1" }; CheckMarks.args = { - filterOptions: ["option1", "option2", "option3"], + filterOptions: options, selected: "option1", variation: "check" }; diff --git a/stories/atoms/team-member-row.stories.tsx b/stories/atoms/team-member-row.stories.tsx index bb19612492..c5d7e700cb 100644 --- a/stories/atoms/team-member-row.stories.tsx +++ b/stories/atoms/team-member-row.stories.tsx @@ -20,23 +20,23 @@ Default.args = { className: "max-w-2xl", name: "John Doe", avatarUrl: "https://avatars.githubusercontent.com/u/7252105?v=4", - role: "admin" + access: "admin" }; Editor.args = { className: "max-w-2xl", name: "John Doe", avatarUrl: "https://avatars.githubusercontent.com/u/7252105?v=4", - role: "editor" + access: "edit" }; Viewer.args = { className: "max-w-2xl", name: "John Doe", avatarUrl: "https://avatars.githubusercontent.com/u/7252105?v=4", - role: "viewer" + access: "view" }; Pending.args = { className: "max-w-2xl", name: "John Doe", avatarUrl: "https://avatars.githubusercontent.com/u/7252105?v=4", - role: "pending" + access: "pending" }; diff --git a/stories/atoms/team-members-config.stories.tsx b/stories/atoms/team-members-config.stories.tsx index 38e11cda97..658627ac22 100644 --- a/stories/atoms/team-members-config.stories.tsx +++ b/stories/atoms/team-members-config.stories.tsx @@ -18,17 +18,23 @@ Default.args = { { name: "John Doe", avatarUrl: "https://avatars.githubusercontent.com/u/7252105?v=4", - role: "admin" + access: "admin", + id: "3", + insight_id: 3 }, { name: "John Cena", avatarUrl: "https://avatars.githubusercontent.com/u/7252105?v=4", - role: "editor" + access: "edit", + id: "4", + insight_id: 4 }, { name: "John Wick", avatarUrl: "https://avatars.githubusercontent.com/u/7252105?v=4", - role: "viewer" + access: "view", + id: "5", + insight_id: 5 } ] }; From 55afaf99b016d3ca5a8f526dc17fb16ce7c9bc64 Mon Sep 17 00:00:00 2001 From: OGBONNA SUNDAY <62995161+OgDev-01@users.noreply.github.com> Date: Tue, 18 Apr 2023 21:03:37 +0000 Subject: [PATCH 04/11] chore(minor): release 1.43.0-beta.2 on beta channel [skip ci] MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit ## [1.43.0-beta.2](https://github.com/open-sauced/insights/compare/v1.43.0-beta.1...v1.43.0-beta.2) (2023-04-18) ### πŸ• Features * implement insights team feature ([#1080](https://github.com/open-sauced/insights/issues/1080)) ([5186a60](https://github.com/open-sauced/insights/commit/5186a6089c7dd5f306b7854f5a7706015e33e0f0)) --- CHANGELOG.md | 7 +++++++ npm-shrinkwrap.json | 4 ++-- package.json | 2 +- 3 files changed, 10 insertions(+), 3 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index dd8128d3f4..834bc90d51 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -5,6 +5,13 @@ > All notable changes to this project will be documented in this file +## [1.43.0-beta.2](https://github.com/open-sauced/insights/compare/v1.43.0-beta.1...v1.43.0-beta.2) (2023-04-18) + + +### πŸ• Features + +* implement insights team feature ([#1080](https://github.com/open-sauced/insights/issues/1080)) ([5186a60](https://github.com/open-sauced/insights/commit/5186a6089c7dd5f306b7854f5a7706015e33e0f0)) + ## [1.43.0-beta.1](https://github.com/open-sauced/insights/compare/v1.42.0...v1.43.0-beta.1) (2023-04-18) diff --git a/npm-shrinkwrap.json b/npm-shrinkwrap.json index c7f689d291..7321914a83 100644 --- a/npm-shrinkwrap.json +++ b/npm-shrinkwrap.json @@ -1,12 +1,12 @@ { "name": "@open-sauced/insights", - "version": "1.43.0-beta.1", + "version": "1.43.0-beta.2", "lockfileVersion": 3, "requires": true, "packages": { "": { "name": "@open-sauced/insights", - "version": "1.43.0-beta.1", + "version": "1.43.0-beta.2", "hasInstallScript": true, "license": "MIT", "dependencies": { diff --git a/package.json b/package.json index 69cbf1cd0b..1b1b7497f1 100644 --- a/package.json +++ b/package.json @@ -2,7 +2,7 @@ "name": "@open-sauced/insights", "description": "πŸ•The dashboard for open source discovery.", "keywords": [], - "version": "1.43.0-beta.1", + "version": "1.43.0-beta.2", "author": "TED Vortex <ted.vortex@gmail.com>", "private": true, "license": "MIT", From 83d89bd95212fd6e739343c3b9774217b5433cab Mon Sep 17 00:00:00 2001 From: Brian Douglas <bdougie@users.noreply.github.com> Date: Tue, 18 Apr 2023 19:04:14 -0700 Subject: [PATCH 05/11] fix: adds spacing to contributor highlights container (#1089) Fixes #1057 --- .../organisms/ContributorProfileTab/contributor-profile-tab.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/components/organisms/ContributorProfileTab/contributor-profile-tab.tsx b/components/organisms/ContributorProfileTab/contributor-profile-tab.tsx index 057be6b686..c8f7824b92 100644 --- a/components/organisms/ContributorProfileTab/contributor-profile-tab.tsx +++ b/components/organisms/ContributorProfileTab/contributor-profile-tab.tsx @@ -121,7 +121,7 @@ const ContributorProfileTab = ({ <div> {/* eslint-disable-next-line camelcase */} {highlights.map(({ id, title, highlight, url, created_at }) => ( - <div className="flex flex-col gap-2 lg:flex-row lg:gap-7" key={id}> + <div className="flex flex-col gap-2 lg:flex-row lg:gap-7 mb-6" key={id}> <Link href={`/feed/${id}`}> <p className="text-sm text-light-slate-10">{getFormattedDate(created_at)}</p> </Link> From 4fc471c3223a6cff4bf8cc3c1a4c8a074a56d576 Mon Sep 17 00:00:00 2001 From: Brandon Roberts <robertsbt@gmail.com> Date: Thu, 20 Apr 2023 12:40:32 -0500 Subject: [PATCH 06/11] feat: connect contributor page and graphs to the API (#1072) (#1112) --- .../ContributorCard/contributor-card.tsx | 8 ++--- .../contributor-profile-page.tsx | 20 ++++++++----- .../contributor-profile-tab.tsx | 2 +- lib/hooks/api/useContributorPullRequests.ts | 4 ++- ....ts => useContributorPullRequestsChart.ts} | 30 ++++++------------- lib/hooks/useRepoList.ts | 2 +- lib/utils/get-prs-to-days.ts | 4 +-- pages/user/[username]/index.tsx | 14 +++++---- 8 files changed, 39 insertions(+), 45 deletions(-) rename lib/hooks/{useTopicContributorCommits.ts => useContributorPullRequestsChart.ts} (52%) diff --git a/components/organisms/ContributorCard/contributor-card.tsx b/components/organisms/ContributorCard/contributor-card.tsx index db0beae842..57db88de42 100644 --- a/components/organisms/ContributorCard/contributor-card.tsx +++ b/components/organisms/ContributorCard/contributor-card.tsx @@ -1,6 +1,6 @@ import { useState } from "react"; -import { useTopicContributorCommits } from "lib/hooks/useTopicContributorCommits"; +import { useContributorPullRequestsChart } from "lib/hooks/useContributorPullRequestsChart"; import Card from "components/atoms/Card/card"; import Text from "components/atoms/Typography/text"; @@ -12,10 +12,6 @@ import CardProfile from "components/molecules/CardProfile/card-profile"; import CardRepoList, { RepoList } from "components/molecules/CardRepoList/card-repo-list"; import PullRequestTable from "components/molecules/PullRequestTable/pull-request-table"; -/* - Use this hook in the Contributor Page componenttbecause it has all the mock data: - import useContributorCard from "lib/hooks/useContributorCard"; -*/ export interface ContributorObject { profile: { githubAvatar: string; @@ -38,7 +34,7 @@ const ContributorCard = ({ className, contributor, topic, repositories }: Contri const { profile, repoList, languageList } = contributor; const [showPRs, setShowPRs] = useState(false); - const { chart } = useTopicContributorCommits(profile.githubName, topic, repositories); + const { chart } = useContributorPullRequestsChart(profile.githubName, topic, repositories); return ( <Card className={className && className}> diff --git a/components/organisms/ContributorProfilePage/contributor-profile-page.tsx b/components/organisms/ContributorProfilePage/contributor-profile-page.tsx index 087b8bda4b..06098e2794 100644 --- a/components/organisms/ContributorProfilePage/contributor-profile-page.tsx +++ b/components/organisms/ContributorProfilePage/contributor-profile-page.tsx @@ -8,7 +8,7 @@ import PullRequestTable from "components/molecules/PullRequestTable/pull-request import SkeletonWrapper from "components/atoms/SkeletonLoader/skeleton-wrapper"; import color from "lib/utils/color.json"; -import { useTopicContributorCommits } from "lib/hooks/useTopicContributorCommits"; +import { useContributorPullRequestsChart } from "lib/hooks/useContributorPullRequestsChart"; import { getRelativeDays } from "lib/utils/date-utils"; import Pill from "components/atoms/Pill/pill"; import getPercent from "lib/utils/get-percent"; @@ -17,6 +17,7 @@ import ContributorProfileTab from "../ContributorProfileTab/contributor-profile- import ProfileLanguageChart from "components/molecules/ProfileLanguageChart/profile-language-chart"; import useFollowUser from "lib/hooks/useFollowUser"; import useSupabaseAuth from "lib/hooks/useSupabaseAuth"; +import { getAvatarByUsername } from "lib/utils/github"; const colorKeys = Object.keys(color); interface PrObjectType { @@ -39,7 +40,6 @@ interface ContributorProfilePageProps { githubAvatar?: string; githubName: string; langList: string[]; - repoList: RepoList[]; recentContributionCount: number; user?: DbUser; prTotal: number; @@ -57,7 +57,6 @@ const ContributorProfilePage = ({ githubAvatar, githubName, langList, - repoList, openPrs, prTotal, loading, @@ -74,8 +73,15 @@ const ContributorProfilePage = ({ }); const { user: loggedInUser, signIn } = useSupabaseAuth(); + const { chart, data } = useContributorPullRequestsChart(githubName, "*", repositories); + const repoList: RepoList[] = Array.from(new Set(data.map(prData => prData.full_name))).map(repo => { + const [repoOwner, repoName] = repo.split("/"); - const { chart } = useTopicContributorCommits(githubName, "*", repositories); + return { + repoName: repoName, + repoIcon: getAvatarByUsername(repoOwner) + }; + }); const prsMergedPercentage = getPercent(prTotal, prMerged || 0); const { data: Follower, isError: followError, follow, unFollow } = useFollowUser(user?.login || ""); @@ -164,7 +170,7 @@ const ContributorProfilePage = ({ <div className="flex flex-col justify-between gap-2 lg:flex-row md:gap-12 lg:gap-16"> <div> <span className="text-xs text-light-slate-11">PRs opened</span> - {openPrs ? ( + {openPrs >= 0 ? ( <div className="flex mt-1 lg:justify-center md:pr-8"> <Text className="!text-lg md:!text-xl lg:!text-2xl !text-black !leading-none"> {openPrs} PRs @@ -190,7 +196,7 @@ const ContributorProfilePage = ({ </div> <div> <span className="text-xs text-light-slate-11">Contributed Repos</span> - {recentContributionCount ? ( + {recentContributionCount >= 0 ? ( <div className="flex mt-1 lg:justify-center"> <Text className="!text-lg md:!text-xl lg:!text-2xl !text-black !leading-none"> {`${recentContributionCount} Repo${recentContributionCount > 1 ? "s" : ""}`} @@ -205,7 +211,7 @@ const ContributorProfilePage = ({ <CardLineChart lineChartOption={chart} className="!h-32" /> </div> <div> - <CardRepoList limit={7} repoList={repoList} /> + <CardRepoList limit={7} repoList={repoList} total={repoList.length} /> </div> <div className="mt-6"> diff --git a/components/organisms/ContributorProfileTab/contributor-profile-tab.tsx b/components/organisms/ContributorProfileTab/contributor-profile-tab.tsx index c8f7824b92..f861332a18 100644 --- a/components/organisms/ContributorProfileTab/contributor-profile-tab.tsx +++ b/components/organisms/ContributorProfileTab/contributor-profile-tab.tsx @@ -200,7 +200,7 @@ const ContributorProfileTab = ({ <div className="flex items-end justify-center mt-1"> - </div> )} </div> - <div> + <div className="hidden"> <span className="text-xs text-light-slate-11">Avg PRs velocity</span> {prVelocity ? ( <div className="flex items-center gap-2 lg:justify-center"> diff --git a/lib/hooks/api/useContributorPullRequests.ts b/lib/hooks/api/useContributorPullRequests.ts index 8f34507b4e..08d6514401 100644 --- a/lib/hooks/api/useContributorPullRequests.ts +++ b/lib/hooks/api/useContributorPullRequests.ts @@ -9,7 +9,7 @@ interface PaginatedResponse { readonly meta: Meta; } -const useContributorPullRequests = (contributor: string, topic: string, repoIds: number[] = [], limit = 8) => { +const useContributorPullRequests = (contributor: string, topic: string, repoIds: number[] = [], limit = 8, range = 30) => { const router = useRouter(); const { selectedFilter } = router.query; const filterQuery = getFilterQuery(selectedFilter); @@ -27,6 +27,8 @@ const useContributorPullRequests = (contributor: string, topic: string, repoIds: query.set("repoIds", repoIds.join(",")); } + query.set("range", `${range}`); + const baseEndpoint = `users/${contributor}/prs`; const endpointString = `${baseEndpoint}?${query.toString()}`; diff --git a/lib/hooks/useTopicContributorCommits.ts b/lib/hooks/useContributorPullRequestsChart.ts similarity index 52% rename from lib/hooks/useTopicContributorCommits.ts rename to lib/hooks/useContributorPullRequestsChart.ts index 498ba346df..6102c7f34a 100644 --- a/lib/hooks/useTopicContributorCommits.ts +++ b/lib/hooks/useContributorPullRequestsChart.ts @@ -1,14 +1,8 @@ import { useEffect, useState } from "react"; -import useSWR from "swr"; -import { getCommitsLast30Days } from "lib/utils/get-recent-commits"; -import { useRouter } from "next/router"; -import getFilterQuery from "lib/utils/get-filter-query"; +import getPullRequestsToDays from "lib/utils/get-prs-to-days"; +import useContributorPullRequests from "./api/useContributorPullRequests"; -interface PaginatedTopicCommitResponse { - readonly data: DbRepoCommit[]; - readonly meta: Meta; -} -const useTopicContributorCommits = (contributor: string, topic: string, repoIds: number[] = []) => { +const useContributorPullRequestsChart = (contributor: string, topic: string, repoIds: number[] = []) => { const lineChart = { xAxis: { type: "category", @@ -49,18 +43,11 @@ const useTopicContributorCommits = (contributor: string, topic: string, repoIds: }; const [chart, setChart] = useState(lineChart); - const router = useRouter(); - const baseEndpoint = `${topic}/${contributor}/commits`; - const { selectedFilter } = router.query; - const filterQuery = getFilterQuery(selectedFilter); - const reposQuery = repoIds.length > 0 ? `repoIds=${repoIds.join(",")}`: ""; - const endpointString = `${baseEndpoint}?${filterQuery.replace("&", "")}${reposQuery}`; - - const { data } = useSWR<PaginatedTopicCommitResponse, Error>(contributor ? endpointString : null); + const { data } = useContributorPullRequests(contributor, topic, repoIds, 100); useEffect(() => { - if (data && Array.isArray(data.data)) { - const graphData = getCommitsLast30Days(data.data); + if (data && Array.isArray(data)) { + const graphData = getPullRequestsToDays(data); setChart((prevChart) => ({ ...prevChart, @@ -77,8 +64,9 @@ const useTopicContributorCommits = (contributor: string, topic: string, repoIds: }, [data]); return { - chart + chart, + data }; }; -export { useTopicContributorCommits }; +export { useContributorPullRequestsChart }; diff --git a/lib/hooks/useRepoList.ts b/lib/hooks/useRepoList.ts index 9d73b5c8c5..6abb73cb99 100644 --- a/lib/hooks/useRepoList.ts +++ b/lib/hooks/useRepoList.ts @@ -1,5 +1,5 @@ const useRepoList = (repos: string) => { - return repos.split(",").map((repo) => { + return repos.split(",").filter(rpo => !!rpo).map((repo) => { const [repoOwner, repoName] = repo.split("/"); return { diff --git a/lib/utils/get-prs-to-days.ts b/lib/utils/get-prs-to-days.ts index 512bb1c133..f3ae9b4d7a 100644 --- a/lib/utils/get-prs-to-days.ts +++ b/lib/utils/get-prs-to-days.ts @@ -5,7 +5,7 @@ interface GraphData { y: number; } -const getPullRequestsToDays = (pull_requests: DbRepoPR[]) => { +const getPullRequestsToDays = (pull_requests: DbRepoPR[], range = 30) => { const graphDays = pull_requests.reduce((days: { [name: string]: number }, curr: DbRepoPR) => { const day = differenceInDays(new Date(), new Date(curr.updated_at)); @@ -19,7 +19,7 @@ const getPullRequestsToDays = (pull_requests: DbRepoPR[]) => { }, {}); const days: GraphData[] = []; - for(let d=30;d>=0;d--) { + for(let d=range;d>=0;d--) { days.push({ x: d, y: graphDays[d] || 0 }); } diff --git a/pages/user/[username]/index.tsx b/pages/user/[username]/index.tsx index e4bc1c6650..cfce7e3d0a 100644 --- a/pages/user/[username]/index.tsx +++ b/pages/user/[username]/index.tsx @@ -10,6 +10,7 @@ import SEO from "layouts/SEO/SEO"; import { supabase } from "lib/utils/supabase"; import dynamic from "next/dynamic"; import { getAvatarByUsername } from "lib/utils/github"; +import useContributorPullRequests from "lib/hooks/api/useContributorPullRequests"; // A quick fix to the hydration issue. Should be replaced with a real solution. // Slows down the page's initial client rendering as the component won't be loaded on the server. @@ -28,8 +29,10 @@ const Contributor: WithPageLayout<ContributorSSRProps> = ({ username, user, ogIm const { data: contributor, isError: contributorError } = useSingleContributor(username); + const { data: contributorPRData, meta: contributorPRMeta } = useContributorPullRequests(username, "*", [], 100); const isError = contributorError; - const repoList = useRepoList(contributor[0]?.recent_repo_list || ""); + const repoList = useRepoList(Array.from(new Set(contributorPRData.map(prData => prData.full_name))).join(",")); + const mergedPrs = contributorPRData.filter(prData => prData.merged); const contributorLanguageList = (contributor[0]?.langs || "").split(","); const githubAvatar = getAvatarByUsername(username, 300); @@ -62,17 +65,16 @@ const Contributor: WithPageLayout<ContributorSSRProps> = ({ username, user, ogIm </Head> <div className="w-full"> <ClientOnlyContributorProfilePage - prMerged={contributor[0]?.recent_merged_prs} + prMerged={mergedPrs.length} error={isError} loading={false} user={user} - repoList={repoList} langList={contributorLanguageList} githubName={username} githubAvatar={githubAvatar} - prTotal={contributor[0]?.recent_pr_total} - openPrs={contributor[0]?.recent_opened_prs} - recentContributionCount={contributor[0]?.recent_contribution_count} + prTotal={contributorPRMeta.itemCount} + openPrs={contributorPRData.length} + recentContributionCount={repoList.length} prReviews={contributor[0]?.recent_pr_reviews} prVelocity={contributor[0]?.recent_pr_velocity} /> From e9f5056f9e44ad56d7493c158f8136b9dcdc1174 Mon Sep 17 00:00:00 2001 From: Brandon Roberts <robertsbt@gmail.com> Date: Thu, 20 Apr 2023 17:44:36 +0000 Subject: [PATCH 07/11] chore(minor): release 1.43.0-beta.3 on beta channel [skip ci] MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit ## [1.43.0-beta.3](https://github.com/open-sauced/insights/compare/v1.43.0-beta.2...v1.43.0-beta.3) (2023-04-20) ### πŸ› Bug Fixes * adds spacing to contributor highlights container ([#1089](https://github.com/open-sauced/insights/issues/1089)) ([83d89bd](https://github.com/open-sauced/insights/commit/83d89bd95212fd6e739343c3b9774217b5433cab)), closes [#1057](https://github.com/open-sauced/insights/issues/1057) ### πŸ• Features * connect contributor page and graphs to the API ([#1072](https://github.com/open-sauced/insights/issues/1072)) ([#1112](https://github.com/open-sauced/insights/issues/1112)) ([4fc471c](https://github.com/open-sauced/insights/commit/4fc471c3223a6cff4bf8cc3c1a4c8a074a56d576)) --- CHANGELOG.md | 12 ++++++++++++ npm-shrinkwrap.json | 4 ++-- package.json | 2 +- 3 files changed, 15 insertions(+), 3 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 834bc90d51..0940b546a5 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -5,6 +5,18 @@ > All notable changes to this project will be documented in this file +## [1.43.0-beta.3](https://github.com/open-sauced/insights/compare/v1.43.0-beta.2...v1.43.0-beta.3) (2023-04-20) + + +### πŸ› Bug Fixes + +* adds spacing to contributor highlights container ([#1089](https://github.com/open-sauced/insights/issues/1089)) ([83d89bd](https://github.com/open-sauced/insights/commit/83d89bd95212fd6e739343c3b9774217b5433cab)), closes [#1057](https://github.com/open-sauced/insights/issues/1057) + + +### πŸ• Features + +* connect contributor page and graphs to the API ([#1072](https://github.com/open-sauced/insights/issues/1072)) ([#1112](https://github.com/open-sauced/insights/issues/1112)) ([4fc471c](https://github.com/open-sauced/insights/commit/4fc471c3223a6cff4bf8cc3c1a4c8a074a56d576)) + ## [1.43.0-beta.2](https://github.com/open-sauced/insights/compare/v1.43.0-beta.1...v1.43.0-beta.2) (2023-04-18) diff --git a/npm-shrinkwrap.json b/npm-shrinkwrap.json index 7321914a83..c1ddfc913b 100644 --- a/npm-shrinkwrap.json +++ b/npm-shrinkwrap.json @@ -1,12 +1,12 @@ { "name": "@open-sauced/insights", - "version": "1.43.0-beta.2", + "version": "1.43.0-beta.3", "lockfileVersion": 3, "requires": true, "packages": { "": { "name": "@open-sauced/insights", - "version": "1.43.0-beta.2", + "version": "1.43.0-beta.3", "hasInstallScript": true, "license": "MIT", "dependencies": { diff --git a/package.json b/package.json index 1b1b7497f1..2d77bfac89 100644 --- a/package.json +++ b/package.json @@ -2,7 +2,7 @@ "name": "@open-sauced/insights", "description": "πŸ•The dashboard for open source discovery.", "keywords": [], - "version": "1.43.0-beta.2", + "version": "1.43.0-beta.3", "author": "TED Vortex <ted.vortex@gmail.com>", "private": true, "license": "MIT", From e51c51e4b4f6bc21fa171495578993325c3427ba Mon Sep 17 00:00:00 2001 From: Brandon Roberts <robertsbt@gmail.com> Date: Thu, 20 Apr 2023 14:47:31 -0500 Subject: [PATCH 08/11] feat: connect contributors page to API (#1113) --- .../card-horizontal-bar-chart.tsx | 4 +- .../PullRequestTable/pull-request-table.tsx | 5 +- components/molecules/RepoRow/repo-row.tsx | 4 +- .../ContributorCard/contributor-card.tsx | 45 +++++++++--- .../organisms/Contributors/contributors.tsx | 46 +++++-------- components/organisms/Dashboard/dashboard.tsx | 4 +- .../organisms/Repositories/repositories.tsx | 4 +- lib/hooks/api/useContributors.ts | 69 +++++++++++++++++++ lib/hooks/api/usePullRequests.ts | 8 ++- lib/hooks/api/useRepositories.ts | 6 +- lib/hooks/api/useRepositoryPullRequests.ts | 3 +- lib/hooks/useContributionsList.ts | 31 --------- lib/hooks/useContributorPullRequestsChart.ts | 7 +- lib/hooks/useNav.ts | 9 +-- lib/hooks/useTopicContributions.ts | 42 ----------- next-types.d.ts | 2 + .../organisms/contributor-card.stories.tsx | 4 +- 17 files changed, 157 insertions(+), 136 deletions(-) create mode 100644 lib/hooks/api/useContributors.ts delete mode 100644 lib/hooks/useContributionsList.ts delete mode 100644 lib/hooks/useTopicContributions.ts diff --git a/components/molecules/CardHorizontalBarChart/card-horizontal-bar-chart.tsx b/components/molecules/CardHorizontalBarChart/card-horizontal-bar-chart.tsx index 0698fa037b..b8c627ff56 100644 --- a/components/molecules/CardHorizontalBarChart/card-horizontal-bar-chart.tsx +++ b/components/molecules/CardHorizontalBarChart/card-horizontal-bar-chart.tsx @@ -29,13 +29,15 @@ const CardHorizontalBarChart = ({ languageList, withDescription }: CardHorizonta // used this state to calculate thte percentage of each language const [percentage, setPercentage] = useState<any>(0); - const [descriptText, setDescriptText] = useState(sortedLangArray[0].languageName); + const [descriptText, setDescriptText] = useState(sortedLangArray[0]?.languageName || "javascript"); const handleChangeDescriptText = (descriptText: string) => { setDescriptText(descriptText); }; useEffect(() => { + if (sortedLangArray.length === 0) return; + const totalSumOfFirstFivePercentage = sortedLangArray .slice(0, 4) .map((lang) => lang.percentageUsed) diff --git a/components/molecules/PullRequestTable/pull-request-table.tsx b/components/molecules/PullRequestTable/pull-request-table.tsx index 0a7589290b..4451e8c5a3 100644 --- a/components/molecules/PullRequestTable/pull-request-table.tsx +++ b/components/molecules/PullRequestTable/pull-request-table.tsx @@ -19,10 +19,11 @@ interface CardTableProps { repositories?: number[]; limit?: number; isHoverCard?: boolean; + range?: number; } -const PullRequestTable = ({ contributor, topic, repositories, limit, isHoverCard }: CardTableProps): JSX.Element => { - const { data, isLoading } = useContributorPullRequests(contributor, topic, repositories, limit); +const PullRequestTable = ({ contributor, topic, repositories, limit, isHoverCard, range }: CardTableProps): JSX.Element => { + const { data, isLoading } = useContributorPullRequests(contributor, topic, repositories, limit, range); return data.length > 0 ? ( <> diff --git a/components/molecules/RepoRow/repo-row.tsx b/components/molecules/RepoRow/repo-row.tsx index 93909c724f..cf963d52b5 100644 --- a/components/molecules/RepoRow/repo-row.tsx +++ b/components/molecules/RepoRow/repo-row.tsx @@ -24,6 +24,7 @@ import { getAvatarByUsername } from "lib/utils/github"; import useRepositoryPullRequests from "lib/hooks/api/useRepositoryPullRequests"; import getPullRequestsToDays from "lib/utils/get-prs-to-days"; import getPullRequestsContributors from "lib/utils/get-pr-contributors"; +import useStore from "lib/store"; interface RepoProps { repo: RepositoriesRows; @@ -92,7 +93,8 @@ const RepoRow = ({ repo, topic, userPage, selected, handleOnSelectRepo }: RepoPr const ownerAvatar = getAvatarByUsername(fullName.split("/")[0]); const { user } = useSupabaseAuth(); - const { data: repositoryPullRequests } = useRepositoryPullRequests(repo.full_name, 100); + const range = useStore((state) => state.range); + const { data: repositoryPullRequests } = useRepositoryPullRequests(repo.full_name, 100, range); const totalPrs = getTotalPrs(openPrsCount, mergedPrsCount, closedPrsCount, draftPrsCount); const prsMergedPercentage = getPercent(totalPrs, mergedPrsCount || 0); const spamPrsPercentage = getPrsSpam(totalPrs, spamPrsCount || 0); diff --git a/components/organisms/ContributorCard/contributor-card.tsx b/components/organisms/ContributorCard/contributor-card.tsx index 57db88de42..bdcf9aa299 100644 --- a/components/organisms/ContributorCard/contributor-card.tsx +++ b/components/organisms/ContributorCard/contributor-card.tsx @@ -1,7 +1,5 @@ import { useState } from "react"; -import { useContributorPullRequestsChart } from "lib/hooks/useContributorPullRequestsChart"; - import Card from "components/atoms/Card/card"; import Text from "components/atoms/Typography/text"; import CardHorizontalBarChart, { @@ -12,15 +10,19 @@ import CardProfile from "components/molecules/CardProfile/card-profile"; import CardRepoList, { RepoList } from "components/molecules/CardRepoList/card-repo-list"; import PullRequestTable from "components/molecules/PullRequestTable/pull-request-table"; +import { useContributorPullRequestsChart } from "lib/hooks/useContributorPullRequestsChart"; +import color from "lib/utils/color.json"; +import { getAvatarByUsername } from "lib/utils/github"; +import useRepositories from "lib/hooks/api/useRepositories"; + +const colorKeys = Object.keys(color); + export interface ContributorObject { profile: { githubAvatar: string; githubName: string; - totalPRs: number; dateOfFirstPR: string; }; - repoList: RepoList[]; - languageList: LanguageObject[]; } interface ContributorCardProps { @@ -28,19 +30,40 @@ interface ContributorCardProps { contributor: ContributorObject; topic: string; repositories?: number[]; + range?: number; } -const ContributorCard = ({ className, contributor, topic, repositories }: ContributorCardProps) => { - const { profile, repoList, languageList } = contributor; +const ContributorCard = ({ className, contributor, topic, repositories, range }: ContributorCardProps) => { + const { profile } = contributor; const [showPRs, setShowPRs] = useState(false); - const { chart } = useContributorPullRequestsChart(profile.githubName, topic, repositories); + const { chart, data, meta } = useContributorPullRequestsChart(profile.githubName, topic, repositories, range); + const repoList: RepoList[] = Array.from(new Set(data.map(prData => prData.full_name))).map(repo => { + const [repoOwner, repoName] = repo.split("/"); + + return { + repoName: repoName, + repoIcon: getAvatarByUsername(repoOwner) + }; + }); + const repoIds = data.map(pr => pr.repo_id); + const { data: repoData } = useRepositories(repoIds); + const contributorLanguageList = Array.from(new Set(repoData.map(repo => repo.language).filter(language => !!language))); + const languageList: LanguageObject[] = contributorLanguageList + .map((language) => { + const preparedLanguageKey = colorKeys.find((key) => key.toLowerCase() === language.toLowerCase()); + + return { + languageName: preparedLanguageKey ? preparedLanguageKey.toLowerCase() : language, + percentageUsed: Math.round((1 / contributorLanguageList.length) * 100) + }; + }); return ( <Card className={className && className}> <div className="flex flex-col gap-3"> <div className="flex w-full justify-between items-center gap-2"> - <CardProfile {...profile} /> + <CardProfile {...profile} totalPRs={meta.itemCount} /> <div> <CardHorizontalBarChart withDescription={false} languageList={languageList} /> </div> @@ -48,10 +71,10 @@ const ContributorCard = ({ className, contributor, topic, repositories }: Contri <div className="h-[110px] overflow-hidden"> <CardLineChart lineChartOption={chart} /> </div> - <CardRepoList repoList={repoList} /> + <CardRepoList repoList={repoList} total={repoList.length} /> {showPRs ? ( - <PullRequestTable contributor={profile.githubName} topic={topic} repositories={repositories} /> + <PullRequestTable contributor={profile.githubName} topic={topic} repositories={repositories} range={range} /> ) : null} <div className="flex w-full justify-center"> diff --git a/components/organisms/Contributors/contributors.tsx b/components/organisms/Contributors/contributors.tsx index cdaa167871..08e8ec3321 100644 --- a/components/organisms/Contributors/contributors.tsx +++ b/components/organisms/Contributors/contributors.tsx @@ -7,13 +7,11 @@ import TableHeader from "components/molecules/TableHeader/table-header"; import Select from "components/atoms/Select/custom-select"; import { calcDistanceFromToday } from "lib/utils/date-utils"; -import color from "lib/utils/color.json"; -import { useTopicContributions } from "lib/hooks/useTopicContributions"; import ContributorCard from "../ContributorCard/contributor-card"; import SkeletonWrapper from "components/atoms/SkeletonLoader/skeleton-wrapper"; - -const colorKeys = Object.keys(color); +import useContributors from "lib/hooks/api/useContributors"; +import { getAvatarByUsername } from "lib/utils/github"; interface ContributorProps { repositories?: number[]; @@ -23,41 +21,28 @@ const Contributors = ({ repositories }: ContributorProps): JSX.Element => { const router = useRouter(); const { filterName } = router.query; const topic = filterName as string; - const { data, setLimit, meta, setPage, page, isError, isLoading } = useTopicContributions(10, repositories); - const range = useStore((state) => state.range); const store = useStore(); + const range = useStore((state) => state.range); + const { data, meta, setPage, setLimit, isError, isLoading } = useContributors(10, repositories, range); + + const contributors = data.map(pr => { + return { + host_login: pr.author_login, + first_commit_time: pr.created_at + }; + }); const contributorArray = isError ? [] - : data?.map((contributor) => { - const timeSinceFirstCommit = calcDistanceFromToday(new Date(parseInt(contributor.first_commit_time))); - const contributorLanguageList = (contributor.langs || "").split(","); - const repoList = (contributor.recent_repo_list || "").split(",").map((repo) => { - const [repoOwner, repoName] = repo.split("/"); - - return { - repoName, - repoIcon: `https://www.github.com/${repoOwner ?? "github"}.png?size=460` - }; - }); - const languageList = contributorLanguageList.map((language) => { - const preparedLanguageKey = colorKeys.find((key) => key.toLowerCase() === language.toLowerCase()); - - return { - languageName: preparedLanguageKey ? preparedLanguageKey : language, - percentageUsed: Math.round((1 / contributorLanguageList.length) * 100) - }; - }); + : contributors.map((contributor) => { + const timeSinceFirstCommit = calcDistanceFromToday(new Date(contributor.first_commit_time)); return { profile: { - githubAvatar: `https://www.github.com/${contributor.host_login}.png?size=60`, + githubAvatar: getAvatarByUsername(contributor.host_login), githubName: contributor.host_login, - totalPRs: contributor.recent_pr_total, dateOfFirstPR: timeSinceFirstCommit - }, - languageList, - repoList + } }; }); @@ -83,6 +68,7 @@ const Contributors = ({ repositories }: ContributorProps): JSX.Element => { contributor={{ ...contributor }} topic={topic} repositories={repositories} + range={range} /> ))} </div> diff --git a/components/organisms/Dashboard/dashboard.tsx b/components/organisms/Dashboard/dashboard.tsx index 6dd5e1fbfa..0443d54d49 100644 --- a/components/organisms/Dashboard/dashboard.tsx +++ b/components/organisms/Dashboard/dashboard.tsx @@ -23,7 +23,7 @@ interface DashboardProps { const Dashboard = ({ repositories }: DashboardProps): JSX.Element => { const { data: insightsData, isLoading } = useInsights(repositories); - const { data: prData, isError: prError } = usePullRequests(undefined, repositories); + const { data: prData, meta: prMeta, isError: prError } = usePullRequests(undefined, repositories); const [showBots, setShowBots] = useState(false); const isMobile = useMediaQuery("(max-width:720px)"); const [prStateFilter, setPrStateFilter] = useState<PrStatusFilter>("all"); @@ -99,7 +99,7 @@ const Dashboard = ({ repositories }: DashboardProps): JSX.Element => { metricIncreases={compare1.allContributors - compare2.allContributors >= 0} increased={compare1.allContributors - compare2.allContributors >= 0} numChanged={humanizeNumber(Math.abs(compare1.allContributors - compare2.allContributors), "abbreviation")} - value={humanizeNumber(compare1.allContributors, "comma")} + value={humanizeNumber(prMeta.itemCount, "comma")} contributors={contributorData} isLoading={isLoading} /> diff --git a/components/organisms/Repositories/repositories.tsx b/components/organisms/Repositories/repositories.tsx index d3e5a87486..3466252313 100644 --- a/components/organisms/Repositories/repositories.tsx +++ b/components/organisms/Repositories/repositories.tsx @@ -10,12 +10,12 @@ import TableHeader from "components/molecules/TableHeader/table-header"; import useRepositories from "lib/hooks/api/useRepositories"; import useSupabaseAuth from "lib/hooks/useSupabaseAuth"; +import useStore from "lib/store"; import RepositoriesTable, { classNames, RepositoriesRows } from "../RepositoriesTable/repositories-table"; import RepoNotIndexed from "./repository-not-indexed"; import Checkbox from "components/atoms/Checkbox/checkbox"; import Button from "components/atoms/Button/button"; -import useStore from "lib/store"; interface RepositoriesProps { repositories?: number[]; @@ -36,7 +36,7 @@ const Repositories = ({ repositories }: RepositoriesProps): JSX.Element => { isLoading: repoListIsLoading, setPage, setLimit - } = useRepositories(repositories); + } = useRepositories(repositories, range); const filteredRepoNotIndexed = selectedFilter && !repoListIsLoading && !repoListIsError && repoListData.length === 0; const [selectedRepos, setSelectedRepos] = useState<DbRepo[]>([]); diff --git a/lib/hooks/api/useContributors.ts b/lib/hooks/api/useContributors.ts new file mode 100644 index 0000000000..336d593759 --- /dev/null +++ b/lib/hooks/api/useContributors.ts @@ -0,0 +1,69 @@ +import { useState } from "react"; +import useSWR, { Fetcher } from "swr"; +import { useRouter } from "next/router"; + +import publicApiFetcher from "lib/utils/public-api-fetcher"; +import getFilterQuery from "lib/utils/get-filter-query"; + +interface PaginatedResponse { + readonly data: DbRepoPR[]; + readonly meta: Meta; +} + +/** + * Fetch contributors based on pull requests. + * Replace with contributors API endpoint when available. + * + * @param intialLimit + * @param repoIds + * @param range + * @returns + */ +const useContributors = (intialLimit = 10, repoIds: number[] = [], range = 30) => { + const router = useRouter(); + const [page, setPage] = useState(1); + const [limit, setLimit] = useState(intialLimit); + const { filterName, selectedFilter } = router.query; + const topic = filterName as string; + const filterQuery = getFilterQuery(selectedFilter); + const query = new URLSearchParams(filterQuery); + + if (Number.isNaN(Number(topic))) { + query.set("topic", topic); + } + + if (page) { + query.set("page", `${page}`); + } + + if (limit) { + query.set("limit", `${limit}`); + } + + if (repoIds?.length > 0) { + query.set("repoIds", repoIds.join(",")); + } + + query.set("range", `${range}`); + + const baseEndpoint = "prs/search"; + const endpointString = `${baseEndpoint}?${query.toString()}`; + + const { data, error, mutate } = useSWR<PaginatedResponse, Error>( + endpointString, + publicApiFetcher as Fetcher<PaginatedResponse, Error> + ); + + return { + data: data?.data ?? [], + meta: data?.meta ?? { itemCount: 0, limit: 0, page: 0, hasNextPage: false, hasPreviousPage: false, pageCount: 0 }, + isLoading: !error && !data, + isError: !!error, + mutate, + page, + setPage, + setLimit + }; +}; + +export default useContributors; diff --git a/lib/hooks/api/usePullRequests.ts b/lib/hooks/api/usePullRequests.ts index 30a4f008bd..b17c104022 100644 --- a/lib/hooks/api/usePullRequests.ts +++ b/lib/hooks/api/usePullRequests.ts @@ -10,9 +10,10 @@ interface PaginatedResponse { readonly meta: Meta; } -const usePullRequests = (limit = 1000, repoIds: number[] = []) => { +const usePullRequests = (intialLimit = 1000, repoIds: number[] = [], range = 30) => { const router = useRouter(); const [page, setPage] = useState(1); + const [limit, setLimit] = useState(intialLimit); const { filterName, selectedFilter } = router.query; const topic = filterName as string; const filterQuery = getFilterQuery(selectedFilter); @@ -34,6 +35,8 @@ const usePullRequests = (limit = 1000, repoIds: number[] = []) => { query.set("repoIds", repoIds.join(",")); } + query.set("range", `${range}`); + const baseEndpoint = "prs/search"; const endpointString = `${baseEndpoint}?${query.toString()}`; @@ -49,7 +52,8 @@ const usePullRequests = (limit = 1000, repoIds: number[] = []) => { isError: !!error, mutate, page, - setPage + setPage, + setLimit }; }; diff --git a/lib/hooks/api/useRepositories.ts b/lib/hooks/api/useRepositories.ts index e8ab070d8c..376e3db55b 100644 --- a/lib/hooks/api/useRepositories.ts +++ b/lib/hooks/api/useRepositories.ts @@ -10,7 +10,7 @@ interface PaginatedResponse { readonly meta: Meta; } -const useRepositories = (repoIds: number[] = []) => { +const useRepositories = (repoIds: number[] = [], range = 30) => { const router = useRouter(); const [page, setPage] = useState(1); const [limit, setLimit] = useState(10); @@ -31,6 +31,10 @@ const useRepositories = (repoIds: number[] = []) => { query.set("limit", `${limit}`); } + if (range) { + query.set("range", `${range}`); + } + if (repoIds?.length > 0) { query.set("repoIds", repoIds.join(",")); } diff --git a/lib/hooks/api/useRepositoryPullRequests.ts b/lib/hooks/api/useRepositoryPullRequests.ts index beaf81d378..4cb033c1b4 100644 --- a/lib/hooks/api/useRepositoryPullRequests.ts +++ b/lib/hooks/api/useRepositoryPullRequests.ts @@ -8,7 +8,7 @@ interface PaginatedResponse { readonly meta: Meta; } -const useRepositoryPullRequests = (fullName: string, limit = 10) => { +const useRepositoryPullRequests = (fullName: string, limit = 10, range = 30) => { const router = useRouter(); const { filterName } = router.query; const topic = filterName as string; @@ -21,6 +21,7 @@ const useRepositoryPullRequests = (fullName: string, limit = 10) => { query.set("repo", fullName); query.set("page", "1"); query.set("limit", `${limit}`); + query.set("range", `${range}`); const baseEndpoint = "prs/search"; const endpointString = `${baseEndpoint}?${query.toString()}`; diff --git a/lib/hooks/useContributionsList.ts b/lib/hooks/useContributionsList.ts deleted file mode 100644 index c9a5289782..0000000000 --- a/lib/hooks/useContributionsList.ts +++ /dev/null @@ -1,31 +0,0 @@ -import useSWR from "swr"; -import useStore from "lib/store"; - -interface PaginatedContributorsResponse { - readonly data: DbContribution[]; - readonly meta: Meta; -} - -const useContributionsList = (repoId: string, limit = "", orderBy = "") => { - const range = useStore(state => state.range); - - //The endpoint for all Hacktoberfest contributions doesn't exist yet so will substitute this for now - const baseEndpoint = `repos/${repoId}/contributions`; - const limitQuery = `orderBy=last_commit_time${limit === "" ? limit : `&limit=${limit}`}`; - const orderByQuery = orderBy ? `&updated_at=${orderBy}` : ""; - const rangeQuery = range ? `&range=${range}` : ""; - const endpointString = `${baseEndpoint}?${limitQuery}${orderByQuery}${rangeQuery}`; - - - const { data, error, mutate } = useSWR<PaginatedContributorsResponse, Error>(repoId ? endpointString : null); - - return { - data: data?.data ?? [], - meta: data?.meta ?? { itemCount: 0 }, - isLoading: !error && !data, - isError: !!error, - mutate - }; -}; - -export {useContributionsList}; diff --git a/lib/hooks/useContributorPullRequestsChart.ts b/lib/hooks/useContributorPullRequestsChart.ts index 6102c7f34a..d0baa81753 100644 --- a/lib/hooks/useContributorPullRequestsChart.ts +++ b/lib/hooks/useContributorPullRequestsChart.ts @@ -2,7 +2,7 @@ import { useEffect, useState } from "react"; import getPullRequestsToDays from "lib/utils/get-prs-to-days"; import useContributorPullRequests from "./api/useContributorPullRequests"; -const useContributorPullRequestsChart = (contributor: string, topic: string, repoIds: number[] = []) => { +const useContributorPullRequestsChart = (contributor: string, topic: string, repoIds: number[] = [], range = 30) => { const lineChart = { xAxis: { type: "category", @@ -43,7 +43,7 @@ const useContributorPullRequestsChart = (contributor: string, topic: string, rep }; const [chart, setChart] = useState(lineChart); - const { data } = useContributorPullRequests(contributor, topic, repoIds, 100); + const { data, meta } = useContributorPullRequests(contributor, topic, repoIds, 100, range); useEffect(() => { if (data && Array.isArray(data)) { @@ -65,7 +65,8 @@ const useContributorPullRequestsChart = (contributor: string, topic: string, rep return { chart, - data + data, + meta }; }; diff --git a/lib/hooks/useNav.ts b/lib/hooks/useNav.ts index 70fc357570..95c09e3411 100644 --- a/lib/hooks/useNav.ts +++ b/lib/hooks/useNav.ts @@ -1,12 +1,13 @@ import { useRouter } from "next/router"; +import useStore from "lib/store"; import useRepositories from "./api/useRepositories"; -import { useTopicContributions } from "./useTopicContributions"; - +import useContributors from "./api/useContributors"; const useNav = (repositories: number[] = []) => { const router = useRouter(); - const { meta: repoMetaData } = useRepositories(repositories); - const { meta: conMetaData } = useTopicContributions(10, repositories); + const range = useStore(state => state.range); + const { meta: repoMetaData } = useRepositories(repositories, range); + const { meta: conMetaData } = useContributors(10, repositories, range); const defaultTools = [ { diff --git a/lib/hooks/useTopicContributions.ts b/lib/hooks/useTopicContributions.ts deleted file mode 100644 index 9129a97e67..0000000000 --- a/lib/hooks/useTopicContributions.ts +++ /dev/null @@ -1,42 +0,0 @@ -import { useRouter } from "next/router"; -import { useState } from "react"; -import useSWR from "swr"; -import useStore from "lib/store"; -import getFilterQuery from "lib/utils/get-filter-query"; - -interface PaginatedContributorsResponse { - readonly data: DbContribution[]; - readonly meta: Meta; -} - -const useTopicContributions = (initialLimit = 10, repoIds: number[] = []) => { - const router = useRouter(); - const range = useStore(state => state.range); - const { filterName, selectedFilter } = router.query; - const topic = filterName as string; - const [page, setPage] = useState(1); - const [limit, setLimit] = useState(initialLimit); - - const baseEndpoint = `${topic}/contributions`; - const pageQuery = page ? `page=${page}` : ""; - const filterQuery = getFilterQuery(selectedFilter); - const limitQuery = limit ? `&limit=${limit}` : ""; - const reposQuery = repoIds.length > 0 ? `&repoIds=${repoIds.join(",")}`: ""; - const rangeQuery = range ? `&range=${range}` : ""; - const endpointString = `${baseEndpoint}?${pageQuery}${filterQuery}${limitQuery}${reposQuery}${rangeQuery}`; - - const { data, error, mutate } = useSWR<PaginatedContributorsResponse, Error>(topic ? endpointString : null); - - return { - data: data?.data ?? [], - meta: data?.meta ?? { itemCount: 0, limit: 0, page: 0, hasNextPage: false, hasPreviousPage: false, pageCount: 0 }, - isLoading: !error && !data, - isError: !!error, - mutate, - page, - setPage, - setLimit - }; -}; - -export { useTopicContributions }; diff --git a/next-types.d.ts b/next-types.d.ts index 2bdbd20c63..dade5250a5 100644 --- a/next-types.d.ts +++ b/next-types.d.ts @@ -15,6 +15,7 @@ interface DbRepo { readonly spam_prs_count?: number; readonly pr_velocity_count?: number; readonly churnTotalCount?: number; + readonly language: string; } interface DbRepoPR { @@ -33,6 +34,7 @@ interface DbRepoPR { readonly additions: number; readonly deletions: number; readonly changed_files: number; + readonly repo_id: number; } interface DbFollowUser { diff --git a/stories/organisms/contributor-card.stories.tsx b/stories/organisms/contributor-card.stories.tsx index 2328e00a90..2f369922b0 100644 --- a/stories/organisms/contributor-card.stories.tsx +++ b/stories/organisms/contributor-card.stories.tsx @@ -141,8 +141,6 @@ export const Default = ContributorCardTemplate.bind({}); Default.args = { contributor: { - profile: profile, - languageList: languageList, - repoList: repoList + profile: profile } }; From a8ba65f19b7d78e18030d044725faa5a5a529c91 Mon Sep 17 00:00:00 2001 From: Brandon Roberts <robertsbt@gmail.com> Date: Thu, 20 Apr 2023 19:52:26 +0000 Subject: [PATCH 09/11] chore(minor): release 1.43.0-beta.4 on beta channel [skip ci] MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit ## [1.43.0-beta.4](https://github.com/open-sauced/insights/compare/v1.43.0-beta.3...v1.43.0-beta.4) (2023-04-20) ### πŸ• Features * connect contributors page to API ([#1113](https://github.com/open-sauced/insights/issues/1113)) ([e51c51e](https://github.com/open-sauced/insights/commit/e51c51e4b4f6bc21fa171495578993325c3427ba)) --- CHANGELOG.md | 7 +++++++ npm-shrinkwrap.json | 4 ++-- package.json | 2 +- 3 files changed, 10 insertions(+), 3 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 0940b546a5..0cc4ddd4cf 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -5,6 +5,13 @@ > All notable changes to this project will be documented in this file +## [1.43.0-beta.4](https://github.com/open-sauced/insights/compare/v1.43.0-beta.3...v1.43.0-beta.4) (2023-04-20) + + +### πŸ• Features + +* connect contributors page to API ([#1113](https://github.com/open-sauced/insights/issues/1113)) ([e51c51e](https://github.com/open-sauced/insights/commit/e51c51e4b4f6bc21fa171495578993325c3427ba)) + ## [1.43.0-beta.3](https://github.com/open-sauced/insights/compare/v1.43.0-beta.2...v1.43.0-beta.3) (2023-04-20) diff --git a/npm-shrinkwrap.json b/npm-shrinkwrap.json index c1ddfc913b..d74b9e83d0 100644 --- a/npm-shrinkwrap.json +++ b/npm-shrinkwrap.json @@ -1,12 +1,12 @@ { "name": "@open-sauced/insights", - "version": "1.43.0-beta.3", + "version": "1.43.0-beta.4", "lockfileVersion": 3, "requires": true, "packages": { "": { "name": "@open-sauced/insights", - "version": "1.43.0-beta.3", + "version": "1.43.0-beta.4", "hasInstallScript": true, "license": "MIT", "dependencies": { diff --git a/package.json b/package.json index 2d77bfac89..75f3e947b6 100644 --- a/package.json +++ b/package.json @@ -2,7 +2,7 @@ "name": "@open-sauced/insights", "description": "πŸ•The dashboard for open source discovery.", "keywords": [], - "version": "1.43.0-beta.3", + "version": "1.43.0-beta.4", "author": "TED Vortex <ted.vortex@gmail.com>", "private": true, "license": "MIT", From 483f38c54c6c707873b9e63c78b751bc5a994494 Mon Sep 17 00:00:00 2001 From: Brandon Roberts <robertsbt@gmail.com> Date: Thu, 20 Apr 2023 15:03:27 -0500 Subject: [PATCH 10/11] fix: only redirect on contributor profile if login is defined (#1114) --- .../organisms/ContributorProfileTab/contributor-profile-tab.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/components/organisms/ContributorProfileTab/contributor-profile-tab.tsx b/components/organisms/ContributorProfileTab/contributor-profile-tab.tsx index f861332a18..8ad2620954 100644 --- a/components/organisms/ContributorProfileTab/contributor-profile-tab.tsx +++ b/components/organisms/ContributorProfileTab/contributor-profile-tab.tsx @@ -69,7 +69,7 @@ const ContributorProfileTab = ({ useEffect(() => { setInputVisible(highlights && highlights.length !== 0 ? true : false); - if (currentPathname) { + if (login && currentPathname) { router.push(`/user/${login}/${currentPathname}`); } }, [highlights]); From c27df895bb3dde76b9d12f443056db6691cbe603 Mon Sep 17 00:00:00 2001 From: Brandon Roberts <robertsbt@gmail.com> Date: Thu, 20 Apr 2023 20:11:11 +0000 Subject: [PATCH 11/11] chore(patch): release 1.43.0-beta.5 on beta channel [skip ci] MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit ## [1.43.0-beta.5](https://github.com/open-sauced/insights/compare/v1.43.0-beta.4...v1.43.0-beta.5) (2023-04-20) ### πŸ› Bug Fixes * only redirect on contributor profile if login is defined ([#1114](https://github.com/open-sauced/insights/issues/1114)) ([483f38c](https://github.com/open-sauced/insights/commit/483f38c54c6c707873b9e63c78b751bc5a994494)) --- CHANGELOG.md | 7 +++++++ npm-shrinkwrap.json | 4 ++-- package.json | 2 +- 3 files changed, 10 insertions(+), 3 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 0cc4ddd4cf..61bae595e8 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -5,6 +5,13 @@ > All notable changes to this project will be documented in this file +## [1.43.0-beta.5](https://github.com/open-sauced/insights/compare/v1.43.0-beta.4...v1.43.0-beta.5) (2023-04-20) + + +### πŸ› Bug Fixes + +* only redirect on contributor profile if login is defined ([#1114](https://github.com/open-sauced/insights/issues/1114)) ([483f38c](https://github.com/open-sauced/insights/commit/483f38c54c6c707873b9e63c78b751bc5a994494)) + ## [1.43.0-beta.4](https://github.com/open-sauced/insights/compare/v1.43.0-beta.3...v1.43.0-beta.4) (2023-04-20) diff --git a/npm-shrinkwrap.json b/npm-shrinkwrap.json index d74b9e83d0..22fb7a58ad 100644 --- a/npm-shrinkwrap.json +++ b/npm-shrinkwrap.json @@ -1,12 +1,12 @@ { "name": "@open-sauced/insights", - "version": "1.43.0-beta.4", + "version": "1.43.0-beta.5", "lockfileVersion": 3, "requires": true, "packages": { "": { "name": "@open-sauced/insights", - "version": "1.43.0-beta.4", + "version": "1.43.0-beta.5", "hasInstallScript": true, "license": "MIT", "dependencies": { diff --git a/package.json b/package.json index 75f3e947b6..7aa1d52b6c 100644 --- a/package.json +++ b/package.json @@ -2,7 +2,7 @@ "name": "@open-sauced/insights", "description": "πŸ•The dashboard for open source discovery.", "keywords": [], - "version": "1.43.0-beta.4", + "version": "1.43.0-beta.5", "author": "TED Vortex <ted.vortex@gmail.com>", "private": true, "license": "MIT",