Skip to content

Commit

Permalink
feat: GitHub modal
Browse files Browse the repository at this point in the history
  • Loading branch information
RezaRahemtola authored Mar 9, 2023
2 parents b4e8305 + c1582df commit 3f72bec
Show file tree
Hide file tree
Showing 6 changed files with 143 additions and 90 deletions.
28 changes: 28 additions & 0 deletions src/components/Tooltip.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
import { PopoverTrigger, Text, Popover, PopoverContent, PopoverProps, Box } from '@chakra-ui/react';
import { InfoIcon } from '@chakra-ui/icons';

const Tooltip = ({
text,
content,
...props
}: {
text?: string;
content?: JSX.Element;
color?: string;
} & PopoverProps): JSX.Element => (
<Popover placement="auto" trigger="hover" {...props}>
<PopoverTrigger>
<Box p={{ base: '8px', xl: '4px' }}>
<InfoIcon boxSize="16px" cursor="pointer" color="blue.1100" alignSelf="center" />
</Box>
</PopoverTrigger>
<Box>
<PopoverContent p={4}>
{text && <Text size="md">{text}</Text>}
{content}
</PopoverContent>
</Box>
</Popover>
);

export default Tooltip;
27 changes: 14 additions & 13 deletions src/components/computing/CustomProgram.tsx
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { Input } from '@chakra-ui/react';
import { Input, Text, VStack } from '@chakra-ui/react';
import { ChangeEvent } from 'react';

