mirror of
https://github.com/supabase/supabase.git
synced 2026-10-05 17:35:10 +03:00
## Context Related to Explorer/Notebook - builds on the ExplorerQuerySourceMenu by adding an option for row limit in both Notebook Query cell + Query Tab ## Side note RE persistence of the selected row limit value Note that for QueryTab - its intentional that for now that the row limit isn't scoped to the query draft atm as I wanna avoid making changes to `explorer-query` atm as there's a couple of PRs in flux that touches that file. So will handle that separately ^ This means that switching between query tabs will not change nor persist the row limit <img width="931" height="335" alt="image" src="https://github.com/user-attachments/assets/d1d52ee7-7c1d-42aa-a6ae-1d7d99ab95c9" /> <img width="1381" height="486" alt="image" src="https://github.com/user-attachments/assets/689368c9-c0fc-4000-a09e-f59bfa7afa97" /> ## To test - [ ] Verify that row limit behaviour works in notebooks - [ ] Verify that row limit behaviour works in explorer query tab
143 lines
5.0 KiB
TypeScript
143 lines
5.0 KiB
TypeScript
import { useFlag, useParams } from 'common'
|
|
import { Check, ChevronDown } from 'lucide-react'
|
|
import {
|
|
Button,
|
|
DropdownMenu,
|
|
DropdownMenuContent,
|
|
DropdownMenuItem,
|
|
DropdownMenuSeparator,
|
|
DropdownMenuTrigger,
|
|
} from 'ui'
|
|
|
|
import { RowLimitSubMenu } from '../SQLEditor/UtilityPanel/QuerySourceMenu/RowLimitSubMenu'
|
|
import { DatabaseParametersSubMenu } from '@/components/interfaces/QuerySources/DatabaseParametersSubMenu'
|
|
import { LogsCustomRangeDialog } from '@/components/interfaces/QuerySources/LogsCustomRangeDialog'
|
|
import { LogsTimeRangeSubMenu } from '@/components/interfaces/QuerySources/LogsTimeRangeSubMenu'
|
|
import { QuerySourceIcon } from '@/components/interfaces/QuerySources/QuerySourceIcon'
|
|
import { useLogsCustomRange } from '@/components/interfaces/QuerySources/useLogsCustomRange'
|
|
import UpgradePrompt from '@/components/interfaces/Settings/Logs/UpgradePrompt'
|
|
import {
|
|
createDefaultSourceBinding,
|
|
QUERY_SOURCE_LABELS,
|
|
QUERY_SOURCES,
|
|
type QuerySourceBinding,
|
|
} from '@/data/query-sources/query-source-registry'
|
|
|
|
export type ExplorerQuerySourceMenuProps = {
|
|
rowLimit?: number
|
|
onRowLimitChange?: (val: number) => void
|
|
source: QuerySourceBinding
|
|
onSourceChange: (source: QuerySourceBinding) => void
|
|
}
|
|
|
|
/**
|
|
* Source binding and parameter controls shared by standalone Explorer queries
|
|
* and notebook query-cell toolbars. The consumer owns the binding; this menu
|
|
* only emits complete, validated-by-construction `QuerySourceBinding` values.
|
|
*
|
|
* Selecting a different backend emits that backend's default binding — deciding
|
|
* what happens to the query body is the consumer's call, since a notebook cell
|
|
* has SQL to preserve or discard and a fresh draft does not.
|
|
*/
|
|
export const ExplorerQuerySourceMenu = ({
|
|
rowLimit = 100,
|
|
onRowLimitChange,
|
|
source,
|
|
onSourceChange,
|
|
}: ExplorerQuerySourceMenuProps) => {
|
|
const { ref } = useParams()
|
|
const isLogsSourceEnabled = useFlag('sqlEditorLogsSource')
|
|
const isOtelLogsEnabled = useFlag('otelLegacyLogs')
|
|
const {
|
|
isCustomRangeOpen,
|
|
setIsCustomRangeOpen,
|
|
showUpgradePrompt,
|
|
setShowUpgradePrompt,
|
|
handleApplyCustomRange,
|
|
} = useLogsCustomRange({
|
|
onRangeChange: (time_range) => onSourceChange({ _tag: 'logs', time_range }),
|
|
})
|
|
|
|
const availableSources = QUERY_SOURCES.filter(
|
|
(candidate) =>
|
|
candidate._tag !== 'logs' ||
|
|
(isLogsSourceEnabled && isOtelLogsEnabled) ||
|
|
source._tag === 'logs'
|
|
)
|
|
|
|
return (
|
|
<>
|
|
<DropdownMenu>
|
|
<DropdownMenuTrigger asChild>
|
|
<Button
|
|
variant="text"
|
|
size="tiny"
|
|
aria-label={`Query source: ${QUERY_SOURCE_LABELS[source._tag]}`}
|
|
icon={<QuerySourceIcon source={source._tag} className="text-foreground-light" />}
|
|
iconRight={<ChevronDown className="text-foreground-light" />}
|
|
>
|
|
{QUERY_SOURCE_LABELS[source._tag]}
|
|
</Button>
|
|
</DropdownMenuTrigger>
|
|
<DropdownMenuContent align="end" className="w-60">
|
|
{availableSources.map((candidate) => (
|
|
<DropdownMenuItem
|
|
key={candidate._tag}
|
|
className="justify-between"
|
|
onSelect={(event) => {
|
|
event.preventDefault()
|
|
if (candidate._tag !== source._tag) {
|
|
onSourceChange(createDefaultSourceBinding(candidate._tag))
|
|
}
|
|
}}
|
|
>
|
|
<span className="flex items-center gap-x-2">
|
|
<QuerySourceIcon source={candidate._tag} className="text-foreground-light" />
|
|
{QUERY_SOURCE_LABELS[candidate._tag]}
|
|
</span>
|
|
{source._tag === candidate._tag && <Check size={14} />}
|
|
</DropdownMenuItem>
|
|
))}
|
|
|
|
<DropdownMenuSeparator />
|
|
|
|
{source._tag === 'database' ? (
|
|
<>
|
|
<DatabaseParametersSubMenu
|
|
identifier={source.database_identifier ?? ref}
|
|
onIdentifierChange={(database_identifier) =>
|
|
onSourceChange({ _tag: 'database', database_identifier })
|
|
}
|
|
/>
|
|
{onRowLimitChange !== undefined && (
|
|
<RowLimitSubMenu
|
|
value={rowLimit}
|
|
onValueChange={(val) => onRowLimitChange(Number(val))}
|
|
/>
|
|
)}
|
|
</>
|
|
) : (
|
|
<LogsTimeRangeSubMenu
|
|
range={source.time_range}
|
|
onRangeChange={(time_range) => onSourceChange({ _tag: 'logs', time_range })}
|
|
onOpenCustomRange={() => setIsCustomRangeOpen(true)}
|
|
onShowUpgrade={() => setShowUpgradePrompt(true)}
|
|
/>
|
|
)}
|
|
</DropdownMenuContent>
|
|
</DropdownMenu>
|
|
|
|
{source._tag === 'logs' && (
|
|
<>
|
|
<LogsCustomRangeDialog
|
|
open={isCustomRangeOpen}
|
|
onOpenChange={setIsCustomRangeOpen}
|
|
onApply={handleApplyCustomRange}
|
|
/>
|
|
<UpgradePrompt show={showUpgradePrompt} setShowUpgradePrompt={setShowUpgradePrompt} />
|
|
</>
|
|
)}
|
|
</>
|
|
)
|
|
}
|