mirror of
https://github.com/supabase/supabase.git
synced 2026-10-05 17:35:10 +03:00
## Context There's an issue with copying / exporting rows from the table editor with the following conditions: - Row has a column value that exceeds 10,240 and hence is truncated for performance reasons <img width="300" alt="image" src="https://github.com/user-attachments/assets/4639edbb-ece6-4028-89b6-769ac314c3f3" /> - User is trying to copy/export selected rows (not all rows in the table) <img width="300" alt="image" src="https://github.com/user-attachments/assets/e7c0da77-051c-4c46-af0d-f9510e0b37c4" /> The copy/export action will return the truncated data which is incorrect (Should return the full data) ## Problem This is happening as if we're only copying/exporting selected rows, we're just using what's been loaded in the table editor to export (as opposed to if the user is copying/exporting all rows in the table, we'd be fetching the data from the database first before doing so) Hence am opting to add a data hydration logic, such that if there's a selected row that's been truncated, we'd fetch them on demand first before copying/exporting. There's limitations to this though - e.g if the table doesn't have a primary key we can't do this (since we need to run a query to fetch the data). This is already an existing behaviour when trying to load the column value in the table editor in the grid so no issues I believe. We'll just show this toast: <img width="300" alt="image" src="https://github.com/user-attachments/assets/442637bb-4b9b-492d-b202-bbf6e5ae7512" /> ## To test You'll need a column with a really large value - the way I do it is to load the data directly into the DB via TablePlus - [ ] Verify that copying / exporting selected rows with really large column values copies/exports all the data correctly (there shouldn't be any truncated value) <!-- This is an auto-generated comment: release notes by coderabbit.ai --> ## Summary by CodeRabbit * **New Features** * Improved handling of truncated cell values during copy and export operations * **Bug Fixes** * Copy and export operations now require an active project selection * Fixed data export for tables without primary keys * **Style** * Updated grid header copy and export control layout <!-- review_stack_entry_start --> [](https://app.coderabbit.ai/change-stack/supabase/supabase/pull/46268?utm_source=github_walkthrough&utm_medium=github&utm_campaign=change_stack) <!-- review_stack_entry_end --> <!-- end of auto-generated comment: release notes by coderabbit.ai -->
103 lines
3.1 KiB
TypeScript
103 lines
3.1 KiB
TypeScript
const normalizeCauseAsError = (cause: unknown): Error | undefined => {
|
|
if (!cause) return undefined
|
|
|
|
if (cause instanceof Error) {
|
|
return cause
|
|
}
|
|
|
|
if (typeof cause === 'object' && 'message' in cause) {
|
|
return new Error(String(cause.message))
|
|
}
|
|
|
|
return new Error(String(cause))
|
|
}
|
|
|
|
export class ExportAllRowsErrorFamily extends Error {
|
|
cause?: Error
|
|
|
|
constructor(message: string, options: { cause?: unknown } = {}) {
|
|
super(message, options)
|
|
}
|
|
}
|
|
|
|
export class NoConnectionStringError extends ExportAllRowsErrorFamily {
|
|
constructor() {
|
|
super('No connection string provided for database connection.')
|
|
this.name = 'NoConnectionStringError'
|
|
}
|
|
}
|
|
|
|
export class TableDetailsFetchError extends ExportAllRowsErrorFamily {
|
|
constructor(tableName: string, _cause?: unknown) {
|
|
const cause = normalizeCauseAsError(_cause)
|
|
super(`Failed to fetch table details from the database for table ${tableName}.`, { cause })
|
|
this.name = 'TableDetailsFetchError'
|
|
}
|
|
}
|
|
|
|
export class NoTableError extends ExportAllRowsErrorFamily {
|
|
constructor(tableName: string) {
|
|
super(`The specified table "${tableName}" does not exist in the database.`)
|
|
this.name = 'NoTableError'
|
|
}
|
|
}
|
|
|
|
export class NoRowsToExportError extends ExportAllRowsErrorFamily {
|
|
constructor(tableName: string) {
|
|
super(`There are no rows to export from the table "${tableName}".`)
|
|
this.name = 'NoRowsToExportError'
|
|
}
|
|
}
|
|
|
|
export class TableTooLargeError extends ExportAllRowsErrorFamily {
|
|
constructor(tableName: string, rowCount: number, maxAllowed: number) {
|
|
super(
|
|
`The table "${tableName}" has ${rowCount} rows, which exceeds the maximum allowed limit of ${maxAllowed} rows for export.`
|
|
)
|
|
this.name = 'TableTooLargeError'
|
|
}
|
|
}
|
|
|
|
export class FetchRowsError extends ExportAllRowsErrorFamily {
|
|
constructor(tableName: string, _cause?: unknown) {
|
|
const cause = normalizeCauseAsError(_cause)
|
|
super(`An error occurred while fetching rows from the table "${tableName}".`, { cause })
|
|
this.name = 'FetchRowsError'
|
|
}
|
|
}
|
|
|
|
export class OutputConversionError extends ExportAllRowsErrorFamily {
|
|
constructor(_cause?: unknown) {
|
|
const cause = normalizeCauseAsError(_cause)
|
|
super('Failed to convert the fetched rows into the desired output format.', {
|
|
cause,
|
|
})
|
|
this.name = 'OutputConversionError'
|
|
}
|
|
}
|
|
|
|
export class BlobCreationError extends ExportAllRowsErrorFamily {
|
|
constructor(_cause?: unknown) {
|
|
const cause = normalizeCauseAsError(_cause)
|
|
super('An error occurred while creating a Blob for the exported data.', { cause })
|
|
this.name = 'BlobCreationError'
|
|
}
|
|
}
|
|
|
|
export class DownloadSaveError extends ExportAllRowsErrorFamily {
|
|
constructor(_cause?: unknown) {
|
|
const cause = normalizeCauseAsError(_cause)
|
|
super('An error occurred while saving the exported data to a file.', { cause })
|
|
this.name = 'DownloadSaveError'
|
|
}
|
|
}
|
|
|
|
export class NoPrimaryKeyForTruncatedRowsError extends ExportAllRowsErrorFamily {
|
|
constructor(tableName: string) {
|
|
super(
|
|
`Cannot export rows with truncated values from "${tableName}" because the table has no primary key.`
|
|
)
|
|
this.name = 'NoPrimaryKeyForTruncatedRowsError'
|
|
}
|
|
}
|