From fd98a08a4f5215f9da5ae54347ca313cb85f5a44 Mon Sep 17 00:00:00 2001 From: Joshen Lim Date: Tue, 13 May 2025 11:25:35 +0800 Subject: [PATCH] Chore/default to new organization layout (#35515) * Default to new organization layout + remove feature preview * Remove feature preview * Clean up LayoutUpdateBanner * Clean up * Fix * Fixy fix * Update comment * Nit to fix layout shift --- .../FeaturePreview/FeaturePreviewContext.tsx | 25 +-- .../FeaturePreview/LayoutUpdatePreview.tsx | 90 --------- .../interfaces/App/RouteValidationWrapper.tsx | 8 +- .../components/interfaces/Connect/Connect.tsx | 4 +- .../Home/ProjectList/ProjectList.tsx | 116 +++-------- .../components/interfaces/HomePageActions.tsx | 57 +----- .../BillingSettings/BillingSettings.tsx | 17 +- .../DeleteOrganizationButton.tsx | 14 +- .../OrganizationDeletePanel.tsx | 2 +- .../IntegrationSettings.tsx | 11 +- .../Organization/NewOrg/NewOrgForm.tsx | 12 +- .../TeamSettings/TeamSettings.tsx | 17 +- .../interfaces/Organization/Usage/Usage.tsx | 11 +- .../interfaces/Organization/index.ts | 8 +- .../OrganizationInvite/OrganizationInvite.tsx | 2 +- apps/studio/components/interfaces/Sidebar.tsx | 190 +++++------------- .../interfaces/SignIn/ResetPasswordForm.tsx | 2 +- .../interfaces/SignIn/SignInForm.tsx | 2 +- .../layouts/AccountLayout/AccountLayout.tsx | 58 +++--- .../AccountLayout/AccountSettingsLayout.tsx | 11 +- .../layouts/AppLayout/AssistantButton.tsx | 4 +- .../layouts/AppLayout/BranchDropdown.tsx | 55 ++--- .../EnableBranchingButton.tsx | 8 +- .../layouts/AppLayout/InlineEditorButton.tsx | 4 +- .../AppLayout/OrganizationDropdown.tsx | 76 +++---- .../layouts/AppLayout/ProjectDropdown.tsx | 49 ++--- .../components/layouts/DefaultLayout.tsx | 9 +- .../components/layouts/OrganizationLayout.tsx | 122 +---------- .../LayoutHeader/BreadcrumbsView.tsx | 4 +- .../LayoutHeader/HelpPopover.tsx | 4 +- .../ProjectLayout/LayoutHeader/HomeIcon.tsx | 16 +- .../LayoutHeader/LayoutHeader.tsx | 158 +++++++-------- .../NotificationsPopover.tsx | 4 +- .../NavigationBar/MobileNavigationBar.tsx | 2 +- .../OrganizationSettingsLayout.tsx | 41 +--- .../SignInLayout/ForgotPasswordLayout.tsx | 2 +- .../layouts/SignInLayout/SignInLayout.tsx | 2 +- .../components/layouts/WizardLayout.tsx | 17 +- apps/studio/hooks/misc/useHideSidebar.ts | 6 +- .../hooks/misc/useOrganizationRestrictions.ts | 4 +- apps/studio/hooks/misc/useShowLayoutHeader.ts | 19 -- apps/studio/lib/gotrue.ts | 3 +- apps/studio/next.config.js | 7 +- apps/studio/pages/500.tsx | 19 +- apps/studio/pages/account/audit.tsx | 20 +- apps/studio/pages/account/me.tsx | 27 +-- apps/studio/pages/account/security.tsx | 29 +-- apps/studio/pages/account/tokens.tsx | 103 +++------- apps/studio/pages/authorize.tsx | 2 +- apps/studio/pages/new/[slug].tsx | 24 +-- apps/studio/pages/new/index.tsx | 4 +- apps/studio/pages/org/[slug]/billing.tsx | 2 +- apps/studio/pages/org/[slug]/index.tsx | 22 +- apps/studio/pages/org/[slug]/team.tsx | 10 +- apps/studio/pages/org/index.tsx | 45 +++++ apps/studio/pages/organizations.tsx | 109 ++++++---- apps/studio/pages/projects.tsx | 98 --------- apps/studio/pages/sign-in-fly-tos.tsx | 2 +- 58 files changed, 491 insertions(+), 1298 deletions(-) delete mode 100644 apps/studio/components/interfaces/App/FeaturePreview/LayoutUpdatePreview.tsx delete mode 100644 apps/studio/hooks/misc/useShowLayoutHeader.ts create mode 100644 apps/studio/pages/org/index.tsx delete mode 100644 apps/studio/pages/projects.tsx diff --git a/apps/studio/components/interfaces/App/FeaturePreview/FeaturePreviewContext.tsx b/apps/studio/components/interfaces/App/FeaturePreview/FeaturePreviewContext.tsx index 35c3c6eca40..9a5ef8e64fe 100644 --- a/apps/studio/components/interfaces/App/FeaturePreview/FeaturePreviewContext.tsx +++ b/apps/studio/components/interfaces/App/FeaturePreview/FeaturePreviewContext.tsx @@ -1,26 +1,16 @@ import { noop } from 'lodash' -import { FeatureFlagContext } from 'common' -import { useFlag } from 'hooks/ui/useFlag' +import { PropsWithChildren, createContext, useContext, useEffect, useState } from 'react' + +import { FeatureFlagContext, LOCAL_STORAGE_KEYS } from 'common' import { IS_PLATFORM } from 'lib/constants' import { EMPTY_OBJ } from 'lib/void' -import { PropsWithChildren, createContext, useContext, useEffect, useState } from 'react' import { APISidePanelPreview } from './APISidePanelPreview' import { CLSPreview } from './CLSPreview' import { InlineEditorPreview } from './InlineEditorPreview' -import { LayoutUpdatePreview } from './LayoutUpdatePreview' import { SqlEditorTabsPreview } from './SqlEditorTabs' import { TableEditorTabsPreview } from './TableEditorTabs' -import { LOCAL_STORAGE_KEYS } from 'common' export const FEATURE_PREVIEWS = [ - { - key: LOCAL_STORAGE_KEYS.UI_NEW_LAYOUT_PREVIEW, - name: 'Layout Update for Organizations', - content: , - discussionsUrl: 'https://github.com/orgs/supabase/discussions/33670', - isNew: false, - isPlatformOnly: true, - }, { key: LOCAL_STORAGE_KEYS.UI_PREVIEW_INLINE_EDITOR, name: 'Directly edit database entities', @@ -75,13 +65,10 @@ export const useFeaturePreviewContext = () => useContext(FeaturePreviewContext) export const FeaturePreviewContextProvider = ({ children }: PropsWithChildren<{}>) => { const { hasLoaded } = useContext(FeatureFlagContext) - const enableNewLayoutPreview = useFlag('newLayoutPreview') // [Joshen] Similar logic to feature flagging previews, we can use flags to default opt in previews const isDefaultOptIn = (feature: (typeof FEATURE_PREVIEWS)[number]) => { switch (feature.key) { - case LOCAL_STORAGE_KEYS.UI_NEW_LAYOUT_PREVIEW: - return enableNewLayoutPreview default: return false } @@ -149,9 +136,3 @@ export const useIsSQLEditorTabsEnabled = () => { if (!IS_PLATFORM) return false return flags[LOCAL_STORAGE_KEYS.UI_SQL_EDITOR_TABS] } - -export const useIsNewLayoutEnabled = (): boolean => { - const { flags } = useFeaturePreviewContext() - if (!IS_PLATFORM) return false - return flags[LOCAL_STORAGE_KEYS.UI_NEW_LAYOUT_PREVIEW] -} diff --git a/apps/studio/components/interfaces/App/FeaturePreview/LayoutUpdatePreview.tsx b/apps/studio/components/interfaces/App/FeaturePreview/LayoutUpdatePreview.tsx deleted file mode 100644 index 643c3c0ab1c..00000000000 --- a/apps/studio/components/interfaces/App/FeaturePreview/LayoutUpdatePreview.tsx +++ /dev/null @@ -1,90 +0,0 @@ -import { ButtonTooltip } from 'components/ui/ButtonTooltip' -import { useLocalStorageQuery } from 'hooks/misc/useLocalStorage' -import { BASE_PATH } from 'lib/constants' -import { ExternalLink, X } from 'lucide-react' -import Image from 'next/image' -import { Alert_Shadcn_, AlertDescription_Shadcn_, AlertTitle_Shadcn_, Badge, Button } from 'ui' -import { useIsNewLayoutEnabled } from './FeaturePreviewContext' -import { LOCAL_STORAGE_KEYS } from 'common' - -export const LayoutUpdatePreview = () => { - return ( -
- api-docs-side-panel-preview -

- The layout out of the dashboard is now scoped to the organization that you're currently on - instead of all organizations that you are a member of, in hopes to provide a clearer - navigation to your organization settings. -

-

- This feature preview only updates the layout for the home page, organization settings pages, - and account pages. Layout for project pages will not have any changes. -

-
-

Enabling this preview will:

-
    -
  • - Display only the projects from the organization you are currently viewing on the home - page -
  • -
  • Update homepage sidebar links to go directly to the settings for the organization
  • -
  • - Access to account preferences, access tokens, security settings, and audit logs are - available via the user dropdown in the top navigation bar -
  • -
-
-
- ) -} - -export const LayoutUpdateBanner = () => { - const newLayoutPreview = useIsNewLayoutEnabled() - const [newLayoutPreviewState] = useLocalStorageQuery(LOCAL_STORAGE_KEYS.UI_NEW_LAYOUT_PREVIEW, '') - const [newLayoutAcknowledged, setNewLayoutAcknowledged] = useLocalStorageQuery( - LOCAL_STORAGE_KEYS.NEW_LAYOUT_NOTICE_ACKNOWLEDGED, - false - ) - const isDefaultOptedInNewLayout = newLayoutPreview && newLayoutPreviewState === '' - - if (!isDefaultOptedInNewLayout || newLayoutAcknowledged) return null - - return ( - - - - NEW - - Dashboard layout has been updated! - - - We've updated the dashboard layout to make it easier to find and manage your organization - settings. - - - - - } - className="absolute top-2 right-2 px-1" - onClick={() => setNewLayoutAcknowledged(true)} - tooltip={{ content: { side: 'bottom', text: 'Dismiss' } }} - /> - - ) -} diff --git a/apps/studio/components/interfaces/App/RouteValidationWrapper.tsx b/apps/studio/components/interfaces/App/RouteValidationWrapper.tsx index 00b47042edd..ac381001c9f 100644 --- a/apps/studio/components/interfaces/App/RouteValidationWrapper.tsx +++ b/apps/studio/components/interfaces/App/RouteValidationWrapper.tsx @@ -10,13 +10,11 @@ import { useLocalStorageQuery } from 'hooks/misc/useLocalStorage' import { useSelectedOrganization } from 'hooks/misc/useSelectedOrganization' import { IS_PLATFORM } from 'lib/constants' import { useAppStateSnapshot } from 'state/app-state' -import { useIsNewLayoutEnabled } from './FeaturePreview/FeaturePreviewContext' // Ideally these could all be within a _middleware when we use Next 12 const RouteValidationWrapper = ({ children }: PropsWithChildren<{}>) => { const router = useRouter() const { ref, slug, id } = useParams() - const newLayoutPreview = useIsNewLayoutEnabled() const isLoggedIn = useIsLoggedIn() const snap = useAppStateSnapshot() @@ -33,11 +31,7 @@ const RouteValidationWrapper = ({ children }: PropsWithChildren<{}>) => { '' ) - const DEFAULT_HOME = IS_PLATFORM - ? newLayoutPreview - ? '/organizations' - : '/projects' - : '/project/default' + const DEFAULT_HOME = IS_PLATFORM ? '/organizations' : '/project/default' /** * Array of urls/routes that should be ignored diff --git a/apps/studio/components/interfaces/Connect/Connect.tsx b/apps/studio/components/interfaces/Connect/Connect.tsx index 554353bf42e..24c2a88ed11 100644 --- a/apps/studio/components/interfaces/Connect/Connect.tsx +++ b/apps/studio/components/interfaces/Connect/Connect.tsx @@ -32,7 +32,7 @@ import { getContentFilePath } from './Connect.utils' import ConnectDropdown from './ConnectDropdown' import ConnectTabContent from './ConnectTabContent' -const Connect = () => { +export const Connect = () => { const { ref: projectRef } = useParams() const selectedProject = useSelectedProject() const isActiveHealthy = selectedProject?.status === PROJECT_STATUS.ACTIVE_HEALTHY @@ -293,5 +293,3 @@ const Connect = () => { ) } - -export default Connect diff --git a/apps/studio/components/interfaces/Home/ProjectList/ProjectList.tsx b/apps/studio/components/interfaces/Home/ProjectList/ProjectList.tsx index e29c408c00f..33712924f9a 100644 --- a/apps/studio/components/interfaces/Home/ProjectList/ProjectList.tsx +++ b/apps/studio/components/interfaces/Home/ProjectList/ProjectList.tsx @@ -1,22 +1,16 @@ -import { groupBy } from 'lodash' 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 PartnerIcon from 'components/ui/PartnerIcon' import { useGitHubConnectionsQuery } from 'data/integrations/github-connections-query' import { useOrgIntegrationsQuery } from 'data/integrations/integrations-query-org-only' -import { - OverdueInvoicesResponse, - useOverdueInvoicesQuery, -} from 'data/invoices/invoices-overdue-query' -import { useOrganizationsQuery } from 'data/organizations/organizations-query' import { usePermissionsQuery } from 'data/permissions/permissions-query' import { ProjectInfo, useProjectsQuery } from 'data/projects/projects-query' import { ResourceWarning, useResourceWarningsQuery } from 'data/usage/resource-warnings-query' import { useIsFeatureEnabled } from 'hooks/misc/useIsFeatureEnabled' +import { useSelectedOrganization } from 'hooks/misc/useSelectedOrganization' import { IS_PLATFORM } from 'lib/constants' import { makeRandomString } from 'lib/helpers' import type { Organization, ResponseError } from 'types' @@ -29,8 +23,6 @@ export interface ProjectListProps { search?: string filterStatus?: string[] resetFilterStatus?: () => void - // if true, only show projects for the current organization - filterToSlug?: boolean } const ProjectList = ({ @@ -38,12 +30,12 @@ const ProjectList = ({ rewriteHref, filterStatus, resetFilterStatus, - filterToSlug, }: ProjectListProps) => { const { slug } = useParams() - const { data: organizations, isLoading, isSuccess } = useOrganizationsQuery() + const organization = useSelectedOrganization() + const { - data: allProjects, + data: allProjects = [], isLoading: isLoadingProjects, isSuccess: isSuccessProjects, isError: isErrorProjects, @@ -55,15 +47,15 @@ const ProjectList = ({ error: permissionsError, } = usePermissionsQuery() const { data: resourceWarnings } = useResourceWarningsQuery() - const { data: allOverdueInvoices } = useOverdueInvoicesQuery() - const projectsByOrg = groupBy(allProjects, 'organization_id') + + const orgProjects = allProjects.filter((x) => x.organization_slug === slug) const isLoadingPermissions = IS_PLATFORM ? _isLoadingPermissions : false const hasFilterStatusApplied = filterStatus !== undefined && filterStatus.length !== 2 const noResultsFromSearch = search.length > 0 && isSuccessProjects && - allProjects.filter((project) => { + orgProjects.filter((project) => { return ( project.name.toLowerCase().includes(search.toLowerCase()) || project.ref.includes(search.toLowerCase()) @@ -72,9 +64,9 @@ const ProjectList = ({ const noResultsFromStatusFilter = hasFilterStatusApplied && isSuccessProjects && - allProjects.filter((project) => filterStatus.includes(project.status)).length === 0 + orgProjects.filter((project) => filterStatus.includes(project.status)).length === 0 - if (isLoading) { + if (isLoadingProjects || !organization) { return (