type CustomProgramParams = {
Expand All @@ -14,18 +14,19 @@ const CustomProgram = ({
customEntrypoint,
setCustomEntrypoint,
}: CustomProgramParams): JSX.Element => (
<>
<Input
placeholder="[Optional] Program name"
value={customName}
onChange={(e: ChangeEvent<HTMLInputElement>) => setCustomName(e.target.value)}
/>
<Input
placeholder="[Optional] Program entrypoint"
value={customEntrypoint}
onChange={(e: ChangeEvent<HTMLInputElement>) => setCustomEntrypoint(e.target.value)}
/>
</>
<VStack spacing="16px" w="100%">
<VStack spacing="8px" align="start" w="100%">
<Text size="boldLg">The name of the program</Text>
<Input value={customName} onChange={(e: ChangeEvent<HTMLInputElement>) => setCustomName(e.target.value)} />
</VStack>
<VStack spacing="8px" align="start" w="100%">
<Text size="boldLg">The entrypoint of the program</Text>
<Input
value={customEntrypoint}
onChange={(e: ChangeEvent<HTMLInputElement>) => setCustomEntrypoint(e.target.value)}
/>
</VStack>
</VStack>
);

export default CustomProgram;
112 changes: 62 additions & 50 deletions src/components/computing/github/GithubModal.tsx
Original file line number Diff line number Diff line change
@@ -1,17 +1,19 @@
import { ChangeEvent, useEffect, useState } from 'react';
import { HStack, Select, useToast, Text, VStack } from '@chakra-ui/react';
import { HStack, useToast, Text, VStack, Input, Skeleton } from '@chakra-ui/react';
import axios from 'axios';
import { signIn, signOut, useSession } from 'next-auth/react';
import { useRouter } from 'next/router';

import Modal from 'components/Modal';
import Button from 'components/Button';
import Tooltip from 'components/Tooltip';
import Card from 'components/cards/Card';

import { useUserContext } from 'contexts/user';
import { useDriveContext } from 'contexts/drive';

import { GitHubRepository, IPCProgram } from 'types/types';
import { ChevronLeftIcon, ChevronRightIcon } from '@chakra-ui/icons';

import CustomProgram from '../CustomProgram';

const GithubModal = ({ isOpen, onClose }: { isOpen: boolean; onClose: () => void }): JSX.Element => {
Expand All @@ -27,8 +29,8 @@ const GithubModal = ({ isOpen, onClose }: { isOpen: boolean; onClose: () => void
const [customName, setCustomName] = useState<string>('');
const [customEntrypoint, setCustomEntrypoint] = useState<string>('');
const [repositories, setRepositories] = useState<GitHubRepository[]>([]);
const [selectedPage, setSelectedPage] = useState(1);
const [hasMore, setHasMore] = useState(false);
const [repositoriesLoading, setRepositoriesLoading] = useState(false);
const [searchInput, setSearchInput] = useState(selectedRepository);

useEffect(() => {
(async () => {
Expand All @@ -39,10 +41,10 @@ const GithubModal = ({ isOpen, onClose }: { isOpen: boolean; onClose: () => void
}, []);

useEffect(() => {
(async () => {
await getRepositories();
})();
}, [selectedPage]);
const foundRepository = repositories.find((repository) => repository.html_url === selectedRepository);
if (foundRepository) setSearchInput(`${foundRepository.owner.login} - ${foundRepository.name}`);
else setSearchInput('');
}, [selectedRepository]);

const cloneToBackend = async (repository: string) => {
try {
Expand Down Expand Up @@ -75,14 +77,19 @@ const GithubModal = ({ isOpen, onClose }: { isOpen: boolean; onClose: () => void

const getRepositories = async () => {
try {
const result = await axios.get(`/api/computing/github/repositories?page=${selectedPage}`);
if (result.status !== 200) throw new Error("Unable to load repositories from github's API");
setHasMore(result.data.hasMore);
setRepositories(result.data.repositories);
toast({
title: 'Repositories loaded',
status: 'success',
});
const repositoryList: GitHubRepository[] = [];
let hasMore = true;

setRepositoriesLoading(true);
for (let i = 1; hasMore; i += 1) {
// eslint-disable-next-line no-await-in-loop
const result = await axios.get(`/api/computing/github/repositories?page=${i}`);
if (result.status !== 200) throw new Error("Unable to load repositories from github's API");
hasMore = result.data.hasMore;
repositoryList.push(...result.data.repositories);
}
setRepositories(repositoryList);
setRepositoriesLoading(false);
} catch (error) {
console.error(error);
}
Expand All @@ -94,7 +101,7 @@ const GithubModal = ({ isOpen, onClose }: { isOpen: boolean; onClose: () => void
onClose={onClose}
title="Deploy from Github"
CTA={
<HStack w="100%" justify="space-between">
<HStack w="100%" spacing="32px">
<Button
variant="primary"
w="100%"
Expand All @@ -112,6 +119,7 @@ const GithubModal = ({ isOpen, onClose }: { isOpen: boolean; onClose: () => void
<Button
variant="special"
size="lg"
w="100%"
onClick={() => signIn('github')}
id="ipc-dashboard-github-signin-button"
>
Expand All @@ -121,6 +129,7 @@ const GithubModal = ({ isOpen, onClose }: { isOpen: boolean; onClose: () => void
<Button
variant="secondary"
size="lg"
w="100%"
onClick={async () => signOut()}
id="ipc-dashboard-github-signout-button"
>
Expand All @@ -138,47 +147,50 @@ const GithubModal = ({ isOpen, onClose }: { isOpen: boolean; onClose: () => void
)}
{session && (
<>
<VStack spacing="5%">
<VStack spacing="16px" w="100%" align="start">
<CustomProgram
customName={customName}
setCustomName={setCustomName}
customEntrypoint={customEntrypoint}
setCustomEntrypoint={setCustomEntrypoint}
/>
<VStack w="100%">
<HStack justify="space-between" w="100%">
<Text>Dont see your repository?</Text>
<HStack spacing="16px">
<ChevronLeftIcon
cursor={selectedPage > 1 ? 'pointer' : 'not-allowed'}
onClick={() => setSelectedPage(selectedPage === 1 ? 1 : selectedPage - 1)}
/>
<Text>{selectedPage}</Text>
<ChevronRightIcon
cursor={hasMore ? 'pointer' : 'not-allowed'}
onClick={() => setSelectedPage(hasMore ? selectedPage + 1 : selectedPage)}
/>
<VStack spacing="8px" align="start" w="100%">
<VStack spacing="8px" align="start" w="100%">
<HStack>
<Text size="boldLg">The name of the repository</Text>
<Tooltip text="You need to select a repository from the list below, to deploy your program." />
</HStack>
</HStack>
<Select
onChange={(e: ChangeEvent<HTMLSelectElement>) => setSelectedRepository(e.target.value)}
placeholder="Select repository"
>
{repositories.map((repository, index: number) => (
<option key={index} value={repository.html_url}>
{repository.owner.login} - {repository.name}
</option>
))}
</Select>
<Input
value={searchInput}
onChange={(e: ChangeEvent<HTMLInputElement>) => setSearchInput(e.target.value)}
/>
</VStack>
<Card w="100%" p="8px">
<Skeleton isLoaded={!repositoriesLoading} w="100%" borderRadius="8px">
<VStack h="200px" overflowY="scroll" align="start" spacing="4px" pr="8px" w="100%">
{repositories
.filter((repository) =>
`${repository.owner.login.toLowerCase()} - ${repository.name.toLowerCase()}`.includes(
searchInput.toLowerCase(),
),
)
.map((repository) => (
<Text
p="4px 8px"
borderRadius="8px"
w="100%"
_hover={{
bg: 'blue.100',
}}
onClick={() => setSelectedRepository(repository.html_url)}
>
{repository.owner.login} - {repository.name}
</Text>
))}
</VStack>
</Skeleton>
</Card>
</VStack>
<Button
variant="inline"
w="100%"
onClick={async () => signOut()}
id="ipc-dashboard-github-signout-button"
>
Sign out
</Button>
</VStack>
</>
)}
Expand Down
25 changes: 14 additions & 11 deletions src/components/computing/programs/ProgramModal.tsx
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import { ChangeEvent, useState } from 'react';
import { Input, useToast } from '@chakra-ui/react';
import { Input, Text, useToast, VStack } from '@chakra-ui/react';

import Modal from 'components/Modal';

Expand Down Expand Up @@ -78,22 +78,25 @@ const ProgramModal = ({
</Button>
}
>
<>
<VStack spacing="16px" w="100%" align="start">
<CustomProgram
customName={customName}
setCustomName={setCustomName}
customEntrypoint={customEntrypoint}
setCustomEntrypoint={setCustomEntrypoint}
/>
<Input
type="file"
h="100%"
w="100%"
p="10px"
onChange={(e: ChangeEvent<HTMLInputElement>) => setFileEvent(e)}
id="ipc-dashboard-deploy-program-modal"
/>
</>
<VStack spacing="8px" align="start" w="100%">
<Text size="boldLg">The file of the program</Text>
<Input
type="file"
h="100%"
w="100%"
p="10px"
onChange={(e: ChangeEvent<HTMLInputElement>) => setFileEvent(e)}
id="ipc-dashboard-deploy-program-modal"
/>
</VStack>
</VStack>
</Modal>
);
};
Expand Down
23 changes: 7 additions & 16 deletions src/components/folder/CreateFolder.tsx
Original file line number Diff line number Diff line change
@@ -1,23 +1,14 @@
import {
FormControl,
FormLabel,
HStack,
Icon,
Input,
Text,
useBreakpointValue,
useDisclosure,
useToast,
} from '@chakra-ui/react';
import { HStack, Icon, Input, Text, useBreakpointValue, useDisclosure, useToast, VStack } from '@chakra-ui/react';
import { ChangeEvent, useState } from 'react';
import { AiOutlineFolderAdd } from 'react-icons/ai';

import Modal from 'components/Modal';
import Button from 'components/Button';

import type { IPCFolder } from 'types/types';

import { useDriveContext } from 'contexts/drive';
import { useUserContext } from 'contexts/user';
import { AiOutlineFolderAdd } from 'react-icons/ai';
import Button from 'components/Button';

const CreateFolder = (): JSX.Element => {
const { user } = useUserContext();
Expand Down Expand Up @@ -106,8 +97,8 @@ const CreateFolder = (): JSX.Element => {
</Button>
}
>
<FormControl>
<FormLabel>Name</FormLabel>
<VStack spacing="8px" align="start" w="100%">
<Text size="boldLg">The name of the folder</Text>
<Input
type="text"
w="100%"
Expand All @@ -116,7 +107,7 @@ const CreateFolder = (): JSX.Element => {
onChange={(e: ChangeEvent<HTMLInputElement>) => setName(e.target.value)}
id="ipc-dashboard-input-folder-name"
/>
</FormControl>
</VStack>
</Modal>
</HStack>
);
Expand Down
18 changes: 18 additions & 0 deletions src/theme/index.css
Original file line number Diff line number Diff line change
Expand Up @@ -12,3 +12,21 @@ html {
a {
text-decoration: none !important;
}

::-webkit-scrollbar {
width: 8px;
}

::-webkit-scrollbar-track {
background: #E8EBFF;
border-radius: 4px;
}

::-webkit-scrollbar-thumb {
background: #ADBAFF;
border-radius: 4px;
}

::-webkit-scrollbar-thumb:hover {
background: #7388FF;
}

0 comments on commit 3f72bec

Please sign in to comment.