chore(studio): remove feature flag for dataApiExposedBadge (#42563)

Cleanup / chore — removing a feature flag that has been at 100% rollout
with no issues.

## What is the current behavior?

The `dataApiExposedBadge` feature flag is checked at runtime via
ConfigCat, even though it has been set to 100% for a while with no
issues.

## What is the new behavior?

The feature flag check is removed and the gated behavior is now
unconditionally enabled. A reminder has been set to delete the flag from
ConfigCat in a month.

## Summary by CodeRabbit

**Refactor**
* Simplified API access status indicators in the studio editor, ensuring
security-related tooltips now display consistently based on actual
access conditions.
* Updated component interfaces and consolidated internal hook
dependencies for improved code maintainability and organization.
This commit is contained in:
Charis authored and GitHub committed 2026-02-10 21:18:53 +00:00
1 parent c39747f8b2
commit 6b805289c7
3 files changed
+40 -40

No files matched your search

@@ -1,31 +1,13 @@
import { useFlag, useParams } from 'common'
import { buildTableEditorUrl } from 'components/grid/SupabaseGrid.utils'
import { useTableFilter } from 'components/grid/hooks/useTableFilter'
import { getEntityLintDetails } from 'components/interfaces/TableGridEditor/TableEntity.utils'
import { EntityTypeIcon } from 'components/ui/EntityTypeIcon'
import { InlineLink } from 'components/ui/InlineLink'
import { getTableDefinition } from 'data/database/table-definition-query'
import { ENTITY_TYPE } from 'data/entity-types/entity-type-constants'
import { Entity } from 'data/entity-types/entity-types-infinite-query'
import { useProjectLintsQuery } from 'data/lint/lint-query'
import { EditorTablePageLink } from 'data/prefetchers/project.$ref.editor.$id'
import type { TableApiAccessData, TableApiAccessMap } from 'data/privileges/table-api-access-query'
import { useTableRowsCountQuery } from 'data/table-rows/table-rows-count-query'
import { useQuerySchemaState } from 'hooks/misc/useSchemaQueryState'
import { useSelectedProjectQuery } from 'hooks/misc/useSelectedProject'
import { useParams } from 'common'
import { Copy, Download, Edit, Globe, Lock, MoreVertical, Trash } from 'lucide-react'
import Link from 'next/link'
import { type CSSProperties } from 'react'
import { toast } from 'sonner'
import {
type RoleImpersonationState,
useRoleImpersonationStateSnapshot,
} from 'state/role-impersonation-state'
import { useTableEditorStateSnapshot } from 'state/table-editor'
import { createTabId, useTabsStateSnapshot } from 'state/tabs'
import {
Badge,
Button,
cn,
copyToClipboard,
DropdownMenu,
DropdownMenuContent,
DropdownMenuItem,
@@ -38,12 +20,33 @@ import {
TooltipContent,
TooltipTrigger,
TreeViewItemVariant,
cn,
copyToClipboard,
} from 'ui'
import { useExportAllRowsAsCsv, useExportAllRowsAsSql } from './ExportAllRows'
import { useTableFilter } from '@/components/grid/hooks/useTableFilter'
import { buildTableEditorUrl } from '@/components/grid/SupabaseGrid.utils'
import { getEntityLintDetails } from '@/components/interfaces/TableGridEditor/TableEntity.utils'
import { EntityTypeIcon } from '@/components/ui/EntityTypeIcon'
import { InlineLink } from '@/components/ui/InlineLink'
import { getTableDefinition } from '@/data/database/table-definition-query'
import { ENTITY_TYPE } from '@/data/entity-types/entity-type-constants'
import { Entity } from '@/data/entity-types/entity-types-infinite-query'
import { useProjectLintsQuery } from '@/data/lint/lint-query'
import { EditorTablePageLink } from '@/data/prefetchers/project.$ref.editor.$id'
import type {
TableApiAccessData,
TableApiAccessMap,
} from '@/data/privileges/table-api-access-query'
import { useTableRowsCountQuery } from '@/data/table-rows/table-rows-count-query'
import { useQuerySchemaState } from '@/hooks/misc/useSchemaQueryState'
import { useSelectedProjectQuery } from '@/hooks/misc/useSelectedProject'
import { formatSql } from '@/lib/formatSql'
import {
useRoleImpersonationStateSnapshot,
type RoleImpersonationState,
} from '@/state/role-impersonation-state'
import { useTableEditorStateSnapshot } from '@/state/table-editor'
import { createTabId, useTabsStateSnapshot } from '@/state/tabs'
export interface EntityListItemProps {
id: number | string
@@ -79,7 +82,6 @@ export const EntityListItem = ({
const tabs = useTabsStateSnapshot()
const isPreview = tabs.previewTabId === tabId
const isOpened = Object.values(tabs.tabsMap).some((tab) => tab.metadata?.tableId === entity.id)
const isActive = Number(id) === entity.id
const canEdit = isActive && !isLocked
@@ -405,7 +407,6 @@ const EntityTooltipTrigger = ({
apiAccessData?: TableApiAccessData
}) => {
const { ref } = useParams()
const isDataApiExposedBadgeEnabled = useFlag('dataApiExposedBadge')
let tooltipContent = null
const accessWarning = 'Data is publicly accessible via API'
@@ -476,7 +477,7 @@ const EntityTooltipTrigger = ({
entity.type === ENTITY_TYPE.TABLE &&
apiAccessData?.apiAccessType === 'access' &&
tableHasRlsEnabledNoPolicyLint
if (isDataApiExposedBadgeEnabled && isRlsEnabledNoPolicies) {
if (isRlsEnabledNoPolicies) {
return (
<Tooltip>
<TooltipTrigger className="min-w-4" aria-label="Table exposed via Data API">
@@ -492,7 +493,7 @@ const EntityTooltipTrigger = ({
const isApiExposedWithRlsAndPolicies =
apiAccessData?.apiAccessType === 'access' && !tableHasRlsEnabledNoPolicyLint
if (isDataApiExposedBadgeEnabled && isApiExposedWithRlsAndPolicies) {
if (isApiExposedWithRlsAndPolicies) {
return (
<Tooltip>
<TooltipTrigger className="min-w-4" aria-label="Table exposed via Data API">
@@ -1,6 +1,5 @@
import { useFlag } from 'common'
import { IS_TEST_ENV } from 'lib/constants'
import { usePHFlag } from '../ui/useFlag'
import { IS_TEST_ENV } from '@/lib/constants'
/**
* Determine whether a user has access to Data API grant toggles.
@@ -12,7 +11,6 @@ import { usePHFlag } from '../ui/useFlag'
* without requiring the feature flag infrastructure.
*/
export const useDataApiGrantTogglesEnabled = (): boolean => {
const isDataApiBadgesEnabled = useFlag('dataApiExposedBadge')
const isTableEditorApiAccessEnabled = usePHFlag<boolean>('tableEditorApiAccessToggle')
// In test environment, enable the feature for E2E testing
@@ -20,5 +18,5 @@ export const useDataApiGrantTogglesEnabled = (): boolean => {
return true
}
return isDataApiBadgesEnabled && !!isTableEditorApiAccessEnabled
return !!isTableEditorApiAccessEnabled
}
+10 -9
View File
@@ -1,8 +1,9 @@
import { expect, Page } from '@playwright/test'
import fs from 'fs'
import path from 'path'
import { createTable as dbCreateTable, dropTable } from '../utils/db/index.js'
import { expect, Page } from '@playwright/test'
import { env } from '../env.config.js'
import { createTable as dbCreateTable, dropTable } from '../utils/db/index.js'
import { releaseFileOnceCleanup, withFileOnceSetup } from '../utils/once-per-file.js'
import { resetLocalStorage } from '../utils/reset-local-storage.js'
import { test } from '../utils/test.js'
@@ -165,7 +166,7 @@ testRunner('table editor', () => {
await page
.getByRole('button', { name: `View ${tableNameActions}`, exact: true })
.getByRole('button')
.nth(1)
.nth(2)
.click()
await page.getByRole('menuitem', { name: 'Copy name' }).click()
await page.waitForTimeout(500)
@@ -176,7 +177,7 @@ testRunner('table editor', () => {
await page
.getByRole('button', { name: `View ${tableNameActions}`, exact: true })
.getByRole('button')
.nth(1)
.nth(2)
.click()
await page.getByRole('menuitem', { name: 'Copy table schema' }).click()
await waitForApiResponse(page, 'pg-meta', ref, 'query?key=table-definition-') // wait for endpoint to generate schema
@@ -193,7 +194,7 @@ testRunner('table editor', () => {
await page
.getByRole('button', { name: `View ${tableNameActions}`, exact: true })
.getByRole('button')
.nth(1)
.nth(2)
.click()
await page.getByRole('menuitem', { name: 'Duplicate table' }).click()
await page.getByRole('button', { name: 'Save' }).click()
@@ -367,7 +368,7 @@ testRunner('table editor', () => {
await page
.getByRole('button', { name: `View ${tableNameGridEditor}`, exact: true })
.getByRole('button')
.nth(1)
.nth(2)
.click()
await page.getByRole('menuitem', { name: 'Edit table' }).click()
await page.getByTestId('table-name-input').fill(tableNameUpdated)
@@ -386,7 +387,7 @@ testRunner('table editor', () => {
await page
.getByRole('button', { name: `View ${tableNameUpdated}`, exact: true })
.getByRole('button')
.nth(1)
.nth(2)
.click()
// Open nested export submenu via keyboard (more stable than hover in headless)
const exportDataItemCsv = page.getByRole('menuitem', { name: 'Export data' })
@@ -425,7 +426,7 @@ testRunner('table editor', () => {
await page
.getByRole('button', { name: `View ${tableNameUpdated}`, exact: true })
.getByRole('button')
.nth(1)
.nth(2)
.click()
// Open nested export submenu via keyboard (more stable than hover in headless)
const exportDataItemSql = page.getByRole('menuitem', { name: 'Export data' })
@@ -459,7 +460,7 @@ testRunner('table editor', () => {
await page
.getByRole('button', { name: `View ${tableNameUpdated}`, exact: true })
.getByRole('button')
.nth(1)
.nth(2)
.click()
const exportDataItemCli = page.getByRole('menuitem', { name: 'Export data' })