diff --git a/apps/studio/components/interfaces/Auth/AuthProvidersForm/ProviderForm.tsx b/apps/studio/components/interfaces/Auth/AuthProvidersForm/ProviderForm.tsx index 32ddff87b3550..daf0e8bbe13e4 100644 --- a/apps/studio/components/interfaces/Auth/AuthProvidersForm/ProviderForm.tsx +++ b/apps/studio/components/interfaces/Auth/AuthProvidersForm/ProviderForm.tsx @@ -1,10 +1,10 @@ import { PermissionAction } from '@supabase/shared-types/out/constants' import { Check } from 'lucide-react' +import { useTheme } from 'next-themes' import { useQueryState } from 'nuqs' import { useEffect, useState } from 'react' import ReactMarkdown from 'react-markdown' import { toast } from 'sonner' -import { useTheme } from 'next-themes' import { useParams } from 'common' import { Markdown } from 'components/interfaces/Markdown' @@ -214,6 +214,10 @@ export const ProviderForm = ({ config, provider, isActive }: ProviderFormProps) : description, } const isDisabledDueToPlan = properties.isPaid && isFreePlan + const shouldDisable = + properties.type === 'boolean' + ? isDisabledDueToPlan && !values[x] + : isDisabledDueToPlan return ( ) })} diff --git a/apps/studio/components/interfaces/Auth/Policies/Policies.utils.test.ts b/apps/studio/components/interfaces/Auth/Policies/Policies.utils.test.ts index 25cebe323bb27..a271cbba20896 100644 --- a/apps/studio/components/interfaces/Auth/Policies/Policies.utils.test.ts +++ b/apps/studio/components/interfaces/Auth/Policies/Policies.utils.test.ts @@ -156,7 +156,7 @@ describe('Policies.utils - Policy Generation', () => { expect(policy).toHaveProperty('schema', 'public') expect(policy).toHaveProperty('action', 'PERMISSIVE') expect(policy).toHaveProperty('roles') - expect(policy.roles).toContain('public') + expect(policy.roles).toContain('authenticated') } }) @@ -214,7 +214,7 @@ describe('Policies.utils - Policy Generation', () => { expect(selectPolicy?.sql).toContain('CREATE POLICY') expect(selectPolicy?.sql).toContain('public.posts') expect(selectPolicy?.sql).toContain('AS PERMISSIVE FOR SELECT') - expect(selectPolicy?.sql).toContain('TO public') + expect(selectPolicy?.sql).toContain('TO authenticated') expect(selectPolicy?.sql).toContain('USING') expect(selectPolicy?.sql).toContain('auth.uid()') }) diff --git a/apps/studio/components/interfaces/Auth/Policies/Policies.utils.ts b/apps/studio/components/interfaces/Auth/Policies/Policies.utils.ts index 128668a8d7109..c741b45ab0755 100644 --- a/apps/studio/components/interfaces/Auth/Policies/Policies.utils.ts +++ b/apps/studio/components/interfaces/Auth/Policies/Policies.utils.ts @@ -316,7 +316,7 @@ const buildPoliciesForPath = ( return (['SELECT', 'INSERT', 'UPDATE', 'DELETE'] as const).map((command) => { const name = `Enable ${command.toLowerCase()} access for users based on ${ident(targetCol)}` - const base = `CREATE POLICY "${name}" ON ${ident(table.schema)}.${ident(table.name)} AS PERMISSIVE FOR ${command} TO public` + const base = `CREATE POLICY "${name}" ON ${ident(table.schema)}.${ident(table.name)} AS PERMISSIVE FOR ${command} TO authenticated` const sql = command === 'INSERT' @@ -338,7 +338,7 @@ const buildPoliciesForPath = ( definition, check, action: 'PERMISSIVE' as const, - roles: ['public'], + roles: ['authenticated'], } }) } diff --git a/apps/studio/components/interfaces/TableGridEditor/SidePanelEditor/TableEditor/ApiAccessToggle.tsx b/apps/studio/components/interfaces/TableGridEditor/SidePanelEditor/TableEditor/ApiAccessToggle.tsx index 2357d328d357d..b70de35f06d30 100644 --- a/apps/studio/components/interfaces/TableGridEditor/SidePanelEditor/TableEditor/ApiAccessToggle.tsx +++ b/apps/studio/components/interfaces/TableGridEditor/SidePanelEditor/TableEditor/ApiAccessToggle.tsx @@ -319,9 +319,10 @@ export const ApiAccessToggle = ({

Data API Access - This controls which operations the anon and{' '} - authenticated roles can perform on this table via - the Data API. Unselected privileges are revoked from these roles. + This controls which operations the anon{' '} + and authenticated roles + can perform on this table via the Data API. Unselected privileges are revoked from + these roles.

diff --git a/apps/www/data/solutions/convex.tsx b/apps/www/data/solutions/convex.tsx index e31d496a3682a..6ead8869eb81a 100644 --- a/apps/www/data/solutions/convex.tsx +++ b/apps/www/data/solutions/convex.tsx @@ -11,6 +11,9 @@ import { Code2, Check, InfoIcon, + TrendingUp, + Puzzle, + DollarSign, } from 'lucide-react' import RealtimeLogs from 'components/Products/Functions/RealtimeLogs' @@ -90,9 +93,23 @@ const data = { { id: 'postgres-first', icon: Database, - heading: 'A proven Postgres foundation', + heading: "It's just Postgres", subheading: - "Real Postgres means real scale. Start small and grow to millions of users on the same database that powers the world's most demanding applications. Use any SQL client, ORM, or database tool. Connect with pgAdmin, Postico, DBeaver, or your favorite tool. Tap into the most popular Postgres extensions, including: PostGIS for geospatial, pgvector for AI, and more. No proprietary query language. No artificial limits. Just standard SQL that works everywhere.", + "Familiar SQL, familiar model, proven platform. No proprietary query language. No artificial limits. Just standard SQL that works everywhere. Postgres powers the world's most demanding applications, and you get the same battle-tested database.", + }, + { + id: 'scale-to-millions', + icon: TrendingUp, + heading: 'Scale to millions', + subheading: + 'Real Postgres means real scale. Start small and grow to millions of users on the same database. Postgres handles everything from startups to enterprise workloads with proven scalability. Your database grows with you, no migrations needed.', + }, + { + id: 'powerful-ecosystem', + icon: Puzzle, + heading: 'A powerful ecosystem', + subheading: + 'Connect with pgAdmin, Postico, DBeaver, or your favorite tool. Use any SQL client, ORM, or database tool. Tap into the most popular Postgres extensions, including: PostGIS for geospatial, pgvector for AI, and more. The entire Postgres ecosystem is at your fingertips.', }, { id: 'complete-stack', @@ -124,7 +141,7 @@ const data = { }, { id: 'predictable-pricing', - icon: Lock, + icon: DollarSign, heading: 'Fair, predictable pricing', subheading: "Supabase charges for what you use, not how your data syncs. No surprise bandwidth bills from real-time subscriptions. No per-function-call pricing that explodes with traffic. Postgres connection pooling means efficient resource usage at any scale. Know what you'll pay before you ship.", diff --git a/packages/ui-patterns/src/FilterBar/FilterBarContext.tsx b/packages/ui-patterns/src/FilterBar/FilterBarContext.tsx index e17ba0f0d68ba..3209976d6f01f 100644 --- a/packages/ui-patterns/src/FilterBar/FilterBarContext.tsx +++ b/packages/ui-patterns/src/FilterBar/FilterBarContext.tsx @@ -42,7 +42,10 @@ export type FilterBarContextValue = { handleLogicalOperatorChange: (path: number[]) => void // Options cache - propertyOptionsCache: Record + propertyOptionsCache: Record< + string, + { options: (string | FilterOptionObject)[]; searchValue: string } + > loadingOptions: Record loadPropertyOptions: (property: FilterProperty, search: string) => void optionsError: string | null diff --git a/packages/ui-patterns/src/FilterBar/menuItems.ts b/packages/ui-patterns/src/FilterBar/menuItems.ts index aed549c0f0d1e..85d3d67e66212 100644 --- a/packages/ui-patterns/src/FilterBar/menuItems.ts +++ b/packages/ui-patterns/src/FilterBar/menuItems.ts @@ -1,6 +1,11 @@ import { ActiveInput } from './hooks' import { FilterBarAction, FilterGroup, FilterProperty } from './types' -import { findConditionByPath, isCustomOptionObject, isFilterOptionObject, isFilterOperatorObject } from './utils' +import { + findConditionByPath, + isCustomOptionObject, + isFilterOptionObject, + isFilterOperatorObject, +} from './utils' export type MenuItem = { value: string diff --git a/packages/ui-patterns/src/FilterBar/types.ts b/packages/ui-patterns/src/FilterBar/types.ts index 37c5102cf6e03..73d2b58e9db62 100644 --- a/packages/ui-patterns/src/FilterBar/types.ts +++ b/packages/ui-patterns/src/FilterBar/types.ts @@ -61,7 +61,10 @@ export type FilterBarAction = { ) => void | Promise } -export type SerializableFilterProperty = Pick & { +export type SerializableFilterProperty = Pick< + FilterProperty, + 'label' | 'name' | 'type' | 'operators' +> & { options?: string[] } diff --git a/packages/ui-patterns/src/FilterBar/useKeyboardNavigation.ts b/packages/ui-patterns/src/FilterBar/useKeyboardNavigation.ts index a18d0231639f0..2e50b9ecbb1b4 100644 --- a/packages/ui-patterns/src/FilterBar/useKeyboardNavigation.ts +++ b/packages/ui-patterns/src/FilterBar/useKeyboardNavigation.ts @@ -246,7 +246,13 @@ export function useKeyboardNavigation({ } } }, - [activeInput, activeFilters, findFirstConditionInGroup, findNextConditionFromGroup, setActiveInput] + [ + activeInput, + activeFilters, + findFirstConditionInGroup, + findNextConditionFromGroup, + setActiveInput, + ] ) const handleKeyDown = useCallback( diff --git a/packages/ui-patterns/src/FilterBar/utils.ts b/packages/ui-patterns/src/FilterBar/utils.ts index 709bd6ef1171e..62f8253562cab 100644 --- a/packages/ui-patterns/src/FilterBar/utils.ts +++ b/packages/ui-patterns/src/FilterBar/utils.ts @@ -59,7 +59,9 @@ export function isFilterOptionObject(option: any): option is FilterOptionObject } export function isFilterOperatorObject(operator: any): operator is FilterOperatorObject { - return typeof operator === 'object' && operator !== null && 'value' in operator && 'label' in operator + return ( + typeof operator === 'object' && operator !== null && 'value' in operator && 'label' in operator + ) } export function isAsyncOptionsFunction( @@ -132,7 +134,9 @@ export function addFilterToGroup( ): FilterGroup { if (path.length === 0) { const firstOperator = property.operators?.[0] || '=' - const operatorValue = isFilterOperatorObject(firstOperator) ? firstOperator.value : firstOperator + const operatorValue = isFilterOperatorObject(firstOperator) + ? firstOperator.value + : firstOperator return { ...group,