♻️ refactor: restructured and restryling repository list component
This commit is contained in:
parent
b1bf47d104
commit
99eb514306
@ -3,13 +3,17 @@ import { Octokit } from 'octokit';
|
|||||||
import assert from 'assert';
|
import assert from 'assert';
|
||||||
import { useDebounce } from 'usehooks-ts';
|
import { useDebounce } from 'usehooks-ts';
|
||||||
|
|
||||||
import { Button, Typography, Option } from '@material-tailwind/react';
|
import { Button, Typography } from '@material-tailwind/react';
|
||||||
|
|
||||||
import SearchBar from '../../SearchBar';
|
import { ProjectRepoCard } from 'components/projects/create/ProjectRepoCard';
|
||||||
import ProjectRepoCard from './ProjectRepoCard';
|
import { GitOrgDetails, GitRepositoryDetails } from 'types';
|
||||||
import { GitOrgDetails, GitRepositoryDetails } from '../../../types';
|
import {
|
||||||
import AsyncSelect from '../../shared/AsyncSelect';
|
ChevronGrabberHorizontal,
|
||||||
import { GithubIcon } from 'components/shared/CustomIcon';
|
GithubIcon,
|
||||||
|
SearchIcon,
|
||||||
|
} from 'components/shared/CustomIcon';
|
||||||
|
import { Select, SelectOption } from 'components/shared/Select';
|
||||||
|
import { Input } from 'components/shared/Input';
|
||||||
|
|
||||||
const DEFAULT_SEARCHED_REPO = '';
|
const DEFAULT_SEARCHED_REPO = '';
|
||||||
const REPOS_PER_PAGE = 5;
|
const REPOS_PER_PAGE = 5;
|
||||||
@ -18,9 +22,9 @@ interface RepositoryListProps {
|
|||||||
octokit: Octokit;
|
octokit: Octokit;
|
||||||
}
|
}
|
||||||
|
|
||||||
const RepositoryList = ({ octokit }: RepositoryListProps) => {
|
export const RepositoryList = ({ octokit }: RepositoryListProps) => {
|
||||||
const [searchedRepo, setSearchedRepo] = useState(DEFAULT_SEARCHED_REPO);
|
const [searchedRepo, setSearchedRepo] = useState(DEFAULT_SEARCHED_REPO);
|
||||||
const [selectedAccount, setSelectedAccount] = useState('');
|
const [selectedAccount, setSelectedAccount] = useState<SelectOption>();
|
||||||
const [orgs, setOrgs] = useState<GitOrgDetails[]>([]);
|
const [orgs, setOrgs] = useState<GitOrgDetails[]>([]);
|
||||||
// TODO: Add new type for Git user when required
|
// TODO: Add new type for Git user when required
|
||||||
const [gitUser, setGitUser] = useState<GitOrgDetails>();
|
const [gitUser, setGitUser] = useState<GitOrgDetails>();
|
||||||
@ -35,7 +39,7 @@ const RepositoryList = ({ octokit }: RepositoryListProps) => {
|
|||||||
const orgs = await octokit.rest.orgs.listForAuthenticatedUser();
|
const orgs = await octokit.rest.orgs.listForAuthenticatedUser();
|
||||||
setOrgs(orgs.data);
|
setOrgs(orgs.data);
|
||||||
setGitUser(user.data);
|
setGitUser(user.data);
|
||||||
setSelectedAccount(user.data.login);
|
setSelectedAccount({ label: user.data.login, value: user.data.login });
|
||||||
};
|
};
|
||||||
|
|
||||||
fetchUserAndOrgs();
|
fetchUserAndOrgs();
|
||||||
@ -54,7 +58,7 @@ const RepositoryList = ({ octokit }: RepositoryListProps) => {
|
|||||||
let query = `${debouncedSearchedRepo} in:name fork:true`;
|
let query = `${debouncedSearchedRepo} in:name fork:true`;
|
||||||
|
|
||||||
// Check if selected account is an organization
|
// Check if selected account is an organization
|
||||||
if (selectedAccount === gitUser.login) {
|
if (selectedAccount.value === gitUser.login) {
|
||||||
query = query + ` user:${selectedAccount}`;
|
query = query + ` user:${selectedAccount}`;
|
||||||
} else {
|
} else {
|
||||||
query = query + ` org:${selectedAccount}`;
|
query = query + ` org:${selectedAccount}`;
|
||||||
@ -69,7 +73,7 @@ const RepositoryList = ({ octokit }: RepositoryListProps) => {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (selectedAccount === gitUser.login) {
|
if (selectedAccount.value === gitUser.login) {
|
||||||
const result = await octokit.rest.repos.listForAuthenticatedUser({
|
const result = await octokit.rest.repos.listForAuthenticatedUser({
|
||||||
per_page: REPOS_PER_PAGE,
|
per_page: REPOS_PER_PAGE,
|
||||||
affiliation: 'owner',
|
affiliation: 'owner',
|
||||||
@ -78,7 +82,9 @@ const RepositoryList = ({ octokit }: RepositoryListProps) => {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
const selectedOrg = orgs.find((org) => org.login === selectedAccount);
|
const selectedOrg = orgs.find(
|
||||||
|
(org) => org.login === selectedAccount.value,
|
||||||
|
);
|
||||||
assert(selectedOrg, 'Selected org not found in list');
|
assert(selectedOrg, 'Selected org not found in list');
|
||||||
|
|
||||||
const result = await octokit.rest.repos.listForOrg({
|
const result = await octokit.rest.repos.listForOrg({
|
||||||
@ -96,7 +102,7 @@ const RepositoryList = ({ octokit }: RepositoryListProps) => {
|
|||||||
const handleResetFilters = useCallback(() => {
|
const handleResetFilters = useCallback(() => {
|
||||||
assert(gitUser, 'Git user is not available');
|
assert(gitUser, 'Git user is not available');
|
||||||
setSearchedRepo(DEFAULT_SEARCHED_REPO);
|
setSearchedRepo(DEFAULT_SEARCHED_REPO);
|
||||||
setSelectedAccount(gitUser.login);
|
setSelectedAccount({ label: gitUser.login, value: gitUser.login });
|
||||||
}, [gitUser]);
|
}, [gitUser]);
|
||||||
|
|
||||||
const accounts = useMemo(() => {
|
const accounts = useMemo(() => {
|
||||||
@ -107,35 +113,51 @@ const RepositoryList = ({ octokit }: RepositoryListProps) => {
|
|||||||
return [gitUser, ...orgs];
|
return [gitUser, ...orgs];
|
||||||
}, [octokit, orgs, gitUser]);
|
}, [octokit, orgs, gitUser]);
|
||||||
|
|
||||||
|
const options = useMemo(() => {
|
||||||
|
return accounts.map((account) => ({
|
||||||
|
label: account.login,
|
||||||
|
value: account.login,
|
||||||
|
leftIcon: <GithubIcon />,
|
||||||
|
}));
|
||||||
|
}, [accounts]);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className="p-4">
|
<section className="space-y-3">
|
||||||
<div className="flex gap-2 mb-2 items-center">
|
{/* Dropdown and search */}
|
||||||
<div className="basis-1/3">
|
<div className="flex flex-col lg:flex-row gap-0 lg:gap-3 items-center">
|
||||||
<AsyncSelect
|
<div className="lg:basis-1/3 w-full">
|
||||||
|
<Select
|
||||||
|
options={options}
|
||||||
|
placeholder="Select a repository"
|
||||||
value={selectedAccount}
|
value={selectedAccount}
|
||||||
onChange={(value) => setSelectedAccount(value!)}
|
rightIcon={<ChevronGrabberHorizontal />}
|
||||||
>
|
onChange={(value) => setSelectedAccount(value as SelectOption)}
|
||||||
{accounts.map((account) => (
|
/>
|
||||||
<Option key={account.id} value={account.login}>
|
|
||||||
<div className="flex items-center gap-2 justify-start">
|
|
||||||
<GithubIcon /> {account.login}
|
|
||||||
</div>
|
</div>
|
||||||
</Option>
|
<div className="basis-2/3 flex w-full flex-grow">
|
||||||
))}
|
<Input
|
||||||
</AsyncSelect>
|
className="w-full"
|
||||||
</div>
|
|
||||||
<div className="basis-2/3 flex-grow flex items-center">
|
|
||||||
<SearchBar
|
|
||||||
value={searchedRepo}
|
value={searchedRepo}
|
||||||
onChange={(event) => setSearchedRepo(event.target.value)}
|
|
||||||
placeholder="Search for repository"
|
placeholder="Search for repository"
|
||||||
|
leftIcon={<SearchIcon />}
|
||||||
|
onChange={(e) => setSearchedRepo(e.target.value)}
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
{/* Repository list */}
|
||||||
{Boolean(repositoryDetails.length) ? (
|
{Boolean(repositoryDetails.length) ? (
|
||||||
repositoryDetails.map((repo, key) => {
|
<div className="flex flex-col gap-2">
|
||||||
return <ProjectRepoCard repository={repo} key={key} />;
|
{repositoryDetails.map((repo, index) => (
|
||||||
})
|
<>
|
||||||
|
<ProjectRepoCard repository={repo} key={index} />
|
||||||
|
{/* Horizontal line */}
|
||||||
|
{index !== repositoryDetails.length - 1 && (
|
||||||
|
<div className="border-b border-border-separator/[0.06] w-full" />
|
||||||
|
)}
|
||||||
|
</>
|
||||||
|
))}
|
||||||
|
</div>
|
||||||
) : (
|
) : (
|
||||||
<div className="mt-4 p-6 flex items-center justify-center">
|
<div className="mt-4 p-6 flex items-center justify-center">
|
||||||
<div className="text-center">
|
<div className="text-center">
|
||||||
@ -151,8 +173,6 @@ const RepositoryList = ({ octokit }: RepositoryListProps) => {
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
)}
|
)}
|
||||||
</div>
|
</section>
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|
||||||
export default RepositoryList;
|
|
@ -0,0 +1 @@
|
|||||||
|
export * from './RepositoryList';
|
@ -1,7 +1,7 @@
|
|||||||
import React from 'react';
|
import React from 'react';
|
||||||
|
|
||||||
import templates from 'assets/templates';
|
import templates from 'assets/templates';
|
||||||
import RepositoryList from 'components/projects/create/RepositoryList';
|
import { RepositoryList } from 'components/projects/create/RepositoryList';
|
||||||
import ConnectAccount from 'components/projects/create/ConnectAccount';
|
import ConnectAccount from 'components/projects/create/ConnectAccount';
|
||||||
import { useOctokit } from 'context/OctokitContext';
|
import { useOctokit } from 'context/OctokitContext';
|
||||||
import { Heading } from 'components/shared/Heading';
|
import { Heading } from 'components/shared/Heading';
|
||||||
@ -13,8 +13,8 @@ const NewProject = () => {
|
|||||||
return isAuth ? (
|
return isAuth ? (
|
||||||
<>
|
<>
|
||||||
<div className="space-y-3">
|
<div className="space-y-3">
|
||||||
<Heading as="h3" className="font-medium text-lg">
|
<Heading as="h3" className="font-medium text-lg pl-1">
|
||||||
Start with template
|
Start with a template
|
||||||
</Heading>
|
</Heading>
|
||||||
<div className="grid grid-cols-1 sm:grid-cols-2 xl:grid-cols-3 gap-3">
|
<div className="grid grid-cols-1 sm:grid-cols-2 xl:grid-cols-3 gap-3">
|
||||||
{templates.map((template) => {
|
{templates.map((template) => {
|
||||||
@ -28,7 +28,7 @@ const NewProject = () => {
|
|||||||
})}
|
})}
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<Heading as="h3" className="font-medium text-lg mt-10">
|
<Heading as="h3" className="font-medium text-lg mt-10 pl-1 mb-3">
|
||||||
Import a repository
|
Import a repository
|
||||||
</Heading>
|
</Heading>
|
||||||
<RepositoryList octokit={octokit} />
|
<RepositoryList octokit={octokit} />
|
||||||
|
Loading…
Reference in New Issue
Block a user