fix: protect csv import (#47040)

## TL;DR 
fixes protected schema empty tables still exposing CSV import actions in
table editor...
## ref: 
- closes https://github.com/supabase/supabase/issues/41358
- supersedes: https://github.com/supabase/supabase/pull/41362
<!-- This is an auto-generated comment: release notes by coderabbit.ai
-->
## Summary by CodeRabbit

* **Bug Fixes**
* Updated the table empty state so CSV import actions are shown only
when the table is allowed to accept imports, and are hidden for
protected cases (including foreign-table scenarios).

* **Tests**
* Added an end-to-end test confirming that empty tables in protected
schemas do not expose the “Import data from CSV” button or the
drag-and-drop CSV hint.
<!-- end of auto-generated comment: release notes by coderabbit.ai -->
This commit is contained in:
Vaibhav authored and GitHub committed 2026-06-18 15:43:46 +01:00
1 parent cedc4c8187
commit 84edf0dc94
2 files changed
+36 -5

No files matched your search

@@ -89,11 +89,12 @@ export const Grid = memo(
const tableEntityType = snap.originalTable?.entity_type
const isForeignTable = tableEntityType === ENTITY_TYPE.FOREIGN_TABLE
const isTableEmpty = (rows ?? []).length === 0
const canImportData = snap.editable && !isForeignTable
const track = useTrack()
const { isDraggedOver, onDragOver, onFileDrop } = useCsvFileDrop({
enabled: isTableEmpty && !isForeignTable,
enabled: isTableEmpty && canImportData,
onFileDropped: (file) => tableEditorSnap.onImportData(valtioRef(file)),
onTelemetryEvent: (eventName) => track(eventName),
})
@@ -322,7 +323,7 @@ export const Grid = memo(
started.
</p>
</div>
) : (
) : canImportData ? (
<div className="flex flex-col items-center gap-4 mt-4">
<Button
variant="default"
@@ -338,7 +339,7 @@ export const Grid = memo(
or drag and drop a CSV file here
</p>
</div>
)}
) : null}
</div>
) : (
<div className="flex flex-col items-center justify-center">
+32 -2
View File
@@ -1,7 +1,5 @@
import fs from 'fs'
import path from 'path'
import { expect, Page } from '@playwright/test'
import { env } from '../env.config.js'
import { expectClipboardValue } from '../utils/clipboard.js'
import { dropTable, query } from '../utils/db/index.js'
@@ -16,6 +14,7 @@ import {
waitForGridDataToLoad,
waitForTableToLoad,
} from '../utils/wait-for-response.js'
import { expect, Page } from '@playwright/test'
const deleteTable = async (page: Page, ref: string, tableName: string) => {
const viewLocator = page.getByLabel(`View ${tableName}`)
@@ -155,6 +154,37 @@ testRunner('table editor', () => {
await expect(page.getByLabel(`View ${authTableMfa}`)).toBeVisible()
})
test('protected schema empty tables do not expose CSV import actions', async ({ page, ref }) => {
const emptyAuthTables = await query<{ relname: string }>(`
select relname
from pg_stat_user_tables
where schemaname = 'auth'
and n_live_tup = 0
and relname <> 'schema_migrations'
order by relname
limit 1;
`)
test.skip(emptyAuthTables.length === 0, 'Requires an empty auth table in the test dataset')
const [{ relname: tableName }] = emptyAuthTables
await page.goto(toUrl(`/project/${ref}/editor?schema=public`))
await page.getByTestId('schema-selector').click()
await page.getByPlaceholder('Find schema...').fill('auth')
const tableLoadPromise = waitForTableToLoad(page, ref, 'auth')
await page.getByRole('option', { name: 'auth' }).click()
await tableLoadPromise
await expect(page.getByRole('button', { name: `View ${tableName}`, exact: true })).toBeVisible()
await page.getByRole('button', { name: `View ${tableName}`, exact: true }).click()
await page.waitForURL(/\/editor\/\d+\?schema=auth$/)
await expect(page.getByText('This table is empty')).toBeVisible()
await expect(page.getByRole('button', { name: 'Import data from CSV' })).not.toBeVisible()
await expect(page.getByText('or drag and drop a CSV file here')).not.toBeVisible()
})
test('should show rls accordingly', async ({ page, ref }) => {
const tableNameRlsEnabled = 'pw_table_rls_enabled'
const tableNameRlsDisabled = 'pw_table_rls_disabled'