diff --git a/apps/studio/components/grid/components/grid/Grid.tsx b/apps/studio/components/grid/components/grid/Grid.tsx
index 04cad32dd0b..d5ba2b094b7 100644
--- a/apps/studio/components/grid/components/grid/Grid.tsx
+++ b/apps/studio/components/grid/components/grid/Grid.tsx
@@ -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.
- ) : (
+ ) : canImportData ? (
- )}
+ ) : null}
) : (
diff --git a/e2e/studio/features/table-editor.spec.ts b/e2e/studio/features/table-editor.spec.ts
index e149f30fd3d..0d1688e34ca 100644
--- a/e2e/studio/features/table-editor.spec.ts
+++ b/e2e/studio/features/table-editor.spec.ts
@@ -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'