Skip to content

Commit 4d31c85

Browse files
fix(studio): fix column drag in empty table triggers file drop behaviour (supabase#40189)
* fix: togling csv import only when draging files * stamp: improve invalid file feeback * stamp: format
1 parent 0ec1c38 commit 4d31c85

File tree

2 files changed

+40
-12
lines changed

2 files changed

+40
-12
lines changed

apps/studio/components/grid/components/grid/Grid.tsx

Lines changed: 24 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -80,7 +80,12 @@ export const Grid = memo(
8080

8181
const { mutate: sendEvent } = useSendEventMutation()
8282

83-
const { isDraggedOver, onDragOver, onFileDrop } = useCsvFileDrop({
83+
const {
84+
isValidFile: isValidFileDraggedOver,
85+
isDraggedOver,
86+
onDragOver,
87+
onFileDrop,
88+
} = useCsvFileDrop({
8489
enabled: isTableEmpty && !isForeignTable,
8590
onFileDropped: (file) => tableEditorSnap.onImportData(valtioRef(file)),
8691
onTelemetryEvent: (eventName) => {
@@ -133,21 +138,21 @@ export const Grid = memo(
133138

134139
return (
135140
<div
136-
className={cn(
137-
'flex flex-col relative transition-colors',
138-
containerClass,
139-
isTableEmpty && isDraggedOver && 'border-2 border-dashed border-brand-600'
140-
)}
141+
className={cn('flex flex-col relative transition-colors', containerClass)}
141142
style={{ width: width || '100%', height: height || '50vh' }}
142-
onDragOver={onDragOver}
143-
onDragLeave={onDragOver}
144-
onDrop={onFileDrop}
145143
>
146144
{/* Render no rows fallback outside of the DataGrid */}
147145
{(rows ?? []).length === 0 && (
148146
<div
147+
className={cn(
148+
'absolute top-9 p-2 w-full z-[1]',
149+
isTableEmpty && isDraggedOver && 'border-2 border-dashed',
150+
isValidFileDraggedOver ? 'border-brand-600' : 'border-destructive-600'
151+
)}
149152
style={{ height: `calc(100% - 35px)` }}
150-
className="absolute top-9 p-2 w-full z-[1] pointer-events-none"
153+
onDragOver={onDragOver}
154+
onDragLeave={onDragOver}
155+
onDrop={onFileDrop}
151156
>
152157
{isLoading && <GenericSkeletonLoader />}
153158

@@ -171,7 +176,15 @@ export const Grid = memo(
171176
) : (filters ?? []).length === 0 ? (
172177
<div className="flex flex-col items-center justify-center col-span-full h-full">
173178
<p className="text-sm text-light">
174-
{isDraggedOver ? 'Drop your CSV file here' : 'This table is empty'}
179+
{isDraggedOver ? (
180+
isValidFileDraggedOver ? (
181+
'Drop your CSV file here'
182+
) : (
183+
<span className="text-destructive">Only CSV files are accepted</span>
184+
)
185+
) : (
186+
'This table is empty'
187+
)}
175188
</p>
176189
{tableEntityType === ENTITY_TYPE.FOREIGN_TABLE ? (
177190
<div className="flex items-center space-x-2 mt-4">

apps/studio/hooks/ui/useCsvFileDrop.ts

Lines changed: 16 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@ interface UseCsvFileDropOptions {
1111

1212
interface UseCsvFileDropReturn {
1313
isDraggedOver: boolean
14+
isValidFile: boolean
1415
onDragOver: (event: DragEvent<HTMLDivElement>) => void
1516
onFileDrop: (event: DragEvent<HTMLDivElement>) => void
1617
}
@@ -21,20 +22,28 @@ export function useCsvFileDrop({
2122
onTelemetryEvent,
2223
}: UseCsvFileDropOptions): UseCsvFileDropReturn {
2324
const [isDraggedOver, setIsDraggedOver] = useState(false)
25+
const [isValidFile, setIsValidFile] = useState(false)
2426

2527
const onDragOver = useCallback(
2628
(event: DragEvent<HTMLDivElement>) => {
2729
if (!enabled) return
2830

31+
const [item] = event.dataTransfer.items
32+
33+
// ignore non files drop, like column headers
34+
if (item && item.kind !== 'file') return
35+
2936
if (event.type === 'dragover' && !isDraggedOver) {
3037
setIsDraggedOver(true)
38+
setIsValidFile(item.type === 'text/csv')
3139
} else if (event.type === 'dragleave' || event.type === 'drop') {
3240
setIsDraggedOver(false)
41+
setIsValidFile(false)
3342
}
3443
event.stopPropagation()
3544
event.preventDefault()
3645
},
37-
[enabled, isDraggedOver]
46+
[enabled, isDraggedOver, isValidFile]
3847
)
3948

4049
const onFileDrop = useCallback(
@@ -44,6 +53,11 @@ export function useCsvFileDrop({
4453
onDragOver(event)
4554

4655
const [file] = event.dataTransfer.files
56+
const [item] = event.dataTransfer.items
57+
58+
// ignore non files drop, like column headers
59+
if (item && item.kind !== 'file') return
60+
4761
if (flagInvalidFileImport(file)) return
4862

4963
onFileDropped(file)
@@ -54,6 +68,7 @@ export function useCsvFileDrop({
5468
)
5569

5670
return {
71+
isValidFile: isValidFile && isDraggedOver,
5772
isDraggedOver,
5873
onDragOver,
5974
onFileDrop,

0 commit comments

Comments
 (0)