From 5c995840017e43d85545f5dfd501b6757b08a65c Mon Sep 17 00:00:00 2001 From: Joshen Lim Date: Fri, 16 May 2025 15:42:02 +0800 Subject: [PATCH] Chore/project wildcard route sort last visited org (#35680) * Project wildcard route, sort last visited org first * Add search and filter status * Smol fix --- .../Home/ProjectList/ProjectList.tsx | 13 +- .../components/interfaces/HomePageActions.tsx | 4 +- apps/studio/pages/org/_/[[...routeSlug]].tsx | 115 +++++++++--------- .../pages/project/_/[[...routeSlug]].tsx | 100 +++++++++++---- 4 files changed, 141 insertions(+), 91 deletions(-) diff --git a/apps/studio/components/interfaces/Home/ProjectList/ProjectList.tsx b/apps/studio/components/interfaces/Home/ProjectList/ProjectList.tsx index 67ebf90c391..c0fb01b1a05 100644 --- a/apps/studio/components/interfaces/Home/ProjectList/ProjectList.tsx +++ b/apps/studio/components/interfaces/Home/ProjectList/ProjectList.tsx @@ -1,7 +1,6 @@ import { Plus } from 'lucide-react' import Link from 'next/link' -import { useParams } from 'common' import AlertError from 'components/ui/AlertError' import NoSearchResults from 'components/ui/NoSearchResults' import { useGitHubConnectionsQuery } from 'data/integrations/github-connections-query' @@ -19,7 +18,7 @@ import ProjectCard from './ProjectCard' import ShimmeringCard from './ShimmeringCard' export interface ProjectListProps { - forOrganization?: Organization + organization?: Organization rewriteHref?: (projectRef: string) => string search?: string filterStatus?: string[] @@ -28,13 +27,13 @@ export interface ProjectListProps { const ProjectList = ({ search = '', - forOrganization, + organization: organization_, rewriteHref, filterStatus, resetFilterStatus, }: ProjectListProps) => { - const { slug } = useParams() - const organization = useSelectedOrganization() ?? forOrganization + const selectedOrganization = useSelectedOrganization() + const organization = organization_ ?? selectedOrganization const { data: allProjects = [], @@ -50,9 +49,7 @@ const ProjectList = ({ } = usePermissionsQuery() const { data: resourceWarnings } = useResourceWarningsQuery() - const orgProjects = allProjects.filter( - (x) => x.organization_slug === slug || x.organization_slug === organization?.slug - ) + const orgProjects = allProjects.filter((x) => x.organization_slug === organization?.slug) const isLoadingPermissions = IS_PLATFORM ? _isLoadingPermissions : false const hasFilterStatusApplied = filterStatus !== undefined && filterStatus.length !== 2 diff --git a/apps/studio/components/interfaces/HomePageActions.tsx b/apps/studio/components/interfaces/HomePageActions.tsx index c86d3531ccd..7fad412833c 100644 --- a/apps/studio/components/interfaces/HomePageActions.tsx +++ b/apps/studio/components/interfaces/HomePageActions.tsx @@ -17,6 +17,7 @@ import { interface HomePageActionsProps { search: string filterStatus: string[] + hideNewProject?: boolean setSearch: (value: string) => void setFilterStatus: (value: string[]) => void } @@ -24,6 +25,7 @@ interface HomePageActionsProps { const HomePageActions = ({ search, filterStatus, + hideNewProject = false, setSearch, setFilterStatus, }: HomePageActionsProps) => { @@ -32,7 +34,7 @@ const HomePageActions = ({ return (
- {projectCreationEnabled && ( + {projectCreationEnabled && !hideNewProject && ( diff --git a/apps/studio/pages/org/_/[[...routeSlug]].tsx b/apps/studio/pages/org/_/[[...routeSlug]].tsx index 687760233ef..c23714346a5 100644 --- a/apps/studio/pages/org/_/[[...routeSlug]].tsx +++ b/apps/studio/pages/org/_/[[...routeSlug]].tsx @@ -8,7 +8,7 @@ import CardButton from 'components/ui/CardButton' import { useOrganizationsQuery } from 'data/organizations/organizations-query' import { withAuth } from 'hooks/misc/withAuth' import { BASE_PATH } from 'lib/constants' -import { Button } from 'ui' +import { Button, cn } from 'ui' const Header = () => { return ( @@ -27,6 +27,7 @@ const Header = () => { ) } +// [Joshen] Thinking we can deprecate this page in favor of /organizations const GenericOrganizationPage: NextPage = () => { const router = useRouter() @@ -51,64 +52,68 @@ const GenericOrganizationPage: NextPage = () => { return ( <>
-
-

Select an organization to continue

+
+

+ Select an organization to continue +

- {isLoading ? ( -
    - - -
- ) : organizations?.length === 0 ? ( -
-
-

You are not part of any organizations yet

-

- Get started by creating a new organization. -

+
+ {isLoading ? ( +
    + + +
+ ) : organizations?.length === 0 ? ( +
+
+

You are not part of any organizations yet

+

+ Get started by creating a new organization. +

+
+
+ +
-
- -
-
- ) : ( -
    - {organizations?.map((organization) => ( -
  • - - {organization.name} -
- } - footer={ -
- - {organization.slug} - -
- } - /> - - ))} - - )} + ) : ( +
    + {organizations?.map((organization) => ( +
  • + + {organization.name} +
+ } + footer={ +
+ + {organization.slug} + +
+ } + /> + + ))} + + )} +
diff --git a/apps/studio/pages/project/_/[[...routeSlug]].tsx b/apps/studio/pages/project/_/[[...routeSlug]].tsx index 7b963eb08a2..e65fbb6469b 100644 --- a/apps/studio/pages/project/_/[[...routeSlug]].tsx +++ b/apps/studio/pages/project/_/[[...routeSlug]].tsx @@ -1,15 +1,18 @@ +import { partition } from 'lodash' import { AlertTriangleIcon, Boxes } from 'lucide-react' import { NextPage } from 'next' import Link from 'next/link' import { useRouter } from 'next/router' -import { Fragment } from 'react' +import { Fragment, useMemo, useState } from 'react' -import { IS_PLATFORM } from 'common' +import { IS_PLATFORM, LOCAL_STORAGE_KEYS } from 'common' import { ProjectList } from 'components/interfaces/Home/ProjectList' +import HomePageActions from 'components/interfaces/HomePageActions' import { useOrganizationsQuery } from 'data/organizations/organizations-query' +import { useLocalStorageQuery } from 'hooks/misc/useLocalStorage' import { withAuth } from 'hooks/misc/withAuth' -import { BASE_PATH } from 'lib/constants' -import { Alert_Shadcn_, AlertDescription_Shadcn_, AlertTitle_Shadcn_ } from 'ui' +import { BASE_PATH, PROJECT_STATUS } from 'lib/constants' +import { Alert_Shadcn_, AlertDescription_Shadcn_, AlertTitle_Shadcn_, Badge } from 'ui' import ShimmeringLoader from 'ui-patterns/ShimmeringLoader' const Header = () => { @@ -37,8 +40,19 @@ const GenericProjectPage: NextPage = () => { const router = useRouter() const { routeSlug, ...queryParams } = router.query + const [search, setSearch] = useState('') + const [filterStatus, setFilterStatus] = useState([ + PROJECT_STATUS.ACTIVE_HEALTHY, + PROJECT_STATUS.INACTIVE, + ]) + + const [lastVisitedOrgSlug] = useLocalStorageQuery( + LOCAL_STORAGE_KEYS.LAST_VISITED_ORGANIZATION, + '' + ) + const { - data: organizations, + data: organizations = [], isLoading: isLoadingOrganizations, isError: isErrorOrganizations, } = useOrganizationsQuery({ @@ -62,34 +76,66 @@ const GenericProjectPage: NextPage = () => { } } + const [[lastVisitedOrganization], otherOrganizations] = useMemo( + () => partition(organizations, (org) => org.slug === lastVisitedOrgSlug), + [lastVisitedOrgSlug, organizations] + ) + return ( <>
-
-

Select a project to continue

+
+

Select a project to continue

- {isLoadingOrganizations ? ( - - ) : isErrorOrganizations ? ( - - ) : ( - organizations.map((organization) => ( - -

- - {organization.name} -

- -
- )) - )} +
+ + {isLoadingOrganizations ? ( + + ) : isErrorOrganizations ? ( + + ) : ( + <> + {!!lastVisitedOrganization && ( + <> +

+ + {lastVisitedOrganization.name} + Recently visited +

+ + + )} + {otherOrganizations.map((organization) => ( + +

+ + {organization.name} +

+ +
+ ))} + + )} +