Files
supabase/apps/studio/hooks/ui/useCsvFileDrop.ts
Pamela Chia dc5ddd8c4c chore(telemetry): align event interface names with action strings (#47048)
## Summary

Aligns 16 telemetry event interface identifiers in
`packages/common/telemetry-constants.ts` so each interface name equals
the PascalCase of its `action` string (`PascalCase(action) + Event`).
This is a follow-up to the GROWTH-798 audit (#45964), which fixed the
`action` strings and several interface names but left these 16
identifiers mismatched. I renamed identifiers only: every `action`
string is untouched, so there is zero impact on PostHog event names or
historical data.

Before this change, 176/192 interfaces matched the convention. This
brings it to 192/192.

## Changes

Structural renames (interface name was dropping or reordering words vs
the action):
- `AskAIEvent` to `AskAiClickedEvent`
- `CopyAsMarkdownEvent` to `CopyAsMarkdownClickedEvent`
- `DocsRecommendation404ClickedEvent` to
`Docs404RecommendationClickedEvent` (from #46990)
- `EventPageCtaClickedEvent` to `WwwEventPageCtaClickedEvent` (completes
the interface side of GROWTH-798 HIGH #1)
- `ImportDataFileAddedEvent` to `ImportDataDropzoneFileAddedEvent` (also
updates the consumer `apps/studio/hooks/ui/useCsvFileDrop.ts`)
- `QueryPerformanceAIExplanationButtonClickedEvent` to
`QueryPerformanceExplainWithAiButtonClickedEvent`

Initialism casing (normalized to the file-majority lowercase transform;
`Sql` 9:2, `Api` 3:2, `Ai` 6:2):
- `CustomReportAddSQLBlockClickedEvent` to
`CustomReportAddSqlBlockClickedEvent`
- `CustomReportAssistantSQLBlockAddedEvent` to
`CustomReportAssistantSqlBlockAddedEvent`
- `HomepageGitHubButtonClickedEvent` to
`HomepageGithubButtonClickedEvent`
- `MetricsAPIBannerCtaButtonClickedEvent` to
`MetricsApiBannerCtaButtonClickedEvent`
- `MetricsAPIBannerDismissButtonClickedEvent` to
`MetricsApiBannerDismissButtonClickedEvent`
- `TableRLSEnabledEvent` to `TableRlsEnabledEvent`
- `RLSGeneratePoliciesClickedEvent` to `RlsGeneratePoliciesClickedEvent`
- `RLSGeneratedPolicyRemovedEvent` to `RlsGeneratedPolicyRemovedEvent`
- `RLSGeneratedPoliciesCreatedEvent` to
`RlsGeneratedPoliciesCreatedEvent`
- `RLSTesterRunQueryClickedEvent` to `RlsTesterRunQueryClickedEvent`

## Testing

Type-only change, no runtime or PostHog behavior to exercise. Verified
that all 192 interfaces now match `PascalCase(action) + Event` (0
mismatches), the `TelemetryEvent` union has no duplicates, no old
identifier names remain anywhere in the repo, and the one external
consumer (`useCsvFileDrop.ts`) still resolves via its `['action']`
indexed access since the action strings are unchanged.

## Linear

- fixes GROWTH-928


<!-- This is an auto-generated comment: release notes by coderabbit.ai
-->

## Summary by CodeRabbit

* **Chores**
* Updated internal telemetry infrastructure for consistency and
maintainability.

<!-- end of auto-generated comment: release notes by coderabbit.ai -->
2026-06-17 23:31:03 +08:00

72 lines
1.9 KiB
TypeScript

import { type ImportDataDropzoneFileAddedEvent } from 'common/telemetry-constants'
import { useCallback, useState, type DragEvent } from 'react'
import { flagInvalidFileImport } from '@/components/interfaces/TableGridEditor/SidePanelEditor/SpreadsheetImport/SpreadsheetImport.utils'
interface UseCsvFileDropOptions {
enabled: boolean
onFileDropped: (file: File) => void
onTelemetryEvent?: (eventName: ImportDataDropzoneFileAddedEvent['action']) => void
}
interface UseCsvFileDropReturn {
isDraggedOver: boolean
onDragOver: (event: DragEvent<HTMLDivElement>) => void
onFileDrop: (event: DragEvent<HTMLDivElement>) => void
}
export function useCsvFileDrop({
enabled,
onFileDropped,
onTelemetryEvent,
}: UseCsvFileDropOptions): UseCsvFileDropReturn {
const [isDraggedOver, setIsDraggedOver] = useState(false)
const onDragOver = useCallback(
(event: DragEvent<HTMLDivElement>) => {
if (!enabled) return
const [item] = event.dataTransfer.items
// ignore non files drop, like column headers
if (item && item.kind !== 'file') return
if (event.type === 'dragover' && !isDraggedOver) {
setIsDraggedOver(true)
} else if (event.type === 'dragleave' || event.type === 'drop') {
setIsDraggedOver(false)
}
event.stopPropagation()
event.preventDefault()
},
[enabled, isDraggedOver]
)
const onFileDrop = useCallback(
(event: DragEvent<HTMLDivElement>) => {
if (!enabled) return
onDragOver(event)
const [file] = event.dataTransfer.files
const [item] = event.dataTransfer.items
// ignore non files drop, like column headers
if (item && item.kind !== 'file') return
if (flagInvalidFileImport(file)) return
onFileDropped(file)
onTelemetryEvent?.('import_data_dropzone_file_added')
},
[enabled, onDragOver, onFileDropped, onTelemetryEvent]
)
return {
isDraggedOver,
onDragOver,
onFileDrop,
}
}