From f596989ed4746524b4699f6a09c4185fe0b7e217 Mon Sep 17 00:00:00 2001 From: Danny White <3104761+dnywh@users.noreply.github.com> Date: Wed, 1 Oct 2025 12:16:20 +1000 Subject: [PATCH 1/5] chore: feature flag for new Storage UI (#39093) * feat: bucket type page and corresponding sidebar * feat: handle /storage URL redirection based on feature flag * fix: default sidebar selection * Use feature flag for feature preview, and have new UI behind feature preview instead * Remove hardcode * Minor clean ups * chore: improve feature preview description * chore: more descriptive name for general file storage type * fix: preview image * Minor nits --------- Co-authored-by: Joshen Lim --- .../FeaturePreview.constants.tsx | 9 +++- .../FeaturePreview/FeaturePreviewContext.tsx | 8 ++++ .../FeaturePreview/FeaturePreviewModal.tsx | 2 + .../FeaturePreview/NewStorageUIPreview.tsx | 42 ++++++++++++++++++ .../App/FeaturePreview/UnifiedLogsPreview.tsx | 6 +-- apps/studio/components/interfaces/Sidebar.tsx | 10 +++-- .../interfaces/Storage/Storage.constants.ts | 26 +++++++++++ .../interfaces/Storage/StorageMenu.tsx | 6 +-- .../interfaces/Storage/StorageMenuV2.tsx | 30 +++++++++++++ .../NavigationBar/NavigationBar.utils.tsx | 16 ++++++- .../layouts/StorageLayout/BucketLayout.tsx | 30 +++++++++++++ .../layouts/StorageLayout/StorageLayout.tsx | 10 +++-- apps/studio/hooks/ui/useFlag.ts | 3 +- .../[ref]/storage/[bucketType]/index.tsx | 40 +++++++++++++++++ .../project/[ref]/storage/buckets/index.tsx | 17 +++++-- .../pages/project/[ref]/storage/index.tsx | 22 ++++++++- .../img/previews/new-storage-preview.png | Bin 0 -> 62298 bytes packages/common/constants/local-storage.ts | 1 + 18 files changed, 253 insertions(+), 25 deletions(-) create mode 100644 apps/studio/components/interfaces/App/FeaturePreview/NewStorageUIPreview.tsx create mode 100644 apps/studio/components/interfaces/Storage/StorageMenuV2.tsx create mode 100644 apps/studio/components/layouts/StorageLayout/BucketLayout.tsx create mode 100644 apps/studio/pages/project/[ref]/storage/[bucketType]/index.tsx create mode 100644 apps/studio/public/img/previews/new-storage-preview.png diff --git a/apps/studio/components/interfaces/App/FeaturePreview/FeaturePreview.constants.tsx b/apps/studio/components/interfaces/App/FeaturePreview/FeaturePreview.constants.tsx index f7448acba9807..9a56fd87b21e4 100644 --- a/apps/studio/components/interfaces/App/FeaturePreview/FeaturePreview.constants.tsx +++ b/apps/studio/components/interfaces/App/FeaturePreview/FeaturePreview.constants.tsx @@ -1,9 +1,16 @@ import { LOCAL_STORAGE_KEYS } from 'common' export const FEATURE_PREVIEWS = [ + { + key: LOCAL_STORAGE_KEYS.UI_PREVIEW_NEW_STORAGE_UI, + name: 'New Storage interface', + discussionsUrl: undefined, + isNew: true, + isPlatformOnly: false, + }, { key: LOCAL_STORAGE_KEYS.UI_PREVIEW_UNIFIED_LOGS, - name: 'New Logs Interface', + name: 'New Logs interface', discussionsUrl: 'https://github.com/orgs/supabase/discussions/37234', isNew: true, isPlatformOnly: true, diff --git a/apps/studio/components/interfaces/App/FeaturePreview/FeaturePreviewContext.tsx b/apps/studio/components/interfaces/App/FeaturePreview/FeaturePreviewContext.tsx index e33348dd18dc4..885724aca13c0 100644 --- a/apps/studio/components/interfaces/App/FeaturePreview/FeaturePreviewContext.tsx +++ b/apps/studio/components/interfaces/App/FeaturePreview/FeaturePreviewContext.tsx @@ -110,12 +110,18 @@ export const useIsAdvisorRulesEnabled = () => { return flags[LOCAL_STORAGE_KEYS.UI_PREVIEW_ADVISOR_RULES] } +export const useIsNewStorageUIEnabled = () => { + const { flags } = useFeaturePreviewContext() + return flags[LOCAL_STORAGE_KEYS.UI_PREVIEW_NEW_STORAGE_UI] +} + export const useFeaturePreviewModal = () => { const [featurePreviewModal, setFeaturePreviewModal] = useQueryState('featurePreviewModal') const gitlessBranchingEnabled = useFlag('gitlessBranching') const advisorRulesEnabled = useFlag('advisorRules') const isUnifiedLogsPreviewAvailable = useFlag('unifiedLogs') + const isNewStorageUIAvailable = useFlag('storageAnalyticsVector') const selectedFeatureKeyFromQuery = featurePreviewModal?.trim() ?? null const showFeaturePreviewModal = selectedFeatureKeyFromQuery !== null @@ -130,6 +136,8 @@ export const useFeaturePreviewModal = () => { return advisorRulesEnabled case 'supabase-ui-preview-unified-logs': return isUnifiedLogsPreviewAvailable + case 'new-storage-ui': + return isNewStorageUIAvailable default: return true } diff --git a/apps/studio/components/interfaces/App/FeaturePreview/FeaturePreviewModal.tsx b/apps/studio/components/interfaces/App/FeaturePreview/FeaturePreviewModal.tsx index 751c08f92c961..ec463be8a6477 100644 --- a/apps/studio/components/interfaces/App/FeaturePreview/FeaturePreviewModal.tsx +++ b/apps/studio/components/interfaces/App/FeaturePreview/FeaturePreviewModal.tsx @@ -14,6 +14,7 @@ import { CLSPreview } from './CLSPreview' import { FEATURE_PREVIEWS } from './FeaturePreview.constants' import { useFeaturePreviewContext, useFeaturePreviewModal } from './FeaturePreviewContext' import { InlineEditorPreview } from './InlineEditorPreview' +import { NewStorageUIPreview } from './NewStorageUIPreview' import { UnifiedLogsPreview } from './UnifiedLogsPreview' const FEATURE_PREVIEW_KEY_TO_CONTENT: { @@ -25,6 +26,7 @@ const FEATURE_PREVIEW_KEY_TO_CONTENT: { [LOCAL_STORAGE_KEYS.UI_PREVIEW_API_SIDE_PANEL]: , [LOCAL_STORAGE_KEYS.UI_PREVIEW_CLS]: , [LOCAL_STORAGE_KEYS.UI_PREVIEW_UNIFIED_LOGS]: , + [LOCAL_STORAGE_KEYS.UI_PREVIEW_NEW_STORAGE_UI]: , } const FeaturePreviewModal = () => { diff --git a/apps/studio/components/interfaces/App/FeaturePreview/NewStorageUIPreview.tsx b/apps/studio/components/interfaces/App/FeaturePreview/NewStorageUIPreview.tsx new file mode 100644 index 0000000000000..6225b04d5237c --- /dev/null +++ b/apps/studio/components/interfaces/App/FeaturePreview/NewStorageUIPreview.tsx @@ -0,0 +1,42 @@ +import Image from 'next/image' + +import { useParams } from 'common' +import { InlineLink } from 'components/ui/InlineLink' +import { BASE_PATH } from 'lib/constants' +import { useIsNewStorageUIEnabled } from './FeaturePreviewContext' + +export const NewStorageUIPreview = () => { + const { ref } = useParams() + const isStorageV2 = useIsNewStorageUIEnabled() + + return ( +
+

+ Experience our enhanced{' '} + + Storage interface + {' '} + with support for analytics and vector bucket types. +

+ new-storage-preview +
+

Enabling this preview will:

+
    +
  • Move Storage buckets from the sidebar into the main content area
  • +
  • Change the role of the sidebar to a bucket type selector
  • +
  • Nest settings and policies under their respective bucket types
  • +
+

+ These changes are necessary to support incoming analytics and vector bucket types. File + storage will remain the default, and be shown by default when entering Storage. +

+
+
+ ) +} diff --git a/apps/studio/components/interfaces/App/FeaturePreview/UnifiedLogsPreview.tsx b/apps/studio/components/interfaces/App/FeaturePreview/UnifiedLogsPreview.tsx index b757cba8f45a1..0edff67d49fe8 100644 --- a/apps/studio/components/interfaces/App/FeaturePreview/UnifiedLogsPreview.tsx +++ b/apps/studio/components/interfaces/App/FeaturePreview/UnifiedLogsPreview.tsx @@ -16,7 +16,7 @@ export const UnifiedLogsPreview = () => { className="rounded border mb-4" />

- Experience our enhanced logs interface with improved filtering, real-time updates, and a + Experience our enhanced Logs interface with improved filtering, real-time updates, and a unified view across all your services. Built for better performance and easier debugging.

@@ -26,8 +26,8 @@ export const UnifiedLogsPreview = () => {

Enabling this preview will:

  • - Replace the current logs interface on the{' '} - logs page with a unified view + Replace the current Logs interface on the{' '} + Logs page with a unified view
  • Provide enhanced filtering capabilities and real-time log streaming
  • Improve performance with optimized data loading and virtualization
  • diff --git a/apps/studio/components/interfaces/Sidebar.tsx b/apps/studio/components/interfaces/Sidebar.tsx index a4a7b9b4ea50e..63c0ee2600e15 100644 --- a/apps/studio/components/interfaces/Sidebar.tsx +++ b/apps/studio/components/interfaces/Sidebar.tsx @@ -43,6 +43,7 @@ import { } from 'ui' import { useIsAPIDocsSidePanelEnabled, + useIsNewStorageUIEnabled, useUnifiedLogsPreview, } from './App/FeaturePreview/FeaturePreviewContext' @@ -222,10 +223,13 @@ const ProjectLinks = () => { const { ref } = useParams() const { data: project } = useSelectedProjectQuery() const snap = useAppStateSnapshot() - const isNewAPIDocsEnabled = useIsAPIDocsSidePanelEnabled() const { securityLints, errorLints } = useLints() const showReports = useIsFeatureEnabled('reports:all') + const isNewAPIDocsEnabled = useIsAPIDocsSidePanelEnabled() + const isStorageV2 = useIsNewStorageUIEnabled() + const { isEnabled: isUnifiedLogsEnabled } = useUnifiedLogsPreview() + const activeRoute = router.pathname.split('/')[3] const { @@ -246,10 +250,8 @@ const ProjectLinks = () => { edgeFunctions: edgeFunctionsEnabled, storage: storageEnabled, realtime: realtimeEnabled, + isStorageV2, }) - - const { isEnabled: isUnifiedLogsEnabled } = useUnifiedLogsPreview() - const otherRoutes = generateOtherRoutes(ref, project, { unifiedLogs: isUnifiedLogsEnabled, showReports, diff --git a/apps/studio/components/interfaces/Storage/Storage.constants.ts b/apps/studio/components/interfaces/Storage/Storage.constants.ts index 674153a2cc0d0..9dc6cae7b37b2 100644 --- a/apps/studio/components/interfaces/Storage/Storage.constants.ts +++ b/apps/studio/components/interfaces/Storage/Storage.constants.ts @@ -1,3 +1,6 @@ +import { DOCS_URL } from 'lib/constants' + +// Original storage constants export enum URL_EXPIRY_DURATION { WEEK = 60 * 60 * 24 * 7, MONTH = 60 * 60 * 24 * 30, @@ -56,3 +59,26 @@ export const CONTEXT_MENU_KEYS = { STORAGE_ITEM: 'STORAGE_ITEM', STORAGE_FOLDER: 'STORAGE_FOLDER', } + +// New bucket types configuration + +export const BUCKET_TYPES = { + files: { + displayName: 'Files', + description: 'General file storage for most types of digital content.', + docsUrl: `${DOCS_URL}/guides/storage/buckets/fundamentals`, + }, + analytics: { + displayName: 'Analytics', + description: 'Purpose-built storage for analytical workloads.', + docsUrl: `${DOCS_URL}/guides/storage/analytics/introduction`, + }, + vectors: { + displayName: 'Vectors', + description: 'Purpose-built storage for vector data.', + docsUrl: `${DOCS_URL}/guides/storage/vectors`, + }, +} + +export const BUCKET_TYPE_KEYS = Object.keys(BUCKET_TYPES) as Array +export const DEFAULT_BUCKET_TYPE: keyof typeof BUCKET_TYPES = 'files' diff --git a/apps/studio/components/interfaces/Storage/StorageMenu.tsx b/apps/studio/components/interfaces/Storage/StorageMenu.tsx index 86f85653f4dc9..40dca82bbfe2f 100644 --- a/apps/studio/components/interfaces/Storage/StorageMenu.tsx +++ b/apps/studio/components/interfaces/Storage/StorageMenu.tsx @@ -7,6 +7,7 @@ import { CreateBucketModal } from 'components/interfaces/Storage/CreateBucketMod import ShimmeringLoader from 'components/ui/ShimmeringLoader' import { useBucketsQuery } from 'data/storage/buckets-query' import { useSelectedProjectQuery } from 'hooks/misc/useSelectedProject' +import { IS_PLATFORM } from 'lib/constants' import { useStorageExplorerStateSnapshot } from 'state/storage-explorer' import { Alert_Shadcn_, AlertDescription_Shadcn_, AlertTitle_Shadcn_, Menu } from 'ui' import { @@ -16,10 +17,9 @@ import { InnerSideBarFilterSortDropdown, InnerSideBarFilterSortDropdownItem, } from 'ui-patterns/InnerSideMenu' -import { IS_PLATFORM } from 'lib/constants' import { BucketRow } from './BucketRow' -const StorageMenu = () => { +export const StorageMenu = () => { const router = useRouter() const { ref, bucketId } = useParams() const { data: projectDetails } = useSelectedProjectQuery() @@ -169,5 +169,3 @@ const StorageMenu = () => { ) } - -export default StorageMenu diff --git a/apps/studio/components/interfaces/Storage/StorageMenuV2.tsx b/apps/studio/components/interfaces/Storage/StorageMenuV2.tsx new file mode 100644 index 0000000000000..e5b8e8592efb3 --- /dev/null +++ b/apps/studio/components/interfaces/Storage/StorageMenuV2.tsx @@ -0,0 +1,30 @@ +import { useParams } from 'common' +import Link from 'next/link' +import { Menu } from 'ui' +import { BUCKET_TYPES, BUCKET_TYPE_KEYS, DEFAULT_BUCKET_TYPE } from './Storage.constants' + +export const StorageMenuV2 = () => { + const { ref, bucketType } = useParams() + const selectedBucketType = bucketType || DEFAULT_BUCKET_TYPE + + return ( + +
    + Bucket Types} /> + + {BUCKET_TYPE_KEYS.map((bucketTypeKey) => { + const isSelected = selectedBucketType === bucketTypeKey + const config = BUCKET_TYPES[bucketTypeKey] + + return ( + + +

    {config.displayName}

    +
    + + ) + })} +
    +
    + ) +} diff --git a/apps/studio/components/layouts/ProjectLayout/NavigationBar/NavigationBar.utils.tsx b/apps/studio/components/layouts/ProjectLayout/NavigationBar/NavigationBar.utils.tsx index c08feee6cd642..2f0b698771ca5 100644 --- a/apps/studio/components/layouts/ProjectLayout/NavigationBar/NavigationBar.utils.tsx +++ b/apps/studio/components/layouts/ProjectLayout/NavigationBar/NavigationBar.utils.tsx @@ -41,10 +41,17 @@ export const generateToolRoutes = (ref?: string, project?: Project, features?: { }, ] } + export const generateProductRoutes = ( ref?: string, project?: Project, - features?: { auth?: boolean; edgeFunctions?: boolean; storage?: boolean; realtime?: boolean } + features?: { + auth?: boolean + edgeFunctions?: boolean + storage?: boolean + realtime?: boolean + isStorageV2?: boolean + } ): Route[] => { const isProjectActive = project?.status === PROJECT_STATUS.ACTIVE_HEALTHY const isProjectBuilding = project?.status === PROJECT_STATUS.COMING_UP @@ -54,6 +61,7 @@ export const generateProductRoutes = ( const edgeFunctionsEnabled = features?.edgeFunctions ?? true const storageEnabled = features?.storage ?? true const realtimeEnabled = features?.realtime ?? true + const isStorageV2 = features?.isStorageV2 ?? false const databaseMenu = generateDatabaseMenu(project) const authMenu = generateAuthMenu(ref as string) @@ -89,7 +97,11 @@ export const generateProductRoutes = ( key: 'storage', label: 'Storage', icon: , - link: ref && (isProjectBuilding ? buildingUrl : `/project/${ref}/storage/buckets`), + link: + ref && + (isProjectBuilding + ? buildingUrl + : `/project/${ref}/storage/${isStorageV2 ? 'files' : 'buckets'}`), }, ] : []), diff --git a/apps/studio/components/layouts/StorageLayout/BucketLayout.tsx b/apps/studio/components/layouts/StorageLayout/BucketLayout.tsx new file mode 100644 index 0000000000000..53d2a252e6f2c --- /dev/null +++ b/apps/studio/components/layouts/StorageLayout/BucketLayout.tsx @@ -0,0 +1,30 @@ +import { PropsWithChildren } from 'react' + +import { useParams } from 'common' +import { BUCKET_TYPES, DEFAULT_BUCKET_TYPE } from 'components/interfaces/Storage/Storage.constants' +import { DocsButton } from 'components/ui/DocsButton' +import DefaultLayout from '../DefaultLayout' +import { PageLayout } from '../PageLayout/PageLayout' +import { ScaffoldContainer } from '../Scaffold' +import StorageLayout from './StorageLayout' + +export const BucketTypeLayout = ({ children }: PropsWithChildren) => { + const { bucketType } = useParams() + const bucketTypeKey = bucketType || DEFAULT_BUCKET_TYPE + const config = BUCKET_TYPES[bucketTypeKey as keyof typeof BUCKET_TYPES] + const secondaryActions = [] + + return ( + + + + {children} + + + + ) +} diff --git a/apps/studio/components/layouts/StorageLayout/StorageLayout.tsx b/apps/studio/components/layouts/StorageLayout/StorageLayout.tsx index 79c1898809f2e..101a5c519c9af 100644 --- a/apps/studio/components/layouts/StorageLayout/StorageLayout.tsx +++ b/apps/studio/components/layouts/StorageLayout/StorageLayout.tsx @@ -1,6 +1,8 @@ import { ReactNode } from 'react' -import StorageMenu from 'components/interfaces/Storage/StorageMenu' +import { useIsNewStorageUIEnabled } from 'components/interfaces/App/FeaturePreview/FeaturePreviewContext' +import { StorageMenu } from 'components/interfaces/Storage/StorageMenu' +import { StorageMenuV2 } from 'components/interfaces/Storage/StorageMenuV2' import { withAuth } from 'hooks/misc/withAuth' import ProjectLayout from '../ProjectLayout/ProjectLayout' @@ -10,12 +12,14 @@ export interface StorageLayoutProps { } const StorageLayout = ({ title, children }: StorageLayoutProps) => { + const isStorageV2 = useIsNewStorageUIEnabled() + return ( } + productMenu={isStorageV2 ? : } > {children} diff --git a/apps/studio/hooks/ui/useFlag.ts b/apps/studio/hooks/ui/useFlag.ts index 979334882d3c0..3ad15f0cc5ede 100644 --- a/apps/studio/hooks/ui/useFlag.ts +++ b/apps/studio/hooks/ui/useFlag.ts @@ -1,8 +1,7 @@ import * as Sentry from '@sentry/nextjs' -import { useFeatureFlags, useFlag } from 'common' +import { useFeatureFlags } from 'common' import { useLocalStorageQuery } from 'hooks/misc/useLocalStorage' -import { useSelectedProjectQuery } from 'hooks/misc/useSelectedProject' import { trackFeatureFlag } from 'lib/posthog' const isObjectEmpty = (obj: Object) => { diff --git a/apps/studio/pages/project/[ref]/storage/[bucketType]/index.tsx b/apps/studio/pages/project/[ref]/storage/[bucketType]/index.tsx new file mode 100644 index 0000000000000..c762752bc478d --- /dev/null +++ b/apps/studio/pages/project/[ref]/storage/[bucketType]/index.tsx @@ -0,0 +1,40 @@ +import { useRouter } from 'next/router' +import { useEffect } from 'react' + +import { useParams } from 'common' +import { useIsNewStorageUIEnabled } from 'components/interfaces/App/FeaturePreview/FeaturePreviewContext' +import { BUCKET_TYPES, DEFAULT_BUCKET_TYPE } from 'components/interfaces/Storage/Storage.constants' +import { BucketTypeLayout } from 'components/layouts/StorageLayout/BucketLayout' +import type { NextPageWithLayout } from 'types' + +const BucketTypePage: NextPageWithLayout = () => { + const router = useRouter() + const { bucketType, ref } = useParams() + const isStorageV2 = useIsNewStorageUIEnabled() + + const bucketTypeKey = bucketType || DEFAULT_BUCKET_TYPE + const config = BUCKET_TYPES[bucketTypeKey as keyof typeof BUCKET_TYPES] + + useEffect(() => { + if (!isStorageV2) router.replace(`/project/${ref}/storage`) + }, [isStorageV2, ref]) + + useEffect(() => { + if (!config) { + router.replace(`/project/${ref}/storage`) + } + }, [config, ref, router]) + + return ( +
    + {/* [Danny] Purposefully duplicated directly below StorageLayout's config.description for now. Will be placed in a conditional empty state in next PR. TODO: consider reusing FormHeader for non-empty state.*/} + {/*

    {config.description}

    */} +
    + ) +} + +BucketTypePage.getLayout = (page) => { + return {page} +} + +export default BucketTypePage diff --git a/apps/studio/pages/project/[ref]/storage/buckets/index.tsx b/apps/studio/pages/project/[ref]/storage/buckets/index.tsx index 4ca7587160f3e..6cefe0c843d33 100644 --- a/apps/studio/pages/project/[ref]/storage/buckets/index.tsx +++ b/apps/studio/pages/project/[ref]/storage/buckets/index.tsx @@ -1,5 +1,9 @@ import { useParams } from 'common' +import { useRouter } from 'next/router' +import { useEffect } from 'react' +import { useIsNewStorageUIEnabled } from 'components/interfaces/App/FeaturePreview/FeaturePreviewContext' +import { DEFAULT_BUCKET_TYPE } from 'components/interfaces/Storage/Storage.constants' import StorageBucketsError from 'components/interfaces/Storage/StorageBucketsError' import DefaultLayout from 'components/layouts/DefaultLayout' import StorageLayout from 'components/layouts/StorageLayout/StorageLayout' @@ -9,17 +13,22 @@ import { useSelectedProjectQuery } from 'hooks/misc/useSelectedProject' import { DOCS_URL } from 'lib/constants' import type { NextPageWithLayout } from 'types' -/** - * PageLayout is used to setup layout - as usual it will requires inject global store - */ const PageLayout: NextPageWithLayout = () => { const { ref } = useParams() + const router = useRouter() + const isStorageV2 = useIsNewStorageUIEnabled() const { data: project } = useSelectedProjectQuery() const { error, isError } = useBucketsQuery({ projectRef: ref }) + useEffect(() => { + if (isStorageV2) { + router.replace(`/project/${ref}/storage/${DEFAULT_BUCKET_TYPE}`) + } + }, [isStorageV2, ref, router]) + if (!project) return null - if (isError) + if (isError) return return (
    diff --git a/apps/studio/pages/project/[ref]/storage/index.tsx b/apps/studio/pages/project/[ref]/storage/index.tsx index 153afc04db514..0b9672eb09d41 100644 --- a/apps/studio/pages/project/[ref]/storage/index.tsx +++ b/apps/studio/pages/project/[ref]/storage/index.tsx @@ -1,9 +1,27 @@ -import StorageLayout from 'components/layouts/StorageLayout/StorageLayout' +import { useRouter } from 'next/router' +import { useEffect } from 'react' + +import { useParams } from 'common' +import { useIsNewStorageUIEnabled } from 'components/interfaces/App/FeaturePreview/FeaturePreviewContext' +import { DEFAULT_BUCKET_TYPE } from 'components/interfaces/Storage/Storage.constants' import DefaultLayout from 'components/layouts/DefaultLayout' +import StorageLayout from 'components/layouts/StorageLayout/StorageLayout' import type { NextPageWithLayout } from 'types' const Storage: NextPageWithLayout = () => { - return <>{/*

    Use this as a template for storage pages

    */} + const { ref } = useParams() + const router = useRouter() + const isStorageV2 = useIsNewStorageUIEnabled() + + useEffect(() => { + if (isStorageV2) { + router.replace(`/project/${ref}/storage/${DEFAULT_BUCKET_TYPE}`) + } else { + router.replace(`/project/${ref}/storage/buckets`) + } + }, [isStorageV2, ref, router]) + + return null } Storage.getLayout = (page) => ( diff --git a/apps/studio/public/img/previews/new-storage-preview.png b/apps/studio/public/img/previews/new-storage-preview.png new file mode 100644 index 0000000000000000000000000000000000000000..18e6b9344d6470697aa7fd0a1421ced4a63ca7d4 GIT binary patch literal 62298 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
    OLdvkYm}TDey>5V$@o9n}&q`b6#ElfX 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 Date: Wed, 1 Oct 2025 10:26:06 +0800 Subject: [PATCH 2/5] chore: disable billing support form options (#39137) * chore: disable billing support form options * add sales enquiry --- .../interfaces/Support/SupportFormV2.tsx | 23 ++++++++++++++++--- 1 file changed, 20 insertions(+), 3 deletions(-) diff --git a/apps/studio/components/interfaces/Support/SupportFormV2.tsx b/apps/studio/components/interfaces/Support/SupportFormV2.tsx index 23f571d3a55b7..891d344b5f3ed 100644 --- a/apps/studio/components/interfaces/Support/SupportFormV2.tsx +++ b/apps/studio/components/interfaces/Support/SupportFormV2.tsx @@ -20,6 +20,7 @@ import { SubmitHandler, useForm } from 'react-hook-form' import { toast } from 'sonner' import * as z from 'zod' +import { SupportCategories } from '@supabase/shared-types/out/constants' import { useDocsSearch, useParams, type DocsSearchResult as Page } from 'common' import { CLIENT_LIBRARIES } from 'common/constants' import CopyButton from 'components/ui/CopyButton' @@ -29,6 +30,7 @@ import { useSendSupportTicketMutation } from 'data/feedback/support-ticket-send' import { useOrganizationsQuery } from 'data/organizations/organizations-query' import { getProjectDetail } from 'data/projects/project-detail-query' import { useSendEventMutation } from 'data/telemetry/send-event-mutation' +import { useIsFeatureEnabled } from 'hooks/misc/useIsFeatureEnabled' import { DOCS_URL } from 'lib/constants' import { detectBrowser } from 'lib/helpers' import { useProfile } from 'lib/profile' @@ -139,6 +141,21 @@ export const SupportFormV2 = ({ const router = useRouter() const dashboardSentryIssueId = router.query.sid as string + const isBillingEnabled = useIsFeatureEnabled('billing:all') + + const categoryOptions = useMemo(() => { + return CATEGORY_OPTIONS.filter((option) => { + if ( + option.value === SupportCategories.BILLING || + option.value === SupportCategories.REFUND || + option.value === SupportCategories.SALES_ENQUIRY + ) { + return isBillingEnabled + } + return true + }) + }, [isBillingEnabled]) + const uploadButtonRef = useRef(null) const [isSubmitting, setIsSubmitting] = useState(false) const [docsResults, setDocsResults] = useState([]) @@ -317,7 +334,7 @@ export const SupportFormV2 = ({ useEffect(() => { if (urlCategory) { - const validCategory = CATEGORY_OPTIONS.find((option) => { + const validCategory = categoryOptions.find((option) => { if (option.value.toLowerCase() === ((urlCategory as string) ?? '').toLowerCase()) return option }) @@ -533,13 +550,13 @@ export const SupportFormV2 = ({ {field.value - ? CATEGORY_OPTIONS.find((o) => o.value === field.value)?.label + ? categoryOptions.find((o) => o.value === field.value)?.label : null} - {CATEGORY_OPTIONS.map((option) => ( + {categoryOptions.map((option) => ( {option.label} From 4dcf78342e1c69492fc58b90967ac87cf21ca61f Mon Sep 17 00:00:00 2001 From: Alaister Young Date: Wed, 1 Oct 2025 10:30:08 +0800 Subject: [PATCH 3/5] fix(enabled-features): auth providers settings link (#39138) --- .../layouts/ProjectSettingsLayout/SettingsLayout.tsx | 3 +++ .../layouts/ProjectSettingsLayout/SettingsMenu.utils.tsx | 6 +++++- 2 files changed, 8 insertions(+), 1 deletion(-) diff --git a/apps/studio/components/layouts/ProjectSettingsLayout/SettingsLayout.tsx b/apps/studio/components/layouts/ProjectSettingsLayout/SettingsLayout.tsx index 7ab7becd7566d..52123de65e16c 100644 --- a/apps/studio/components/layouts/ProjectSettingsLayout/SettingsLayout.tsx +++ b/apps/studio/components/layouts/ProjectSettingsLayout/SettingsLayout.tsx @@ -35,6 +35,7 @@ const SettingsLayout = ({ title, children }: PropsWithChildren, }, From 6136b52cb306afc1b9c006a37e5f9a783a0f0b3f Mon Sep 17 00:00:00 2001 From: Alaister Young Date: Wed, 1 Oct 2025 10:33:01 +0800 Subject: [PATCH 4/5] fix: edge function url in list (#39139) --- .../Functions/EdgeFunctionsListItem.tsx | 22 ++++++++----------- 1 file changed, 9 insertions(+), 13 deletions(-) diff --git a/apps/studio/components/interfaces/Functions/EdgeFunctionsListItem.tsx b/apps/studio/components/interfaces/Functions/EdgeFunctionsListItem.tsx index 186616f953ee6..b7a152514bebb 100644 --- a/apps/studio/components/interfaces/Functions/EdgeFunctionsListItem.tsx +++ b/apps/studio/components/interfaces/Functions/EdgeFunctionsListItem.tsx @@ -4,10 +4,9 @@ import { useRouter } from 'next/router' import { useState } from 'react' import { useParams } from 'common/hooks' -import Table from 'components/to-be-cleaned/Table' +import { useProjectSettingsV2Query } from 'data/config/project-settings-v2-query' import { useCustomDomainsQuery } from 'data/custom-domains/custom-domains-query' import type { EdgeFunctionsResponse } from 'data/edge-functions/edge-functions-query' -import { useSelectedProjectQuery } from 'hooks/misc/useSelectedProject' import { copyToClipboard, TableCell, TableRow, Tooltip, TooltipContent, TooltipTrigger } from 'ui' interface EdgeFunctionsListItemProps { @@ -17,20 +16,17 @@ interface EdgeFunctionsListItemProps { export const EdgeFunctionsListItem = ({ function: item }: EdgeFunctionsListItemProps) => { const router = useRouter() const { ref } = useParams() - const { data: project } = useSelectedProjectQuery() const [isCopied, setIsCopied] = useState(false) + const { data: settings } = useProjectSettingsV2Query({ projectRef: ref }) const { data: customDomainData } = useCustomDomainsQuery({ projectRef: ref }) - // get the .co or .net TLD from the restUrl - const restUrl = project?.restUrl - const restUrlTld = restUrl !== undefined ? new URL(restUrl).hostname.split('.').pop() : 'co' - const functionUrl = `https://${ref}.supabase.${restUrlTld}/functions/v1/${item.slug}` - - const endpoint = + const protocol = settings?.app_config?.protocol ?? 'https' + const endpoint = settings?.app_config?.endpoint ?? '' + const functionUrl = customDomainData?.customDomain?.status === 'active' ? `https://${customDomainData.customDomain.hostname}/functions/v1/${item.slug}` - : functionUrl + : `${protocol}://${endpoint}/functions/v1/${item.slug}` return (
    -

    - {endpoint} +

    + {functionUrl}