From b43ee3b7bbf8f3c4d0d6a37f19201c29e44bca1f Mon Sep 17 00:00:00 2001 From: Sushan Yadav Date: Wed, 28 Feb 2024 16:39:26 +0545 Subject: [PATCH 01/64] feat: add deplyment infos --- .../project/overview/Activity/Activity.tsx | 28 +++ .../{ => overview/Activity}/ActivityCard.tsx | 6 +- .../project/overview/Activity/index.ts | 1 + .../project/overview/OverviewInfo.tsx | 29 ++++ .../shared/CustomIcon/BranchStrokeIcon.tsx | 20 +++ .../shared/CustomIcon/CalendarDaysIcon.tsx | 41 +++++ .../shared/CustomIcon/CursorBoxIcon.tsx | 22 +++ .../shared/CustomIcon/GithubStrokeIcon.tsx | 19 ++ .../components/shared/CustomIcon/LinkIcon.tsx | 21 +++ .../shared/CustomIcon/StorageIcon.tsx | 21 +++ .../src/components/shared/CustomIcon/index.ts | 5 + .../src/components/shared/Tag/Tag.theme.ts | 16 +- .../src/components/shared/Tag/Tag.tsx | 4 +- .../pages/org-slug/projects/id/Overview.tsx | 163 ++++++++++-------- packages/frontend/src/utils/cloneElement.tsx | 43 +++++ 15 files changed, 360 insertions(+), 79 deletions(-) create mode 100644 packages/frontend/src/components/projects/project/overview/Activity/Activity.tsx rename packages/frontend/src/components/projects/project/{ => overview/Activity}/ActivityCard.tsx (95%) create mode 100644 packages/frontend/src/components/projects/project/overview/Activity/index.ts create mode 100644 packages/frontend/src/components/projects/project/overview/OverviewInfo.tsx create mode 100644 packages/frontend/src/components/shared/CustomIcon/BranchStrokeIcon.tsx create mode 100644 packages/frontend/src/components/shared/CustomIcon/CalendarDaysIcon.tsx create mode 100644 packages/frontend/src/components/shared/CustomIcon/CursorBoxIcon.tsx create mode 100644 packages/frontend/src/components/shared/CustomIcon/GithubStrokeIcon.tsx create mode 100644 packages/frontend/src/components/shared/CustomIcon/LinkIcon.tsx create mode 100644 packages/frontend/src/components/shared/CustomIcon/StorageIcon.tsx create mode 100644 packages/frontend/src/utils/cloneElement.tsx diff --git a/packages/frontend/src/components/projects/project/overview/Activity/Activity.tsx b/packages/frontend/src/components/projects/project/overview/Activity/Activity.tsx new file mode 100644 index 00000000..040683b9 --- /dev/null +++ b/packages/frontend/src/components/projects/project/overview/Activity/Activity.tsx @@ -0,0 +1,28 @@ +import React from 'react'; + +import { GitCommitWithBranch } from 'types'; +import { Heading } from 'components/shared/Heading'; +import ActivityCard from './ActivityCard'; +import { Button } from 'components/shared/Button'; + +export const Activity = ({ + activities, +}: { + activities: GitCommitWithBranch[]; +}) => { + return ( +
+
+ Activity + +
+
+ {activities.map((activity, index) => { + return ; + })} +
+
+ ); +}; diff --git a/packages/frontend/src/components/projects/project/ActivityCard.tsx b/packages/frontend/src/components/projects/project/overview/Activity/ActivityCard.tsx similarity index 95% rename from packages/frontend/src/components/projects/project/ActivityCard.tsx rename to packages/frontend/src/components/projects/project/overview/Activity/ActivityCard.tsx index 3f3cc55e..6d86ecd5 100644 --- a/packages/frontend/src/components/projects/project/ActivityCard.tsx +++ b/packages/frontend/src/components/projects/project/overview/Activity/ActivityCard.tsx @@ -1,11 +1,11 @@ import React from 'react'; import { Link } from 'react-router-dom'; -import { GitCommitWithBranch } from '../../../types'; +import { GitCommitWithBranch } from '../../../../../types'; import { Avatar } from 'components/shared/Avatar'; import { Button } from 'components/shared/Button'; import { ArrowRightCircleFilledIcon, - BranchIcon, + BranchStrokeIcon, } from 'components/shared/CustomIcon'; import { formatDistance } from 'date-fns'; import { getInitials } from 'utils/geInitials'; @@ -50,7 +50,7 @@ const ActivityCard = ({ activity }: ActivityCardProps) => {
- +
) => { + const styledIcon = cloneElement({ + element: icon, + className: 'w-4 h-4', + }); + + return ( +
+
+ {styledIcon} + {label} +
+
{children}
+
+ ); +}; diff --git a/packages/frontend/src/components/shared/CustomIcon/BranchStrokeIcon.tsx b/packages/frontend/src/components/shared/CustomIcon/BranchStrokeIcon.tsx new file mode 100644 index 00000000..e8b95175 --- /dev/null +++ b/packages/frontend/src/components/shared/CustomIcon/BranchStrokeIcon.tsx @@ -0,0 +1,20 @@ +import React from 'react'; +import { CustomIcon, CustomIconProps } from './CustomIcon'; + +export const BranchStrokeIcon = (props: CustomIconProps) => { + return ( + + + + ); +}; diff --git a/packages/frontend/src/components/shared/CustomIcon/CalendarDaysIcon.tsx b/packages/frontend/src/components/shared/CustomIcon/CalendarDaysIcon.tsx new file mode 100644 index 00000000..2528559e --- /dev/null +++ b/packages/frontend/src/components/shared/CustomIcon/CalendarDaysIcon.tsx @@ -0,0 +1,41 @@ +import React from 'react'; +import { CustomIcon, CustomIconProps } from './CustomIcon'; + +export const CalendarDaysIcon = (props: CustomIconProps) => { + return ( + + + + + + + + + ); +}; diff --git a/packages/frontend/src/components/shared/CustomIcon/CursorBoxIcon.tsx b/packages/frontend/src/components/shared/CustomIcon/CursorBoxIcon.tsx new file mode 100644 index 00000000..df7889cc --- /dev/null +++ b/packages/frontend/src/components/shared/CustomIcon/CursorBoxIcon.tsx @@ -0,0 +1,22 @@ +import React from 'react'; +import { CustomIcon, CustomIconProps } from './CustomIcon'; + +export const CursorBoxIcon = (props: CustomIconProps) => { + return ( + + + + ); +}; diff --git a/packages/frontend/src/components/shared/CustomIcon/GithubStrokeIcon.tsx b/packages/frontend/src/components/shared/CustomIcon/GithubStrokeIcon.tsx new file mode 100644 index 00000000..74d259ba --- /dev/null +++ b/packages/frontend/src/components/shared/CustomIcon/GithubStrokeIcon.tsx @@ -0,0 +1,19 @@ +import React from 'react'; +import { CustomIcon, CustomIconProps } from './CustomIcon'; + +export const GithubStrokeIcon = (props: CustomIconProps) => { + return ( + + + + ); +}; diff --git a/packages/frontend/src/components/shared/CustomIcon/LinkIcon.tsx b/packages/frontend/src/components/shared/CustomIcon/LinkIcon.tsx new file mode 100644 index 00000000..2f0aa923 --- /dev/null +++ b/packages/frontend/src/components/shared/CustomIcon/LinkIcon.tsx @@ -0,0 +1,21 @@ +import React from 'react'; +import { CustomIcon, CustomIconProps } from './CustomIcon'; + +export const LinkIcon = (props: CustomIconProps) => { + return ( + + + + ); +}; diff --git a/packages/frontend/src/components/shared/CustomIcon/StorageIcon.tsx b/packages/frontend/src/components/shared/CustomIcon/StorageIcon.tsx new file mode 100644 index 00000000..38a651f1 --- /dev/null +++ b/packages/frontend/src/components/shared/CustomIcon/StorageIcon.tsx @@ -0,0 +1,21 @@ +import React from 'react'; +import { CustomIcon, CustomIconProps } from './CustomIcon'; + +export const StorageIcon = (props: CustomIconProps) => { + return ( + + + + ); +}; diff --git a/packages/frontend/src/components/shared/CustomIcon/index.ts b/packages/frontend/src/components/shared/CustomIcon/index.ts index 2493420c..dfba3424 100644 --- a/packages/frontend/src/components/shared/CustomIcon/index.ts +++ b/packages/frontend/src/components/shared/CustomIcon/index.ts @@ -33,3 +33,8 @@ export * from './ClockIcon'; export * from './HorizontalDotIcon'; export * from './WarningDiamondIcon'; export * from './ArrowRightCircleFilledIcon'; +export * from './GithubStrokeIcon'; +export * from './BranchStrokeIcon'; +export * from './StorageIcon'; +export * from './LinkIcon'; +export * from './CursorBoxIcon'; diff --git a/packages/frontend/src/components/shared/Tag/Tag.theme.ts b/packages/frontend/src/components/shared/Tag/Tag.theme.ts index 086b59b3..a027185d 100644 --- a/packages/frontend/src/components/shared/Tag/Tag.theme.ts +++ b/packages/frontend/src/components/shared/Tag/Tag.theme.ts @@ -5,25 +5,25 @@ export const tagTheme = tv( { slots: { wrapper: ['flex', 'gap-1.5', 'rounded-lg', 'border'], - icon: ['h-4', 'w-4'], + icon: [], label: ['font-inter', 'text-xs'], }, variants: { type: { attention: { - icon: ['text-elements-warning'], + wrapper: ['text-elements-warning'], }, negative: { - icon: ['text-elements-danger'], + wrapper: ['text-elements-danger'], }, positive: { - icon: ['text-elements-success'], + wrapper: ['text-elements-success'], }, emphasized: { - icon: ['text-elements-on-secondary'], + wrapper: ['text-elements-on-secondary'], }, neutral: { - icon: ['text-elements-mid-em'], + wrapper: ['text-elements-mid-em'], }, }, style: { @@ -36,9 +36,11 @@ export const tagTheme = tv( size: { sm: { wrapper: ['px-2', 'py-2'], + icon: ['h-4', 'w-4'], }, xs: { - wrapper: ['px-2', 'py-1.5'], + wrapper: ['px-2', 'py-1'], + icon: ['h-3', 'w-3'], }, }, }, diff --git a/packages/frontend/src/components/shared/Tag/Tag.tsx b/packages/frontend/src/components/shared/Tag/Tag.tsx index 086d3515..8be34c85 100644 --- a/packages/frontend/src/components/shared/Tag/Tag.tsx +++ b/packages/frontend/src/components/shared/Tag/Tag.tsx @@ -27,6 +27,8 @@ export const Tag = ({ type = 'attention', style = 'default', size = 'sm', + className, + ...props }: TagProps) => { const { wrapper: wrapperCls, @@ -51,7 +53,7 @@ export const Tag = ({ }, [cloneIcon, iconCls, rightIcon]); return ( -
+
{renderLeftIcon}

{children}

{renderRightIcon} diff --git a/packages/frontend/src/pages/org-slug/projects/id/Overview.tsx b/packages/frontend/src/pages/org-slug/projects/id/Overview.tsx index 21f281c1..15aa4e73 100644 --- a/packages/frontend/src/pages/org-slug/projects/id/Overview.tsx +++ b/packages/frontend/src/pages/org-slug/projects/id/Overview.tsx @@ -1,18 +1,30 @@ import React, { useEffect, useState } from 'react'; import { Domain, DomainStatus } from 'gql-client'; -import { useNavigate, useOutletContext } from 'react-router-dom'; +import { Link, useNavigate, useOutletContext } from 'react-router-dom'; import { RequestError } from 'octokit'; -import { Typography, Chip, Avatar, Tooltip } from '@material-tailwind/react'; - -import ActivityCard from '../../../../components/projects/project/ActivityCard'; -import { relativeTimeMs } from '../../../../utils/time'; import { useOctokit } from '../../../../context/OctokitContext'; import { GitCommitWithBranch, OutletContextType } from '../../../../types'; import { useGQLClient } from '../../../../context/GQLClientContext'; -import { formatAddress } from '../../../../utils/format'; import { Button } from 'components/shared/Button'; import { Heading } from 'components/shared/Heading'; +import { Avatar } from 'components/shared/Avatar'; +import { getInitials } from 'utils/geInitials'; +import { + BranchStrokeIcon, + CheckRoundFilledIcon, + ClockIcon, + CursorBoxIcon, + GithubStrokeIcon, + GlobeIcon, + LinkIcon, + StorageIcon, +} from 'components/shared/CustomIcon'; +import { Tag } from 'components/shared/Tag'; +import { Activity } from 'components/projects/project/overview/Activity'; +import { OverviewInfo } from 'components/projects/project/overview/OverviewInfo'; +import { CalendarDaysIcon } from 'components/shared/CustomIcon/CalendarDaysIcon'; +import { relativeTimeMs } from 'utils/time'; const COMMITS_PER_PAGE = 4; @@ -105,90 +117,105 @@ const OverviewTabPanel = () => { return (
-
+
-
- {project.name} - +
+ + {project.name} + + {project.subDomain} - +
-
-
^ Domain
+ }> {liveDomain ? ( - + }> + Connected + ) : ( -
- +
+ }> + Not connected +
)} -
+
{project.deployments.length !== 0 ? ( <> -
-

^ Source

-

^ {project.deployments[0]?.branch}

-
-
-

^ Deployment

-

{liveDomain?.name}

-
-
-

^ Created

-

- {relativeTimeMs(project.deployments[0].createdAt)} by ^{' '} - - {formatAddress(project.deployments[0].createdBy.name ?? '')} - -

-
+ {/* SOURCE */} + }> +
+ + + feature/add-remote-control + +
+
+ + {/* DEPLOYMENT */} + }> +
+ + + dbname{' '} + + + +
+
+ + {/* DEPLOYMENT */} + }> +
+ + + {liveDomain?.name}{' '} + + + +
+
+ + {/* DEPLOYMENT DATE */} + }> +
+ {relativeTimeMs(project.deployments[0].createdAt)} + by + + {project.deployments[0]?.createdBy?.name} +
+
) : ( -
No current deployment found
+

+ No current deployment found. +

)}
-
-
- Activity - -
-
- {activities.map((activity, index) => { - return ( - - ); - })} -
-
+
); }; diff --git a/packages/frontend/src/utils/cloneElement.tsx b/packages/frontend/src/utils/cloneElement.tsx new file mode 100644 index 00000000..202f9e45 --- /dev/null +++ b/packages/frontend/src/utils/cloneElement.tsx @@ -0,0 +1,43 @@ +import React, { + ReactElement, + isValidElement, + Children, + cloneElement as reactCloneElement, + HTMLProps, + ReactNode, +} from 'react'; +import { ClassProp } from 'tailwind-variants'; +import { cn } from './classnames'; + +interface cloneElement extends HTMLProps { + element: ReactNode; + themeStyle?: (props: ClassProp) => string; +} + +export const cloneElement = ({ + element, + themeStyle, + className, + ...props +}: cloneElement) => { + if (isValidElement(element)) { + return ( + <> + {Children.map(element, (child) => { + const originalClassName = (child.props as HTMLProps) + ?.className; + + return reactCloneElement(child as ReactElement, { + className: themeStyle + ? themeStyle({ + className: cn(originalClassName, className), // overriding icon classNames + }) + : originalClassName, + ...props, + }); + })} + + ); + } + return <>; +}; From 6b6582c28752311402c644d54a1e0f2f2de6fd3c Mon Sep 17 00:00:00 2001 From: Sushan Yadav Date: Wed, 28 Feb 2024 16:56:28 +0545 Subject: [PATCH 02/64] feat: top section --- .../src/pages/org-slug/projects/Id.tsx | 33 +++++++++++-------- 1 file changed, 19 insertions(+), 14 deletions(-) diff --git a/packages/frontend/src/pages/org-slug/projects/Id.tsx b/packages/frontend/src/pages/org-slug/projects/Id.tsx index 37ce9719..92250632 100644 --- a/packages/frontend/src/pages/org-slug/projects/Id.tsx +++ b/packages/frontend/src/pages/org-slug/projects/Id.tsx @@ -3,28 +3,23 @@ import { Link, Outlet, useLocation, - useNavigate, + // useNavigate, useParams, } from 'react-router-dom'; import { Project as ProjectType } from 'gql-client'; -import { - Button, - Tab, - Tabs, - TabsBody, - TabsHeader, - Typography, -} from '@material-tailwind/react'; +import { Tab, Tabs, TabsBody, TabsHeader } from '@material-tailwind/react'; -import HorizontalLine from '../../../components/HorizontalLine'; import { useGQLClient } from '../../../context/GQLClientContext'; import { useOctokit } from '../../../context/OctokitContext'; +import { Button } from 'components/shared/Button'; +import { ChevronLeft } from 'components/shared/CustomIcon'; +import { WavyBorder } from 'components/shared/WavyBorder'; const Id = () => { const { id } = useParams(); const { octokit } = useOctokit(); - const navigate = useNavigate(); + // const navigate = useNavigate(); const client = useGQLClient(); const location = useLocation(); @@ -69,7 +64,16 @@ const Id = () => {
{project ? ( <> -
+
+
+ {/*
-
- +
*/} + + {/* */}
Date: Wed, 28 Feb 2024 17:35:02 +0545 Subject: [PATCH 03/64] feat: add layout --- .../src/pages/org-slug/projects/Id.tsx | 151 ++++++------------ .../pages/org-slug/projects/id/Overview.tsx | 2 +- 2 files changed, 54 insertions(+), 99 deletions(-) diff --git a/packages/frontend/src/pages/org-slug/projects/Id.tsx b/packages/frontend/src/pages/org-slug/projects/Id.tsx index 92250632..8b164852 100644 --- a/packages/frontend/src/pages/org-slug/projects/Id.tsx +++ b/packages/frontend/src/pages/org-slug/projects/Id.tsx @@ -3,23 +3,23 @@ import { Link, Outlet, useLocation, - // useNavigate, + useNavigate, useParams, } from 'react-router-dom'; import { Project as ProjectType } from 'gql-client'; -import { Tab, Tabs, TabsBody, TabsHeader } from '@material-tailwind/react'; - import { useGQLClient } from '../../../context/GQLClientContext'; import { useOctokit } from '../../../context/OctokitContext'; import { Button } from 'components/shared/Button'; import { ChevronLeft } from 'components/shared/CustomIcon'; import { WavyBorder } from 'components/shared/WavyBorder'; +import { Heading } from 'components/shared/Heading'; +import { Tabs } from 'components/shared/Tabs'; const Id = () => { const { id } = useParams(); const { octokit } = useOctokit(); - // const navigate = useNavigate(); + const navigate = useNavigate(); const client = useGQLClient(); const location = useLocation(); @@ -64,106 +64,61 @@ const Id = () => {
{project ? ( <> -
-
- {/*
- - - {project?.name} - - +
+
- - -
*/} - - {/* */} -
- - - - - Overview - - - - - Deployments - - - - - Database - - - - - Integrations - - - - - Settings - - - - + variant="tertiary" + className="rounded-full h-11 w-11 p-0" + aria-label="Go back" + leftIcon={} + onClick={() => navigate(-1)} + /> + + {project?.name} + +
+
+ + + + +
+
+ +
+ + + + Overview + + + Deployments + + + Database + + + Integrations + + + Settings + + + {/* Not wrapping in Tab.Content because we are using Outlet */} +
- +
) : ( -

Project not found

+
+ + Project not found. + +
)}
); diff --git a/packages/frontend/src/pages/org-slug/projects/id/Overview.tsx b/packages/frontend/src/pages/org-slug/projects/id/Overview.tsx index 15aa4e73..e4c93a8b 100644 --- a/packages/frontend/src/pages/org-slug/projects/id/Overview.tsx +++ b/packages/frontend/src/pages/org-slug/projects/id/Overview.tsx @@ -115,7 +115,7 @@ const OverviewTabPanel = () => { }, [project]); return ( -
+
Date: Wed, 28 Feb 2024 21:16:26 +0700 Subject: [PATCH 04/64] =?UTF-8?q?=E2=99=BB=EF=B8=8F=20refactor:=20restruct?= =?UTF-8?q?ured=20and=20restryling=20repository=20list=20component?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../{ => RepositoryList}/RepositoryList.tsx | 92 +++++++++++-------- .../projects/create/RepositoryList/index.ts | 1 + .../pages/org-slug/projects/create/index.tsx | 8 +- 3 files changed, 61 insertions(+), 40 deletions(-) rename packages/frontend/src/components/projects/create/{ => RepositoryList}/RepositoryList.tsx (59%) create mode 100644 packages/frontend/src/components/projects/create/RepositoryList/index.ts diff --git a/packages/frontend/src/components/projects/create/RepositoryList.tsx b/packages/frontend/src/components/projects/create/RepositoryList/RepositoryList.tsx similarity index 59% rename from packages/frontend/src/components/projects/create/RepositoryList.tsx rename to packages/frontend/src/components/projects/create/RepositoryList/RepositoryList.tsx index f09e61d6..171082ed 100644 --- a/packages/frontend/src/components/projects/create/RepositoryList.tsx +++ b/packages/frontend/src/components/projects/create/RepositoryList/RepositoryList.tsx @@ -3,13 +3,17 @@ import { Octokit } from 'octokit'; import assert from 'assert'; 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 './ProjectRepoCard'; -import { GitOrgDetails, GitRepositoryDetails } from '../../../types'; -import AsyncSelect from '../../shared/AsyncSelect'; -import { GithubIcon } from 'components/shared/CustomIcon'; +import { ProjectRepoCard } from 'components/projects/create/ProjectRepoCard'; +import { GitOrgDetails, GitRepositoryDetails } from 'types'; +import { + ChevronGrabberHorizontal, + GithubIcon, + SearchIcon, +} from 'components/shared/CustomIcon'; +import { Select, SelectOption } from 'components/shared/Select'; +import { Input } from 'components/shared/Input'; const DEFAULT_SEARCHED_REPO = ''; const REPOS_PER_PAGE = 5; @@ -18,9 +22,9 @@ interface RepositoryListProps { octokit: Octokit; } -const RepositoryList = ({ octokit }: RepositoryListProps) => { +export const RepositoryList = ({ octokit }: RepositoryListProps) => { const [searchedRepo, setSearchedRepo] = useState(DEFAULT_SEARCHED_REPO); - const [selectedAccount, setSelectedAccount] = useState(''); + const [selectedAccount, setSelectedAccount] = useState(); const [orgs, setOrgs] = useState([]); // TODO: Add new type for Git user when required const [gitUser, setGitUser] = useState(); @@ -35,7 +39,7 @@ const RepositoryList = ({ octokit }: RepositoryListProps) => { const orgs = await octokit.rest.orgs.listForAuthenticatedUser(); setOrgs(orgs.data); setGitUser(user.data); - setSelectedAccount(user.data.login); + setSelectedAccount({ label: user.data.login, value: user.data.login }); }; fetchUserAndOrgs(); @@ -54,7 +58,7 @@ const RepositoryList = ({ octokit }: RepositoryListProps) => { let query = `${debouncedSearchedRepo} in:name fork:true`; // Check if selected account is an organization - if (selectedAccount === gitUser.login) { + if (selectedAccount.value === gitUser.login) { query = query + ` user:${selectedAccount}`; } else { query = query + ` org:${selectedAccount}`; @@ -69,7 +73,7 @@ const RepositoryList = ({ octokit }: RepositoryListProps) => { return; } - if (selectedAccount === gitUser.login) { + if (selectedAccount.value === gitUser.login) { const result = await octokit.rest.repos.listForAuthenticatedUser({ per_page: REPOS_PER_PAGE, affiliation: 'owner', @@ -78,7 +82,9 @@ const RepositoryList = ({ octokit }: RepositoryListProps) => { 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'); const result = await octokit.rest.repos.listForOrg({ @@ -96,7 +102,7 @@ const RepositoryList = ({ octokit }: RepositoryListProps) => { const handleResetFilters = useCallback(() => { assert(gitUser, 'Git user is not available'); setSearchedRepo(DEFAULT_SEARCHED_REPO); - setSelectedAccount(gitUser.login); + setSelectedAccount({ label: gitUser.login, value: gitUser.login }); }, [gitUser]); const accounts = useMemo(() => { @@ -107,35 +113,51 @@ const RepositoryList = ({ octokit }: RepositoryListProps) => { return [gitUser, ...orgs]; }, [octokit, orgs, gitUser]); + const options = useMemo(() => { + return accounts.map((account) => ({ + label: account.login, + value: account.login, + leftIcon: , + })); + }, [accounts]); + return ( -
-
-
- + {/* Dropdown and search */} +
+
+ setSearchedRepo(event.target.value)} placeholder="Search for repository" + leftIcon={} + onChange={(e) => setSearchedRepo(e.target.value)} />
+ + {/* Repository list */} {Boolean(repositoryDetails.length) ? ( - repositoryDetails.map((repo, key) => { - return ; - }) +
+ {repositoryDetails.map((repo, index) => ( + <> + + {/* Horizontal line */} + {index !== repositoryDetails.length - 1 && ( +
+ )} + + ))} +
) : (
@@ -151,8 +173,6 @@ const RepositoryList = ({ octokit }: RepositoryListProps) => {
)} -
+ ); }; - -export default RepositoryList; diff --git a/packages/frontend/src/components/projects/create/RepositoryList/index.ts b/packages/frontend/src/components/projects/create/RepositoryList/index.ts new file mode 100644 index 00000000..dc3bc8c5 --- /dev/null +++ b/packages/frontend/src/components/projects/create/RepositoryList/index.ts @@ -0,0 +1 @@ +export * from './RepositoryList'; diff --git a/packages/frontend/src/pages/org-slug/projects/create/index.tsx b/packages/frontend/src/pages/org-slug/projects/create/index.tsx index 1c86ee3b..49eeed96 100644 --- a/packages/frontend/src/pages/org-slug/projects/create/index.tsx +++ b/packages/frontend/src/pages/org-slug/projects/create/index.tsx @@ -1,7 +1,7 @@ import React from 'react'; 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 { useOctokit } from 'context/OctokitContext'; import { Heading } from 'components/shared/Heading'; @@ -13,8 +13,8 @@ const NewProject = () => { return isAuth ? ( <>
- - Start with template + + Start with a template
{templates.map((template) => { @@ -28,7 +28,7 @@ const NewProject = () => { })}
- + Import a repository From eda2cc76edad4b94d83f26c0e38fe1dbc73cba57 Mon Sep 17 00:00:00 2001 From: Wahyu Kurniawan Date: Wed, 28 Feb 2024 21:16:59 +0700 Subject: [PATCH 05/64] =?UTF-8?q?=E2=99=BB=EF=B8=8F=20refactor:=20restruct?= =?UTF-8?q?ured=20and=20restyling=20project=20repo=20card=20component?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../projects/create/ProjectRepoCard.tsx | 81 ---------------- .../ProjectRepoCard/ProjectRepoCard.tsx | 94 +++++++++++++++++++ .../projects/create/ProjectRepoCard/index.ts | 1 + 3 files changed, 95 insertions(+), 81 deletions(-) delete mode 100644 packages/frontend/src/components/projects/create/ProjectRepoCard.tsx create mode 100644 packages/frontend/src/components/projects/create/ProjectRepoCard/ProjectRepoCard.tsx create mode 100644 packages/frontend/src/components/projects/create/ProjectRepoCard/index.ts diff --git a/packages/frontend/src/components/projects/create/ProjectRepoCard.tsx b/packages/frontend/src/components/projects/create/ProjectRepoCard.tsx deleted file mode 100644 index fbcf50b4..00000000 --- a/packages/frontend/src/components/projects/create/ProjectRepoCard.tsx +++ /dev/null @@ -1,81 +0,0 @@ -import React, { useCallback } from 'react'; -import toast from 'react-hot-toast'; -import { useNavigate, useParams } from 'react-router-dom'; - -import { Chip, IconButton, Spinner } from '@material-tailwind/react'; - -import { relativeTimeISO } from '../../../utils/time'; -import { GitRepositoryDetails } from '../../../types'; -import { useGQLClient } from '../../../context/GQLClientContext'; -import { GithubIcon, LockIcon } from 'components/shared/CustomIcon'; - -interface ProjectRepoCardProps { - repository: GitRepositoryDetails; -} - -const ProjectRepoCard: React.FC = ({ repository }) => { - const client = useGQLClient(); - const navigate = useNavigate(); - const [isLoading, setIsLoading] = React.useState(false); - - const { orgSlug } = useParams(); - - const createProject = useCallback(async () => { - if (!repository) { - return; - } - - setIsLoading(true); - const { addProject } = await client.addProject(orgSlug!, { - name: `${repository.owner!.login}-${repository.name}`, - prodBranch: repository.default_branch!, - repository: repository.full_name, - // TODO: Compute template from repo - template: 'webapp', - }); - - if (Boolean(addProject)) { - setIsLoading(false); - navigate(`import?projectId=${addProject.id}`); - } else { - setIsLoading(false); - toast.error('Failed to create project'); - } - }, [client, repository]); - - return ( -
-
- -
-
-
- {repository.full_name} - {repository.visibility === 'private' && ( - } - /> - )} -
-

{repository.updated_at && relativeTimeISO(repository.updated_at)}

-
- {isLoading ? ( - - ) : ( -
- - {'>'} - -
- )} -
- ); -}; - -export default ProjectRepoCard; diff --git a/packages/frontend/src/components/projects/create/ProjectRepoCard/ProjectRepoCard.tsx b/packages/frontend/src/components/projects/create/ProjectRepoCard/ProjectRepoCard.tsx new file mode 100644 index 00000000..6c8363ef --- /dev/null +++ b/packages/frontend/src/components/projects/create/ProjectRepoCard/ProjectRepoCard.tsx @@ -0,0 +1,94 @@ +import React, { useCallback } from 'react'; +import toast from 'react-hot-toast'; +import { useNavigate, useParams } from 'react-router-dom'; + +import { Spinner } from '@material-tailwind/react'; + +import { relativeTimeISO } from 'utils/time'; +import { GitRepositoryDetails } from 'types'; +import { useGQLClient } from 'context/GQLClientContext'; +import { + ArrowRightCircleIcon, + GithubIcon, + LockIcon, +} from 'components/shared/CustomIcon'; +import { Button } from 'components/shared/Button'; + +interface ProjectRepoCardProps { + repository: GitRepositoryDetails; +} + +export const ProjectRepoCard: React.FC = ({ + repository, +}) => { + const client = useGQLClient(); + const navigate = useNavigate(); + const [isLoading, setIsLoading] = React.useState(false); + + const { orgSlug } = useParams(); + + const createProject = useCallback(async () => { + if (!repository) { + return; + } + + setIsLoading(true); + const { addProject } = await client.addProject(orgSlug!, { + name: `${repository.owner!.login}-${repository.name}`, + prodBranch: repository.default_branch!, + repository: repository.full_name, + // TODO: Compute template from repo + template: 'webapp', + }); + + if (Boolean(addProject)) { + setIsLoading(false); + navigate(`import?projectId=${addProject.id}`); + } else { + setIsLoading(false); + toast.error('Failed to create project'); + } + }, [client, repository]); + + return ( +
+ {/* Icon container */} +
+ +
+ {/* Content */} +
+
+

+ {repository.full_name} +

+

+ {repository.updated_at && relativeTimeISO(repository.updated_at)} +

+
+ {repository.visibility === 'private' && ( +
+ + Private +
+ )} +
+ {/* Right action */} + {isLoading ? ( + + ) : ( + + )} +
+ ); +}; diff --git a/packages/frontend/src/components/projects/create/ProjectRepoCard/index.ts b/packages/frontend/src/components/projects/create/ProjectRepoCard/index.ts new file mode 100644 index 00000000..78472497 --- /dev/null +++ b/packages/frontend/src/components/projects/create/ProjectRepoCard/index.ts @@ -0,0 +1 @@ +export * from './ProjectRepoCard'; From 769593913e22b2ea6ac71d50a67f6f6bdf6ef60f Mon Sep 17 00:00:00 2001 From: Wahyu Kurniawan Date: Wed, 28 Feb 2024 21:17:30 +0700 Subject: [PATCH 06/64] =?UTF-8?q?=F0=9F=90=9B=20fix:=20button=20inside=20b?= =?UTF-8?q?utton=20console=20browser=20error?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../projects/create/TemplateCard/TemplateCard.tsx | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/packages/frontend/src/components/projects/create/TemplateCard/TemplateCard.tsx b/packages/frontend/src/components/projects/create/TemplateCard/TemplateCard.tsx index b7c549fd..b26ff856 100644 --- a/packages/frontend/src/components/projects/create/TemplateCard/TemplateCard.tsx +++ b/packages/frontend/src/components/projects/create/TemplateCard/TemplateCard.tsx @@ -49,9 +49,9 @@ export const TemplateCard = ({ template, isGitAuth }: TemplateCardProps) => { }, [isGitAuth, navigate, template, toast]); return ( - )} - +
); }; From eb4ccfbc9cb4a7cef1c5522b28d3e8ba1ac834e7 Mon Sep 17 00:00:00 2001 From: Wahyu Kurniawan Date: Wed, 28 Feb 2024 21:17:59 +0700 Subject: [PATCH 07/64] =?UTF-8?q?=F0=9F=8E=A8=20style:=20make=20the=20inpu?= =?UTF-8?q?t=20width=20full?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- packages/frontend/src/components/shared/Input/Input.theme.ts | 4 +++- packages/frontend/src/components/shared/Input/Input.tsx | 4 ++-- 2 files changed, 5 insertions(+), 3 deletions(-) diff --git a/packages/frontend/src/components/shared/Input/Input.theme.ts b/packages/frontend/src/components/shared/Input/Input.theme.ts index b1ecb705..0144d578 100644 --- a/packages/frontend/src/components/shared/Input/Input.theme.ts +++ b/packages/frontend/src/components/shared/Input/Input.theme.ts @@ -8,6 +8,8 @@ export const inputTheme = tv( 'items-center', 'rounded-lg', 'relative', + 'gap-2', + 'w-full', 'placeholder:text-elements-disabled', 'disabled:cursor-not-allowed', 'disabled:bg-controls-disabled', @@ -27,7 +29,7 @@ export const inputTheme = tv( 'disabled:shadow-none', 'disabled:border-none', ], - icon: ['text-elements-mid-em'], + icon: ['text-elements-low-em'], iconContainer: [ 'absolute', 'inset-y-0', diff --git a/packages/frontend/src/components/shared/Input/Input.tsx b/packages/frontend/src/components/shared/Input/Input.tsx index fb3fd7d6..dd88bd80 100644 --- a/packages/frontend/src/components/shared/Input/Input.tsx +++ b/packages/frontend/src/components/shared/Input/Input.tsx @@ -87,12 +87,12 @@ export const Input = ({ ); return ( -
+
{renderLabels}
{leftIcon && renderLeftIcon} Date: Wed, 28 Feb 2024 21:18:29 +0700 Subject: [PATCH 08/64] =?UTF-8?q?=F0=9F=90=9B=20fix:=20controlled=20and=20?= =?UTF-8?q?uncontroller=20console=20error?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../components/shared/Select/Select.theme.ts | 4 +-- .../src/components/shared/Select/Select.tsx | 34 +++++-------------- 2 files changed, 11 insertions(+), 27 deletions(-) diff --git a/packages/frontend/src/components/shared/Select/Select.theme.ts b/packages/frontend/src/components/shared/Select/Select.theme.ts index 43d4b0f4..fed6531e 100644 --- a/packages/frontend/src/components/shared/Select/Select.theme.ts +++ b/packages/frontend/src/components/shared/Select/Select.theme.ts @@ -85,7 +85,7 @@ export const selectTheme = tv({ size: { md: { container: ['min-h-11'], - inputWrapper: ['min-h-11', 'text-sm', 'pl-4', 'pr-4', 'py-1'], + inputWrapper: ['min-h-11', 'text-sm', 'pl-4', 'pr-4'], icon: ['h-[18px]', 'w-[18px]'], helperText: 'text-sm', helperIcon: ['h-5', 'w-5'], @@ -93,7 +93,7 @@ export const selectTheme = tv({ }, sm: { container: ['min-h-8'], - inputWrapper: ['min-h-8', 'text-xs', 'pl-3', 'pr-3', 'py-0.5'], + inputWrapper: ['min-h-8', 'text-xs', 'pl-3', 'pr-3'], icon: ['h-4', 'w-4'], helperText: 'text-xs', helperIcon: ['h-4', 'w-4'], diff --git a/packages/frontend/src/components/shared/Select/Select.tsx b/packages/frontend/src/components/shared/Select/Select.tsx index 963cc0bb..8c7e9149 100644 --- a/packages/frontend/src/components/shared/Select/Select.tsx +++ b/packages/frontend/src/components/shared/Select/Select.tsx @@ -3,7 +3,6 @@ import React, { useState, ComponentPropsWithoutRef, useMemo, - useCallback, MouseEvent, useRef, useEffect, @@ -135,7 +134,9 @@ export const Select = ({ const theme = selectTheme({ size, error, variant, orientation }); const [inputValue, setInputValue] = useState(''); - const [selectedItem, setSelectedItem] = useState(null); + const [selectedItem, setSelectedItem] = useState( + (value as SelectOption) || null, + ); const [dropdownOpen, setDropdownOpen] = useState(false); const [dropdownPosition, setDropdownPosition] = useState<'top' | 'bottom'>( 'bottom', @@ -166,22 +167,6 @@ export const Select = ({ } }, [dropdownOpen]); // Re-calculate whenever the dropdown is opened - useEffect(() => { - // If multiple selection is enabled, ensure the internal state is an array - if (multiple) { - if (Array.isArray(value)) { - // Directly use the provided array - setSelectedItems(value); - } else { - // Reset or set to empty array if the value is not an array - setSelectedItems([]); - } - } else { - // For single selection, directly set the selected item - setSelectedItem(value as SelectOption); - } - }, [value, multiple]); - const handleSelectedItemChange = (selectedItem: SelectOption | null) => { setSelectedItem(selectedItem); setInputValue(selectedItem ? selectedItem.label : ''); @@ -194,9 +179,10 @@ export const Select = ({ addSelectedItem, removeSelectedItem, selectedItems, - setSelectedItems, + // setSelectedItems, reset, } = useMultipleSelection({ + selectedItems: multiple ? (value as SelectOption[]) : [], onSelectedItemsChange: multiple ? undefined : ({ selectedItems }) => { @@ -234,6 +220,7 @@ export const Select = ({ openMenu, } = useCombobox({ items: filteredItems, + selectedItem: multiple ? null : (value as SelectOption) || null, // @ts-expect-error – there are two params but we don't need the second one isItemDisabled: (item) => item.disabled, onInputValueChange: ({ inputValue = '' }) => setInputValue(inputValue), @@ -265,16 +252,12 @@ export const Select = ({ setInputValue(''); } }, - selectedItem: multiple ? null : selectedItem, // TODO: Make the input value empty when the dropdown is open, has a value, it is not multiple, and searchable itemToString: (item) => (item && !multiple ? item.label : ''), }); - const isSelected = useCallback( - (item: SelectOption) => - multiple ? selectedItems.includes(item) : selectedItem === item, - [selectedItems, selectedItem, multiple], - ); + const isSelected = (item: SelectOption) => + multiple ? selectedItems.includes(item) : selectedItem === item; const handleClear = (e: MouseEvent) => { e.stopPropagation(); @@ -336,6 +319,7 @@ export const Select = ({ const isMultipleHasValue = multiple && selectedItems.length > 0; const isMultipleHasValueButNotSearchable = multiple && !searchable && selectedItems.length > 0; + const displayPlaceholder = useMemo(() => { if (hideValues && isMultipleHasValue) { return `${selectedItems.length} selected`; From 075cec58e5d039ef4c3dd5c7feb6349df43dd715 Mon Sep 17 00:00:00 2001 From: Wahyu Kurniawan Date: Wed, 28 Feb 2024 21:27:04 +0700 Subject: [PATCH 09/64] =?UTF-8?q?=F0=9F=8E=A8=20style:=20add=20github=20ic?= =?UTF-8?q?on?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../projects/create/RepositoryList/RepositoryList.tsx | 1 + packages/frontend/src/components/shared/Select/Select.tsx | 2 ++ 2 files changed, 3 insertions(+) diff --git a/packages/frontend/src/components/projects/create/RepositoryList/RepositoryList.tsx b/packages/frontend/src/components/projects/create/RepositoryList/RepositoryList.tsx index 171082ed..14af57e6 100644 --- a/packages/frontend/src/components/projects/create/RepositoryList/RepositoryList.tsx +++ b/packages/frontend/src/components/projects/create/RepositoryList/RepositoryList.tsx @@ -130,6 +130,7 @@ export const RepositoryList = ({ octokit }: RepositoryListProps) => { options={options} placeholder="Select a repository" value={selectedAccount} + leftIcon={selectedAccount ? : undefined} rightIcon={} onChange={(value) => setSelectedAccount(value as SelectOption)} /> diff --git a/packages/frontend/src/components/shared/Select/Select.tsx b/packages/frontend/src/components/shared/Select/Select.tsx index 8c7e9149..0e82edcc 100644 --- a/packages/frontend/src/components/shared/Select/Select.tsx +++ b/packages/frontend/src/components/shared/Select/Select.tsx @@ -375,6 +375,8 @@ export const Select = ({ 'w-6': isMultipleHasValueButNotSearchable && !hideValues, // Add margin to the X icon 'ml-6': isMultipleHasValueButNotSearchable && clearable, + // Add padding if there's a left icon + 'pl-7': leftIcon, }, )} /> From 563059e88764edddb1b4bf466114935a9c463985 Mon Sep 17 00:00:00 2001 From: Sushan Yadav Date: Wed, 28 Feb 2024 20:46:08 +0545 Subject: [PATCH 10/64] chore: comment fixes - tab issues and hardcoded strings --- packages/frontend/src/components/shared/Tabs/Tabs.theme.ts | 5 ++++- .../frontend/src/pages/org-slug/projects/id/Overview.tsx | 6 ++++-- 2 files changed, 8 insertions(+), 3 deletions(-) diff --git a/packages/frontend/src/components/shared/Tabs/Tabs.theme.ts b/packages/frontend/src/components/shared/Tabs/Tabs.theme.ts index 3f9ef417..81a32589 100644 --- a/packages/frontend/src/components/shared/Tabs/Tabs.theme.ts +++ b/packages/frontend/src/components/shared/Tabs/Tabs.theme.ts @@ -8,7 +8,6 @@ export const tabsTheme = tv({ triggerWrapper: [ // Horizontal – default 'px-1', - 'pb-5', 'cursor-default', 'select-none', 'text-elements-low-em', @@ -55,9 +54,13 @@ export const tabsTheme = tv({ 'outline-none', 'leading-none', 'tracking-[-0.006em]', + 'text-sm', 'rounded-md', // Horizontal – default 'data-[orientation=horizontal]:focus-ring', + 'data-[orientation=horizontal]:h-10', + // select direct child of data-[orientation=horizontal] + '[&[data-orientation=horizontal]_>_*]:h-full', // Vertical 'data-[orientation=vertical]:gap-2', 'data-[orientation=vertical]:justify-start', diff --git a/packages/frontend/src/pages/org-slug/projects/id/Overview.tsx b/packages/frontend/src/pages/org-slug/projects/id/Overview.tsx index e4c93a8b..eeec4aa8 100644 --- a/packages/frontend/src/pages/org-slug/projects/id/Overview.tsx +++ b/packages/frontend/src/pages/org-slug/projects/id/Overview.tsx @@ -162,7 +162,7 @@ const OverviewTabPanel = () => {
- feature/add-remote-control + {project.deployments[0]?.branch}
@@ -172,7 +172,9 @@ const OverviewTabPanel = () => {
- dbname{' '} + {/* // TODO: add db name + dbname + */} From 0fb378386a231ac41a795fc8d6c3659195594d38 Mon Sep 17 00:00:00 2001 From: Sushan Yadav Date: Wed, 28 Feb 2024 20:51:58 +0545 Subject: [PATCH 11/64] chore: update comment --- packages/frontend/src/pages/org-slug/projects/id/Overview.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/frontend/src/pages/org-slug/projects/id/Overview.tsx b/packages/frontend/src/pages/org-slug/projects/id/Overview.tsx index eeec4aa8..81cdbe16 100644 --- a/packages/frontend/src/pages/org-slug/projects/id/Overview.tsx +++ b/packages/frontend/src/pages/org-slug/projects/id/Overview.tsx @@ -167,7 +167,7 @@ const OverviewTabPanel = () => {
- {/* DEPLOYMENT */} + {/* DATABASE */} }>
From f08081932c9b298a96fff00057b27fba4539e2bd Mon Sep 17 00:00:00 2001 From: Wahyu Kurniawan Date: Thu, 29 Feb 2024 09:21:28 +0700 Subject: [PATCH 12/64] =?UTF-8?q?=E2=99=BB=EF=B8=8F=20refactor:=20use=20cu?= =?UTF-8?q?stom=20toast=20component=20and=20handle=20error?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../ProjectRepoCard/ProjectRepoCard.tsx | 60 ++++++++++++------- 1 file changed, 40 insertions(+), 20 deletions(-) diff --git a/packages/frontend/src/components/projects/create/ProjectRepoCard/ProjectRepoCard.tsx b/packages/frontend/src/components/projects/create/ProjectRepoCard/ProjectRepoCard.tsx index 6c8363ef..b06fc233 100644 --- a/packages/frontend/src/components/projects/create/ProjectRepoCard/ProjectRepoCard.tsx +++ b/packages/frontend/src/components/projects/create/ProjectRepoCard/ProjectRepoCard.tsx @@ -1,5 +1,4 @@ -import React, { useCallback } from 'react'; -import toast from 'react-hot-toast'; +import React, { useCallback, useState } from 'react'; import { useNavigate, useParams } from 'react-router-dom'; import { Spinner } from '@material-tailwind/react'; @@ -13,6 +12,7 @@ import { LockIcon, } from 'components/shared/CustomIcon'; import { Button } from 'components/shared/Button'; +import { useToast } from 'components/shared/Toast'; interface ProjectRepoCardProps { repository: GitRepositoryDetails; @@ -23,32 +23,52 @@ export const ProjectRepoCard: React.FC = ({ }) => { const client = useGQLClient(); const navigate = useNavigate(); - const [isLoading, setIsLoading] = React.useState(false); + const [isLoading, setIsLoading] = useState(false); const { orgSlug } = useParams(); + const { toast, dismiss } = useToast(); const createProject = useCallback(async () => { - if (!repository) { - return; + if (!repository || !orgSlug) { + return toast({ + id: 'missing-repository-or-org-slug', + title: 'Repository or organization slug is missing', + variant: 'error', + onDismiss: dismiss, + }); } - setIsLoading(true); - const { addProject } = await client.addProject(orgSlug!, { - name: `${repository.owner!.login}-${repository.name}`, - prodBranch: repository.default_branch!, - repository: repository.full_name, - // TODO: Compute template from repo - template: 'webapp', - }); - - if (Boolean(addProject)) { + try { + setIsLoading(true); + const { addProject } = await client.addProject(orgSlug, { + name: `${repository.owner?.login}-${repository.name}`, + prodBranch: repository.default_branch as string, + repository: repository.full_name, + // TODO: Compute template from repo + template: 'webapp', + }); + if (addProject) { + navigate(`import?projectId=${addProject.id}`); + } else { + toast({ + id: 'failed-to-create-project', + title: 'Failed to create project', + variant: 'error', + onDismiss: dismiss, + }); + } + } catch (error) { + console.error(error); + toast({ + id: 'failed-to-create-project', + title: 'Failed to create project', + variant: 'error', + onDismiss: dismiss, + }); + } finally { setIsLoading(false); - navigate(`import?projectId=${addProject.id}`); - } else { - setIsLoading(false); - toast.error('Failed to create project'); } - }, [client, repository]); + }, [client, repository, orgSlug, setIsLoading, navigate, toast]); return (
Date: Thu, 29 Feb 2024 09:21:49 +0700 Subject: [PATCH 13/64] =?UTF-8?q?=E2=99=BB=EF=B8=8F=20refactor:=20remove?= =?UTF-8?q?=20unused=20comment?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- packages/frontend/src/components/shared/Select/Select.tsx | 1 - 1 file changed, 1 deletion(-) diff --git a/packages/frontend/src/components/shared/Select/Select.tsx b/packages/frontend/src/components/shared/Select/Select.tsx index 0e82edcc..fa22428c 100644 --- a/packages/frontend/src/components/shared/Select/Select.tsx +++ b/packages/frontend/src/components/shared/Select/Select.tsx @@ -179,7 +179,6 @@ export const Select = ({ addSelectedItem, removeSelectedItem, selectedItems, - // setSelectedItems, reset, } = useMultipleSelection({ selectedItems: multiple ? (value as SelectOption[]) : [], From 87307381cbd616e7085920767d71ecad5a1cc175 Mon Sep 17 00:00:00 2001 From: Wahyu Kurniawan Date: Thu, 29 Feb 2024 10:43:24 +0700 Subject: [PATCH 14/64] =?UTF-8?q?=F0=9F=8E=A8=20style:=20refactor=20and=20?= =?UTF-8?q?re-styling=20filter=20form=20component?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../project/deployments/FilterForm.tsx | 82 ++++++++++--------- 1 file changed, 43 insertions(+), 39 deletions(-) diff --git a/packages/frontend/src/components/projects/project/deployments/FilterForm.tsx b/packages/frontend/src/components/projects/project/deployments/FilterForm.tsx index c28c6218..5cf4c200 100644 --- a/packages/frontend/src/components/projects/project/deployments/FilterForm.tsx +++ b/packages/frontend/src/components/projects/project/deployments/FilterForm.tsx @@ -1,10 +1,10 @@ import React, { useEffect, useState } from 'react'; -import { DateRange } from 'react-day-picker'; -import { IconButton, Option, Select } from '@material-tailwind/react'; - -import SearchBar from '../../../SearchBar'; -import DatePicker from '../../../DatePicker'; +import { Input } from 'components/shared/Input'; +import { CrossCircleIcon, SearchIcon } from 'components/shared/CustomIcon'; +import { DatePicker } from 'components/shared/DatePicker'; +import { Value } from 'react-calendar/dist/cjs/shared/types'; +import { Select, SelectOption } from 'components/shared/Select'; export enum StatusOptions { ALL_STATUS = 'All status', @@ -16,7 +16,7 @@ export enum StatusOptions { export interface FilterValue { searchedBranch: string; status: StatusOptions; - updateAtRange?: DateRange; + updateAtRange?: Value; } interface FilterFormProps { @@ -27,7 +27,7 @@ interface FilterFormProps { const FilterForm = ({ value, onChange }: FilterFormProps) => { const [searchedBranch, setSearchedBranch] = useState(value.searchedBranch); const [selectedStatus, setSelectedStatus] = useState(value.status); - const [dateRange, setDateRange] = useState(); + const [dateRange, setDateRange] = useState(); useEffect(() => { onChange({ @@ -43,46 +43,50 @@ const FilterForm = ({ value, onChange }: FilterFormProps) => { setDateRange(value.updateAtRange); }, [value]); + const statusOptions = Object.values(StatusOptions) + .map((status) => ({ + label: status, + value: status, + })) + .filter((status) => status.value !== StatusOptions.ALL_STATUS); + + const handleReset = () => { + setSearchedBranch(''); + }; + return ( -
-
- +
+ } + rightIcon={ + searchedBranch && + } value={searchedBranch} - onChange={(event) => setSearchedBranch(event.target.value)} + onChange={(e) => setSearchedBranch(e.target.value)} />
-
- +
+ setDateRange(undefined)} + />
-
+
- {selectedStatus !== StatusOptions.ALL_STATUS && ( -
- setSelectedStatus(StatusOptions.ALL_STATUS)} - className="rounded-full" - size="sm" - placeholder={''} - > - X - -
- )} + value={{ label: selectedStatus, value: selectedStatus }} + onChange={(item) => + setSelectedStatus((item as SelectOption).value as StatusOptions) + } + onClear={() => setSelectedStatus(StatusOptions.ALL_STATUS)} + />
); From 630af612a290970aa80b38da386161cafba6f9d3 Mon Sep 17 00:00:00 2001 From: Wahyu Kurniawan Date: Thu, 29 Feb 2024 10:43:53 +0700 Subject: [PATCH 15/64] =?UTF-8?q?=E2=9A=A1=EF=B8=8F=20feat:=20add=20some?= =?UTF-8?q?=20components?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../shared/CustomIcon/CrossCircleIcon.tsx | 21 +++++++++++++++++ .../shared/CustomIcon/RefreshIcon.tsx | 23 +++++++++++++++++++ .../src/components/shared/CustomIcon/index.ts | 2 ++ 3 files changed, 46 insertions(+) create mode 100644 packages/frontend/src/components/shared/CustomIcon/CrossCircleIcon.tsx create mode 100644 packages/frontend/src/components/shared/CustomIcon/RefreshIcon.tsx diff --git a/packages/frontend/src/components/shared/CustomIcon/CrossCircleIcon.tsx b/packages/frontend/src/components/shared/CustomIcon/CrossCircleIcon.tsx new file mode 100644 index 00000000..78f563c5 --- /dev/null +++ b/packages/frontend/src/components/shared/CustomIcon/CrossCircleIcon.tsx @@ -0,0 +1,21 @@ +import React from 'react'; +import { CustomIcon, CustomIconProps } from './CustomIcon'; + +export const CrossCircleIcon = (props: CustomIconProps) => { + return ( + + + + ); +}; diff --git a/packages/frontend/src/components/shared/CustomIcon/RefreshIcon.tsx b/packages/frontend/src/components/shared/CustomIcon/RefreshIcon.tsx new file mode 100644 index 00000000..ca818a25 --- /dev/null +++ b/packages/frontend/src/components/shared/CustomIcon/RefreshIcon.tsx @@ -0,0 +1,23 @@ +import React from 'react'; +import { CustomIcon, CustomIconProps } from './CustomIcon'; + +export const RefreshIcon = (props: CustomIconProps) => { + return ( + + + + + ); +}; diff --git a/packages/frontend/src/components/shared/CustomIcon/index.ts b/packages/frontend/src/components/shared/CustomIcon/index.ts index b9965188..4b8e4b18 100644 --- a/packages/frontend/src/components/shared/CustomIcon/index.ts +++ b/packages/frontend/src/components/shared/CustomIcon/index.ts @@ -41,6 +41,8 @@ export * from './BranchStrokeIcon'; export * from './StorageIcon'; export * from './LinkIcon'; export * from './CursorBoxIcon'; +export * from './CrossCircleIcon'; +export * from './RefreshIcon'; // Templates export * from './templates'; From e0c5895e9c6a48826fd045855041f0b640962cea Mon Sep 17 00:00:00 2001 From: Wahyu Kurniawan Date: Thu, 29 Feb 2024 10:44:25 +0700 Subject: [PATCH 16/64] =?UTF-8?q?=E2=9A=A1=EF=B8=8F=20feat:=20add=20`onRes?= =?UTF-8?q?et`=20prop?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../components/shared/Calendar/Calendar.tsx | 41 ++++++++++++++----- .../shared/DatePicker/DatePicker.theme.ts | 2 +- .../shared/DatePicker/DatePicker.tsx | 25 +++++++---- .../components/shared/Select/Select.theme.ts | 2 +- .../src/components/shared/Select/Select.tsx | 14 +++---- .../shared/Select/SelectItem/SelectItem.tsx | 4 +- 6 files changed, 59 insertions(+), 29 deletions(-) diff --git a/packages/frontend/src/components/shared/Calendar/Calendar.tsx b/packages/frontend/src/components/shared/Calendar/Calendar.tsx index bf01dc06..1a67c34f 100644 --- a/packages/frontend/src/components/shared/Calendar/Calendar.tsx +++ b/packages/frontend/src/components/shared/Calendar/Calendar.tsx @@ -19,6 +19,7 @@ import { import './Calendar.css'; import { format } from 'date-fns'; +import { cn } from 'utils/classnames'; type ValuePiece = Date | null; export type Value = ValuePiece | [ValuePiece, ValuePiece]; @@ -63,6 +64,11 @@ export interface CalendarProps extends CustomReactCalendarProps, CalendarTheme { * @returns None */ onCancel?: () => void; + /** + * Optional callback function that is called when a reset action is triggered. + * @returns None + */ + onReset?: () => void; } /** @@ -80,6 +86,7 @@ export const Calendar = ({ actions, onSelect, onCancel, + onReset, onChange: onChangeProp, ...props }: CalendarProps): JSX.Element => { @@ -217,6 +224,11 @@ export const Calendar = ({ [setValue, setActiveDate, changeNavigationLabel, selectRange], ); + const handleReset = useCallback(() => { + setValue(null); + onReset?.(); + }, [setValue, onReset]); + return (
{actions ? ( actions ) : ( <> - - + {value && ( + + )} +
+ + +
)}
diff --git a/packages/frontend/src/components/shared/DatePicker/DatePicker.theme.ts b/packages/frontend/src/components/shared/DatePicker/DatePicker.theme.ts index 522bd348..ee1b7466 100644 --- a/packages/frontend/src/components/shared/DatePicker/DatePicker.theme.ts +++ b/packages/frontend/src/components/shared/DatePicker/DatePicker.theme.ts @@ -2,7 +2,7 @@ import { VariantProps, tv } from 'tailwind-variants'; export const datePickerTheme = tv({ slots: { - input: [], + input: ['w-full'], }, }); diff --git a/packages/frontend/src/components/shared/DatePicker/DatePicker.tsx b/packages/frontend/src/components/shared/DatePicker/DatePicker.tsx index 99fd82a5..bae4502a 100644 --- a/packages/frontend/src/components/shared/DatePicker/DatePicker.tsx +++ b/packages/frontend/src/components/shared/DatePicker/DatePicker.tsx @@ -1,4 +1,4 @@ -import React, { useCallback, useState } from 'react'; +import React, { useCallback, useMemo, useState } from 'react'; import { Input, InputProps } from 'components/shared/Input'; import * as Popover from '@radix-ui/react-popover'; import { datePickerTheme } from './DatePicker.theme'; @@ -27,6 +27,10 @@ export interface DatePickerProps * Whether to allow the selection of a date range. */ selectRange?: boolean; + /** + * Optional callback function that is called when the date picker is reset. + */ + onReset?: () => void; } /** @@ -39,6 +43,7 @@ export const DatePicker = ({ calendarProps, value, onChange, + onReset, selectRange = false, ...props }: DatePickerProps) => { @@ -50,16 +55,16 @@ export const DatePicker = ({ * Renders the value of the date based on the current state of `props.value`. * @returns {string | undefined} - The formatted date value or `undefined` if `props.value` is falsy. */ - const renderValue = useCallback(() => { - if (!value) return undefined; + const renderValue = useMemo(() => { + if (!value) return ''; if (Array.isArray(value)) { return value .map((date) => format(date as Date, 'dd/MM/yyyy')) .join(' - '); } return format(value, 'dd/MM/yyyy'); - }, [value]); - + }, [value, onReset]); + console.log(renderValue); /** * Handles the selection of a date from the calendar. */ @@ -71,15 +76,20 @@ export const DatePicker = ({ [setOpen, onChange], ); + const handleReset = useCallback(() => { + setOpen(false); + onReset?.(); + }, [setOpen, onReset]); + return ( - + setOpen(true)} />} readOnly placeholder="Select a date..." - value={renderValue()} + value={renderValue} className={input({ className })} onClick={() => setOpen(true)} /> @@ -93,6 +103,7 @@ export const DatePicker = ({ {...calendarProps} selectRange={selectRange} value={value} + onReset={handleReset} onCancel={() => setOpen(false)} onSelect={handleSelect} /> diff --git a/packages/frontend/src/components/shared/Select/Select.theme.ts b/packages/frontend/src/components/shared/Select/Select.theme.ts index 43d4b0f4..9c00a5c2 100644 --- a/packages/frontend/src/components/shared/Select/Select.theme.ts +++ b/packages/frontend/src/components/shared/Select/Select.theme.ts @@ -2,7 +2,7 @@ import { VariantProps, tv } from 'tailwind-variants'; export const selectTheme = tv({ slots: { - container: ['flex', 'flex-col', 'relative', 'gap-2'], + container: ['flex', 'flex-col', 'relative', 'gap-2', 'w-full'], label: ['text-sm', 'text-elements-high-em'], description: ['text-xs', 'text-elements-low-em'], inputWrapper: [ diff --git a/packages/frontend/src/components/shared/Select/Select.tsx b/packages/frontend/src/components/shared/Select/Select.tsx index 963cc0bb..b009e856 100644 --- a/packages/frontend/src/components/shared/Select/Select.tsx +++ b/packages/frontend/src/components/shared/Select/Select.tsx @@ -3,7 +3,6 @@ import React, { useState, ComponentPropsWithoutRef, useMemo, - useCallback, MouseEvent, useRef, useEffect, @@ -12,7 +11,7 @@ import { useMultipleSelection, useCombobox } from 'downshift'; import { SelectTheme, selectTheme } from './Select.theme'; import { ChevronDownIcon, - CrossIcon, + CrossCircleIcon, WarningIcon, } from 'components/shared/CustomIcon'; import { cloneIcon } from 'utils/cloneIcon'; @@ -270,11 +269,8 @@ export const Select = ({ itemToString: (item) => (item && !multiple ? item.label : ''), }); - const isSelected = useCallback( - (item: SelectOption) => - multiple ? selectedItems.includes(item) : selectedItem === item, - [selectedItems, selectedItem, multiple], - ); + const isSelected = (item: SelectOption) => + multiple ? selectedItems.includes(item) : selectedItem === item; const handleClear = (e: MouseEvent) => { e.stopPropagation(); @@ -306,7 +302,7 @@ export const Select = ({ return (
{clearable && (selectedItems.length > 0 || selectedItem) && ( - @@ -318,7 +314,7 @@ export const Select = ({ )}
); - }, [cloneIcon, theme, rightIcon]); + }, [cloneIcon, theme, rightIcon, selectedItem, selectedItems, clearable]); const renderHelperText = useMemo( () => ( diff --git a/packages/frontend/src/components/shared/Select/SelectItem/SelectItem.tsx b/packages/frontend/src/components/shared/Select/SelectItem/SelectItem.tsx index a6bbc487..8ac93774 100644 --- a/packages/frontend/src/components/shared/Select/SelectItem/SelectItem.tsx +++ b/packages/frontend/src/components/shared/Select/SelectItem/SelectItem.tsx @@ -62,7 +62,9 @@ const SelectItem = forwardRef(

{label}

- {orientation === 'horizontal' && } + {orientation === 'horizontal' && description && ( + + )} {description && (

{description} From 6db58718684e41447831155bde15ef0b4e3367d5 Mon Sep 17 00:00:00 2001 From: Wahyu Kurniawan Date: Thu, 29 Feb 2024 10:44:45 +0700 Subject: [PATCH 17/64] =?UTF-8?q?=F0=9F=8E=A8=20style:=20make=20the=20inpu?= =?UTF-8?q?t=20width=20to=20full?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- packages/frontend/src/components/shared/Input/Input.theme.ts | 4 +++- packages/frontend/src/components/shared/Input/Input.tsx | 4 ++-- 2 files changed, 5 insertions(+), 3 deletions(-) diff --git a/packages/frontend/src/components/shared/Input/Input.theme.ts b/packages/frontend/src/components/shared/Input/Input.theme.ts index b1ecb705..0144d578 100644 --- a/packages/frontend/src/components/shared/Input/Input.theme.ts +++ b/packages/frontend/src/components/shared/Input/Input.theme.ts @@ -8,6 +8,8 @@ export const inputTheme = tv( 'items-center', 'rounded-lg', 'relative', + 'gap-2', + 'w-full', 'placeholder:text-elements-disabled', 'disabled:cursor-not-allowed', 'disabled:bg-controls-disabled', @@ -27,7 +29,7 @@ export const inputTheme = tv( 'disabled:shadow-none', 'disabled:border-none', ], - icon: ['text-elements-mid-em'], + icon: ['text-elements-low-em'], iconContainer: [ 'absolute', 'inset-y-0', diff --git a/packages/frontend/src/components/shared/Input/Input.tsx b/packages/frontend/src/components/shared/Input/Input.tsx index fb3fd7d6..dd88bd80 100644 --- a/packages/frontend/src/components/shared/Input/Input.tsx +++ b/packages/frontend/src/components/shared/Input/Input.tsx @@ -87,12 +87,12 @@ export const Input = ({ ); return ( -

+
{renderLabels}
{leftIcon && renderLeftIcon} Date: Thu, 29 Feb 2024 10:45:12 +0700 Subject: [PATCH 18/64] =?UTF-8?q?=F0=9F=8E=A8=20style:=20refactor=20and=20?= =?UTF-8?q?re-styling=20deployment=20tab=20page?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../frontend/src/layouts/ProjectSearch.tsx | 4 +- .../src/pages/org-slug/projects/Id.tsx | 6 +- .../org-slug/projects/id/Deployments.tsx | 63 ++++++++++--------- 3 files changed, 40 insertions(+), 33 deletions(-) diff --git a/packages/frontend/src/layouts/ProjectSearch.tsx b/packages/frontend/src/layouts/ProjectSearch.tsx index c471ab5d..5805ba37 100644 --- a/packages/frontend/src/layouts/ProjectSearch.tsx +++ b/packages/frontend/src/layouts/ProjectSearch.tsx @@ -32,7 +32,7 @@ const ProjectSearch = () => { }, []); return ( -
+
@@ -64,7 +64,7 @@ const ProjectSearch = () => {
-
+
diff --git a/packages/frontend/src/pages/org-slug/projects/Id.tsx b/packages/frontend/src/pages/org-slug/projects/Id.tsx index 8b164852..55f979c0 100644 --- a/packages/frontend/src/pages/org-slug/projects/Id.tsx +++ b/packages/frontend/src/pages/org-slug/projects/Id.tsx @@ -87,8 +87,8 @@ const Id = () => {
-
- +
+ Overview @@ -107,7 +107,7 @@ const Id = () => { {/* Not wrapping in Tab.Content because we are using Outlet */} -
+
diff --git a/packages/frontend/src/pages/org-slug/projects/id/Deployments.tsx b/packages/frontend/src/pages/org-slug/projects/id/Deployments.tsx index d26a2dd4..8ae231d9 100644 --- a/packages/frontend/src/pages/org-slug/projects/id/Deployments.tsx +++ b/packages/frontend/src/pages/org-slug/projects/id/Deployments.tsx @@ -2,15 +2,15 @@ import React, { useCallback, useEffect, useMemo, useState } from 'react'; import { Deployment, Domain } from 'gql-client'; import { useOutletContext } from 'react-router-dom'; -import { Button, Typography } from '@material-tailwind/react'; - -import DeploymentDetailsCard from '../../../../components/projects/project/deployments/DeploymentDetailsCard'; +import DeploymentDetailsCard from 'components/projects/project/deployments/DeploymentDetailsCard'; import FilterForm, { FilterValue, StatusOptions, -} from '../../../../components/projects/project/deployments/FilterForm'; -import { OutletContextType } from '../../../../types'; -import { useGQLClient } from '../../../../context/GQLClientContext'; +} from 'components/projects/project/deployments/FilterForm'; +import { OutletContextType } from 'types'; +import { useGQLClient } from 'context/GQLClientContext'; +import { Button } from 'components/shared/Button'; +import { RefreshIcon } from 'components/shared/CustomIcon'; const DEFAULT_FILTER_VALUE: FilterValue = { searchedBranch: '', @@ -73,12 +73,19 @@ const DeploymentsTabPanel = () => { // TODO: match status field types (deployment.status as unknown as StatusOptions) === filterValue.status; + const startDate = + filterValue.updateAtRange instanceof Array + ? filterValue.updateAtRange[0] + : null; + const endDate = + filterValue.updateAtRange instanceof Array + ? filterValue.updateAtRange[1] + : null; + const dateMatch = !filterValue.updateAtRange || - (new Date(Number(deployment.createdAt)) >= - filterValue.updateAtRange!.from! && - new Date(Number(deployment.createdAt)) <= - filterValue.updateAtRange!.to!); + (new Date(Number(deployment.createdAt)) >= startDate! && + new Date(Number(deployment.createdAt)) <= endDate!); return branchMatch && statusMatch && dateMatch; }); @@ -93,12 +100,12 @@ const DeploymentsTabPanel = () => { }; return ( -
+
setFilterValue(value)} /> -
+
{Boolean(filteredDeployments.length) ? ( filteredDeployments.map((deployment, key) => { return ( @@ -113,27 +120,27 @@ const DeploymentsTabPanel = () => { ); }) ) : ( -
-
- + // TODO: Update the height based on the layout, need to re-styling the layout similar to create project layout +
+
+

No deployments found - - - Please change your search query or filters - - +

+

+ Please change your search query or filters. +

+
)}
-
+
); }; From 4532a962d898adfeae521a62925419ce8a9878d3 Mon Sep 17 00:00:00 2001 From: Vivian Phung Date: Wed, 28 Feb 2024 23:44:10 -0700 Subject: [PATCH 19/64] fix navigate --- packages/frontend/src/assets/templates.ts | 4 ++-- .../projects/create/TemplateCard/TemplateCard.tsx | 9 ++++++--- 2 files changed, 8 insertions(+), 5 deletions(-) diff --git a/packages/frontend/src/assets/templates.ts b/packages/frontend/src/assets/templates.ts index 84c60bb5..2d12165a 100644 --- a/packages/frontend/src/assets/templates.ts +++ b/packages/frontend/src/assets/templates.ts @@ -18,14 +18,14 @@ export default [ name: 'Kotlin', icon: 'kotlin', repoFullName: '', - isComingSoon: false, + isComingSoon: true, }, { id: '4', name: 'React Native', icon: 'react-native', repoFullName: '', - isComingSoon: false, + isComingSoon: true, }, { id: '5', diff --git a/packages/frontend/src/components/projects/create/TemplateCard/TemplateCard.tsx b/packages/frontend/src/components/projects/create/TemplateCard/TemplateCard.tsx index b7c549fd..450760ba 100644 --- a/packages/frontend/src/components/projects/create/TemplateCard/TemplateCard.tsx +++ b/packages/frontend/src/components/projects/create/TemplateCard/TemplateCard.tsx @@ -1,3 +1,4 @@ +import React, { ComponentPropsWithoutRef, useCallback } from 'react'; import { Button } from 'components/shared/Button'; import { ArrowRightCircleIcon, @@ -6,7 +7,6 @@ import { TemplateIconType, } from 'components/shared/CustomIcon'; import { Tag } from 'components/shared/Tag'; -import React, { ComponentPropsWithoutRef, useCallback } from 'react'; import { useNavigate } from 'react-router-dom'; import { useToast } from 'components/shared/Toast'; import { cn } from 'utils/classnames'; @@ -24,7 +24,10 @@ export interface TemplateCardProps extends ComponentPropsWithoutRef<'div'> { isGitAuth: boolean; } -export const TemplateCard = ({ template, isGitAuth }: TemplateCardProps) => { +export const TemplateCard: React.FC = ({ + template, + isGitAuth, +}: TemplateCardProps) => { const { toast, dismiss } = useToast(); const navigate = useNavigate(); @@ -38,7 +41,7 @@ export const TemplateCard = ({ template, isGitAuth }: TemplateCardProps) => { }); } if (isGitAuth) { - return navigate(`/template?templateId=${template.id}`); + return navigate(`template?templateId=${template.id}`); } return toast({ id: 'connect-git-account', From 59467557498a5ae893a31f2b4f2d46edd20c3ba1 Mon Sep 17 00:00:00 2001 From: Vivian Phung Date: Wed, 28 Feb 2024 23:52:37 -0700 Subject: [PATCH 20/64] fix navigate --- .../projects/create/TemplateCard/TemplateCard.tsx | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/packages/frontend/src/components/projects/create/TemplateCard/TemplateCard.tsx b/packages/frontend/src/components/projects/create/TemplateCard/TemplateCard.tsx index 450760ba..dce0e20b 100644 --- a/packages/frontend/src/components/projects/create/TemplateCard/TemplateCard.tsx +++ b/packages/frontend/src/components/projects/create/TemplateCard/TemplateCard.tsx @@ -7,7 +7,7 @@ import { TemplateIconType, } from 'components/shared/CustomIcon'; import { Tag } from 'components/shared/Tag'; -import { useNavigate } from 'react-router-dom'; +import { useNavigate, useParams } from 'react-router-dom'; import { useToast } from 'components/shared/Toast'; import { cn } from 'utils/classnames'; @@ -30,6 +30,7 @@ export const TemplateCard: React.FC = ({ }: TemplateCardProps) => { const { toast, dismiss } = useToast(); const navigate = useNavigate(); + const { orgSlug } = useParams(); const handleClick = useCallback(() => { if (template?.isComingSoon) { @@ -41,7 +42,9 @@ export const TemplateCard: React.FC = ({ }); } if (isGitAuth) { - return navigate(`template?templateId=${template.id}`); + return navigate( + `/${orgSlug}/projects/create/template?templateId=${template.id}`, + ); } return toast({ id: 'connect-git-account', From dd5f93050d7282cb507cd4ad117b7fc9719fb0b7 Mon Sep 17 00:00:00 2001 From: Vivian Phung Date: Thu, 29 Feb 2024 00:01:56 -0700 Subject: [PATCH 21/64] fix navigate --- .../components/projects/create/TemplateCard/TemplateCard.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/frontend/src/components/projects/create/TemplateCard/TemplateCard.tsx b/packages/frontend/src/components/projects/create/TemplateCard/TemplateCard.tsx index dce0e20b..ad073c2e 100644 --- a/packages/frontend/src/components/projects/create/TemplateCard/TemplateCard.tsx +++ b/packages/frontend/src/components/projects/create/TemplateCard/TemplateCard.tsx @@ -52,7 +52,7 @@ export const TemplateCard: React.FC = ({ variant: 'error', onDismiss: dismiss, }); - }, [isGitAuth, navigate, template, toast]); + }, [orgSlug, dismiss, isGitAuth, navigate, template, toast]); return (
-
-
- -
-
-
); From 207b32ce65afc30c7354ddf1d14b80896c16c577 Mon Sep 17 00:00:00 2001 From: Andre H Date: Fri, 1 Mar 2024 11:23:38 +0800 Subject: [PATCH 32/64] =?UTF-8?q?=E2=9A=A1=EF=B8=8F=20feat:=20integrate=20?= =?UTF-8?q?useform?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../projects/create/template/index.tsx | 68 ++++++++++++++----- 1 file changed, 50 insertions(+), 18 deletions(-) diff --git a/packages/frontend/src/pages/org-slug/projects/create/template/index.tsx b/packages/frontend/src/pages/org-slug/projects/create/template/index.tsx index 8f8a0f39..8364f60a 100644 --- a/packages/frontend/src/pages/org-slug/projects/create/template/index.tsx +++ b/packages/frontend/src/pages/org-slug/projects/create/template/index.tsx @@ -1,5 +1,5 @@ import React, { useCallback, useEffect, useState } from 'react'; -import { useForm, SubmitHandler } from 'react-hook-form'; +import { useForm, SubmitHandler, Controller } from 'react-hook-form'; import { useNavigate, useOutletContext, useParams } from 'react-router-dom'; import toast from 'react-hot-toast'; import assert from 'assert'; @@ -10,7 +10,7 @@ import { Template } from '../../../../../types'; import { Heading } from 'components/shared/Heading'; import { Input } from 'components/shared/Input'; import { Radio } from 'components/shared/Radio'; -import { Select } from 'components/shared/Select'; +import { Select, SelectOption } from 'components/shared/Select'; import { ArrowRightCircleFilledIcon, GitIcon, @@ -40,12 +40,12 @@ const CreateRepo = () => { const FRAMEWORK_OPTIONS = [ { - value: 'react-native', + value: 'React', label: 'React Native', leftIcon: , }, { - value: 'expo', + value: 'Expo', label: 'Expo', leftIcon: , }, @@ -114,7 +114,7 @@ const CreateRepo = () => { fetchUserAndOrgs(); }, [octokit]); - const { handleSubmit, reset } = useForm({ + const { handleSubmit, control, reset } = useForm({ defaultValues: { framework: 'React', repoName: '', @@ -140,29 +140,61 @@ const CreateRepo = () => {
Framework - ( + + )} />
Git account - onChange((value as SelectOption).value)} + options={ + gitAccounts.map((account) => ({ + value: account, + label: account, + })) ?? [] + } + /> + )} />
Name the repo - + ( + + )} + />
- + ( + + )} + />
- - - - - ^ Visit - - - setAssignDomainDialog(!assignDomainDialog)} - placeholder={''} - > - ^ Assign domain - - setChangeToProduction(!changeToProduction)} - disabled={!(deployment.environment !== Environment.Production)} - placeholder={''} - > - ^ Change to production - -
- setRedeployToProduction(!redeployToProduction)} - disabled={ - !( - deployment.environment === Environment.Production && - deployment.isCurrent - ) - } - placeholder={''} - > - ^ Redeploy to production - - setRollbackDeployment(!rollbackDeployment)} - disabled={ - deployment.isCurrent || - deployment.environment !== Environment.Production || - !Boolean(currentDeployment) - } - placeholder={''} - > - ^ Rollback to this version - -
- -
- setChangeToProduction((preVal) => !preVal)} - open={changeToProduction} - confirmButtonTitle="Change" - color="blue" - handleConfirm={async () => { - await updateDeployment(); - setChangeToProduction((preVal) => !preVal); - }} - > -
- - Upon confirmation, this deployment will be changed to production. - - - - The new deployment will be associated with these domains: - - {prodBranchDomains.length > 0 && - prodBranchDomains.map((value) => { - return ( - - ^ {value.name} - - ); - })} -
-
- setRedeployToProduction((preVal) => !preVal)} - open={redeployToProduction} - confirmButtonTitle="Redeploy" - color="blue" - handleConfirm={async () => { - await redeployToProd(); - setRedeployToProduction((preVal) => !preVal); - }} - > -
- - Upon confirmation, new deployment will be created with the same - source code as current deployment. - - - - These domains will point to your new deployment: - - {deployment.domain?.name && ( - - {deployment.domain?.name} - - )} -
-
- {Boolean(currentDeployment) && ( - setRollbackDeployment((preVal) => !preVal)} - open={rollbackDeployment} - confirmButtonTitle="Rollback" - color="blue" - handleConfirm={async () => { - await rollbackDeploymentHandler(); - setRollbackDeployment((preVal) => !preVal); - }} - > -
- - Upon confirmation, this deployment will replace your current - deployment - - - - - These domains will point to your new deployment: - - - ^ {currentDeployment.domain?.name} - -
-
- )} - setAssignDomainDialog(!assignDomainDialog)} - />
); }; diff --git a/packages/frontend/src/components/projects/project/deployments/DeploymentMenu.tsx b/packages/frontend/src/components/projects/project/deployments/DeploymentMenu.tsx new file mode 100644 index 00000000..f4eb9808 --- /dev/null +++ b/packages/frontend/src/components/projects/project/deployments/DeploymentMenu.tsx @@ -0,0 +1,268 @@ +import React, { useState } from 'react'; +import toast from 'react-hot-toast'; +import { Deployment, Domain, Environment, Project } from 'gql-client'; +import { Button } from 'components/shared/Button'; +import { + GlobeIcon, + HorizontalDotIcon, + LinkIcon, + RefreshIcon, + RocketIcon, + UndoIcon, +} from 'components/shared/CustomIcon'; +import { + Menu, + MenuHandler, + MenuItem, + MenuList, +} from '@material-tailwind/react'; +import { ComponentPropsWithRef } from 'react'; +import ConfirmDialog from '../../../shared/ConfirmDialog'; +import AssignDomainDialog from './AssignDomainDialog'; +import DeploymentDialogBodyCard from './DeploymentDialogBodyCard'; +import { Typography } from '@material-tailwind/react'; +import { useGQLClient } from '../../../../context/GQLClientContext'; +import { cn } from 'utils/classnames'; + +interface DeploymentMenuProps extends ComponentPropsWithRef<'div'> { + deployment: Deployment; + currentDeployment: Deployment; + onUpdate: () => Promise; + project: Project; + prodBranchDomains: Domain[]; +} + +export const DeploymentMenu = ({ + deployment, + currentDeployment, + onUpdate, + project, + prodBranchDomains, + className, + ...props +}: DeploymentMenuProps) => { + const client = useGQLClient(); + + const [changeToProduction, setChangeToProduction] = useState(false); + const [redeployToProduction, setRedeployToProduction] = useState(false); + const [rollbackDeployment, setRollbackDeployment] = useState(false); + const [assignDomainDialog, setAssignDomainDialog] = useState(false); + + const updateDeployment = async () => { + const isUpdated = await client.updateDeploymentToProd(deployment.id); + if (isUpdated) { + await onUpdate(); + toast.success('Deployment changed to production'); + } else { + toast.error('Unable to change deployment to production'); + } + }; + + const redeployToProd = async () => { + const isRedeployed = await client.redeployToProd(deployment.id); + if (isRedeployed) { + await onUpdate(); + toast.success('Redeployed to production'); + } else { + toast.error('Unable to redeploy to production'); + } + }; + + const rollbackDeploymentHandler = async () => { + const isRollbacked = await client.rollbackDeployment( + project.id, + deployment.id, + ); + if (isRollbacked) { + await onUpdate(); + toast.success('Deployment rolled back'); + } else { + toast.error('Unable to rollback deployment'); + } + }; + + return ( + <> +
+ + + +
+ {/* Dialogs */} + setChangeToProduction((preVal) => !preVal)} + open={changeToProduction} + confirmButtonTitle="Change" + color="blue" + handleConfirm={async () => { + await updateDeployment(); + setChangeToProduction((preVal) => !preVal); + }} + > +
+ + Upon confirmation, this deployment will be changed to production. + + + + The new deployment will be associated with these domains: + + {prodBranchDomains.length > 0 && + prodBranchDomains.map((value) => { + return ( + + ^ {value.name} + + ); + })} +
+
+ setRedeployToProduction((preVal) => !preVal)} + open={redeployToProduction} + confirmButtonTitle="Redeploy" + color="blue" + handleConfirm={async () => { + await redeployToProd(); + setRedeployToProduction((preVal) => !preVal); + }} + > +
+ + Upon confirmation, new deployment will be created with the same + source code as current deployment. + + + + These domains will point to your new deployment: + + {deployment.domain?.name && ( + + {deployment.domain?.name} + + )} +
+
+ {Boolean(currentDeployment) && ( + setRollbackDeployment((preVal) => !preVal)} + open={rollbackDeployment} + confirmButtonTitle="Rollback" + color="blue" + handleConfirm={async () => { + await rollbackDeploymentHandler(); + setRollbackDeployment((preVal) => !preVal); + }} + > +
+ + Upon confirmation, this deployment will replace your current + deployment + + + + + These domains will point to your new deployment: + + + ^ {currentDeployment.domain?.name} + +
+
+ )} + setAssignDomainDialog(!assignDomainDialog)} + /> + + ); +}; diff --git a/packages/frontend/src/components/projects/project/deployments/FilterForm.tsx b/packages/frontend/src/components/projects/project/deployments/FilterForm.tsx index c28c6218..dd549c57 100644 --- a/packages/frontend/src/components/projects/project/deployments/FilterForm.tsx +++ b/packages/frontend/src/components/projects/project/deployments/FilterForm.tsx @@ -44,7 +44,7 @@ const FilterForm = ({ value, onChange }: FilterFormProps) => { }, [value]); return ( -
+
{ + return ( + + + + + + + + + + + ); +}; diff --git a/packages/frontend/src/components/shared/CustomIcon/RefreshIcon.tsx b/packages/frontend/src/components/shared/CustomIcon/RefreshIcon.tsx new file mode 100644 index 00000000..3873c371 --- /dev/null +++ b/packages/frontend/src/components/shared/CustomIcon/RefreshIcon.tsx @@ -0,0 +1,41 @@ +import React from 'react'; +import { CustomIcon, CustomIconProps } from './CustomIcon'; + +export const RefreshIcon = (props: CustomIconProps) => { + return ( + + + + + + + + + ); +}; diff --git a/packages/frontend/src/components/shared/CustomIcon/RocketIcon.tsx b/packages/frontend/src/components/shared/CustomIcon/RocketIcon.tsx new file mode 100644 index 00000000..488fba8f --- /dev/null +++ b/packages/frontend/src/components/shared/CustomIcon/RocketIcon.tsx @@ -0,0 +1,20 @@ +import React from 'react'; +import { CustomIcon, CustomIconProps } from './CustomIcon'; + +export const RocketIcon = (props: CustomIconProps) => { + return ( + + + + ); +}; diff --git a/packages/frontend/src/components/shared/CustomIcon/UndoIcon.tsx b/packages/frontend/src/components/shared/CustomIcon/UndoIcon.tsx new file mode 100644 index 00000000..713a0b6e --- /dev/null +++ b/packages/frontend/src/components/shared/CustomIcon/UndoIcon.tsx @@ -0,0 +1,21 @@ +import React from 'react'; +import { CustomIcon, CustomIconProps } from './CustomIcon'; + +export const UndoIcon = (props: CustomIconProps) => { + return ( + + + + ); +}; diff --git a/packages/frontend/src/components/shared/CustomIcon/index.ts b/packages/frontend/src/components/shared/CustomIcon/index.ts index b9965188..61239304 100644 --- a/packages/frontend/src/components/shared/CustomIcon/index.ts +++ b/packages/frontend/src/components/shared/CustomIcon/index.ts @@ -41,6 +41,10 @@ export * from './BranchStrokeIcon'; export * from './StorageIcon'; export * from './LinkIcon'; export * from './CursorBoxIcon'; +export * from './CommitIcon'; +export * from './RocketIcon'; +export * from './RefreshIcon'; +export * from './UndoIcon'; // Templates export * from './templates'; diff --git a/packages/frontend/src/components/shared/OverflownText/OverflownText.tsx b/packages/frontend/src/components/shared/OverflownText/OverflownText.tsx new file mode 100644 index 00000000..b03ea580 --- /dev/null +++ b/packages/frontend/src/components/shared/OverflownText/OverflownText.tsx @@ -0,0 +1,71 @@ +import { cn } from 'utils/classnames'; +import { Tooltip, TooltipProps } from 'components/shared/Tooltip'; +import { debounce } from 'lodash'; +import React, { + ComponentPropsWithRef, + PropsWithChildren, + useRef, + useState, + useEffect, +} from 'react'; +import { PolymorphicProps } from 'types/common'; + +interface OverflownTextProps extends ComponentPropsWithRef<'span'> { + tooltipProps?: TooltipProps; + content?: string; +} + +type ElementType = 'span' | 'div'; + +// This component is used to truncate text and show a tooltip if the text is overflown. +export const OverflownText = ({ + tooltipProps, + children, + content, + className, + as, + ...props +}: PropsWithChildren>) => { + const ref = useRef(null); + const [isOverflown, setIsOverflown] = useState(false); + + useEffect(() => { + const element = ref.current as HTMLElement | null; + if (!element) return; + + setIsOverflown(element.scrollWidth > element.clientWidth); + + const handleResize = () => { + const isOverflown = element.scrollWidth > element.clientWidth; + setIsOverflown(isOverflown); + }; + + window.addEventListener('resize', debounce(handleResize, 500)); + + return () => { + window.removeEventListener('resize', handleResize); + }; + }, []); + + const Component = as || 'span'; + + return ( + + + {children} + + + ); +}; diff --git a/packages/frontend/src/components/shared/OverflownText/index.ts b/packages/frontend/src/components/shared/OverflownText/index.ts new file mode 100644 index 00000000..1ffb16f2 --- /dev/null +++ b/packages/frontend/src/components/shared/OverflownText/index.ts @@ -0,0 +1 @@ +export * from './OverflownText'; diff --git a/packages/frontend/src/components/shared/Tag/Tag.theme.ts b/packages/frontend/src/components/shared/Tag/Tag.theme.ts index a027185d..884f79bc 100644 --- a/packages/frontend/src/components/shared/Tag/Tag.theme.ts +++ b/packages/frontend/src/components/shared/Tag/Tag.theme.ts @@ -4,7 +4,7 @@ import type { VariantProps } from 'tailwind-variants'; export const tagTheme = tv( { slots: { - wrapper: ['flex', 'gap-1.5', 'rounded-lg', 'border'], + wrapper: ['inline-flex', 'gap-1.5', 'rounded-lg', 'border'], icon: [], label: ['font-inter', 'text-xs'], }, diff --git a/packages/frontend/src/pages/org-slug/projects/id/Deployments.tsx b/packages/frontend/src/pages/org-slug/projects/id/Deployments.tsx index d26a2dd4..d5f0346f 100644 --- a/packages/frontend/src/pages/org-slug/projects/id/Deployments.tsx +++ b/packages/frontend/src/pages/org-slug/projects/id/Deployments.tsx @@ -88,17 +88,17 @@ const DeploymentsTabPanel = () => { setFilterValue(DEFAULT_FILTER_VALUE); }, []); - const onUpdateDeploymenToProd = async () => { + const onUpdateDeploymentToProd = async () => { await fetchDeployments(); }; return ( -
+
setFilterValue(value)} /> -
+
{Boolean(filteredDeployments.length) ? ( filteredDeployments.map((deployment, key) => { return ( @@ -106,7 +106,7 @@ const DeploymentsTabPanel = () => { deployment={deployment} key={key} currentDeployment={currentDeployment!} - onUpdate={onUpdateDeploymenToProd} + onUpdate={onUpdateDeploymentToProd} project={project} prodBranchDomains={prodBranchDomains} /> diff --git a/packages/frontend/tailwind.config.js b/packages/frontend/tailwind.config.js index c362e898..4efc11fe 100644 --- a/packages/frontend/tailwind.config.js +++ b/packages/frontend/tailwind.config.js @@ -12,6 +12,9 @@ export default withMT({ zIndex: { tooltip: '52', }, + letterSpacing: { + tight: '-0.084px', + }, fontFamily: { sans: ['Inter', 'sans-serif'], display: ['Inter Display', 'sans-serif'], From ab77ce681a9b98037912a4cecdda7dddae615312 Mon Sep 17 00:00:00 2001 From: Andre H Date: Fri, 1 Mar 2024 13:48:33 +0800 Subject: [PATCH 35/64] =?UTF-8?q?=F0=9F=94=A7=20chore:=20radioItem=20leftI?= =?UTF-8?q?con=20use=20span?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../frontend/src/components/shared/Radio/RadioItem.tsx | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/packages/frontend/src/components/shared/Radio/RadioItem.tsx b/packages/frontend/src/components/shared/Radio/RadioItem.tsx index 4a2c2e37..017d9f69 100644 --- a/packages/frontend/src/components/shared/Radio/RadioItem.tsx +++ b/packages/frontend/src/components/shared/Radio/RadioItem.tsx @@ -75,8 +75,11 @@ export const RadioItem = ({ className={indicator({ className: indicatorProps?.className })} /> - {leftIcon && - cloneIcon(leftIcon, { className: icon(), 'aria-hidden': true })} + {leftIcon && ( + + {cloneIcon(leftIcon, { className: icon(), 'aria-hidden': true })} + + )} {label && (