From a8a5e6851257a1c2bc6e565dd3554e2ff4b9f314 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Filipe=20Caba=C3=A7o?= Date: Mon, 22 Sep 2025 11:56:38 +0100 Subject: [PATCH 1/9] realtime: remove feature preview flag (#38864) * realtime: remove feature preview flag * Fix TS * Smol fix * NIt * add back proper link in docs * Neeeet --------- Co-authored-by: Joshen Lim --- .../content/guides/realtime/authorization.mdx | 3 +- .../docs/content/guides/realtime/settings.mdx | 6 --- .../FeaturePreview/AdvisorRulesPreview.tsx | 10 ++-- .../FeaturePreview.constants.tsx | 7 --- .../FeaturePreview/FeaturePreviewContext.tsx | 16 +----- .../FeaturePreview/FeaturePreviewModal.tsx | 2 - .../RealtimeSettingsPreview.tsx | 49 ------------------- .../ConfirmRestoreDialog.tsx | 1 - .../interfaces/Realtime/RealtimeSettings.tsx | 21 +++++--- .../layouts/RealtimeLayout/RealtimeLayout.tsx | 13 +---- .../RealtimeLayout/RealtimeMenu.utils.ts | 8 +-- apps/studio/hooks/ui/useFlag.ts | 20 -------- packages/common/constants/local-storage.ts | 2 - 13 files changed, 23 insertions(+), 135 deletions(-) delete mode 100644 apps/studio/components/interfaces/App/FeaturePreview/RealtimeSettingsPreview.tsx diff --git a/apps/docs/content/guides/realtime/authorization.mdx b/apps/docs/content/guides/realtime/authorization.mdx index df978682739c6..4bdb5850eabc2 100644 --- a/apps/docs/content/guides/realtime/authorization.mdx +++ b/apps/docs/content/guides/realtime/authorization.mdx @@ -20,10 +20,9 @@ Realtime Authorization is in Public Beta. To use Authorization for your Realtime -To enforce private channels you need to disable the 'Allow public access' setting in [Realtime Settings](/dashboard/project/_?featurePreviewModal=supabase-ui-realtime-settings) +To enforce private channels you need to disable the 'Allow public access' setting in [Realtime Settings](/dashboard/project/_/realtime/settings) - ## How it works Realtime uses the `messages` table in your database's `realtime` schema to generate access policies for your clients when they connect to a Channel topic. diff --git a/apps/docs/content/guides/realtime/settings.mdx b/apps/docs/content/guides/realtime/settings.mdx index da1b323aaafaf..9675d92b5bb21 100644 --- a/apps/docs/content/guides/realtime/settings.mdx +++ b/apps/docs/content/guides/realtime/settings.mdx @@ -6,12 +6,6 @@ subtitle: 'Realtime Settings that allow you to configure your Realtime usage.' ## Settings - - -Realtime settings are currently under Feature Preview section in the dashboard. - - - All changes made in this screen will disconnect all your connected clients to ensure Realtime starts with the appropriate settings and all changes are stored in Supabase middleware. diff --git a/apps/studio/components/interfaces/App/FeaturePreview/AdvisorRulesPreview.tsx b/apps/studio/components/interfaces/App/FeaturePreview/AdvisorRulesPreview.tsx index 42dc1d41ad5a4..254b84f5be021 100644 --- a/apps/studio/components/interfaces/App/FeaturePreview/AdvisorRulesPreview.tsx +++ b/apps/studio/components/interfaces/App/FeaturePreview/AdvisorRulesPreview.tsx @@ -3,11 +3,11 @@ import Image from 'next/image' import { useParams } from 'common' import { InlineLink } from 'components/ui/InlineLink' import { BASE_PATH } from 'lib/constants' -import { useIsRealtimeSettingsEnabled } from './FeaturePreviewContext' +import { useIsAdvisorRulesEnabled } from './FeaturePreviewContext' export const AdvisorRulesPreview = () => { const { ref } = useParams() - const isRealtimeSettingsEnabled = useIsRealtimeSettingsEnabled() + const isAdvisorRulesEnabled = useIsAdvisorRulesEnabled() return (
@@ -30,9 +30,9 @@ export const AdvisorRulesPreview = () => { Allow you to disable advisor rules for your project from the{' '} Advisors section. diff --git a/apps/studio/components/interfaces/App/FeaturePreview/FeaturePreview.constants.tsx b/apps/studio/components/interfaces/App/FeaturePreview/FeaturePreview.constants.tsx index 067fa678f46ad..f7448acba9807 100644 --- a/apps/studio/components/interfaces/App/FeaturePreview/FeaturePreview.constants.tsx +++ b/apps/studio/components/interfaces/App/FeaturePreview/FeaturePreview.constants.tsx @@ -15,13 +15,6 @@ export const FEATURE_PREVIEWS = [ isNew: true, isPlatformOnly: true, }, - { - key: LOCAL_STORAGE_KEYS.UI_PREVIEW_REALTIME_SETTINGS, - name: 'Realtime settings', - discussionsUrl: undefined, - isNew: true, - isPlatformOnly: true, - }, { key: LOCAL_STORAGE_KEYS.UI_PREVIEW_ADVISOR_RULES, name: 'Disable Advisor rules', diff --git a/apps/studio/components/interfaces/App/FeaturePreview/FeaturePreviewContext.tsx b/apps/studio/components/interfaces/App/FeaturePreview/FeaturePreviewContext.tsx index 76301d74f3356..e33348dd18dc4 100644 --- a/apps/studio/components/interfaces/App/FeaturePreview/FeaturePreviewContext.tsx +++ b/apps/studio/components/interfaces/App/FeaturePreview/FeaturePreviewContext.tsx @@ -11,7 +11,6 @@ import { } from 'react' import { FeatureFlagContext, LOCAL_STORAGE_KEYS, useFlag } from 'common' -import { useIsRealtimeSettingsFFEnabled } from 'hooks/ui/useFlag' import { EMPTY_OBJ } from 'lib/void' import { FEATURE_PREVIEWS } from './FeaturePreview.constants' @@ -101,11 +100,6 @@ export const useUnifiedLogsPreview = () => { return { isEnabled, enable, disable } } -export const useIsRealtimeSettingsEnabled = () => { - const { flags } = useFeaturePreviewContext() - return flags[LOCAL_STORAGE_KEYS.UI_PREVIEW_REALTIME_SETTINGS] -} - export const useIsBranching2Enabled = () => { const { flags } = useFeaturePreviewContext() return flags[LOCAL_STORAGE_KEYS.UI_PREVIEW_BRANCHING_2_0] @@ -119,7 +113,6 @@ export const useIsAdvisorRulesEnabled = () => { export const useFeaturePreviewModal = () => { const [featurePreviewModal, setFeaturePreviewModal] = useQueryState('featurePreviewModal') - const isRealtimeSettingsEnabled = useIsRealtimeSettingsFFEnabled() const gitlessBranchingEnabled = useFlag('gitlessBranching') const advisorRulesEnabled = useFlag('advisorRules') const isUnifiedLogsPreviewAvailable = useFlag('unifiedLogs') @@ -131,8 +124,6 @@ export const useFeaturePreviewModal = () => { const isFeaturePreviewReleasedToPublic = useCallback( (feature: (typeof FEATURE_PREVIEWS)[number]) => { switch (feature.key) { - case 'supabase-ui-realtime-settings': - return isRealtimeSettingsEnabled case 'supabase-ui-branching-2-0': return gitlessBranchingEnabled case 'supabase-ui-advisor-rules': @@ -143,12 +134,7 @@ export const useFeaturePreviewModal = () => { return true } }, - [ - isRealtimeSettingsEnabled, - gitlessBranchingEnabled, - advisorRulesEnabled, - isUnifiedLogsPreviewAvailable, - ] + [gitlessBranchingEnabled, advisorRulesEnabled, isUnifiedLogsPreviewAvailable] ) const selectedFeatureKey = ( diff --git a/apps/studio/components/interfaces/App/FeaturePreview/FeaturePreviewModal.tsx b/apps/studio/components/interfaces/App/FeaturePreview/FeaturePreviewModal.tsx index cdb7a69129e89..751c08f92c961 100644 --- a/apps/studio/components/interfaces/App/FeaturePreview/FeaturePreviewModal.tsx +++ b/apps/studio/components/interfaces/App/FeaturePreview/FeaturePreviewModal.tsx @@ -14,14 +14,12 @@ import { CLSPreview } from './CLSPreview' import { FEATURE_PREVIEWS } from './FeaturePreview.constants' import { useFeaturePreviewContext, useFeaturePreviewModal } from './FeaturePreviewContext' import { InlineEditorPreview } from './InlineEditorPreview' -import { RealtimeSettingsPreview } from './RealtimeSettingsPreview' import { UnifiedLogsPreview } from './UnifiedLogsPreview' const FEATURE_PREVIEW_KEY_TO_CONTENT: { [key: string]: ReactNode } = { [LOCAL_STORAGE_KEYS.UI_PREVIEW_BRANCHING_2_0]: , - [LOCAL_STORAGE_KEYS.UI_PREVIEW_REALTIME_SETTINGS]: , [LOCAL_STORAGE_KEYS.UI_PREVIEW_ADVISOR_RULES]: , [LOCAL_STORAGE_KEYS.UI_PREVIEW_INLINE_EDITOR]: , [LOCAL_STORAGE_KEYS.UI_PREVIEW_API_SIDE_PANEL]: , diff --git a/apps/studio/components/interfaces/App/FeaturePreview/RealtimeSettingsPreview.tsx b/apps/studio/components/interfaces/App/FeaturePreview/RealtimeSettingsPreview.tsx deleted file mode 100644 index 43a9c283f25a0..0000000000000 --- a/apps/studio/components/interfaces/App/FeaturePreview/RealtimeSettingsPreview.tsx +++ /dev/null @@ -1,49 +0,0 @@ -import Image from 'next/image' - -import { useParams } from 'common' -import { InlineLink } from 'components/ui/InlineLink' -import { BASE_PATH } from 'lib/constants' -import { useIsRealtimeSettingsEnabled } from './FeaturePreviewContext' - -export const RealtimeSettingsPreview = () => { - const { ref } = useParams() - const isRealtimeSettingsEnabled = useIsRealtimeSettingsEnabled() - - return ( -
-

- Allows you to setup several configurations for Realtime, including configuration channel - restrictions where you can enable or disable public channels from being able to connect. - Learn more about how Realtime Authorization works{' '} - - in our documentation - - . -

- api-docs-side-panel-preview -
-

Enabling this preview will:

-
    -
  • - Allow you to configure realtime settings for your project from the{' '} - - realtime section. - -
  • -
-
-
- ) -} diff --git a/apps/studio/components/interfaces/Database/Backups/RestoreToNewProject/ConfirmRestoreDialog.tsx b/apps/studio/components/interfaces/Database/Backups/RestoreToNewProject/ConfirmRestoreDialog.tsx index 3df3aa095cb4b..ddeaf156a59f5 100644 --- a/apps/studio/components/interfaces/Database/Backups/RestoreToNewProject/ConfirmRestoreDialog.tsx +++ b/apps/studio/components/interfaces/Database/Backups/RestoreToNewProject/ConfirmRestoreDialog.tsx @@ -61,7 +61,6 @@ export const ConfirmRestoreDialog = ({
  • Storage objects & settings
  • Edge Functions
  • Auth settings & API keys
  • -
  • Realtime settings
  • Database extensions and settings
  • Read replicas
  • diff --git a/apps/studio/components/interfaces/Realtime/RealtimeSettings.tsx b/apps/studio/components/interfaces/Realtime/RealtimeSettings.tsx index c755fb5118572..b7b4b05a9e520 100644 --- a/apps/studio/components/interfaces/Realtime/RealtimeSettings.tsx +++ b/apps/studio/components/interfaces/Realtime/RealtimeSettings.tsx @@ -40,11 +40,12 @@ const formId = 'realtime-configuration-form' export const RealtimeSettings = () => { const { ref: projectRef } = useParams() const { data: project } = useSelectedProjectQuery() - const { data: organization } = useSelectedOrganizationQuery() - const { can: canUpdateConfig } = useAsyncCheckPermissions( - PermissionAction.REALTIME_ADMIN_READ, - '*' - ) + const { data: organization, isSuccess: isSuccessOrganization } = useSelectedOrganizationQuery() + const { + can: canUpdateConfig, + isLoading: isLoadingPermissions, + isSuccess: isPermissionsLoaded, + } = useAsyncCheckPermissions(PermissionAction.REALTIME_ADMIN_READ, '*') const { data: maxConn } = useMaxConnectionsQuery({ projectRef: project?.ref, @@ -134,7 +135,11 @@ export const RealtimeSettings = () => { className="!p-0 !pt-2" header={Channel restrictions} > - + { /> - {!isUsageBillingEnabled && ( + {isSuccessOrganization && !isUsageBillingEnabled && ( { */}
    - {!canUpdateConfig && ( + {isPermissionsLoaded && !canUpdateConfig && (

    You need additional permissions to update realtime settings

    diff --git a/apps/studio/components/layouts/RealtimeLayout/RealtimeLayout.tsx b/apps/studio/components/layouts/RealtimeLayout/RealtimeLayout.tsx index e4cef928a7312..004a528e6b431 100644 --- a/apps/studio/components/layouts/RealtimeLayout/RealtimeLayout.tsx +++ b/apps/studio/components/layouts/RealtimeLayout/RealtimeLayout.tsx @@ -1,11 +1,9 @@ import { useRouter } from 'next/router' import { PropsWithChildren } from 'react' -import { useIsRealtimeSettingsEnabled } from 'components/interfaces/App/FeaturePreview/FeaturePreviewContext' import { ProductMenu } from 'components/ui/ProductMenu' import { useSelectedProjectQuery } from 'hooks/misc/useSelectedProject' import { withAuth } from 'hooks/misc/withAuth' -import { useIsRealtimeSettingsFFEnabled } from 'hooks/ui/useFlag' import ProjectLayout from '../ProjectLayout/ProjectLayout' import { generateRealtimeMenu } from './RealtimeMenu.utils' @@ -15,10 +13,6 @@ export interface RealtimeLayoutProps { const RealtimeLayout = ({ title, children }: PropsWithChildren) => { const { data: project } = useSelectedProjectQuery() - const enableRealtimeSettingsFF = useIsRealtimeSettingsFFEnabled() - const enableRealtimeSettingsFP = useIsRealtimeSettingsEnabled() - - const enableRealtimeSettings = enableRealtimeSettingsFF && enableRealtimeSettingsFP const router = useRouter() const page = router.pathname.split('/')[4] @@ -27,12 +21,7 @@ const RealtimeLayout = ({ title, children }: PropsWithChildren - } + productMenu={} > {children} diff --git a/apps/studio/components/layouts/RealtimeLayout/RealtimeMenu.utils.ts b/apps/studio/components/layouts/RealtimeLayout/RealtimeMenu.utils.ts index 1aa33aeb64ae7..2c961d277098d 100644 --- a/apps/studio/components/layouts/RealtimeLayout/RealtimeMenu.utils.ts +++ b/apps/studio/components/layouts/RealtimeLayout/RealtimeMenu.utils.ts @@ -2,13 +2,9 @@ import type { ProductMenuGroup } from 'components/ui/ProductMenu/ProductMenu.typ import type { Project } from 'data/projects/project-detail-query' import { IS_PLATFORM } from 'lib/constants' -export const generateRealtimeMenu = ( - project: Project, - flags?: { enableRealtimeSettings: boolean } -): ProductMenuGroup[] => { +export const generateRealtimeMenu = (project: Project): ProductMenuGroup[] => { const ref = project?.ref ?? 'default' - const { enableRealtimeSettings } = flags || {} - const showRealtimeSettings = IS_PLATFORM && enableRealtimeSettings + const showRealtimeSettings = IS_PLATFORM return [ { diff --git a/apps/studio/hooks/ui/useFlag.ts b/apps/studio/hooks/ui/useFlag.ts index 635c54343a482..979334882d3c0 100644 --- a/apps/studio/hooks/ui/useFlag.ts +++ b/apps/studio/hooks/ui/useFlag.ts @@ -44,23 +44,3 @@ export function usePHFlag(name: string) { return flagValue as T } - -export const useIsRealtimeSettingsFFEnabled = () => { - const { data: project } = useSelectedProjectQuery() - - // This flag is used to enable/disable the realtime settings for specific projects. - const approvedProjects = useFlag('isRealtimeSettingsEnabledOnProjects') - // This flag is used to enable/disable the realtime settings for all projects. - // Will override isRealtimeSettingsEnabledOnProjects if enabled - const enableRealtimeSettingsFlag = useFlag('enableRealtimeSettings') - - const isEnabledOnProject = - !!project?.ref && - typeof approvedProjects === 'string' && - (approvedProjects ?? '') - .split(',') - .map((it) => it.trim()) - .includes(project?.ref) - - return enableRealtimeSettingsFlag || isEnabledOnProject -} diff --git a/packages/common/constants/local-storage.ts b/packages/common/constants/local-storage.ts index 03d597f036654..11e8d32ce6ad6 100644 --- a/packages/common/constants/local-storage.ts +++ b/packages/common/constants/local-storage.ts @@ -13,7 +13,6 @@ export const LOCAL_STORAGE_KEYS = { UI_PREVIEW_INLINE_EDITOR: 'supabase-ui-preview-inline-editor', UI_PREVIEW_UNIFIED_LOGS: 'supabase-ui-preview-unified-logs', UI_ONBOARDING_NEW_PAGE_SHOWN: 'supabase-ui-onboarding-new-page-shown', - UI_PREVIEW_REALTIME_SETTINGS: 'supabase-ui-realtime-settings', UI_PREVIEW_BRANCHING_2_0: 'supabase-ui-branching-2-0', UI_PREVIEW_ADVISOR_RULES: 'supabase-ui-advisor-rules', @@ -109,7 +108,6 @@ const LOCAL_STORAGE_KEYS_ALLOWLIST = [ LOCAL_STORAGE_KEYS.HIDE_PROMO_TOAST, LOCAL_STORAGE_KEYS.BLOG_VIEW, LOCAL_STORAGE_KEYS.AI_ASSISTANT_MCP_OPT_IN, - LOCAL_STORAGE_KEYS.UI_PREVIEW_REALTIME_SETTINGS, LOCAL_STORAGE_KEYS.UI_PREVIEW_BRANCHING_2_0, LOCAL_STORAGE_KEYS.LINTER_SHOW_FOOTER, ] From a54727fb47fd3a9bbbe65ff6bb5d4cf8cf2f7b29 Mon Sep 17 00:00:00 2001 From: DINESH S Date: Mon, 22 Sep 2025 17:57:31 +0530 Subject: [PATCH 2/9] In UI library docs, selecting a line shouldn't select $ (#38906) In UI library docs selecting a line shouldn't select $ --- apps/ui-library/components/command.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/apps/ui-library/components/command.tsx b/apps/ui-library/components/command.tsx index 1956537604e00..752d33bcc6ad8 100644 --- a/apps/ui-library/components/command.tsx +++ b/apps/ui-library/components/command.tsx @@ -67,7 +67,7 @@ export function Command({ name, highlight }: CommandCopyProps) {
    - $ + $ {commands[manager]}
    From 4d91b0956cad9ed2546e0c5b352fbd508d1d6f99 Mon Sep 17 00:00:00 2001 From: "kemal.earth" <606977+kemaldotearth@users.noreply.github.com> Date: Mon, 22 Sep 2025 13:35:58 +0100 Subject: [PATCH 3/9] feat(studio): query details metadata tidy up (#38867) * feat: move query details to sheet This moves the click through on Query Performance to a sheet as opposed to a resizable area. This gives us more space to play with and sets us up for the Query details revamp. * fix: tabs font size * style: expand size of sheet * feat: hasOverlay prop for sheets * feat: add optional overlay for sheets * fix: closing only when clicking outside of rows * style: width of panel on different viewports * fix: horizontal scroll for table * fix: query queries label check in metrics * feat: tidying up metadata values in query details * feat: tidy up ms values * fix: query pattern heading --- .../QueryPerformance/QueryDetail.tsx | 161 +++++++++++++++--- .../QueryPerformance/QueryPanel.tsx | 2 +- 2 files changed, 139 insertions(+), 24 deletions(-) diff --git a/apps/studio/components/interfaces/QueryPerformance/QueryDetail.tsx b/apps/studio/components/interfaces/QueryPerformance/QueryDetail.tsx index 768d10a996d25..7c68d531f8005 100644 --- a/apps/studio/components/interfaces/QueryPerformance/QueryDetail.tsx +++ b/apps/studio/components/interfaces/QueryPerformance/QueryDetail.tsx @@ -1,6 +1,8 @@ import { Lightbulb } from 'lucide-react' import { useEffect, useState } from 'react' import dynamic from 'next/dynamic' +import dayjs from 'dayjs' +import duration from 'dayjs/plugin/duration' import { formatSql } from 'lib/formatSql' import { AlertDescription_Shadcn_, AlertTitle_Shadcn_, Alert_Shadcn_, Button, cn } from 'ui' @@ -37,10 +39,26 @@ export const QueryDetail = ({ selectedRow, onClickViewSuggestion }: QueryDetailP } }, [selectedRow]) + const formatDuration = (seconds: number) => { + const dur = dayjs.duration(seconds, 'seconds') + + const minutes = Math.floor(dur.asMinutes()) + const remainingSeconds = dur.seconds() + dur.milliseconds() / 1000 + + const parts = [] + if (minutes > 0) parts.push(`${minutes}m`) + if (remainingSeconds > 0) { + const formattedSeconds = remainingSeconds.toFixed(2) + parts.push(`${formattedSeconds}s`) + } + + return parts.join(' ') + } + return ( -

    Query pattern

    +

    Query pattern

    {isLinterWarning && (
    - - {report - .filter((x) => x.id !== 'query') - .map((x) => { - const rawValue = selectedRow?.[x.id] - const isTime = x.name.includes('time') - - const formattedValue = isTime - ? typeof rawValue === 'number' && !isNaN(rawValue) && isFinite(rawValue) - ? `${rawValue.toFixed(2)}ms` - : 'N/A' - : rawValue != null - ? String(rawValue) - : 'N/A' - - return ( -
    -

    {x.name}

    -

    {formattedValue}

    -
    - ) - })} + +

    Metadata

    +
      + {report + .filter((x) => x.id !== 'query') + .map((x) => { + const rawValue = selectedRow?.[x.id] + const isTime = x.name.includes('time') + + const formattedValue = isTime + ? typeof rawValue === 'number' && !isNaN(rawValue) && isFinite(rawValue) + ? `${Math.round(rawValue).toLocaleString()}ms` + : 'n/a' + : rawValue != null + ? String(rawValue) + : 'n/a' + + if (x.id === 'prop_total_time') { + return ( +
    • +

      {x.name}

      + {rawValue ? ( +

      + {rawValue.toFixed(1)}% +

      + ) : ( +

      + )} +
    • + ) + } + + if (x.id == 'total_time') { + return ( +
    • +

      + {x.name + ' '} + latency +

      + {isTime && + typeof rawValue === 'number' && + !isNaN(rawValue) && + isFinite(rawValue) ? ( +

      + {formatDuration(rawValue / 1000)} +

      + ) : ( +

      + )} +
    • + ) + } + + if (x.id == 'rows_read') { + return ( +
    • +

      {x.name}

      + {typeof rawValue === 'number' && !isNaN(rawValue) && isFinite(rawValue) ? ( +

      + {rawValue.toLocaleString()} +

      + ) : ( +

      + )} +
    • + ) + } + + const cacheHitRateToNumber = (value: number | string) => { + if (typeof value === 'number') return value + return parseFloat(value.toString().replace('%', '')) || 0 + } + + if (x.id === 'cache_hit_rate') { + return ( +
    • +

      {x.name}

      + {typeof rawValue === 'string' ? ( +

      + {cacheHitRateToNumber(rawValue).toLocaleString(undefined, { + minimumFractionDigits: 2, + maximumFractionDigits: 2, + })} + % +

      + ) : ( +

      + )} +
    • + ) + } + + return ( +
    • +

      {x.name}

      +

      + {formattedValue} +

      +
    • + ) + })} +
    ) diff --git a/apps/studio/components/interfaces/QueryPerformance/QueryPanel.tsx b/apps/studio/components/interfaces/QueryPerformance/QueryPanel.tsx index 4cee87a3ece2c..c4748326ad41c 100644 --- a/apps/studio/components/interfaces/QueryPerformance/QueryPanel.tsx +++ b/apps/studio/components/interfaces/QueryPerformance/QueryPanel.tsx @@ -14,7 +14,7 @@ export const QueryPanelSection = ({ children, className, }: PropsWithChildren<{ className?: string }>) => ( -
    {children}
    +
    {children}
    ) export const QueryPanelScoreSection = ({ From 3fe03d07ab44265aaa6153bfed432138214adc4a Mon Sep 17 00:00:00 2001 From: Charis <26616127+charislam@users.noreply.github.com> Date: Mon, 22 Sep 2025 09:04:19 -0400 Subject: [PATCH 4/9] feat: negate feature flags in $Show (#38871) Previous behavior: $Show component only works with enabled feature flags: if feature flag is on, content is shown New behavior: $Show component also works with negated feature flags: if feature flag is off, content is shown Required for enabling custom content in forked builds --- apps/docs/content/guides/getting-started.mdx | 10 +++++ apps/docs/features/directives/Show.test.ts | 45 ++++++++++++++++--- apps/docs/features/directives/Show.ts | 17 +++++-- .../enabled-features/enabled-features.json | 2 + .../enabled-features.schema.json | 6 +++ 5 files changed, 71 insertions(+), 9 deletions(-) diff --git a/apps/docs/content/guides/getting-started.mdx b/apps/docs/content/guides/getting-started.mdx index c41613e11db9a..b95027ac13447 100644 --- a/apps/docs/content/guides/getting-started.mdx +++ b/apps/docs/content/guides/getting-started.mdx @@ -93,6 +93,8 @@ hideToc: true ### Framework quickstarts +<$Show if="docs:framework_quickstarts"> +
    {[ { @@ -211,6 +213,14 @@ hideToc: true })}
    + + +<$Show if="!quickstarts:hide_nimbus"> + +<$Partial path="quickstart_nimbus.mdx" /> + + + <$Show if="docs:web_apps"> ### Web app demos diff --git a/apps/docs/features/directives/Show.test.ts b/apps/docs/features/directives/Show.test.ts index cbe3024a11472..3fea57f501206 100644 --- a/apps/docs/features/directives/Show.test.ts +++ b/apps/docs/features/directives/Show.test.ts @@ -59,18 +59,51 @@ Content after the show block. expect(isFeatureEnabled).toHaveBeenCalledWith('test-feature') }) - it('should remove entire $Show block and children when feature is disabled', async () => { + it('should keep children when negated feature is disabled', async () => { vi.mocked(isFeatureEnabled).mockReturnValue(false) const markdown = ` # Test content -<$Show if="disabled-feature"> -This content should NOT be visible when feature is disabled. +<$Show if="!negated-feature"> +This content should be visible when the feature is disabled. + +## Additional content + +More text that should remain. + + +Content after the show block. +`.trim() + + const mdast = fromDocsMarkdown(markdown) + const transformed = showRemark()(mdast) + const output = toMarkdown(transformed, { extensions: [mdxToMarkdown()] }) + + const expected = ` +# Test content -## This heading should also be removed +This content should be visible when the feature is disabled. -Some more content that should be hidden. +## Additional content + +More text that should remain. + +Content after the show block. +`.trimStart() + + expect(output).toEqual(expected) + expect(isFeatureEnabled).toHaveBeenCalledWith('negated-feature') + }) + + it('should remove $Show block when negated feature is enabled', async () => { + vi.mocked(isFeatureEnabled).mockReturnValue(true) + + const markdown = ` +# Test content + +<$Show if="!enabled-negated-feature"> +This content should NOT be visible because the feature is enabled. Content after the show block should remain. @@ -87,7 +120,7 @@ Content after the show block should remain. `.trimStart() expect(output).toEqual(expected) - expect(isFeatureEnabled).toHaveBeenCalledWith('disabled-feature') + expect(isFeatureEnabled).toHaveBeenCalledWith('enabled-negated-feature') }) it('should handle multiple $Show blocks with different feature flags', async () => { diff --git a/apps/docs/features/directives/Show.ts b/apps/docs/features/directives/Show.ts index 94401222466aa..5a1e0b32e4362 100644 --- a/apps/docs/features/directives/Show.ts +++ b/apps/docs/features/directives/Show.ts @@ -38,13 +38,24 @@ export function showRemark() { if (node.name !== '$Show') return const parent = ancestors[ancestors.length - 1] - const featureName = getAttributeValue(node, 'if') + const rawFeatureName = getAttributeValue(node, 'if') - if (typeof featureName !== 'string') { + if (typeof rawFeatureName !== 'string') { throw new Error('$Show directive requires a string value for the "if" attribute') } - const shouldShow = isFeatureEnabled(featureName as Feature) + const trimmedFeatureName = rawFeatureName.trim() + const isNegated = trimmedFeatureName.startsWith('!') + const normalizedFeatureName = ( + isNegated ? trimmedFeatureName.slice(1) : trimmedFeatureName + ).trim() + + if (!normalizedFeatureName) { + throw new Error('$Show directive requires a non-empty feature name for the "if" attribute') + } + + const isEnabled = isFeatureEnabled(normalizedFeatureName as Feature) + const shouldShow = isNegated ? !isEnabled : isEnabled nodesToProcess.push({ node, diff --git a/packages/common/enabled-features/enabled-features.json b/packages/common/enabled-features/enabled-features.json index 5b3494a78500d..3221a0c981284 100644 --- a/packages/common/enabled-features/enabled-features.json +++ b/packages/common/enabled-features/enabled-features.json @@ -80,6 +80,8 @@ "project_settings:legacy_jwt_keys": true, "project_settings:log_drains": true, + "quickstarts:hide_nimbus": true, + "reports:all": true, "sdk:csharp": true, diff --git a/packages/common/enabled-features/enabled-features.schema.json b/packages/common/enabled-features/enabled-features.schema.json index 9943b890297ee..cbb99e6bfb782 100644 --- a/packages/common/enabled-features/enabled-features.schema.json +++ b/packages/common/enabled-features/enabled-features.schema.json @@ -269,6 +269,11 @@ "description": "Enable the log drains page in project settings" }, + "quickstarts:hide_nimbus": { + "type": "boolean", + "description": "Whether to show the Nimbus quickstart" + }, + "reports:all": { "type": "boolean", "description": "Enable the project reports page" @@ -362,6 +367,7 @@ "project_connection:show_app_frameworks", "project_connection:show_mobile_frameworks", "project_connection:show_orms", + "quickstarts:hide_nimbus", "reports:all", "sdk:csharp", "sdk:dart", From 3d8e5d9cfd67e4b3f7561ad37d74623fc0b85f09 Mon Sep 17 00:00:00 2001 From: Chris Chinchilla Date: Mon, 22 Sep 2025 15:16:17 +0200 Subject: [PATCH 5/9] docs: Set default priority in sitemap and lower auth-helper priority (#38918) Set default priority in sitemap and lower auth-helper priority --- apps/docs/content/guides/auth/auth-helpers/auth-ui.mdx | 2 +- .../content/guides/auth/auth-helpers/flutter-auth-ui.mdx | 2 +- .../docs/content/guides/auth/auth-helpers/nextjs-pages.mdx | 2 +- apps/docs/content/guides/auth/auth-helpers/nextjs.mdx | 2 +- apps/docs/content/guides/auth/auth-helpers/remix.mdx | 2 +- apps/docs/content/guides/auth/auth-helpers/sveltekit.mdx | 2 +- apps/docs/internals/files/cli.ts | 4 ++-- apps/docs/internals/files/reference-lib.ts | 1 + apps/docs/internals/generate-sitemap.ts | 7 ++++--- 9 files changed, 13 insertions(+), 11 deletions(-) diff --git a/apps/docs/content/guides/auth/auth-helpers/auth-ui.mdx b/apps/docs/content/guides/auth/auth-helpers/auth-ui.mdx index 810e447bb2ca0..951cdc75d9423 100644 --- a/apps/docs/content/guides/auth/auth-helpers/auth-ui.mdx +++ b/apps/docs/content/guides/auth/auth-helpers/auth-ui.mdx @@ -2,7 +2,7 @@ id: 'auth-ui' title: 'Auth UI' description: 'A prebuilt, customizable React component for authenticating users.' -sitemapPriority: 0.5 +sitemapPriority: 0.3 --- diff --git a/apps/docs/content/guides/auth/auth-helpers/flutter-auth-ui.mdx b/apps/docs/content/guides/auth/auth-helpers/flutter-auth-ui.mdx index c0e25cb4fd099..2c82ecfb49674 100644 --- a/apps/docs/content/guides/auth/auth-helpers/flutter-auth-ui.mdx +++ b/apps/docs/content/guides/auth/auth-helpers/flutter-auth-ui.mdx @@ -2,7 +2,7 @@ id: 'flutter-auth-ui' title: 'Flutter Auth UI' description: 'Prebuilt, customizable Flutter widgets for authenticating users.' -sitemapPriority: 0.5 +sitemapPriority: 0.3 --- Flutter Auth UI is a Flutter package containing pre-built widgets for authenticating users. diff --git a/apps/docs/content/guides/auth/auth-helpers/nextjs-pages.mdx b/apps/docs/content/guides/auth/auth-helpers/nextjs-pages.mdx index cae3db4e57b03..ab64eefb190c9 100644 --- a/apps/docs/content/guides/auth/auth-helpers/nextjs-pages.mdx +++ b/apps/docs/content/guides/auth/auth-helpers/nextjs-pages.mdx @@ -3,7 +3,7 @@ id: 'nextjs-pages' title: 'Supabase Auth with Next.js Pages Directory' description: 'Authentication helpers for Next.js API routes, middleware, and SSR in the Pages Directory.' sidebar_label: 'Next.js (pages)' -sitemapPriority: 0.5 +sitemapPriority: 0.3 --- diff --git a/apps/docs/content/guides/auth/auth-helpers/nextjs.mdx b/apps/docs/content/guides/auth/auth-helpers/nextjs.mdx index 94af0d45b25c6..46b44999358bb 100644 --- a/apps/docs/content/guides/auth/auth-helpers/nextjs.mdx +++ b/apps/docs/content/guides/auth/auth-helpers/nextjs.mdx @@ -3,7 +3,7 @@ id: 'nextjs' title: 'Supabase Auth with the Next.js App Router' description: 'Authentication and Authorization helpers for creating an authenticated Supabase client with the Next.js 13 App Router.' sidebar_label: 'Next.js' -sitemapPriority: 0.5 +sitemapPriority: 0.3 --- diff --git a/apps/docs/content/guides/auth/auth-helpers/remix.mdx b/apps/docs/content/guides/auth/auth-helpers/remix.mdx index cd75f826aec89..ffd0ad4f39c2c 100644 --- a/apps/docs/content/guides/auth/auth-helpers/remix.mdx +++ b/apps/docs/content/guides/auth/auth-helpers/remix.mdx @@ -3,7 +3,7 @@ id: 'remix' title: 'Supabase Auth with Remix' description: 'Authentication helpers for loaders and actions in Remix.' sidebar_label: 'Remix' -sitemapPriority: 0.5 +sitemapPriority: 0.3 --- diff --git a/apps/docs/content/guides/auth/auth-helpers/sveltekit.mdx b/apps/docs/content/guides/auth/auth-helpers/sveltekit.mdx index 5b96f99bcc0a0..310be26f91a25 100644 --- a/apps/docs/content/guides/auth/auth-helpers/sveltekit.mdx +++ b/apps/docs/content/guides/auth/auth-helpers/sveltekit.mdx @@ -3,7 +3,7 @@ id: 'sveltekit' title: 'Supabase Auth with SvelteKit' description: 'Convenience helpers for implementing user authentication in SvelteKit.' sidebar_label: 'SvelteKit' -sitemapPriority: 0.5 +sitemapPriority: 0.3 --- diff --git a/apps/docs/internals/files/cli.ts b/apps/docs/internals/files/cli.ts index eb3b18f8f977e..818a425de84af 100644 --- a/apps/docs/internals/files/cli.ts +++ b/apps/docs/internals/files/cli.ts @@ -13,11 +13,11 @@ const cliSpec = yaml.load(fs.readFileSync(`spec/cli_v1_commands.yaml`, 'utf8')) * @returns {Array<{link: string}>} - An array of CLI page links. */ export function generateCLIPages() { - let cliPages: Array<{ link: string }> = [] + let cliPages: Array<{ link: string; priority: number }> = [] cliSpec.commands.map((section: any) => { const slug = (flatCLISections as any[]).find((item: any) => item.id === section.id)?.slug - if (slug) cliPages.push({ link: `reference/cli/${slug}` }) + if (slug) cliPages.push({ link: `reference/cli/${slug}`, priority: 0.8 }) }) return cliPages } diff --git a/apps/docs/internals/files/reference-lib.ts b/apps/docs/internals/files/reference-lib.ts index 5fbc1dea2db78..f1dbafbf5cc11 100644 --- a/apps/docs/internals/files/reference-lib.ts +++ b/apps/docs/internals/files/reference-lib.ts @@ -33,6 +33,7 @@ export async function generateReferencePages() { link: isLatestVersion ? `reference/${libPath}/${section.slug}` : `reference/${libPath}/${version}/${section.slug}`, + priority: 0.8, })) ?? [] ) }) diff --git a/apps/docs/internals/generate-sitemap.ts b/apps/docs/internals/generate-sitemap.ts index f1d37d6d8b5f0..5e90098ba67bf 100644 --- a/apps/docs/internals/generate-sitemap.ts +++ b/apps/docs/internals/generate-sitemap.ts @@ -25,7 +25,7 @@ async function generate() { return { link: filePath.replace(/^content\//, '').replace(/\.mdx$/, ''), - priority: sitemapPriority, + priority: sitemapPriority ?? 0.8, } }) ) @@ -40,7 +40,7 @@ async function generate() { }) ) - const allPages = (contentPages as Array<{ link: string; priority?: number }>).concat( + const allPages = (contentPages as Array<{ link: string; priority: number }>).concat( troubleshootingPages, referencePages, cliPages @@ -51,11 +51,12 @@ async function generate() { ${allPages .map(({ link, priority }) => { + const finalPriority = priority ?? 0.8 return ` ${`https://supabase.com/docs/${link}`} weekly - ${priority ? `${priority}` : ''} + ${finalPriority} ` }) From 2a0911379e3d8c238affadf2baf604217d9704b8 Mon Sep 17 00:00:00 2001 From: Chris Chinchilla Date: Mon, 22 Sep 2025 15:25:51 +0200 Subject: [PATCH 6/9] docs: Remove or deprioritise as many auth helpers mentions as possible (#38919) * Draft * Overhaul and remove as many mentions of auth-helpers as possible * Update apps/docs/content/guides/getting-started/tutorials/with-nextjs.mdx Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com> * Update apps/docs/content/guides/auth/auth-helpers.mdx Co-authored-by: Charis <26616127+charislam@users.noreply.github.com> * Prettier --------- Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com> Co-authored-by: Charis <26616127+charislam@users.noreply.github.com> --- apps/docs/content/_partials/auth_helpers.mdx | 5 +++++ apps/docs/content/guides/auth/auth-helpers.mdx | 8 +++----- .../content/guides/auth/auth-helpers/nextjs-pages.mdx | 4 +++- apps/docs/content/guides/auth/auth-helpers/nextjs.mdx | 4 +++- apps/docs/content/guides/auth/auth-helpers/remix.mdx | 2 +- apps/docs/content/guides/auth/auth-helpers/sveltekit.mdx | 2 +- apps/docs/content/guides/auth/quickstarts/nextjs.mdx | 2 +- apps/docs/content/guides/auth/server-side.mdx | 8 +++----- .../content/guides/auth/server-side/advanced-guide.mdx | 2 -- .../content/guides/getting-started/quickstarts/nextjs.mdx | 2 +- .../guides/getting-started/tutorials/with-nextjs.mdx | 3 +-- 11 files changed, 22 insertions(+), 20 deletions(-) create mode 100644 apps/docs/content/_partials/auth_helpers.mdx diff --git a/apps/docs/content/_partials/auth_helpers.mdx b/apps/docs/content/_partials/auth_helpers.mdx new file mode 100644 index 0000000000000..ccbf1888699a0 --- /dev/null +++ b/apps/docs/content/_partials/auth_helpers.mdx @@ -0,0 +1,5 @@ + + +The Auth helpers package is deprecated. Use the new `@supabase/ssr` package for Server Side Authentication. `@supabase/ssr` takes the core concepts of the Auth Helpers package and makes them available to any server framework. Read out the [migration doc](/docs/guides/auth/server-side/migrating-to-ssr-from-auth-helpers) to learn more. + + diff --git a/apps/docs/content/guides/auth/auth-helpers.mdx b/apps/docs/content/guides/auth/auth-helpers.mdx index 52fd9f29bfe2c..9c1d1653e9a04 100644 --- a/apps/docs/content/guides/auth/auth-helpers.mdx +++ b/apps/docs/content/guides/auth/auth-helpers.mdx @@ -5,11 +5,9 @@ description: 'Server-Side Auth guides and utilities for working with Supabase.' sidebar_label: 'Overview' --- - - -The Auth helpers package is deprecated. Use the new `@supabase/ssr` package for Server Side Authentication. `@supabase/ssr` takes the core concepts of the Auth Helpers package and makes them available to any server framework. Check out the [migration doc](/docs/guides/auth/server-side/migrating-to-ssr-from-auth-helpers) to learn more. - - +<$Partial +path="auth_helpers.mdx" +/> Working with server-side frameworks is slightly different to client-side frameworks. In this section we cover the various ways of handling server-side authentication and demonstrate how to use the Supabase helper-libraries to make the process more seamless. diff --git a/apps/docs/content/guides/auth/auth-helpers/nextjs-pages.mdx b/apps/docs/content/guides/auth/auth-helpers/nextjs-pages.mdx index ab64eefb190c9..bac6b7abc5805 100644 --- a/apps/docs/content/guides/auth/auth-helpers/nextjs-pages.mdx +++ b/apps/docs/content/guides/auth/auth-helpers/nextjs-pages.mdx @@ -8,7 +8,9 @@ sitemapPriority: 0.3 -The `auth-helpers` package has been replaced with the `@supabase/ssr` package. We recommend setting up Auth for your Next.js app with `@supabase/ssr` instead. See the [Next.js Server-Side Auth guide](/docs/guides/auth/server-side/nextjs?router=pages) to learn how. +The Auth helpers package is deprecated. Use the new `@supabase/ssr` package for Server Side Authentication. `@supabase/ssr` takes the core concepts of the Auth Helpers package and makes them available to any server framework. Read the [migration doc](/docs/guides/auth/server-side/migrating-to-ssr-from-auth-helpers) to learn more. + +We recommend setting up Auth for your Next.js app with `@supabase/ssr` instead. Read the [Next.js Server-Side Auth guide](/docs/guides/auth/server-side/nextjs?router=pages) to learn how. diff --git a/apps/docs/content/guides/auth/auth-helpers/nextjs.mdx b/apps/docs/content/guides/auth/auth-helpers/nextjs.mdx index 46b44999358bb..9eaab4f00aacb 100644 --- a/apps/docs/content/guides/auth/auth-helpers/nextjs.mdx +++ b/apps/docs/content/guides/auth/auth-helpers/nextjs.mdx @@ -8,7 +8,9 @@ sitemapPriority: 0.3 -The `auth-helpers` are now deprecated. Use `@supabase/ssr` to set up Auth for your Next.js app. See the [Next.js Server-Side Auth guide](/docs/guides/auth/server-side/nextjs) to learn how. +The Auth helpers package is deprecated. Use the new `@supabase/ssr` package for Server Side Authentication. `@supabase/ssr` takes the core concepts of the Auth Helpers package and makes them available to any server framework. Read the [migration doc](/docs/guides/auth/server-side/migrating-to-ssr-from-auth-helpers) to learn more. + +We recommend setting up Auth for your Next.js app with `@supabase/ssr` instead. Read the [Next.js Server-Side Auth guide](/docs/guides/auth/server-side/nextjs?router=pages) to learn how. diff --git a/apps/docs/content/guides/auth/auth-helpers/remix.mdx b/apps/docs/content/guides/auth/auth-helpers/remix.mdx index ffd0ad4f39c2c..a8b7074c9ec87 100644 --- a/apps/docs/content/guides/auth/auth-helpers/remix.mdx +++ b/apps/docs/content/guides/auth/auth-helpers/remix.mdx @@ -8,7 +8,7 @@ sitemapPriority: 0.3 -We generally recommend using the new `@supabase/ssr` package instead of `auth-helpers`. `@supabase/ssr` takes the core concepts of the Auth Helpers package and makes them available to any server framework. Check out the [migration doc](/docs/guides/auth/server-side/migrating-to-ssr-from-auth-helpers) to learn more. +The Auth helpers package is deprecated. Use the new `@supabase/ssr` package for Server Side Authentication. `@supabase/ssr` takes the core concepts of the Auth Helpers package and makes them available to any server framework. Read the [migration doc](/docs/guides/auth/server-side/migrating-to-ssr-from-auth-helpers) to learn more. diff --git a/apps/docs/content/guides/auth/auth-helpers/sveltekit.mdx b/apps/docs/content/guides/auth/auth-helpers/sveltekit.mdx index 310be26f91a25..9a2e26f135499 100644 --- a/apps/docs/content/guides/auth/auth-helpers/sveltekit.mdx +++ b/apps/docs/content/guides/auth/auth-helpers/sveltekit.mdx @@ -8,7 +8,7 @@ sitemapPriority: 0.3 -We generally recommend using the new `@supabase/ssr` package instead of `auth-helpers`. `@supabase/ssr` takes the core concepts of the Auth Helpers package and makes them available to any server framework. Check out the [migration doc](/docs/guides/auth/server-side/migrating-to-ssr-from-auth-helpers) to learn more. +The Auth helpers package is deprecated. Use the new `@supabase/ssr` package for Server Side Authentication. `@supabase/ssr` takes the core concepts of the Auth Helpers package and makes them available to any server framework. Read the [migration doc](/docs/guides/auth/server-side/migrating-to-ssr-from-auth-helpers) to learn more. diff --git a/apps/docs/content/guides/auth/quickstarts/nextjs.mdx b/apps/docs/content/guides/auth/quickstarts/nextjs.mdx index 5c42213369253..94924ff67ca5c 100644 --- a/apps/docs/content/guides/auth/quickstarts/nextjs.mdx +++ b/apps/docs/content/guides/auth/quickstarts/nextjs.mdx @@ -31,7 +31,7 @@ hideToc: true Use the `create-next-app` command and the `with-supabase` template, to create a Next.js app pre-configured with: - - [Cookie-based Auth](/docs/guides/auth/auth-helpers/nextjs) + - [Cookie-based Auth](docs/guides/auth/server-side/creating-a-client?queryGroups=package-manager&package-manager=npm&queryGroups=framework&framework=nextjs&queryGroups=environment&environment=server) - [TypeScript](https://www.typescriptlang.org/) - [Tailwind CSS](https://tailwindcss.com/) diff --git a/apps/docs/content/guides/auth/server-side.mdx b/apps/docs/content/guides/auth/server-side.mdx index b18e8f0950fbc..3c7d3d3cb64d2 100644 --- a/apps/docs/content/guides/auth/server-side.mdx +++ b/apps/docs/content/guides/auth/server-side.mdx @@ -17,11 +17,9 @@ Make sure to use the PKCE flow instructions where those differ from the implicit We have developed an [`@supabase/ssr`](https://www.npmjs.com/package/@supabase/ssr) package to make setting up the Supabase client as simple as possible. This package is currently in beta. Adoption is recommended but be aware that the API is still unstable and may have breaking changes in the future. - - -If you're currently using the [Auth Helpers package](https://github.com/supabase/auth-helpers), the [docs are still available](/docs/guides/auth/auth-helpers), however we recommend migrating to the new `@supabase/ssr` package as this will be the recommended path moving forward. - - +<$Partial +path="auth_helpers.mdx" +/> ## Framework quickstarts diff --git a/apps/docs/content/guides/auth/server-side/advanced-guide.mdx b/apps/docs/content/guides/auth/server-side/advanced-guide.mdx index d189ff66a969c..536b92ddd08aa 100644 --- a/apps/docs/content/guides/auth/server-side/advanced-guide.mdx +++ b/apps/docs/content/guides/auth/server-side/advanced-guide.mdx @@ -24,8 +24,6 @@ In the PKCE flow, a redirect is made to your app, with an Auth Code contained in To maintain the session, these tokens must be stored in a storage medium securely shared between client and server, which is traditionally cookies. Whenever the session is refreshed, the auth and refresh tokens in the shared storage medium must be updated. Supabase client libraries provide a customizable `storage` option when a client is initiated, allowing you to change where tokens are stored. -For an implementation example, see the [@supabase/ssr](https://github.com/supabase/auth-helpers/blob/main/packages/ssr/src/index.ts) package. - ## Frequently asked questions {/* supa-mdx-lint-disable Rule004ExcludeWords */} diff --git a/apps/docs/content/guides/getting-started/quickstarts/nextjs.mdx b/apps/docs/content/guides/getting-started/quickstarts/nextjs.mdx index 5dace7e590c41..e7fc33911c063 100644 --- a/apps/docs/content/guides/getting-started/quickstarts/nextjs.mdx +++ b/apps/docs/content/guides/getting-started/quickstarts/nextjs.mdx @@ -18,7 +18,7 @@ hideToc: true Use the `create-next-app` command and the `with-supabase` template, to create a Next.js app pre-configured with: - - [Cookie-based Auth](/docs/guides/auth/auth-helpers/nextjs) + - [Cookie-based Auth](docs/guides/auth/server-side/creating-a-client?queryGroups=package-manager&package-manager=npm&queryGroups=framework&framework=nextjs&queryGroups=environment&environment=server) - [TypeScript](https://www.typescriptlang.org/) - [Tailwind CSS](https://tailwindcss.com/) diff --git a/apps/docs/content/guides/getting-started/tutorials/with-nextjs.mdx b/apps/docs/content/guides/getting-started/tutorials/with-nextjs.mdx index 00dfdeacf8997..4fe57e4e3aa12 100644 --- a/apps/docs/content/guides/getting-started/tutorials/with-nextjs.mdx +++ b/apps/docs/content/guides/getting-started/tutorials/with-nextjs.mdx @@ -1028,7 +1028,6 @@ At this stage you have a fully functional application! - See the complete [example on GitHub](https://github.com/supabase/supabase/tree/master/examples/user-management/nextjs-user-management) and deploy it to Vercel - [Build a Twitter Clone with the Next.js App Router and Supabase - free egghead course](https://egghead.io/courses/build-a-twitter-clone-with-the-next-js-app-router-and-supabase-19bebadb) -- Explore the [pre-built Auth UI for React](/docs/guides/auth/auth-helpers/auth-ui) -- Explore the [Auth Helpers for Next.js](/docs/guides/auth/auth-helpers/nextjs) +- Explore the [pre-built Auth components](/ui/docs/nextjs/password-based-auth) - Explore the [Supabase Cache Helpers](https://github.com/psteinroe/supabase-cache-helpers) - See the [Next.js Subscription Payments Starter](https://github.com/vercel/nextjs-subscription-payments) template on GitHub From 73b0b21bb70c1fb7b2e78c7cba8cf52c095d206a Mon Sep 17 00:00:00 2001 From: "kemal.earth" <606977+kemaldotearth@users.noreply.github.com> Date: Mon, 22 Sep 2025 14:54:24 +0100 Subject: [PATCH 7/9] feat(studio): combine time consumed cols in query perf (#38920) * chore: remove forgotten dayjs helper * feat: combined time consumed column --- .../QueryPerformance/QueryDetail.tsx | 57 +++++++---------- .../QueryPerformance.constants.ts | 3 +- .../QueryPerformance/QueryPerformanceGrid.tsx | 63 +++++++++---------- 3 files changed, 53 insertions(+), 70 deletions(-) diff --git a/apps/studio/components/interfaces/QueryPerformance/QueryDetail.tsx b/apps/studio/components/interfaces/QueryPerformance/QueryDetail.tsx index 7c68d531f8005..b792220b71449 100644 --- a/apps/studio/components/interfaces/QueryPerformance/QueryDetail.tsx +++ b/apps/studio/components/interfaces/QueryPerformance/QueryDetail.tsx @@ -2,7 +2,6 @@ import { Lightbulb } from 'lucide-react' import { useEffect, useState } from 'react' import dynamic from 'next/dynamic' import dayjs from 'dayjs' -import duration from 'dayjs/plugin/duration' import { formatSql } from 'lib/formatSql' import { AlertDescription_Shadcn_, AlertTitle_Shadcn_, Alert_Shadcn_, Button, cn } from 'ui' @@ -97,43 +96,31 @@ export const QueryDetail = ({ selectedRow, onClickViewSuggestion }: QueryDetailP : 'n/a' if (x.id === 'prop_total_time') { - return ( -
  • -

    {x.name}

    - {rawValue ? ( -

    - {rawValue.toFixed(1)}% -

    - ) : ( -

    - )} -
  • - ) - } + const percentage = selectedRow?.prop_total_time || 0 + const totalTime = selectedRow?.total_time || 0 - if (x.id == 'total_time') { return (
  • -

    - {x.name + ' '} - latency -

    - {isTime && - typeof rawValue === 'number' && - !isNaN(rawValue) && - isFinite(rawValue) ? ( -

    - {formatDuration(rawValue / 1000)} +

    {x.name}

    + {percentage && totalTime ? ( +

    + + {percentage.toFixed(1)}% + {' '} + /{' '} + + {formatDuration(totalTime / 1000)} +

    ) : (

    diff --git a/apps/studio/components/interfaces/QueryPerformance/QueryPerformance.constants.ts b/apps/studio/components/interfaces/QueryPerformance/QueryPerformance.constants.ts index a09da9a32b1df..4b96763edfa4d 100644 --- a/apps/studio/components/interfaces/QueryPerformance/QueryPerformance.constants.ts +++ b/apps/studio/components/interfaces/QueryPerformance/QueryPerformance.constants.ts @@ -14,8 +14,7 @@ export const QUERY_PERFORMANCE_PRESET_MAP = { export const QUERY_PERFORMANCE_COLUMNS = [ { id: 'query', name: 'Query', description: undefined, minWidth: 500 }, - { id: 'prop_total_time', name: 'Time consumed', description: undefined, minWidth: 130 }, - { id: 'total_time', name: 'Total time', description: 'latency', minWidth: 150 }, + { id: 'prop_total_time', name: 'Time consumed', description: undefined, minWidth: 150 }, { id: 'calls', name: 'Count', description: undefined, minWidth: 100 }, { id: 'max_time', name: 'Max time', description: undefined, minWidth: 100 }, { id: 'mean_time', name: 'Mean time', description: undefined, minWidth: 100 }, diff --git a/apps/studio/components/interfaces/QueryPerformance/QueryPerformanceGrid.tsx b/apps/studio/components/interfaces/QueryPerformance/QueryPerformanceGrid.tsx index 36cadf22a8600..62e3bb4973204 100644 --- a/apps/studio/components/interfaces/QueryPerformance/QueryPerformanceGrid.tsx +++ b/apps/studio/components/interfaces/QueryPerformance/QueryPerformanceGrid.tsx @@ -141,51 +141,48 @@ export const QueryPerformanceGrid = ({ queryPerformanceQuery }: QueryPerformance ) } + const isTime = col.name.includes('time') + const formattedValue = + !!value && typeof value === 'number' && !isNaN(value) && isFinite(value) + ? isTime + ? `${value.toFixed(0).toLocaleString()}ms` + : value.toLocaleString() + : '' + if (col.id === 'prop_total_time') { const percentage = props.row.prop_total_time || 0 + const totalTime = props.row.total_time || 0 const fillWidth = Math.min(percentage, 100) return (
    - {value ? ( -

    - {value.toFixed(1)}% -

    - ) : ( -

    - )} -
    - ) - } - - const isTime = col.name.includes('time') - const formattedValue = - !!value && typeof value === 'number' && !isNaN(value) && isFinite(value) - ? isTime - ? `${value.toFixed(0).toLocaleString()}ms` - : value.toLocaleString() - : '' - - if (col.id === 'total_time') { - return ( -
    - {isTime && typeof value === 'number' && !isNaN(value) && isFinite(value) ? ( -

    - {(value / 1000).toLocaleString(undefined, { - minimumFractionDigits: 2, - maximumFractionDigits: 2, - })} - s -

    + {percentage && totalTime ? ( + + + {percentage.toFixed(1)}% + {' '} + / + + {(totalTime / 1000).toLocaleString(undefined, { + minimumFractionDigits: 2, + maximumFractionDigits: 2, + })} + s + + ) : (

    )} From cd20c43f504804eb46f1e4e51eff3bd8dea5c25b Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" <41898282+github-actions[bot]@users.noreply.github.com> Date: Mon, 22 Sep 2025 15:38:10 +0000 Subject: [PATCH 8/9] feat: update mgmt api docs (#38902) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: phamhieu <689843+phamhieu@users.noreply.github.com> Co-authored-by: Raúl Barroso --- apps/docs/spec/api_v1_openapi.json | 47 +++- .../transforms/api_v1_openapi_deparsed.json | 206 +++++++++++++++++- 2 files changed, 248 insertions(+), 5 deletions(-) diff --git a/apps/docs/spec/api_v1_openapi.json b/apps/docs/spec/api_v1_openapi.json index 658a292fa0665..36e0d4f4a64a7 100644 --- a/apps/docs/spec/api_v1_openapi.json +++ b/apps/docs/spec/api_v1_openapi.json @@ -449,7 +449,10 @@ "required": false, "in": "query", "description": "Resource indicator for MCP (Model Context Protocol) clients", - "schema": { "type": "string", "enum": ["https://api.supabase.io/mcp"] } + "schema": { + "type": "string", + "enum": ["https://api.supabase.com/mcp", "https://mcp.supabase.com/mcp"] + } } ], "responses": { "204": { "description": "" } }, @@ -4790,7 +4793,7 @@ "refresh_token": { "type": "string" }, "resource": { "type": "string", - "enum": ["https://api.supabase.io/mcp"], + "enum": ["https://api.supabase.com/mcp", "https://mcp.supabase.com/mcp"], "description": "Resource indicator for MCP (Model Context Protocol) clients" } }, @@ -5615,7 +5618,17 @@ { "type": "object", "properties": { + "kid": { "type": "string", "format": "uuid" }, + "use": { "type": "string", "enum": ["sig"] }, + "key_ops": { + "type": "array", + "items": { "type": "string", "enum": ["sign", "verify"] }, + "minItems": 2, + "maxItems": 2 + }, + "ext": { "type": "boolean", "enum": [true] }, "kty": { "type": "string", "enum": ["RSA"] }, + "alg": { "type": "string", "enum": ["RS256"] }, "n": { "type": "string" }, "e": { "type": "string", "enum": ["AQAB"] }, "d": { "type": "string" }, @@ -5631,7 +5644,17 @@ { "type": "object", "properties": { + "kid": { "type": "string", "format": "uuid" }, + "use": { "type": "string", "enum": ["sig"] }, + "key_ops": { + "type": "array", + "items": { "type": "string", "enum": ["sign", "verify"] }, + "minItems": 2, + "maxItems": 2 + }, + "ext": { "type": "boolean", "enum": [true] }, "kty": { "type": "string", "enum": ["EC"] }, + "alg": { "type": "string", "enum": ["ES256"] }, "crv": { "type": "string", "enum": ["P-256"] }, "x": { "type": "string" }, "y": { "type": "string" }, @@ -5643,7 +5666,17 @@ { "type": "object", "properties": { + "kid": { "type": "string", "format": "uuid" }, + "use": { "type": "string", "enum": ["sig"] }, + "key_ops": { + "type": "array", + "items": { "type": "string", "enum": ["sign", "verify"] }, + "minItems": 2, + "maxItems": 2 + }, + "ext": { "type": "boolean", "enum": [true] }, "kty": { "type": "string", "enum": ["OKP"] }, + "alg": { "type": "string", "enum": ["EdDSA"] }, "crv": { "type": "string", "enum": ["Ed25519"] }, "x": { "type": "string" }, "d": { "type": "string" } @@ -5654,7 +5687,17 @@ { "type": "object", "properties": { + "kid": { "type": "string", "format": "uuid" }, + "use": { "type": "string", "enum": ["sig"] }, + "key_ops": { + "type": "array", + "items": { "type": "string", "enum": ["sign", "verify"] }, + "minItems": 2, + "maxItems": 2 + }, + "ext": { "type": "boolean", "enum": [true] }, "kty": { "type": "string", "enum": ["oct"] }, + "alg": { "type": "string", "enum": ["HS256"] }, "k": { "type": "string", "minLength": 16 } }, "required": ["kty", "k"], diff --git a/apps/docs/spec/transforms/api_v1_openapi_deparsed.json b/apps/docs/spec/transforms/api_v1_openapi_deparsed.json index 4001882bb25ae..2d2a2ccae8014 100644 --- a/apps/docs/spec/transforms/api_v1_openapi_deparsed.json +++ b/apps/docs/spec/transforms/api_v1_openapi_deparsed.json @@ -1134,7 +1134,7 @@ "description": "Resource indicator for MCP (Model Context Protocol) clients", "schema": { "type": "string", - "enum": ["https://api.supabase.io/mcp"] + "enum": ["https://api.supabase.com/mcp", "https://mcp.supabase.com/mcp"] } } ], @@ -1188,7 +1188,7 @@ }, "resource": { "type": "string", - "enum": ["https://api.supabase.io/mcp"], + "enum": ["https://api.supabase.com/mcp", "https://mcp.supabase.com/mcp"], "description": "Resource indicator for MCP (Model Context Protocol) clients" } }, @@ -5930,10 +5930,35 @@ { "type": "object", "properties": { + "kid": { + "type": "string", + "format": "uuid" + }, + "use": { + "type": "string", + "enum": ["sig"] + }, + "key_ops": { + "type": "array", + "items": { + "type": "string", + "enum": ["sign", "verify"] + }, + "minItems": 2, + "maxItems": 2 + }, + "ext": { + "type": "boolean", + "enum": [true] + }, "kty": { "type": "string", "enum": ["RSA"] }, + "alg": { + "type": "string", + "enum": ["RS256"] + }, "n": { "type": "string" }, @@ -5966,10 +5991,35 @@ { "type": "object", "properties": { + "kid": { + "type": "string", + "format": "uuid" + }, + "use": { + "type": "string", + "enum": ["sig"] + }, + "key_ops": { + "type": "array", + "items": { + "type": "string", + "enum": ["sign", "verify"] + }, + "minItems": 2, + "maxItems": 2 + }, + "ext": { + "type": "boolean", + "enum": [true] + }, "kty": { "type": "string", "enum": ["EC"] }, + "alg": { + "type": "string", + "enum": ["ES256"] + }, "crv": { "type": "string", "enum": ["P-256"] @@ -5990,10 +6040,35 @@ { "type": "object", "properties": { + "kid": { + "type": "string", + "format": "uuid" + }, + "use": { + "type": "string", + "enum": ["sig"] + }, + "key_ops": { + "type": "array", + "items": { + "type": "string", + "enum": ["sign", "verify"] + }, + "minItems": 2, + "maxItems": 2 + }, + "ext": { + "type": "boolean", + "enum": [true] + }, "kty": { "type": "string", "enum": ["OKP"] }, + "alg": { + "type": "string", + "enum": ["EdDSA"] + }, "crv": { "type": "string", "enum": ["Ed25519"] @@ -6011,10 +6086,35 @@ { "type": "object", "properties": { + "kid": { + "type": "string", + "format": "uuid" + }, + "use": { + "type": "string", + "enum": ["sig"] + }, + "key_ops": { + "type": "array", + "items": { + "type": "string", + "enum": ["sign", "verify"] + }, + "minItems": 2, + "maxItems": 2 + }, + "ext": { + "type": "boolean", + "enum": [true] + }, "kty": { "type": "string", "enum": ["oct"] }, + "alg": { + "type": "string", + "enum": ["HS256"] + }, "k": { "type": "string", "minLength": 16 @@ -15906,7 +16006,7 @@ }, "resource": { "type": "string", - "enum": ["https://api.supabase.io/mcp"], + "enum": ["https://api.supabase.com/mcp", "https://mcp.supabase.com/mcp"], "description": "Resource indicator for MCP (Model Context Protocol) clients" } }, @@ -17216,10 +17316,35 @@ { "type": "object", "properties": { + "kid": { + "type": "string", + "format": "uuid" + }, + "use": { + "type": "string", + "enum": ["sig"] + }, + "key_ops": { + "type": "array", + "items": { + "type": "string", + "enum": ["sign", "verify"] + }, + "minItems": 2, + "maxItems": 2 + }, + "ext": { + "type": "boolean", + "enum": [true] + }, "kty": { "type": "string", "enum": ["RSA"] }, + "alg": { + "type": "string", + "enum": ["RS256"] + }, "n": { "type": "string" }, @@ -17252,10 +17377,35 @@ { "type": "object", "properties": { + "kid": { + "type": "string", + "format": "uuid" + }, + "use": { + "type": "string", + "enum": ["sig"] + }, + "key_ops": { + "type": "array", + "items": { + "type": "string", + "enum": ["sign", "verify"] + }, + "minItems": 2, + "maxItems": 2 + }, + "ext": { + "type": "boolean", + "enum": [true] + }, "kty": { "type": "string", "enum": ["EC"] }, + "alg": { + "type": "string", + "enum": ["ES256"] + }, "crv": { "type": "string", "enum": ["P-256"] @@ -17276,10 +17426,35 @@ { "type": "object", "properties": { + "kid": { + "type": "string", + "format": "uuid" + }, + "use": { + "type": "string", + "enum": ["sig"] + }, + "key_ops": { + "type": "array", + "items": { + "type": "string", + "enum": ["sign", "verify"] + }, + "minItems": 2, + "maxItems": 2 + }, + "ext": { + "type": "boolean", + "enum": [true] + }, "kty": { "type": "string", "enum": ["OKP"] }, + "alg": { + "type": "string", + "enum": ["EdDSA"] + }, "crv": { "type": "string", "enum": ["Ed25519"] @@ -17297,10 +17472,35 @@ { "type": "object", "properties": { + "kid": { + "type": "string", + "format": "uuid" + }, + "use": { + "type": "string", + "enum": ["sig"] + }, + "key_ops": { + "type": "array", + "items": { + "type": "string", + "enum": ["sign", "verify"] + }, + "minItems": 2, + "maxItems": 2 + }, + "ext": { + "type": "boolean", + "enum": [true] + }, "kty": { "type": "string", "enum": ["oct"] }, + "alg": { + "type": "string", + "enum": ["HS256"] + }, "k": { "type": "string", "minLength": 16 From 4978d24adc9e0165b9ef2f8971357814d672717c Mon Sep 17 00:00:00 2001 From: "kemal.earth" <606977+kemaldotearth@users.noreply.github.com> Date: Mon, 22 Sep 2025 16:43:52 +0100 Subject: [PATCH 9/9] feat(studio): update query pattern section in query details (#38876) * feat: basic toggle test * feat: first draft of query pattern revamp * style: small styling tweaks --- .../QueryPerformance/QueryDetail.tsx | 74 +++++++++++++------ .../QueryPerformance/QueryPanel.tsx | 2 +- 2 files changed, 53 insertions(+), 23 deletions(-) diff --git a/apps/studio/components/interfaces/QueryPerformance/QueryDetail.tsx b/apps/studio/components/interfaces/QueryPerformance/QueryDetail.tsx index b792220b71449..78f7b8291285e 100644 --- a/apps/studio/components/interfaces/QueryPerformance/QueryDetail.tsx +++ b/apps/studio/components/interfaces/QueryPerformance/QueryDetail.tsx @@ -1,10 +1,11 @@ -import { Lightbulb } from 'lucide-react' +import { Lightbulb, ChevronsUpDown, Expand } from 'lucide-react' import { useEffect, useState } from 'react' import dynamic from 'next/dynamic' import dayjs from 'dayjs' import { formatSql } from 'lib/formatSql' import { AlertDescription_Shadcn_, AlertTitle_Shadcn_, Alert_Shadcn_, Button, cn } from 'ui' +import { ButtonTooltip } from 'components/ui/ButtonTooltip' import { QueryPanelContainer, QueryPanelSection } from './QueryPanel' import { QUERY_PERFORMANCE_COLUMNS, @@ -38,6 +39,8 @@ export const QueryDetail = ({ selectedRow, onClickViewSuggestion }: QueryDetailP } }, [selectedRow]) + const [isExpanded, setIsExpanded] = useState(false) + const formatDuration = (seconds: number) => { const dur = dayjs.duration(seconds, 'seconds') @@ -56,29 +59,56 @@ export const QueryDetail = ({ selectedRow, onClickViewSuggestion }: QueryDetailP return ( - -

    Query pattern

    - - {isLinterWarning && ( - +

    Query pattern

    +
    + + {isLinterWarning && ( + + + Suggested optimization: Add an index + + Adding an index will help this query execute faster + + + + + + )} +
    +
    +
    + - - - )} + {isExpanded ? 'Collapse' : 'Expand'} + +
    -
    - +

    Metadata

      {report diff --git a/apps/studio/components/interfaces/QueryPerformance/QueryPanel.tsx b/apps/studio/components/interfaces/QueryPerformance/QueryPanel.tsx index c4748326ad41c..57c33a87f5910 100644 --- a/apps/studio/components/interfaces/QueryPerformance/QueryPanel.tsx +++ b/apps/studio/components/interfaces/QueryPerformance/QueryPanel.tsx @@ -7,7 +7,7 @@ export const QueryPanelContainer = ({ children, className, }: PropsWithChildren<{ className?: string }>) => ( -
      {children}
      +
      {children}
      ) export const QueryPanelSection = ({