Files
Joshen Lim aba4e147eb Joshen/fe 3613 database tables query should have schema filter wherever appropriate (#46935)
## Context

There's certain areas in the dashboard where we're calling
`useTablesQuery` without a schema filter, in which case the dashboard
then fires a query against the project's database to fetch _all_ tables
across _all_ schemas - this could easily be a heavy query if there's a
large number of relations in the project's database.

Am hence opting to either add a schema filter if appropriate, or
otherwise opt to use the infinite loading behaviour

## Changes involved
- Add schema filter to `useTablesQuery` in database triggers and
publications
- Use infinite loading for tables in Cmd K for "Run query on table" and
"Search database tables"

## To test
- [x] Verify that database triggers + publications still function as
expected
- [x] Verify that CMD K "Run query on table" and "Search database
tables" still function as expected (including search)

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

* **New Features**
* Implemented debounced infinite-scrolling table search in the command
menu and SQL editor command flow.
* Added a schema selector dropdown to publications management for easier
navigation.
* **Improvements**
  * Removed the “Schema” column from the publications tables UI.
* Updated search guidance and table-picker status (counts/loading)
during infinite browsing.
  * Trigger table listings now follow the selected schema context.
* Refined command menu list height and improved the database-tables
placeholder text.
<!-- end of auto-generated comment: release notes by coderabbit.ai -->
2026-06-16 15:45:39 +08:00

126 lines
2.8 KiB
TypeScript

'use client'
import { Auth, EdgeFunctions, Storage } from 'icons'
import { Database } from 'lucide-react'
import dynamic from 'next/dynamic'
import { EmptyState, SkeletonResults } from './ContextSearchResults.shared'
import type { SearchContextValue } from './SearchContext.types'
const TableSearchResults = dynamic(
() => import('./TableSearchResults').then((mod) => ({ default: mod.TableSearchResults })),
{
loading: () => <SkeletonResults />,
ssr: false,
}
)
const PolicySearchResults = dynamic(
() => import('./PolicySearchResults').then((mod) => ({ default: mod.PolicySearchResults })),
{
loading: () => <SkeletonResults />,
ssr: false,
}
)
const EdgeFunctionSearchResults = dynamic(
() =>
import('./EdgeFunctionSearchResults').then((mod) => ({
default: mod.EdgeFunctionSearchResults,
})),
{
loading: () => <SkeletonResults />,
ssr: false,
}
)
const StorageSearchResults = dynamic(
() => import('./StorageSearchResults').then((mod) => ({ default: mod.StorageSearchResults })),
{
loading: () => <SkeletonResults />,
ssr: false,
}
)
interface ContextSearchResultsProps {
context: SearchContextValue
query: string
debouncedFilterString: string
}
const CONTEXT_CONFIG: Record<
SearchContextValue,
{
icon: React.ComponentType<React.SVGProps<SVGSVGElement>>
label: string
requiresInput?: boolean // requires user input before showing results
}
> = {
'database-tables': {
icon: Database,
label: 'Database Tables',
requiresInput: false,
},
'auth-policies': {
icon: Auth,
label: 'RLS Policies',
requiresInput: false,
},
'edge-functions': {
icon: EdgeFunctions,
label: 'Edge Functions',
requiresInput: false,
},
storage: {
icon: Storage,
label: 'Storage',
requiresInput: false,
},
}
export function ContextSearchResults({
context,
query,
debouncedFilterString,
}: ContextSearchResultsProps) {
const config = CONTEXT_CONFIG[context]
if (context === 'database-tables') {
return (
<div className="flex-1 min-h-0 flex flex-col">
<TableSearchResults debouncedFilterString={debouncedFilterString} />
</div>
)
}
if (context === 'auth-policies') {
return (
<div className="flex-1 min-h-0 flex flex-col">
<PolicySearchResults query={query} />
</div>
)
}
if (context === 'edge-functions') {
return (
<div className="flex-1 min-h-0 flex flex-col">
<EdgeFunctionSearchResults query={query} />
</div>
)
}
if (context === 'storage') {
return (
<div className="flex-1 min-h-0 flex flex-col">
<StorageSearchResults query={query} />
</div>
)
}
return (
<div className="flex-1 min-h-0 flex flex-col">
<EmptyState icon={config.icon} label={config.label} query={query} />
</div>
)
}