From c58cd3e4547b4732675b0213d9cf5e8888e79d24 Mon Sep 17 00:00:00 2001 From: Brandon Roberts Date: Tue, 10 Oct 2023 12:14:48 -0500 Subject: [PATCH 01/21] chore: update occurrences of insights to app (#1850) --- .github/workflows/release.yml | 2 +- README.md | 2 +- .../molecules/RecommendedRepoCard/recommended-repo-card.tsx | 2 +- components/organisms/InsightPage/InsightPage.tsx | 1 - package.json | 2 +- pages/_app.tsx | 2 +- stories/atoms/text-input.stories.tsx | 2 +- stories/atoms/typography-wrapper.stories.tsx | 4 ++-- tests/lib/utils/github.test.ts | 2 +- 9 files changed, 9 insertions(+), 10 deletions(-) diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index 21277a299c..31a8c990d8 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -79,7 +79,7 @@ jobs: release: environment: name: ${{ needs.setup.outputs.DEPLOY_ENVIRONMENT }} - url: https://${{ needs.setup.outputs.DEPLOY_SUBDOMAIN }}insights.opensauced.pizza + url: https://${{ needs.setup.outputs.DEPLOY_SUBDOMAIN }}app.opensauced.pizza name: Semantic release needs: - setup diff --git a/README.md b/README.md index 9dec85eeee..a15af1fd25 100644 --- a/README.md +++ b/README.md @@ -1,7 +1,7 @@

Open Sauced -

πŸ• insights.opensauced.pizza πŸ•

+

πŸ• app.opensauced.pizza πŸ•

The site provides insights to Open Source projects.

diff --git a/components/molecules/RecommendedRepoCard/recommended-repo-card.tsx b/components/molecules/RecommendedRepoCard/recommended-repo-card.tsx index 50e59fbaba..63108d3d58 100644 --- a/components/molecules/RecommendedRepoCard/recommended-repo-card.tsx +++ b/components/molecules/RecommendedRepoCard/recommended-repo-card.tsx @@ -52,7 +52,7 @@ const RecommendedRepoCard = ({ fullName, className }: RecommendedRepoCardProps):
diff --git a/components/organisms/InsightPage/InsightPage.tsx b/components/organisms/InsightPage/InsightPage.tsx index 3e22496001..3b4219dc9b 100644 --- a/components/organisms/InsightPage/InsightPage.tsx +++ b/components/organisms/InsightPage/InsightPage.tsx @@ -457,7 +457,6 @@ const InsightPage = ({ edit, insight, pageRepos }: InsightPageProps) => { - {/* insights.opensauced.pizza/pages/{username}/{`{pageId}`}/dashboard */}
diff --git a/package.json b/package.json index 06c9f22020..83967b0d55 100644 --- a/package.json +++ b/package.json @@ -9,7 +9,7 @@ "files": [ "build/**/*" ], - "homepage": "https://insights.opensauced.pizza", + "homepage": "https://app.opensauced.pizza", "bugs": { "url": "https://github.com/open-sauced/insights/issues" }, diff --git a/pages/_app.tsx b/pages/_app.tsx index cd174f52c8..4a3827e9dd 100644 --- a/pages/_app.tsx +++ b/pages/_app.tsx @@ -64,7 +64,7 @@ function MyApp({ Component, pageProps }: ComponentWithPageLayout) { const interval = setInterval(() => { chatButton = document.getElementById("sitegpt-chat-icon"); if (chatButton) { - if (hostname !== "insights.opensauced.pizza") { + if (hostname !== "app.opensauced.pizza") { chatButton.style.display = "none"; } if (router.asPath === "/feed" && isMobile) { diff --git a/stories/atoms/text-input.stories.tsx b/stories/atoms/text-input.stories.tsx index c26a648b5a..e09b6d6a3b 100644 --- a/stories/atoms/text-input.stories.tsx +++ b/stories/atoms/text-input.stories.tsx @@ -35,7 +35,7 @@ WithDescriptionText.args = { disabled: false, autoFocus: true, borderless: false, - descriptionText: "insights.opensauced.pizza/statelyai/slug", + descriptionText: "app.opensauced.pizza/statelyai/slug", }; IsInvalid.args = { diff --git a/stories/atoms/typography-wrapper.stories.tsx b/stories/atoms/typography-wrapper.stories.tsx index b1aec7df18..bed4633d36 100644 --- a/stories/atoms/typography-wrapper.stories.tsx +++ b/stories/atoms/typography-wrapper.stories.tsx @@ -137,8 +137,8 @@ const TypographyTemplate: StoryFn = (args) => (

There are other elements we need to style

I almost forgot to mention links, like{" "} - this link to the OpenSauced Insights website. We almost made them - blue but that's so yesterday, so we went with dark gray, feels edgier. + this link to the OpenSauced Insights website. We almost made them blue + but that's so yesterday, so we went with dark gray, feels edgier.

We even included table styles, check it out:

diff --git a/tests/lib/utils/github.test.ts b/tests/lib/utils/github.test.ts index 4bdb27b7b6..204b46db86 100644 --- a/tests/lib/utils/github.test.ts +++ b/tests/lib/utils/github.test.ts @@ -77,7 +77,7 @@ describe("[lib] github methods", () => { }); }); it("Should return an object with isValidUrl set to false", () => { - const result = generateRepoParts("https://insights.opensauced.pizza/hub/insights/new"); + const result = generateRepoParts("https://app.opensauced.pizza/hub/insights/new"); expect(result.isValidUrl).toBeFalsy(); }); it("Should return an object with isValidUrl set to false", () => { From 2ea3989c823cca57c9c56ec495f3fcc308bbba1e Mon Sep 17 00:00:00 2001 From: Brandon Roberts Date: Tue, 10 Oct 2023 13:36:33 -0500 Subject: [PATCH 02/21] chore: add redirects for beta deployments (#1852) --- netlify.toml | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/netlify.toml b/netlify.toml index 5726d8995a..9ba4c89c67 100644 --- a/netlify.toml +++ b/netlify.toml @@ -26,3 +26,9 @@ deno_import_map = "./netlify/edge-functions/deno.json" to = "https://app.opensauced.pizza/:splat" status = 301 force = true + +[[redirects]] + from = "https://beta.insights.opensauced.pizza/*" + to = "https://beta.app.opensauced.pizza/:splat" + status = 301 + force = true From 4d81040d1968b75605eb4b42192f1cf982d090e1 Mon Sep 17 00:00:00 2001 From: OGBONNA SUNDAY <62995161+OgDev-01@users.noreply.github.com> Date: Tue, 10 Oct 2023 19:37:09 +0100 Subject: [PATCH 03/21] feat: add `Add to list` dropdown to user profile (#1843) --- components/atoms/Select/multi-select.tsx | 106 +++++++++--------- .../contributor-profile-header.tsx | 100 +++++++++++++++-- lib/hooks/useList.ts | 39 ++++++- 3 files changed, 178 insertions(+), 67 deletions(-) diff --git a/components/atoms/Select/multi-select.tsx b/components/atoms/Select/multi-select.tsx index d05fa938b7..ef6fb43ccf 100644 --- a/components/atoms/Select/multi-select.tsx +++ b/components/atoms/Select/multi-select.tsx @@ -11,13 +11,17 @@ import { Command, CommandGroup, CommandInput, CommandItem } from "../Cmd/command export type OptionKeys = Record<"value" | "label", string>; interface MultiSelectProps { + open: boolean; + setOpen: React.Dispatch>; options: OptionKeys[]; selected: OptionKeys[]; + setSelected?: React.Dispatch>; handleSelect: (value: OptionKeys) => void; placeholder?: string; inputPlaceholder?: string; className?: string; handleKeyDown?: (e: React.KeyboardEvent) => void; + emptyState?: React.ReactNode; } const MultiSelect = ({ @@ -28,30 +32,20 @@ const MultiSelect = ({ placeholder, handleKeyDown, inputPlaceholder, + setSelected, + open, + setOpen, + emptyState, }: MultiSelectProps) => { const inputRef = useRef(null); - const [open, setOpen] = React.useState(false); const [inputValue, setInputValue] = useState(""); - const [dummySelected, setDummySelected] = useState([]); - - // For testing purposes, this component is meant to be stateless. - - const toggleFramework = (option: OptionKeys) => { - const isOptionSelected = dummySelected.some((s) => s.value === option.value); - if (isOptionSelected) { - setDummySelected((prev) => prev.filter((s) => s.value !== option.value)); - } else { - setDummySelected((prev) => [...prev, option]); - } - inputRef?.current?.focus(); - }; return ( setOpen(value)}> -
+
- - - - - {open && options.length > 0 - ? options.map((option) => ( - { - e.preventDefault(); - e.stopPropagation(); - }} - onSelect={(value) => { - setInputValue(""); - toggleFramework(option); - }} - onClick={() => toggleFramework(option)} - className={clsx( - "!cursor-pointer flex justify-between items-center !px-1 rounded-md truncate break-words w-full", - selected.some((s) => s.value === option.value) && "bg-gray-100" - )} - > - {option.label} - {selected.some((s) => s.value === option.value) && ( - - )} - - )) - : null} - - + + {options.length > 0 && ( + + + + {open && options.length > 0 + ? options.map((option) => ( + { + e.preventDefault(); + e.stopPropagation(); + }} + onSelect={(value) => { + setInputValue(""); + // toggleFramework(option); + handleSelect(option); + }} + onClick={() => handleSelect(option)} + className={clsx( + "!cursor-pointer flex justify-between items-center !px-1 rounded-md truncate break-words w-full", + selected.some((s) => s.value === option.value) && "" + )} + > + {option.label} + {selected.some((s) => s.value === option.value) && ( + + )} + + )) + : null} + + + )} + {options.length === 0 && emptyState ? emptyState : null}
diff --git a/components/molecules/ContributorProfileHeader/contributor-profile-header.tsx b/components/molecules/ContributorProfileHeader/contributor-profile-header.tsx index f1d5372e10..761650b4de 100644 --- a/components/molecules/ContributorProfileHeader/contributor-profile-header.tsx +++ b/components/molecules/ContributorProfileHeader/contributor-profile-header.tsx @@ -1,14 +1,15 @@ import React, { useState, useEffect } from "react"; +import Link from "next/link"; import { useRouter } from "next/router"; import Image from "next/image"; import { TfiMoreAlt } from "react-icons/tfi"; import { HiUserAdd } from "react-icons/hi"; -import { FaIdCard } from "react-icons/fa"; import { SignInWithOAuthCredentials, User } from "@supabase/supabase-js"; import { usePostHog } from "posthog-js/react"; import { clsx } from "clsx"; +import dynamic from "next/dynamic"; import { DropdownMenu, DropdownMenuContent, @@ -23,9 +24,13 @@ import Text from "components/atoms/Typography/text"; import { Textarea } from "components/atoms/Textarea/text-area"; import { useUserConnections } from "lib/hooks/useUserConnections"; import { useToast } from "lib/hooks/useToast"; -import { cardPageUrl } from "lib/utils/urls"; +import { OptionKeys } from "components/atoms/Select/multi-select"; +import { addListContributor, useFetchAllLists } from "lib/hooks/useList"; +import { useFetchUser } from "lib/hooks/useFetchUser"; import { Dialog, DialogContent, DialogHeader, DialogTitle } from "../Dialog/dialog"; +const MultiSelect = dynamic(() => import("components/atoms/Select/multi-select"), { ssr: false }); + interface ContributorProfileHeaderProps { avatarUrl?: string; githubName: string; @@ -156,7 +161,7 @@ const ContributorProfileHeader = ({
{isConnected && (
-
+
{user ? ( !isOwner && ( <> @@ -166,8 +171,8 @@ const ContributorProfileHeader = ({ variant="primary" className="group w-[6.25rem] justify-center items-center" > - Following - Unfollow + Following + Unfollow ) : ( - + {user && !isOwner && } + -
+
{!isOwner && ( { + const [selectListOpen, setSelectListOpen] = useState(false); + const [selectedList, setSelectedList] = useState([]); + const { data } = useFetchAllLists(); + const { data: contributor } = useFetchUser(username ?? ""); + const { toast } = useToast(); + + const listOptions = data ? data.map((list) => ({ label: list.name, value: list.id })) : []; + + const handleSelectList = (value: OptionKeys) => { + const isOptionSelected = selectedList.some((s) => s.value === value.value); + if (isOptionSelected) { + setSelectedList((prev) => prev.filter((s) => s.value !== value.value)); + } else { + setSelectedList((prev) => [...prev, value]); + } + }; + + const handleAddToList = async () => { + if (selectedList.length > 0 && contributor) { + const listIds = selectedList.map((list) => list.value); + const response = Promise.all(listIds.map((listIds) => addListContributor(listIds, [contributor.id]))); + + response + .then((res) => { + toast({ + description: ` + You've added ${username} to ${selectedList.length} list${selectedList.length > 1 ? "s" : ""}!`, + variant: "success", + }); + }) + .catch((res) => { + const failedList = listOptions.filter((list) => res.some((r: any) => r.error?.list_id === list.value)); + toast({ + description: ` + Failed to add ${username} to ${failedList[0].label} ${ + failedList.length > 1 && `and ${failedList.length - 1} other lists` + } ! + `, + variant: "danger", + }); + }); + } + }; + + useEffect(() => { + if (!selectListOpen && selectedList.length > 0) { + handleAddToList(); + setSelectedList([]); + } + }, [selectListOpen]); + + return ( + + You have no lists.
+ + Create a list + +
+ } + className="w-10 px-4" + placeholder="Add to list" + options={listOptions} + selected={selectedList} + setSelected={setSelectedList} + handleSelect={(option) => handleSelectList(option)} + /> + ); +}; + export default ContributorProfileHeader; diff --git a/lib/hooks/useList.ts b/lib/hooks/useList.ts index c1cb56cdb6..83caeb60a9 100644 --- a/lib/hooks/useList.ts +++ b/lib/hooks/useList.ts @@ -2,6 +2,7 @@ import useSWR, { Fetcher } from "swr"; import { useState } from "react"; import publicApiFetcher from "lib/utils/public-api-fetcher"; +import { supabase } from "lib/utils/supabase"; interface PaginatedListResponse { data: DbUserList[]; @@ -69,6 +70,42 @@ const useFetchListContributors = (id: string, range = 30) => { }; }; +const addListContributor = async (listId: string, contributors: number[]) => { + const sessionResponse = await supabase.auth.getSession(); + const sessionToken = sessionResponse?.data.session?.access_token; + + try { + const response = await fetch(`${process.env.NEXT_PUBLIC_API_URL}/lists/${listId}/contributors`, { + method: "POST", + body: JSON.stringify({ contributors }), + headers: { + "Content-Type": "application/json", + Authorization: `Bearer ${sessionToken}`, + }, + }); + + if (response.ok) { + const data = await response.json(); + return { + data, + error: null, + }; + } else { + const error = await response.json(); + return { + data: null, + error: { message: error.message, listId }, + }; + } + } catch (error: any) { + console.log(error); + return { + data: null, + error: { message: error.message, listId }, + }; + } +}; + const useList = (listId: string) => { const { data, error, mutate } = useSWR(`lists/${listId}`, publicApiFetcher as Fetcher); @@ -80,4 +117,4 @@ const useList = (listId: string) => { }; }; -export { useList, useFetchAllLists, useFetchListContributors }; +export { useList, useFetchAllLists, useFetchListContributors, addListContributor }; From 198ee005bc9e57a5739984eccc037d64f0e4fc48 Mon Sep 17 00:00:00 2001 From: OGBONNA SUNDAY <62995161+OgDev-01@users.noreply.github.com> Date: Tue, 10 Oct 2023 18:45:08 +0000 Subject: [PATCH 04/21] chore(minor): release 1.69.0-beta.1 on beta channel [skip ci] MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit ## [1.69.0-beta.1](https://github.com/open-sauced/insights/compare/v1.68.0...v1.69.0-beta.1) (2023-10-10) ### πŸ• Features * add `Add to list` dropdown to user profile ([#1843](https://github.com/open-sauced/insights/issues/1843)) ([4d81040](https://github.com/open-sauced/insights/commit/4d81040d1968b75605eb4b42192f1cf982d090e1)) --- 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 1d5be0af0b..97dc545f6e 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -5,6 +5,13 @@ > All notable changes to this project will be documented in this file +## [1.69.0-beta.1](https://github.com/open-sauced/insights/compare/v1.68.0...v1.69.0-beta.1) (2023-10-10) + + +### πŸ• Features + +* add `Add to list` dropdown to user profile ([#1843](https://github.com/open-sauced/insights/issues/1843)) ([4d81040](https://github.com/open-sauced/insights/commit/4d81040d1968b75605eb4b42192f1cf982d090e1)) + ## [1.68.0](https://github.com/open-sauced/insights/compare/v1.67.0...v1.68.0) (2023-10-10) diff --git a/npm-shrinkwrap.json b/npm-shrinkwrap.json index 1638919b9a..b4f6ab5351 100644 --- a/npm-shrinkwrap.json +++ b/npm-shrinkwrap.json @@ -1,12 +1,12 @@ { "name": "@open-sauced/insights", - "version": "1.68.0", + "version": "1.69.0-beta.1", "lockfileVersion": 3, "requires": true, "packages": { "": { "name": "@open-sauced/insights", - "version": "1.68.0", + "version": "1.69.0-beta.1", "hasInstallScript": true, "license": "Apache 2.0", "dependencies": { diff --git a/package.json b/package.json index 83967b0d55..9db3699da4 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.68.0", + "version": "1.69.0-beta.1", "author": "Brian Douglas ", "private": true, "license": "Apache 2.0", From cabf2929f2d31cca95e8d3fe277d483276615118 Mon Sep 17 00:00:00 2001 From: Aryan Singh <114330931+aryanas159@users.noreply.github.com> Date: Wed, 11 Oct 2023 01:14:34 +0530 Subject: [PATCH 05/21] fix: Repos with long names get cut off (#1769) Signed-off-by: Aryan Singh Co-authored-by: OGBONNA SUNDAY <62995161+OgDev-01@users.noreply.github.com> --- .../table-repository-name.tsx | 16 +++++++++------- 1 file changed, 9 insertions(+), 7 deletions(-) diff --git a/components/molecules/TableRepositoryName/table-repository-name.tsx b/components/molecules/TableRepositoryName/table-repository-name.tsx index 22a801bf66..6c962bc06d 100644 --- a/components/molecules/TableRepositoryName/table-repository-name.tsx +++ b/components/molecules/TableRepositoryName/table-repository-name.tsx @@ -1,7 +1,6 @@ import { StaticImageData } from "next/image"; import Avatar from "components/atoms/Avatar/avatar"; -import { truncateString } from "lib/utils/truncate-string"; - +import Tooltip from "components/atoms/Tooltip/tooltip"; interface TableRepositoryNameProps { avatarURL?: string | StaticImageData; fullName: string; @@ -26,12 +25,15 @@ const TableRepositoryName = ({ avatarURL, fullName }: TableRepositoryNameProps): {/* Text */} +
- + + +
{handle ? `@${handle}` : "handle1234"} From b2a137de3d3bfca00f43a93841af95a943287432 Mon Sep 17 00:00:00 2001 From: Aryan Singh <114330931+aryanas159@users.noreply.github.com> Date: Tue, 10 Oct 2023 19:54:15 +0000 Subject: [PATCH 06/21] chore(patch): release 1.69.0-beta.2 on beta channel [skip ci] MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit ## [1.69.0-beta.2](https://github.com/open-sauced/insights/compare/v1.69.0-beta.1...v1.69.0-beta.2) (2023-10-10) ### πŸ› Bug Fixes * Repos with long names get cut off ([#1769](https://github.com/open-sauced/insights/issues/1769)) ([cabf292](https://github.com/open-sauced/insights/commit/cabf2929f2d31cca95e8d3fe277d483276615118)) --- 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 97dc545f6e..49201c9052 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -5,6 +5,13 @@ > All notable changes to this project will be documented in this file +## [1.69.0-beta.2](https://github.com/open-sauced/insights/compare/v1.69.0-beta.1...v1.69.0-beta.2) (2023-10-10) + + +### πŸ› Bug Fixes + +* Repos with long names get cut off ([#1769](https://github.com/open-sauced/insights/issues/1769)) ([cabf292](https://github.com/open-sauced/insights/commit/cabf2929f2d31cca95e8d3fe277d483276615118)) + ## [1.69.0-beta.1](https://github.com/open-sauced/insights/compare/v1.68.0...v1.69.0-beta.1) (2023-10-10) diff --git a/npm-shrinkwrap.json b/npm-shrinkwrap.json index b4f6ab5351..fd062b5a67 100644 --- a/npm-shrinkwrap.json +++ b/npm-shrinkwrap.json @@ -1,12 +1,12 @@ { "name": "@open-sauced/insights", - "version": "1.69.0-beta.1", + "version": "1.69.0-beta.2", "lockfileVersion": 3, "requires": true, "packages": { "": { "name": "@open-sauced/insights", - "version": "1.69.0-beta.1", + "version": "1.69.0-beta.2", "hasInstallScript": true, "license": "Apache 2.0", "dependencies": { diff --git a/package.json b/package.json index 9db3699da4..9e4c103425 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.69.0-beta.1", + "version": "1.69.0-beta.2", "author": "Brian Douglas ", "private": true, "license": "Apache 2.0", From 264f0ddd2fa1378407c65fdc859a9a04ae3f6a5e Mon Sep 17 00:00:00 2001 From: Shraddha Date: Tue, 10 Oct 2023 16:52:59 -0400 Subject: [PATCH 07/21] refactor: Remove + icon from list contributors stacked avatar (#1851) Co-authored-by: OGBONNA SUNDAY <62995161+OgDev-01@users.noreply.github.com> --- components/molecules/ListCard/list-card.tsx | 12 ------------ 1 file changed, 12 deletions(-) diff --git a/components/molecules/ListCard/list-card.tsx b/components/molecules/ListCard/list-card.tsx index ed0b363dc1..925c6ee8bf 100644 --- a/components/molecules/ListCard/list-card.tsx +++ b/components/molecules/ListCard/list-card.tsx @@ -1,10 +1,8 @@ import React from "react"; import Link from "next/link"; import { MdOutlineArrowForwardIos } from "react-icons/md"; -import { FiPlus } from "react-icons/fi"; import { RiDeleteBinLine } from "react-icons/ri"; import Text from "components/atoms/Typography/text"; -import Tooltip from "components/atoms/Tooltip/tooltip"; import { useFetchListContributors } from "lib/hooks/useList"; import StackedAvatar, { Contributor } from "../StackedAvatar/stacked-avatar"; @@ -41,16 +39,6 @@ const ListCard = ({ list, handleOnDeleteClick }: ListCardProps) => {
- - -
{/* Delete button */} From f4d8b2b9e030177a12a96ab8798b6a3341ff1b59 Mon Sep 17 00:00:00 2001 From: Shraddha Date: Tue, 10 Oct 2023 20:59:52 +0000 Subject: [PATCH 08/21] chore(patch): release 1.69.0-beta.3 on beta channel [skip ci] MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit ## [1.69.0-beta.3](https://github.com/open-sauced/insights/compare/v1.69.0-beta.2...v1.69.0-beta.3) (2023-10-10) ### πŸ§‘β€πŸ’» Code Refactoring * Remove + icon from list contributors stacked avatar ([#1851](https://github.com/open-sauced/insights/issues/1851)) ([264f0dd](https://github.com/open-sauced/insights/commit/264f0ddd2fa1378407c65fdc859a9a04ae3f6a5e)) --- 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 49201c9052..f8def55be9 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -5,6 +5,13 @@ > All notable changes to this project will be documented in this file +## [1.69.0-beta.3](https://github.com/open-sauced/insights/compare/v1.69.0-beta.2...v1.69.0-beta.3) (2023-10-10) + + +### πŸ§‘β€πŸ’» Code Refactoring + +* Remove + icon from list contributors stacked avatar ([#1851](https://github.com/open-sauced/insights/issues/1851)) ([264f0dd](https://github.com/open-sauced/insights/commit/264f0ddd2fa1378407c65fdc859a9a04ae3f6a5e)) + ## [1.69.0-beta.2](https://github.com/open-sauced/insights/compare/v1.69.0-beta.1...v1.69.0-beta.2) (2023-10-10) diff --git a/npm-shrinkwrap.json b/npm-shrinkwrap.json index fd062b5a67..da50f5a769 100644 --- a/npm-shrinkwrap.json +++ b/npm-shrinkwrap.json @@ -1,12 +1,12 @@ { "name": "@open-sauced/insights", - "version": "1.69.0-beta.2", + "version": "1.69.0-beta.3", "lockfileVersion": 3, "requires": true, "packages": { "": { "name": "@open-sauced/insights", - "version": "1.69.0-beta.2", + "version": "1.69.0-beta.3", "hasInstallScript": true, "license": "Apache 2.0", "dependencies": { diff --git a/package.json b/package.json index 9e4c103425..cbba56712b 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.69.0-beta.2", + "version": "1.69.0-beta.3", "author": "Brian Douglas ", "private": true, "license": "Apache 2.0", From ca44b27815d6ad2d68af1b07d998d3bf8282dced Mon Sep 17 00:00:00 2001 From: OGBONNA SUNDAY <62995161+OgDev-01@users.noreply.github.com> Date: Wed, 11 Oct 2023 00:21:03 +0100 Subject: [PATCH 09/21] feat: upgrade posthog version to support posthog survey feedback (#1857) --- npm-shrinkwrap.json | 16 +++++----------- package.json | 2 +- 2 files changed, 6 insertions(+), 12 deletions(-) diff --git a/npm-shrinkwrap.json b/npm-shrinkwrap.json index da50f5a769..fa73d99ea0 100644 --- a/npm-shrinkwrap.json +++ b/npm-shrinkwrap.json @@ -54,7 +54,7 @@ "next": "^13.4.7", "octokit": "^2.0.14", "path-to-regexp": "^6.2.1", - "posthog-js": "^1.57.2", + "posthog-js": "^1.83.0", "react": "^18.2.0", "react-csv": "^2.2.2", "react-day-picker": "^8.7.1", @@ -43427,12 +43427,11 @@ "integrity": "sha512-1NNCs6uurfkVbeXG4S8JFT9t19m45ICnif8zWLd5oPSZ50QnwMfK+H3jv408d4jw/7Bttv5axS5IiHoLaVNHeQ==" }, "node_modules/posthog-js": { - "version": "1.57.2", - "resolved": "https://registry.npmjs.org/posthog-js/-/posthog-js-1.57.2.tgz", - "integrity": "sha512-ER4gkYZasrd2Zwmt/yLeZ5G/nZJ6tpaYBCpx3CvocDx+3F16WdawJlYMT0IyLKHXDniC5+AsjzFd6fi8uyYlJA==", + "version": "1.83.0", + "resolved": "https://registry.npmjs.org/posthog-js/-/posthog-js-1.83.0.tgz", + "integrity": "sha512-3dp/yNbRCYsOgvJovFUMCLv9/KxnwmGBy5Ft27Q7/rbW++iJXVR64liX7i0NrXkudjoL9j1GW1LGh84rV7kv8Q==", "dependencies": { - "fflate": "^0.4.1", - "rrweb-snapshot": "^1.1.14" + "fflate": "^0.4.1" } }, "node_modules/prelude-ls": { @@ -44717,11 +44716,6 @@ "react-dom": "^16.8.0 || ^17.0.0 || ^18.0.0" } }, - "node_modules/rrweb-snapshot": { - "version": "1.1.14", - "resolved": "https://registry.npmjs.org/rrweb-snapshot/-/rrweb-snapshot-1.1.14.tgz", - "integrity": "sha512-eP5pirNjP5+GewQfcOQY4uBiDnpqxNRc65yKPW0eSoU1XamDfc4M8oqpXGMyUyvLyxFDB0q0+DChuxxiU2FXBQ==" - }, "node_modules/rtl-css-js": { "version": "1.16.1", "resolved": "https://registry.npmjs.org/rtl-css-js/-/rtl-css-js-1.16.1.tgz", diff --git a/package.json b/package.json index cbba56712b..5fb378502e 100644 --- a/package.json +++ b/package.json @@ -90,7 +90,7 @@ "next": "^13.4.7", "octokit": "^2.0.14", "path-to-regexp": "^6.2.1", - "posthog-js": "^1.57.2", + "posthog-js": "^1.83.0", "react": "^18.2.0", "react-csv": "^2.2.2", "react-day-picker": "^8.7.1", From ab4d5bd30477a812c4fa74887995594514f992d2 Mon Sep 17 00:00:00 2001 From: OGBONNA SUNDAY <62995161+OgDev-01@users.noreply.github.com> Date: Tue, 10 Oct 2023 23:28:33 +0000 Subject: [PATCH 10/21] chore(minor): release 1.69.0-beta.4 on beta channel [skip ci] MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit ## [1.69.0-beta.4](https://github.com/open-sauced/insights/compare/v1.69.0-beta.3...v1.69.0-beta.4) (2023-10-10) ### πŸ• Features * upgrade posthog version to support posthog survey feedback ([#1857](https://github.com/open-sauced/insights/issues/1857)) ([ca44b27](https://github.com/open-sauced/insights/commit/ca44b27815d6ad2d68af1b07d998d3bf8282dced)) --- 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 f8def55be9..d3adbeb7f2 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -5,6 +5,13 @@ > All notable changes to this project will be documented in this file +## [1.69.0-beta.4](https://github.com/open-sauced/insights/compare/v1.69.0-beta.3...v1.69.0-beta.4) (2023-10-10) + + +### πŸ• Features + +* upgrade posthog version to support posthog survey feedback ([#1857](https://github.com/open-sauced/insights/issues/1857)) ([ca44b27](https://github.com/open-sauced/insights/commit/ca44b27815d6ad2d68af1b07d998d3bf8282dced)) + ## [1.69.0-beta.3](https://github.com/open-sauced/insights/compare/v1.69.0-beta.2...v1.69.0-beta.3) (2023-10-10) diff --git a/npm-shrinkwrap.json b/npm-shrinkwrap.json index fa73d99ea0..e7d8557cc3 100644 --- a/npm-shrinkwrap.json +++ b/npm-shrinkwrap.json @@ -1,12 +1,12 @@ { "name": "@open-sauced/insights", - "version": "1.69.0-beta.3", + "version": "1.69.0-beta.4", "lockfileVersion": 3, "requires": true, "packages": { "": { "name": "@open-sauced/insights", - "version": "1.69.0-beta.3", + "version": "1.69.0-beta.4", "hasInstallScript": true, "license": "Apache 2.0", "dependencies": { diff --git a/package.json b/package.json index 5fb378502e..95e258d387 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.69.0-beta.3", + "version": "1.69.0-beta.4", "author": "Brian Douglas ", "private": true, "license": "Apache 2.0", From 9dd61beaa131ddab744c6f62be5c6029400b61d9 Mon Sep 17 00:00:00 2001 From: OGBONNA SUNDAY <62995161+OgDev-01@users.noreply.github.com> Date: Wed, 11 Oct 2023 01:15:25 +0100 Subject: [PATCH 11/21] feat: add lists link to global top nav (#1861) --- components/organisms/TopNav/top-nav.tsx | 17 ++++++++++++----- 1 file changed, 12 insertions(+), 5 deletions(-) diff --git a/components/organisms/TopNav/top-nav.tsx b/components/organisms/TopNav/top-nav.tsx index d8dfe30618..6e5a9dc14d 100644 --- a/components/organisms/TopNav/top-nav.tsx +++ b/components/organisms/TopNav/top-nav.tsx @@ -36,11 +36,18 @@ const Nav = ({ className, name = "Main" }: { className?: string; name?: string }
{router.pathname.split("/")[2] === "insights" ? ( ) : ( )}
From 821a7b3099d934b8107001d68f33249794a6ec62 Mon Sep 17 00:00:00 2001 From: OGBONNA SUNDAY <62995161+OgDev-01@users.noreply.github.com> Date: Wed, 11 Oct 2023 00:38:25 +0000 Subject: [PATCH 14/21] chore(patch): release 1.69.0-beta.6 on beta channel [skip ci] MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit ## [1.69.0-beta.6](https://github.com/open-sauced/insights/compare/v1.69.0-beta.5...v1.69.0-beta.6) (2023-10-11) ### πŸ› Bug Fixes * show link to hub list page in nav ([#1858](https://github.com/open-sauced/insights/issues/1858)) ([099b1aa](https://github.com/open-sauced/insights/commit/099b1aa51036111cd8c751ca286202b06be76ec4)) --- 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 db9e0d94c0..4472338174 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -5,6 +5,13 @@ > All notable changes to this project will be documented in this file +## [1.69.0-beta.6](https://github.com/open-sauced/insights/compare/v1.69.0-beta.5...v1.69.0-beta.6) (2023-10-11) + + +### πŸ› Bug Fixes + +* show link to hub list page in nav ([#1858](https://github.com/open-sauced/insights/issues/1858)) ([099b1aa](https://github.com/open-sauced/insights/commit/099b1aa51036111cd8c751ca286202b06be76ec4)) + ## [1.69.0-beta.5](https://github.com/open-sauced/insights/compare/v1.69.0-beta.4...v1.69.0-beta.5) (2023-10-11) diff --git a/npm-shrinkwrap.json b/npm-shrinkwrap.json index cddb58393a..05101441d7 100644 --- a/npm-shrinkwrap.json +++ b/npm-shrinkwrap.json @@ -1,12 +1,12 @@ { "name": "@open-sauced/insights", - "version": "1.69.0-beta.5", + "version": "1.69.0-beta.6", "lockfileVersion": 3, "requires": true, "packages": { "": { "name": "@open-sauced/insights", - "version": "1.69.0-beta.5", + "version": "1.69.0-beta.6", "hasInstallScript": true, "license": "Apache 2.0", "dependencies": { diff --git a/package.json b/package.json index 8d37c084c8..424caf9cc2 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.69.0-beta.5", + "version": "1.69.0-beta.6", "author": "Brian Douglas ", "private": true, "license": "Apache 2.0", From 8e99a1df73092edb560357d62bfc700af522ea73 Mon Sep 17 00:00:00 2001 From: Brandon Roberts Date: Tue, 10 Oct 2023 19:44:21 -0500 Subject: [PATCH 15/21] feat: add contributor search to list contributors (#1862) --- .../hub-contributors-header.tsx | 23 ++++++++++++++++++- .../ContributorsTable/contributors-table.tsx | 4 ++-- lib/hooks/useFetchAllContributors.ts | 4 ++++ pages/hub/lists/find.tsx | 11 ++++++++- 4 files changed, 38 insertions(+), 4 deletions(-) diff --git a/components/molecules/HubContributorsHeader/hub-contributors-header.tsx b/components/molecules/HubContributorsHeader/hub-contributors-header.tsx index 5e94ff3d3a..2fff8ac15e 100644 --- a/components/molecules/HubContributorsHeader/hub-contributors-header.tsx +++ b/components/molecules/HubContributorsHeader/hub-contributors-header.tsx @@ -3,6 +3,7 @@ import { FaPlus } from "react-icons/fa"; import clsx from "clsx"; import { FiGlobe } from "react-icons/fi"; +import { useEffect, useState } from "react"; import { useToast } from "lib/hooks/useToast"; import ListNameHeader from "components/atoms/ListNameHeader/list-name-header"; @@ -11,6 +12,8 @@ import SingleSelect from "components/atoms/Select/single-select"; import ToggleSwitch from "components/atoms/ToggleSwitch/toggle-switch"; import Button from "components/atoms/Button/button"; import Text from "components/atoms/Typography/text"; +import Search from "components/atoms/Search/search"; +import useDebounceTerm from "lib/hooks/useDebounceTerm"; // import Search from "components/atoms/Search/search"; interface ListHeaderProps { @@ -25,6 +28,8 @@ interface ListHeaderProps { onAddToList?: () => void; onTitleChange?: (title: string) => void; loading?: boolean; + onSearch: (searchTerm: string | undefined) => void; + searchResults?: DbUser[]; } const HubContributorsHeader = ({ @@ -39,9 +44,17 @@ const HubContributorsHeader = ({ timezone, setTimezoneFilter, timezoneOptions, + onSearch, }: ListHeaderProps): JSX.Element => { const { toast } = useToast(); + const [contributorSearch, setContributorSearch] = useState(""); + const debouncedSearchTerm = useDebounceTerm(contributorSearch, 300); + + useEffect(() => { + onSearch(contributorSearch); + }, [debouncedSearchTerm]); + return (
@@ -86,7 +99,15 @@ const HubContributorsHeader = ({
-
+
+
+ setContributorSearch(value)} + /> +
)) ) : ( -
- No contributors found for the selected filters +
+ Sorry! We couldn't find any contributors.
)}
diff --git a/lib/hooks/useFetchAllContributors.ts b/lib/hooks/useFetchAllContributors.ts index 19b6ab0938..6fcf77feb3 100644 --- a/lib/hooks/useFetchAllContributors.ts +++ b/lib/hooks/useFetchAllContributors.ts @@ -15,6 +15,7 @@ type queryObj = { pr_velocity?: string; timezone?: string; initialLimit?: number; + contributor?: string; }; const useFetchAllContributors = (query: queryObj, config?: SWRConfiguration) => { @@ -37,6 +38,9 @@ const useFetchAllContributors = (query: queryObj, config?: SWRConfiguration) => if (query.timezone) { urlQuery.set("timezone", `${query.timezone}`); } + if (query.contributor) { + urlQuery.set("contributor", `${query.contributor}`); + } if (limit) { urlQuery.set("limit", `${limit}`); } diff --git a/pages/hub/lists/find.tsx b/pages/hub/lists/find.tsx index 3a93af6fc8..aaa5e87a5e 100644 --- a/pages/hub/lists/find.tsx +++ b/pages/hub/lists/find.tsx @@ -87,10 +87,12 @@ const NewListCreationPage = ({ initialData, timezoneOption }: NewListCreationPag const [title, setTitle] = useState(""); const [selectedContributors, setSelectedContributors] = useState([]); const [selectedTimezone, setSelectedTimezone] = useState(undefined); + const [contributor, setContributor] = useState(undefined); const [isPublic, setIsPublic] = useState(false); const { data, meta, isLoading, setLimit, setPage } = useFetchAllContributors( { timezone: selectedTimezone, + contributor, }, { fallbackData: initialData, @@ -217,6 +219,12 @@ const NewListCreationPage = ({ initialData, timezoneOption }: NewListCreationPag setSelectedTimezone(selected); }; + function onSearch(searchTerm: string | undefined) { + if (!searchTerm || searchTerm.length >= 3) { + setContributor(searchTerm); + } + } + return ( @@ -234,10 +242,11 @@ const NewListCreationPage = ({ initialData, timezoneOption }: NewListCreationPag title={title} onAddToList={handleOnListCreate} onTitleChange={(title) => setTitle(title)} + onSearch={onSearch} />
-
+
0 && selectedContributors.length === meta.limit} handleOnSelectAllContributor={handleOnSelectAllChecked} From 9cc8aeb24372a6171af8254ccd315b322ba6b228 Mon Sep 17 00:00:00 2001 From: Brandon Roberts Date: Wed, 11 Oct 2023 00:53:59 +0000 Subject: [PATCH 16/21] chore(minor): release 1.69.0-beta.7 on beta channel [skip ci] MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit ## [1.69.0-beta.7](https://github.com/open-sauced/insights/compare/v1.69.0-beta.6...v1.69.0-beta.7) (2023-10-11) ### πŸ• Features * add contributor search to list contributors ([#1862](https://github.com/open-sauced/insights/issues/1862)) ([8e99a1d](https://github.com/open-sauced/insights/commit/8e99a1df73092edb560357d62bfc700af522ea73)) --- 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 4472338174..e39b633fef 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -5,6 +5,13 @@ > All notable changes to this project will be documented in this file +## [1.69.0-beta.7](https://github.com/open-sauced/insights/compare/v1.69.0-beta.6...v1.69.0-beta.7) (2023-10-11) + + +### πŸ• Features + +* add contributor search to list contributors ([#1862](https://github.com/open-sauced/insights/issues/1862)) ([8e99a1d](https://github.com/open-sauced/insights/commit/8e99a1df73092edb560357d62bfc700af522ea73)) + ## [1.69.0-beta.6](https://github.com/open-sauced/insights/compare/v1.69.0-beta.5...v1.69.0-beta.6) (2023-10-11) diff --git a/npm-shrinkwrap.json b/npm-shrinkwrap.json index 05101441d7..513a47ed11 100644 --- a/npm-shrinkwrap.json +++ b/npm-shrinkwrap.json @@ -1,12 +1,12 @@ { "name": "@open-sauced/insights", - "version": "1.69.0-beta.6", + "version": "1.69.0-beta.7", "lockfileVersion": 3, "requires": true, "packages": { "": { "name": "@open-sauced/insights", - "version": "1.69.0-beta.6", + "version": "1.69.0-beta.7", "hasInstallScript": true, "license": "Apache 2.0", "dependencies": { diff --git a/package.json b/package.json index 424caf9cc2..29ef59ab07 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.69.0-beta.6", + "version": "1.69.0-beta.7", "author": "Brian Douglas ", "private": true, "license": "Apache 2.0", From 5344c59538ae77b0d5f662fcd04e5dcc19807cc8 Mon Sep 17 00:00:00 2001 From: Brandon Roberts Date: Tue, 10 Oct 2023 20:42:49 -0500 Subject: [PATCH 17/21] feat: display featured insight pages to new contributors (#1859) --- .../molecules/InsightRow/insight-row.tsx | 13 ++-- interfaces/global-state-types.ts | 1 + lib/store/index.ts | 5 +- next-types.d.ts | 2 + pages/hub/insights/index.tsx | 59 ++++++++++++++++++- 5 files changed, 73 insertions(+), 7 deletions(-) diff --git a/components/molecules/InsightRow/insight-row.tsx b/components/molecules/InsightRow/insight-row.tsx index e31a2318dd..293a920408 100644 --- a/components/molecules/InsightRow/insight-row.tsx +++ b/components/molecules/InsightRow/insight-row.tsx @@ -75,11 +75,14 @@ const InsightRow = ({ insight, user }: InsightRowProps) => {
- - - - - + {(user?.user_metadata.sub && Number(user?.user_metadata.sub) === Number(insight.user_id)) || + (!insight.is_featured && ( + + + + + + ))} diff --git a/interfaces/global-state-types.ts b/interfaces/global-state-types.ts index ae8e6c7c54..865c72de32 100644 --- a/interfaces/global-state-types.ts +++ b/interfaces/global-state-types.ts @@ -11,4 +11,5 @@ export interface GlobalStateInterface { userId?: number | null; hasReports?: boolean; openSearch?: boolean; + dismissFeaturedInsights?: boolean; } diff --git a/lib/store/index.ts b/lib/store/index.ts index 7beeabc61a..c6059aec23 100644 --- a/lib/store/index.ts +++ b/lib/store/index.ts @@ -12,6 +12,7 @@ const initialState: GlobalStateInterface = { userId: null, hasReports: false, openSearch: false, + dismissFeaturedInsights: false, }; interface AppStore extends GlobalStateInterface { @@ -33,6 +34,7 @@ interface AppStore extends GlobalStateInterface { setUserId: (userId?: number | null) => void; setHasReports: (hasReports: boolean) => void; setOpenSearch: (openSearch: boolean) => void; + setDismissFeaturedInsights: () => void; } const store = create()((set) => ({ @@ -54,7 +56,8 @@ const store = create()((set) => ({ setProviderToken: (providerToken?: string | null) => set((state) => ({ ...state, providerToken })), setUserId: (userId?: number | null) => set((state) => ({ ...state, userId })), setHasReports: (hasReports: boolean) => set((state) => ({ ...state, hasReports })), - setOpenSearch: (openSearch: boolean) => set(() => ({ openSearch: openSearch })), + setOpenSearch: (openSearch: boolean) => set((state) => ({ ...state, openSearch: openSearch })), + setDismissFeaturedInsights: () => set((state) => ({ ...state, dismissFeaturedInsights: true })), })); export default store; diff --git a/next-types.d.ts b/next-types.d.ts index 32c25bee7f..2d2db97377 100644 --- a/next-types.d.ts +++ b/next-types.d.ts @@ -190,6 +190,7 @@ interface DbUserInsight { readonly name: string; readonly is_public: boolean; readonly is_favorite: boolean; + readonly is_featured: boolean; readonly short_code: string; readonly created_at: string; readonly updated_at: string; @@ -231,6 +232,7 @@ interface DbUser { readonly linkedin_url: string; readonly discord_url: string; readonly notification_count: number; + readonly insights_count: number; readonly languages: { [lang]: number }; readonly first_opened_pr_at: string; readonly followers_count: number; diff --git a/pages/hub/insights/index.tsx b/pages/hub/insights/index.tsx index 7593dc7937..a7dd79d666 100644 --- a/pages/hub/insights/index.tsx +++ b/pages/hub/insights/index.tsx @@ -1,4 +1,6 @@ +import { useEffect } from "react"; import Link from "next/link"; +import { useRouter } from "next/router"; import clsx from "clsx"; import InsightRow from "components/molecules/InsightRow/insight-row"; @@ -10,12 +12,67 @@ import HubLayout from "layouts/hub"; import { WithPageLayout } from "interfaces/with-page-layout"; import useUserInsights from "lib/hooks/useUserInsights"; import useSupabaseAuth from "lib/hooks/useSupabaseAuth"; +import useStore from "lib/store"; +import useSession from "lib/hooks/useSession"; +import { useToast } from "lib/hooks/useToast"; +import Text from "components/atoms/Typography/text"; const InsightsHub: WithPageLayout = () => { + const router = useRouter(); const { user } = useSupabaseAuth(); - + const store = useStore(); + const dismissFeaturedInsights = useStore((store) => store.dismissFeaturedInsights); + const { toast } = useToast(); + const { session } = useSession(true); const { data, meta, isError, isLoading, setPage } = useUserInsights(); + function handleView() { + const insight = data.slice(0, 1).shift(); + router.push(`/pages/${user?.user_metadata.user_name}/${insight!.id}/dashboard`); + } + + function openInsightToast() { + const toaster = toast({ + description: "Welcome to your Insights Hub!", + variant: "success", + action: ( +
+
+ + We've included a featured Insight Page for you to test out. You can also create your own to get + insights on repositories. + +
+
+ + +
+
+ ), + }); + + store.setDismissFeaturedInsights(); + } + + useEffect(() => { + if (session && session.insights_count === 0 && !dismissFeaturedInsights) { + openInsightToast(); + } + }, [session, user]); + return ( <>
From 70a67f08f6ab649621ef2c6115ca43f99ccd44ad Mon Sep 17 00:00:00 2001 From: Nick Taylor Date: Tue, 10 Oct 2023 22:01:45 -0400 Subject: [PATCH 18/21] feat: add repos/contributors treemap to list activity page (#1853) --- .../contributions-treemap.tsx | 79 +++++++++++++++++++ helpers/fetchApiData.ts | 2 +- lib/hooks/api/useContributionsByProject.ts | 27 +++++++ lib/hooks/api/useContributorsByProject.ts | 18 +++++ lib/hooks/api/useMostActiveContributors.ts | 6 +- lib/utils/color-utils.ts | 26 ++++++ lib/utils/nivo-utils.ts | 18 +++++ next-types.d.ts | 15 ++++ pages/lists/[listId]/activity.tsx | 56 ++++++++++++- .../treemap-prototype/contributor-node.tsx | 19 ++--- .../treemap-prototype/special-node.tsx | 21 ++--- 11 files changed, 253 insertions(+), 34 deletions(-) create mode 100644 components/molecules/ContributionsTreemap/contributions-treemap.tsx create mode 100644 lib/hooks/api/useContributionsByProject.ts create mode 100644 lib/hooks/api/useContributorsByProject.ts create mode 100644 lib/utils/color-utils.ts create mode 100644 lib/utils/nivo-utils.ts diff --git a/components/molecules/ContributionsTreemap/contributions-treemap.tsx b/components/molecules/ContributionsTreemap/contributions-treemap.tsx new file mode 100644 index 0000000000..7090405b0a --- /dev/null +++ b/components/molecules/ContributionsTreemap/contributions-treemap.tsx @@ -0,0 +1,79 @@ +import { useSpring, animated } from "@react-spring/web"; +import dynamic from "next/dynamic"; +import Card from "components/atoms/Card/card"; +import { SpecialNode } from "stories/molecules/treemap-prototype/special-node"; +import { ContributorNode } from "stories/molecules/treemap-prototype/contributor-node"; +import ClientOnly from "components/atoms/ClientOnly/client-only"; +import type { NodeMouseEventHandler, NodeProps } from "@nivo/treemap"; + +interface ContributionsTreemapProps { + data: any; + color: string; + onClick: NodeMouseEventHandler; + repoId: number | null; + setRepoId: (repoId: number | null) => void; +} + +function BreadCrumb({ isActive, ...rest }: any) { + const separatorStyle = useSpring(isActive ? { opacity: 1 } : { opacity: 0 }); + const textStyle = useSpring(isActive ? { opacity: 1, translateX: 0 } : { opacity: 0, translateX: 100 }); + + return ( + <> + + {"/"} + + + + ); +} + +const ResponsiveTreeMapHtml = dynamic(() => import("@nivo/treemap").then((module) => module.ResponsiveTreeMapHtml)); + +export const ContributionsTreemap = ({ setRepoId, repoId, data, color, onClick }: ContributionsTreemapProps) => { + return ( + +
+ {/* Label: Text */} +
+ +
+ Contributors +
+
+
+ + ({ + node, + animatedProps, + borderWidth, + enableLabel, + labelSkipSize, + }: NodeProps) => JSX.Element) + } + colors={color} + nodeOpacity={1} + borderWidth={0} + onClick={onClick} + motionConfig={"default"} + /> + +
+
+
+
+ ); +}; diff --git a/helpers/fetchApiData.ts b/helpers/fetchApiData.ts index a36d94339b..c7832918d1 100644 --- a/helpers/fetchApiData.ts +++ b/helpers/fetchApiData.ts @@ -1,7 +1,7 @@ export function validateListPath(path: string) { // () const regex = - /^lists\/([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{12}|([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{12}\/(contributors|stats\/(most-active-contributors|contributions-evolution-by-type))))\/??/; + /^lists\/([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{12}|([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{12}\/(contributors|stats\/(most-active-contributors|contributions-evolution-by-type|contributions-by-project))))\/??/; return regex.test(path); } diff --git a/lib/hooks/api/useContributionsByProject.ts b/lib/hooks/api/useContributionsByProject.ts new file mode 100644 index 0000000000..bc44b9f62d --- /dev/null +++ b/lib/hooks/api/useContributionsByProject.ts @@ -0,0 +1,27 @@ +import useSWR, { Fetcher } from "swr"; +import publicApiFetcher from "lib/utils/public-api-fetcher"; + +export const useContributionsByProject = ({ + listId, + range, + initialData, +}: { + listId: string; + range: number; + initialData?: DbProjectContributions[]; +}) => { + const { data, error } = useSWR( + `lists/${listId}/stats/contributions-by-project?range=${range}`, + publicApiFetcher as Fetcher + // { + // fallbackData: { + // `lists/${listId}/stats/contributions-by-project?range=${range}`: initialData + // }, + // } + ); + + return { + data, + error, + }; +}; diff --git a/lib/hooks/api/useContributorsByProject.ts b/lib/hooks/api/useContributorsByProject.ts new file mode 100644 index 0000000000..34a2bdbc8d --- /dev/null +++ b/lib/hooks/api/useContributorsByProject.ts @@ -0,0 +1,18 @@ +import useSWR, { Fetcher } from "swr"; +import { useState } from "react"; +import publicApiFetcher from "lib/utils/public-api-fetcher"; + +export const useContributorsByProject = (listId: string, range: number) => { + const [repoId, setRepoId] = useState(null); + const { data, error } = useSWR( + `lists/${listId}/stats/top-project-contributions-by-contributor?repoId=${repoId}&range=${range}`, + publicApiFetcher as Fetcher + ); + + return { + data, + error, + setRepoId, + repoId, + }; +}; diff --git a/lib/hooks/api/useMostActiveContributors.ts b/lib/hooks/api/useMostActiveContributors.ts index 38efc5a2cb..d3f998e407 100644 --- a/lib/hooks/api/useMostActiveContributors.ts +++ b/lib/hooks/api/useMostActiveContributors.ts @@ -20,16 +20,15 @@ const useMostActiveContributors = ({ listId, initData, intialLimit = 20, - initialRange = 30, + range = 30, defaultContributorType = "all", }: { listId: string; initData?: ContributorStat[]; intialLimit?: number; - initialRange?: number; + range?: number; defaultContributorType?: ContributorType; }) => { - const [range, setRange] = useState(initialRange); const [limit, setLimit] = useState(intialLimit); const [contributorType, setContributorType] = useState(defaultContributorType); @@ -52,7 +51,6 @@ const useMostActiveContributors = ({ data, isLoading: !error && !data, isError: !!error, - setRange, contributorType, setContributorType, }; diff --git a/lib/utils/color-utils.ts b/lib/utils/color-utils.ts new file mode 100644 index 0000000000..083e0bb1d7 --- /dev/null +++ b/lib/utils/color-utils.ts @@ -0,0 +1,26 @@ +export function stringToHSLAColor({ + id, + saturation = 90, + lightness = 48, + alpha = 1, +}: { + id: string; + saturation?: number; + lightness?: number; + alpha?: number; +}) { + // Ensure valid values for saturation and lightness (0-100) and alpha (0-1) + saturation = Math.min(Math.max(saturation, 0), 100); + lightness = Math.min(Math.max(lightness, 0), 100); + alpha = Math.min(Math.max(alpha, 0), 1); + + // Use a simple hashing algorithm to generate H, S, and L values + let hash = 0; + for (let i = 0; i < id.length; i++) { + hash = id.charCodeAt(i) + ((hash << 5) - hash); + } + + const h = ((hash % 360) + 360) % 360; // Ensure H value is between 0 and 360 + + return `hsla(${h}, ${saturation}%, ${lightness}%, ${alpha})`; +} diff --git a/lib/utils/nivo-utils.ts b/lib/utils/nivo-utils.ts new file mode 100644 index 0000000000..a0029df93a --- /dev/null +++ b/lib/utils/nivo-utils.ts @@ -0,0 +1,18 @@ +import { SpringValue, to } from "@react-spring/web"; + +/** + There are several utility functions in the @nico/* packages that are ESM only. If you are + unable to dynamically import them for usage in your project, you can copy the source code +here and use this instead. + +You'll know if you need to do this if you see an error like this: + + Error: require() of ES Module /Users/nicktaylor/dev/work/app/node_modules/@nivo/treemap/node_modules/d3-color/src/index.js from /Users/nicktaylor/dev/work/app/node_modules/@nivo/treemap/node_modules/@nivo/colors/dist/nivo-colors.cjs.js not supported. +Instead change the require of index.js in /Users/nicktaylor/dev/work/app/node_modules/@nivo/treemap/node_modules/@nivo/colors/dist/nivo-colors.cjs.js to a dynamic import() which is available in all CommonJS modules. + +**/ + +// See https://github.com/plouc/nivo/blob/master/packages/treemap/src/transitions.ts#L6-L7 +export function htmlNodeTransform(x: SpringValue, y: SpringValue) { + return to([x, y], (x, y) => `translate(${x}px, ${y}px)`); +} diff --git a/next-types.d.ts b/next-types.d.ts index 2d2db97377..0399ae57dc 100644 --- a/next-types.d.ts +++ b/next-types.d.ts @@ -369,3 +369,18 @@ interface DbListContributorStat { commits: number; prsCreated: number; } +interface DbProjectContributions { + org_id: string; + project_id: string; + repo_id: number; + contributions: number; +} + +interface DBProjectContributor { + login: string; + commits: number; + prs_created: number; + prs_reviewed: number; + issues_created: number; + comments: number; +} diff --git a/pages/lists/[listId]/activity.tsx b/pages/lists/[listId]/activity.tsx index f1a1d97602..c76106b34d 100644 --- a/pages/lists/[listId]/activity.tsx +++ b/pages/lists/[listId]/activity.tsx @@ -1,14 +1,18 @@ import { createPagesServerClient } from "@supabase/auth-helpers-nextjs"; import { GetServerSidePropsContext } from "next"; +import { useState } from "react"; +import { NodeMouseEventHandler } from "@nivo/treemap"; import Error from "components/atoms/Error/Error"; import { fetchApiData, validateListPath } from "helpers/fetchApiData"; import ListPageLayout from "layouts/lists"; import MostActiveContributorsCard, { ContributorStat, } from "components/molecules/MostActiveContributorsCard/most-active-contributors-card"; - import useMostActiveContributors from "lib/hooks/api/useMostActiveContributors"; import ClientOnly from "components/atoms/ClientOnly/client-only"; +import { ContributionsTreemap } from "components/molecules/ContributionsTreemap/contributions-treemap"; +import { useContributorsByProject } from "lib/hooks/api/useContributorsByProject"; +import { useContributionsByProject } from "lib/hooks/api/useContributionsByProject"; interface ContributorListPageProps { list?: DBList; @@ -17,6 +21,7 @@ interface ContributorListPageProps { activityData: { contributorStats: { data: ContributorStat[]; meta: Meta }; topContributor: ContributorStat; + projectData: DbProjectContributions[]; }; } @@ -33,6 +38,7 @@ export const getServerSideProps = async (ctx: GetServerSidePropsContext) => { { data, error: contributorListError }, { data: list, error }, { data: mostActiveData, error: mostActiveError }, + { data: projectData, error: projectError }, ] = await Promise.all([ fetchApiData>({ path: `lists/${listId}/contributors?limit=1`, @@ -45,6 +51,11 @@ export const getServerSideProps = async (ctx: GetServerSidePropsContext) => { bearerToken, pathValidator: validateListPath, }), + fetchApiData({ + path: `lists/${listId}/stats/contributions-by-project?range=${range}`, + bearerToken, + pathValidator: validateListPath, + }), ]); if (error?.status === 404 || error?.status === 401) { @@ -61,21 +72,53 @@ export const getServerSideProps = async (ctx: GetServerSidePropsContext) => { activityData: { contributorStats: mostActiveData, topContributor: mostActiveData?.data?.length ? mostActiveData.data[0] : null, + projectData: projectData ?? [], }, }, }; }; const ListActivityPage = ({ list, numberOfContributors, isError, activityData }: ContributorListPageProps) => { + const [range, setRange] = useState(30); const isOwner = false; const { data: contributorStats, isLoading, isError: isMostActiveError, - setRange, setContributorType, contributorType, - } = useMostActiveContributors({ listId: list!.id, initData: activityData.contributorStats.data }); + } = useMostActiveContributors({ listId: list!.id, initData: activityData.contributorStats.data, range }); + + const { setRepoId, error, data: projectContributionsByUser, repoId } = useContributorsByProject(list!.id, range); + + const { data: projectData, error: projectDataError } = useContributionsByProject({ + listId: list!.id, + range, + initialData: activityData.projectData, + }); + + const onHandleClick: NodeMouseEventHandler = (node) => { + // @ts-ignore TODO: fix this + setRepoId(Number(node.data.repoId)); + }; + const treemapData = { + id: "root", + children: + repoId === null + ? (projectData ?? []).map(({ org_id, project_id, repo_id, contributions }) => { + return { + id: `${org_id}/${project_id}`, + value: contributions, + repoId: `${repo_id}`, + }; + }) + : projectContributionsByUser?.map(({ login, commits, prs_created, prs_reviewed, issues_created, comments }) => { + return { + id: login, + value: commits + prs_created, // Coming soon + prs_reviewed + issues_created + comments, + }; + }), + }; return ( @@ -94,6 +137,13 @@ const ListActivityPage = ({ list, numberOfContributors, isError, activityData }: isLoading={isLoading} /> + )} diff --git a/stories/molecules/treemap-prototype/contributor-node.tsx b/stories/molecules/treemap-prototype/contributor-node.tsx index ca5ffc1098..4cad726a36 100644 --- a/stories/molecules/treemap-prototype/contributor-node.tsx +++ b/stories/molecules/treemap-prototype/contributor-node.tsx @@ -1,7 +1,9 @@ import { memo } from "react"; import { animated } from "@react-spring/web"; -import { NodeProps, htmlNodeTransform } from "@nivo/treemap"; import { getAvatarByUsername } from "lib/utils/github"; +import { htmlNodeTransform } from "lib/utils/nivo-utils"; +import { stringToHSLAColor } from "lib/utils/color-utils"; +import type { NodeProps } from "@nivo/treemap"; const NonMemoizedContributorNode = ({ node, @@ -14,44 +16,35 @@ const NonMemoizedContributorNode = labelSkipSize); const avatarURL = getAvatarByUsername(node.id); + const color = stringToHSLAColor({ id: node.id }); return ( {showLabel && ( ({ node, @@ -11,34 +13,28 @@ const NonMemoizedSpecialNode = ({ }: NodeProps) => { const showLabel = enableLabel && node.isLeaf && (labelSkipSize === 0 || Math.min(node.width, node.height) > labelSkipSize); + const [fullRepoName] = node.id.split(":"); + node.color = stringToHSLAColor({ id: node.id }); return ( ({ /> {showLabel && ( ({ }} >
-
{node.id}
+
{fullRepoName}
{node.label}
From 0b914bab081344fc1d2fc8c67fdcc1bc8e2f09ce Mon Sep 17 00:00:00 2001 From: Nick Taylor Date: Tue, 10 Oct 2023 22:18:47 -0400 Subject: [PATCH 19/21] fix: fixed API querystring param for repo_id for treemap API call --- lib/hooks/api/useContributorsByProject.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/hooks/api/useContributorsByProject.ts b/lib/hooks/api/useContributorsByProject.ts index 34a2bdbc8d..18677a0214 100644 --- a/lib/hooks/api/useContributorsByProject.ts +++ b/lib/hooks/api/useContributorsByProject.ts @@ -5,7 +5,7 @@ import publicApiFetcher from "lib/utils/public-api-fetcher"; export const useContributorsByProject = (listId: string, range: number) => { const [repoId, setRepoId] = useState(null); const { data, error } = useSWR( - `lists/${listId}/stats/top-project-contributions-by-contributor?repoId=${repoId}&range=${range}`, + `lists/${listId}/stats/top-project-contributions-by-contributor?repo_id=${repoId}&range=${range}`, publicApiFetcher as Fetcher ); From 9a94bf08fda293eb1a5f63553e6c8b4f2ce0f223 Mon Sep 17 00:00:00 2001 From: Nick Taylor Date: Tue, 10 Oct 2023 22:50:31 -0400 Subject: [PATCH 20/21] fix: made dynamic treemap import ssr false --- .../molecules/ContributionsTreemap/contributions-treemap.tsx | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/components/molecules/ContributionsTreemap/contributions-treemap.tsx b/components/molecules/ContributionsTreemap/contributions-treemap.tsx index 7090405b0a..e0e9e4e0de 100644 --- a/components/molecules/ContributionsTreemap/contributions-treemap.tsx +++ b/components/molecules/ContributionsTreemap/contributions-treemap.tsx @@ -28,7 +28,9 @@ function BreadCrumb({ isActive, ...rest }: any) { ); } -const ResponsiveTreeMapHtml = dynamic(() => import("@nivo/treemap").then((module) => module.ResponsiveTreeMapHtml)); +const ResponsiveTreeMapHtml = dynamic(() => import("@nivo/treemap").then((module) => module.ResponsiveTreeMapHtml), { + ssr: false, +}); export const ContributionsTreemap = ({ setRepoId, repoId, data, color, onClick }: ContributionsTreemapProps) => { return ( From ae164edf0c6bf0f6ad2ee5cc8fac0346aea93daa Mon Sep 17 00:00:00 2001 From: Nick Taylor Date: Wed, 11 Oct 2023 02:59:09 +0000 Subject: [PATCH 21/21] chore(minor): release 1.69.0-beta.8 on beta channel [skip ci] MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit ## [1.69.0-beta.8](https://github.com/open-sauced/insights/compare/v1.69.0-beta.7...v1.69.0-beta.8) (2023-10-11) ### πŸ• Features * add repos/contributors treemap to list activity page ([#1853](https://github.com/open-sauced/insights/issues/1853)) ([70a67f0](https://github.com/open-sauced/insights/commit/70a67f08f6ab649621ef2c6115ca43f99ccd44ad)) * display featured insight pages to new contributors ([#1859](https://github.com/open-sauced/insights/issues/1859)) ([5344c59](https://github.com/open-sauced/insights/commit/5344c59538ae77b0d5f662fcd04e5dcc19807cc8)) ### πŸ› Bug Fixes * fixed API querystring param for repo_id for treemap API call ([0b914ba](https://github.com/open-sauced/insights/commit/0b914bab081344fc1d2fc8c67fdcc1bc8e2f09ce)) * made dynamic treemap import ssr false ([9a94bf0](https://github.com/open-sauced/insights/commit/9a94bf08fda293eb1a5f63553e6c8b4f2ce0f223)) --- CHANGELOG.md | 14 ++++++++++++++ npm-shrinkwrap.json | 4 ++-- package.json | 2 +- 3 files changed, 17 insertions(+), 3 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index e39b633fef..9f540cc06e 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -5,6 +5,20 @@ > All notable changes to this project will be documented in this file +## [1.69.0-beta.8](https://github.com/open-sauced/insights/compare/v1.69.0-beta.7...v1.69.0-beta.8) (2023-10-11) + + +### πŸ• Features + +* add repos/contributors treemap to list activity page ([#1853](https://github.com/open-sauced/insights/issues/1853)) ([70a67f0](https://github.com/open-sauced/insights/commit/70a67f08f6ab649621ef2c6115ca43f99ccd44ad)) +* display featured insight pages to new contributors ([#1859](https://github.com/open-sauced/insights/issues/1859)) ([5344c59](https://github.com/open-sauced/insights/commit/5344c59538ae77b0d5f662fcd04e5dcc19807cc8)) + + +### πŸ› Bug Fixes + +* fixed API querystring param for repo_id for treemap API call ([0b914ba](https://github.com/open-sauced/insights/commit/0b914bab081344fc1d2fc8c67fdcc1bc8e2f09ce)) +* made dynamic treemap import ssr false ([9a94bf0](https://github.com/open-sauced/insights/commit/9a94bf08fda293eb1a5f63553e6c8b4f2ce0f223)) + ## [1.69.0-beta.7](https://github.com/open-sauced/insights/compare/v1.69.0-beta.6...v1.69.0-beta.7) (2023-10-11) diff --git a/npm-shrinkwrap.json b/npm-shrinkwrap.json index 513a47ed11..fde1f70287 100644 --- a/npm-shrinkwrap.json +++ b/npm-shrinkwrap.json @@ -1,12 +1,12 @@ { "name": "@open-sauced/insights", - "version": "1.69.0-beta.7", + "version": "1.69.0-beta.8", "lockfileVersion": 3, "requires": true, "packages": { "": { "name": "@open-sauced/insights", - "version": "1.69.0-beta.7", + "version": "1.69.0-beta.8", "hasInstallScript": true, "license": "Apache 2.0", "dependencies": { diff --git a/package.json b/package.json index 29ef59ab07..8b64244618 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.69.0-beta.7", + "version": "1.69.0-beta.8", "author": "Brian Douglas ", "private": true, "license": "Apache 2.0",