From c7923f6d445201aad761d8db104ce5d0bb492f01 Mon Sep 17 00:00:00 2001 From: Aaryan Khandelwal <65252264+aaryan610@users.noreply.github.com> Date: Fri, 10 Mar 2023 16:03:49 +0530 Subject: [PATCH] feat: added load more button to github repos dropdown (#414) --- .../project/single-integration-card.tsx | 157 ++++++++++++++---- apps/app/services/api.service.ts | 9 + apps/app/services/project.service.ts | 9 +- apps/app/styles/globals.css | 56 ++++--- 4 files changed, 170 insertions(+), 61 deletions(-) diff --git a/apps/app/components/project/single-integration-card.tsx b/apps/app/components/project/single-integration-card.tsx index 42220647bb..dc2630a2ed 100644 --- a/apps/app/components/project/single-integration-card.tsx +++ b/apps/app/components/project/single-integration-card.tsx @@ -1,16 +1,22 @@ +import React, { useState } from "react"; + import Image from "next/image"; import useSWR, { mutate } from "swr"; +import useSWRInfinite from "swr/infinite"; +// headless ui +import { Combobox, Transition } from "@headlessui/react"; // services import projectService from "services/project.service"; // hooks import { useRouter } from "next/router"; import useToast from "hooks/use-toast"; -// ui -import { CustomSelect } from "components/ui"; // icons +import { CheckIcon, ChevronDownIcon, MagnifyingGlassIcon } from "@heroicons/react/24/outline"; import GithubLogo from "public/logos/github-square.png"; +// helpers +import { truncateText } from "helpers/string.helper"; // types import { IWorkspaceIntegrations } from "types"; // fetch-keys @@ -21,6 +27,8 @@ type Props = { }; export const SingleIntegration: React.FC = ({ integration }) => { + const [query, setQuery] = useState(""); + const router = useRouter(); const { workspaceSlug, projectId } = router.query; @@ -38,11 +46,28 @@ export const SingleIntegration: React.FC = ({ integration }) => { : null ); - const { data: userRepositories } = useSWR("USER_REPOSITORIES", () => - workspaceSlug && integration - ? projectService.getGithubRepositories(workspaceSlug as any, integration.id) - : null - ); + const getKey = (pageIndex: number) => { + if (!workspaceSlug || !integration) return; + + return `${ + process.env.NEXT_PUBLIC_API_BASE_URL + }/api/workspaces/${workspaceSlug}/workspace-integrations/${ + integration.id + }/github-repositories/?page=${++pageIndex}`; + }; + + const fetchGithubRepos = async (url: string) => { + const data = await projectService.getGithubRepositories(url); + + return data; + }; + + const { + data: paginatedData, + size, + setSize, + isValidating, + } = useSWRInfinite(getKey, fetchGithubRepos); const handleChange = (repo: any) => { if (!workspaceSlug || !projectId || !integration) return; @@ -82,6 +107,21 @@ export const SingleIntegration: React.FC = ({ integration }) => { }); }; + const userRepositories = (paginatedData ?? []).map((data) => data.repositories).flat(); + const totalCount = paginatedData && paginatedData.length > 0 ? paginatedData[0].total_count : 0; + + const options = + userRepositories.map((repo) => ({ + value: repo.id, + query: repo.full_name, + content:

{truncateText(repo.full_name, 25)}

, + })) ?? []; + + const filteredOptions = + query === "" + ? options + : options?.filter((option) => option.query.toLowerCase().includes(query.toLowerCase())); + return ( <> {integration && ( @@ -97,42 +137,95 @@ export const SingleIntegration: React.FC = ({ integration }) => {

Select GitHub repository to enable sync.

- 0 ? `${syncedGithubRepository[0].repo_detail.owner}/${syncedGithubRepository[0].repo_detail.name}` : null } onChange={(val: string) => { - const repo = userRepositories?.repositories.find((repo) => repo.full_name === val); + const repo = userRepositories.find((repo) => repo.id === val); handleChange(repo); }} - label={ - syncedGithubRepository && syncedGithubRepository.length > 0 - ? `${syncedGithubRepository[0].repo_detail.owner}/${syncedGithubRepository[0].repo_detail.name}` - : "Select Repository" - } - input + className="relative flex-shrink-0 text-left" > - {userRepositories ? ( - userRepositories.repositories.length > 0 ? ( - userRepositories.repositories.map((repo) => ( - - <>{repo.full_name} - - )) - ) : ( -

No repositories found

- ) - ) : ( -

Loading repositories...

+ {({ open }: any) => ( + <> + + {syncedGithubRepository && syncedGithubRepository.length > 0 + ? `${syncedGithubRepository[0].repo_detail.owner}/${syncedGithubRepository[0].repo_detail.name}` + : "Select Repository"} + + + + +
+ + setQuery(e.target.value)} + placeholder="Type to search..." + displayValue={(assigned: any) => assigned?.name} + /> +
+
+

+ {options.length} of {totalCount} repositories +

+ {paginatedData ? ( + filteredOptions.length > 0 ? ( + filteredOptions.map((option) => ( + + `${active || selected ? "bg-hover-gray" : ""} ${ + selected ? "font-medium" : "" + } flex cursor-pointer select-none items-center justify-between gap-2 truncate rounded px-1 py-1.5 text-gray-500` + } + > + {({ selected }) => ( + <> + {option.content} + {selected && } + + )} + + )) + ) : ( +

No matching results

+ ) + ) : ( +

Loading...

+ )} + {userRepositories && options.length < totalCount && ( + + )} +
+
+
+ )} -
+ )} diff --git a/apps/app/services/api.service.ts b/apps/app/services/api.service.ts index 112a87f9ea..a625c0b37a 100644 --- a/apps/app/services/api.service.ts +++ b/apps/app/services/api.service.ts @@ -39,6 +39,15 @@ abstract class APIService { }; } + getWithoutBase(url: string, config = {}): Promise { + return axios({ + method: "get", + url: url, + headers: this.getAccessToken() ? this.getHeaders() : {}, + ...config, + }); + } + get(url: string, config = {}): Promise { return axios({ method: "get", diff --git a/apps/app/services/project.service.ts b/apps/app/services/project.service.ts index cb280596e0..ec07b7aa4f 100644 --- a/apps/app/services/project.service.ts +++ b/apps/app/services/project.service.ts @@ -209,13 +209,8 @@ class ProjectServices extends APIService { }); } - async getGithubRepositories( - slug: string, - workspaceIntegrationId: string - ): Promise { - return this.get( - `/api/workspaces/${slug}/workspace-integrations/${workspaceIntegrationId}/github-repositories/` - ) + async getGithubRepositories(url: string): Promise { + return this.getWithoutBase(url) .then((response) => response?.data) .catch((error) => { throw error?.response?.data; diff --git a/apps/app/styles/globals.css b/apps/app/styles/globals.css index e6490a822e..f4dd63e48f 100644 --- a/apps/app/styles/globals.css +++ b/apps/app/styles/globals.css @@ -30,34 +30,46 @@ -webkit-font-smoothing: antialiased; } -/* Horizontal Scrollbar style */ -.horizontal-scroll-enable{ - overflow-x: scroll; -} +/* scrollbar style */ -.horizontal-scroll-enable::-webkit-scrollbar{ - display: block; - height: 10px; -} - -.horizontal-scroll-enable::-webkit-scrollbar-thumb{ - border-radius: 5px; - background-color: #9ca3af; -} -/* end Horizontal Scrollbar style */ -.scrollbar-enable::-webkit-scrollbar { - display: block; -} - -/* Scrollbar style */ ::-webkit-scrollbar { display: none; } -.no-scrollbar::-webkit-scrollbar { - display: none; +.horizontal-scroll-enable { + overflow-x: scroll; } -/* End scrollbar style */ + +.horizontal-scroll-enable::-webkit-scrollbar { + display: block; + height: 7px; +} + +.horizontal-scroll-enable::-webkit-scrollbar-track { + height: 7px; + background-color: #f5f5f5; +} + +.horizontal-scroll-enable::-webkit-scrollbar-thumb { + border-radius: 5px; + background-color: #9ca3af; +} + +.vertical-scroll-enable::-webkit-scrollbar { + display: block; + width: 5px; +} + +.vertical-scroll-enable::-webkit-scrollbar-track { + width: 5px; + background-color: #f5f5f5; +} + +.vertical-scroll-enable::-webkit-scrollbar-thumb { + border-radius: 5px; + background-color: #9ca3af; +} +/* end scrollbar style */ .tags-input-container { border: 2px solid #000;