Date: Wed, 20 May 2026 20:03:52 +0700
Subject: [PATCH 07/14] Support multi select logs and add CTA (#45974)
## Context
Supports selecting log rows and allow to copy / ask assistant for
selected rows, similar to what we had for the old logs UI
Selection will clear whenever the search parameters change
## Summary by CodeRabbit
* **New Features**
* Multi-row selection with an action header showing selected count
* Copy selected logs as JSON or Markdown from a dropdown
* "Explain with AI" action to open the assistant pre-filled with
selected logs
* Clear selection button
* **Refactor**
* Row/detail selection now syncs with the URL for shareable views and
improves next/previous navigation and panel behavior
* **Style**
* Minor visual tweak to column level indicator dot size
[](https://app.coderabbit.ai/change-stack/supabase/supabase/pull/45974)
---
.../hooks/useQueryInsightsTableColumns.tsx | 41 +++----
.../UnifiedLogs/RowSelectionHeader.tsx | 114 ++++++++++++++++++
.../components/ServiceFlowPanelControls.tsx | 26 ++--
.../interfaces/UnifiedLogs/UnifiedLogs.tsx | 47 ++++----
.../UnifiedLogs/components/Columns.tsx | 34 +++++-
.../components/ui/AiAssistantDropdown.tsx | 22 +++-
.../ui/DataTable/DataTable.utils.ts | 40 ------
.../DataTableColumnLevelIndicator.tsx | 2 +-
.../DataTableColumnStatusCode.tsx | 34 ++++--
.../ui/DataTable/DataTableInfinite.tsx | 11 +-
apps/studio/components/ui/DataTable/Table.tsx | 2 +-
.../DataTable/providers/DataTableProvider.tsx | 4 +
.../ui/ErrorCodeTooltip/ErrorCodeTooltip.tsx | 33 ++---
13 files changed, 262 insertions(+), 148 deletions(-)
create mode 100644 apps/studio/components/interfaces/UnifiedLogs/RowSelectionHeader.tsx
diff --git a/apps/studio/components/interfaces/QueryInsights/hooks/useQueryInsightsTableColumns.tsx b/apps/studio/components/interfaces/QueryInsights/hooks/useQueryInsightsTableColumns.tsx
index 44ab6291afdf6..17708d338ce47 100644
--- a/apps/studio/components/interfaces/QueryInsights/hooks/useQueryInsightsTableColumns.tsx
+++ b/apps/studio/components/interfaces/QueryInsights/hooks/useQueryInsightsTableColumns.tsx
@@ -8,7 +8,6 @@ import {
DropdownMenu,
DropdownMenuContent,
DropdownMenuItem,
- DropdownMenuSeparator,
DropdownMenuTrigger,
Tooltip,
TooltipContent,
@@ -556,27 +555,25 @@ export function useQueryInsightsTableColumns({
buildPrompt={() => buildQueryInsightFixPrompt(row).prompt}
onOpenAssistant={() => handleAiSuggestedFix(row)}
copyLabel="Copy Markdown"
- extraDropdownItems={
- <>
- handleGoToLogs()} className="gap-2">
-
- Go to Logs
-
- {row.issueType === 'slow' && (
- {
- setSelectedTriageRow(props.rowIdx)
- setSheetView('explain')
- }}
- className="gap-2"
- >
-
- Explain
-
- )}
-
- >
- }
+ additionalDropdownItems={[
+ {
+ label: 'Go to Logs',
+ icon: ,
+ onClick: () => handleGoToLogs(),
+ },
+ ...(row.issueType === 'slow'
+ ? [
+ {
+ label: 'Explain',
+ icon: ,
+ onClick: () => {
+ setSelectedTriageRow(props.rowIdx)
+ setSheetView('explain')
+ },
+ },
+ ]
+ : []),
+ ]}
/>
)}
diff --git a/apps/studio/components/interfaces/UnifiedLogs/RowSelectionHeader.tsx b/apps/studio/components/interfaces/UnifiedLogs/RowSelectionHeader.tsx
new file mode 100644
index 0000000000000..2edf080d685e4
--- /dev/null
+++ b/apps/studio/components/interfaces/UnifiedLogs/RowSelectionHeader.tsx
@@ -0,0 +1,114 @@
+import { AnimatePresence, motion } from 'framer-motion'
+import { Copy, X } from 'lucide-react'
+import { toast } from 'sonner'
+import {
+ copyToClipboard,
+ DropdownMenu,
+ DropdownMenuContent,
+ DropdownMenuItem,
+ DropdownMenuTrigger,
+} from 'ui'
+
+import { type LogData } from '../Settings/Logs/Logs.types'
+import {
+ buildLogsPrompt,
+ formatLogsAsJson,
+ formatLogsAsMarkdown,
+} from '../Settings/Logs/Logs.utils'
+import { SIDEBAR_KEYS } from '@/components/layouts/ProjectLayout/LayoutSidebar/LayoutSidebarProvider'
+import { AiAssistantDropdown } from '@/components/ui/AiAssistantDropdown'
+import { ButtonTooltip } from '@/components/ui/ButtonTooltip'
+import { useDataTable } from '@/components/ui/DataTable/providers/DataTableProvider'
+import { useAiAssistantStateSnapshot } from '@/state/ai-assistant-state'
+import { useSidebarManagerSnapshot } from '@/state/sidebar-manager-state'
+
+// TODO - format Logs as JSON, as markdown, and as prompt
+
+export const RowSelectionHeader = () => {
+ const { openSidebar } = useSidebarManagerSnapshot()
+ const aiSnap = useAiAssistantStateSnapshot()
+
+ const { table } = useDataTable()
+ const selectedRows = table.getSelectedRowModel().rows.map((x) => x.original) as LogData[]
+
+ const handleOpenAiAssistant = () => {
+ const prompt = buildLogsPrompt(selectedRows)
+ openSidebar(SIDEBAR_KEYS.AI_ASSISTANT)
+ aiSnap.newChat({ initialMessage: prompt })
+ }
+
+ const onCopy = (format: 'json' | 'markdown') => {
+ const text =
+ format === 'json' ? formatLogsAsJson(selectedRows) : formatLogsAsMarkdown(selectedRows)
+ copyToClipboard(text, () => {
+ toast.success(
+ `Copied ${selectedRows.length} log${selectedRows.length !== 1 ? 's' : ''} as ${format.toUpperCase()}`
+ )
+ })
+ }
+
+ return (
+
+
+ {selectedRows.length > 0 && (
+
+
+ {selectedRows.length} row{selectedRows.length > 1 ? 's' : ''} selected
+
+
+
+
+
+ }
+ className="w-7"
+ tooltip={{ content: { side: 'bottom', text: 'Copy selected logs' } }}
+ />
+
+
+ onCopy('json')} className="gap-2 text-xs">
+
+ Copy as JSON
+
+ onCopy('markdown')} className="gap-2 text-xs">
+
+ Copy as Markdown
+
+
+
+
+
buildLogsPrompt(selectedRows)}
+ onOpenAssistant={handleOpenAiAssistant}
+ telemetrySource="log_explorer"
+ />
+
+ }
+ className="px-1"
+ onClick={() => table.resetRowSelection()}
+ tooltip={{ content: { side: 'bottom', text: 'Clear selection' } }}
+ />
+
+
+ )}
+
+
+ )
+}
diff --git a/apps/studio/components/interfaces/UnifiedLogs/ServiceFlow/components/ServiceFlowPanelControls.tsx b/apps/studio/components/interfaces/UnifiedLogs/ServiceFlow/components/ServiceFlowPanelControls.tsx
index 07088400a0313..cd421eee538ab 100644
--- a/apps/studio/components/interfaces/UnifiedLogs/ServiceFlow/components/ServiceFlowPanelControls.tsx
+++ b/apps/studio/components/interfaces/UnifiedLogs/ServiceFlow/components/ServiceFlowPanelControls.tsx
@@ -25,14 +25,12 @@ export const ServiceFlowPanelControls = ({
dock = 'bottom',
setDock,
}: ServiceFlowPanelControlsProps) => {
- const { table, rowSelection, isLoading } = useDataTable()
-
- const selectedRowKey = Object.keys(rowSelection)?.[0]
+ const { table, openRowId, setOpenRowId, isLoading } = useDataTable()
const selectedRowData = useMemo(() => {
- if (isLoading && !selectedRowKey) return
- return table.getCoreRowModel().flatRows.find((row) => row.id === selectedRowKey)
- }, [selectedRowKey, isLoading, table])
+ if (isLoading && !openRowId) return
+ return table.getCoreRowModel().flatRows.find((row) => row.id === openRowId)
+ }, [openRowId, isLoading, table])
const index = table.getCoreRowModel().flatRows.findIndex((row) => row.id === selectedRowData?.id)
@@ -49,20 +47,20 @@ export const ServiceFlowPanelControls = ({
)
const onPrev = useCallback(() => {
- if (prevId) table.setRowSelection({ [prevId]: true })
- }, [prevId, table])
+ if (prevId) setOpenRowId(prevId)
+ }, [prevId, setOpenRowId])
const onNext = useCallback(() => {
- if (nextId) table.setRowSelection({ [nextId]: true })
- }, [nextId, table])
+ if (nextId) setOpenRowId(nextId)
+ }, [nextId, setOpenRowId])
const onClose = useCallback(() => {
- table.resetRowSelection()
- }, [table])
+ setOpenRowId(undefined)
+ }, [setOpenRowId])
useEffect(() => {
const down = (e: KeyboardEvent) => {
- if (!selectedRowKey) return
+ if (!openRowId) return
const activeElement = document.activeElement
if (activeElement?.closest('[role="menu"]')) return
@@ -87,7 +85,7 @@ export const ServiceFlowPanelControls = ({
document.addEventListener('keydown', down)
return () => document.removeEventListener('keydown', down)
- }, [selectedRowKey, onNext, onPrev])
+ }, [openRowId, onNext, onPrev])
return (
diff --git a/apps/studio/components/interfaces/UnifiedLogs/UnifiedLogs.tsx b/apps/studio/components/interfaces/UnifiedLogs/UnifiedLogs.tsx
index ae1abc01f5b11..a06406666aa2e 100644
--- a/apps/studio/components/interfaces/UnifiedLogs/UnifiedLogs.tsx
+++ b/apps/studio/components/interfaces/UnifiedLogs/UnifiedLogs.tsx
@@ -33,6 +33,7 @@ import { DownloadLogsButton } from './components/DownloadLogsButton'
import { LogsFilterBar } from './components/LogsFilterBar'
import { LogsListPanel } from './components/LogsListPanel'
import { TooltipLabel } from './components/TooltipLabel'
+import { RowSelectionHeader } from './RowSelectionHeader'
import { ServiceFlowPanel } from './ServiceFlowPanel'
import { SEARCH_PARAMS_PARSER } from './UnifiedLogs.constants'
import { filterFields as defaultFilterFields } from './UnifiedLogs.fields'
@@ -85,7 +86,6 @@ export const UnifiedLogs = () => {
const { sort, start, size, id, cursor, direction, live, ...filter } = search
const defaultColumnSorting = sort ? [sort] : []
const defaultColumnVisibility = { uuid: false }
- const defaultRowSelection = search.id ? { [search.id]: true } : {}
const defaultColumnFilters = Object.entries(filter)
.map(([key, value]) => ({ id: key, value }))
.filter(({ value }) => value ?? undefined)
@@ -106,7 +106,8 @@ export const UnifiedLogs = () => {
const [sorting, setSorting] = useState(defaultColumnSorting)
const [columnFilters, setColumnFilters] = useState(defaultColumnFilters)
- const [rowSelection, setRowSelection] = useState(defaultRowSelection)
+ const [rowSelection, setRowSelection] = useState({})
+ const [openRowId, setOpenRowId] = useState(search.id ?? undefined)
const [dock, setDock] = useLocalStorageQuery<'bottom' | 'right'>(
LOCAL_STORAGE_KEYS.UNIFIED_LOGS_DOCK,
@@ -222,7 +223,7 @@ export const UnifiedLogs = () => {
// Generate dynamic columns based on current data
const { columns: dynamicColumns, columnVisibility: dynamicColumnVisibility } = useMemo(() => {
- return generateDynamicColumns(flatData)
+ return generateDynamicColumns({ data: flatData })
}, [flatData])
const table: Table = useReactTable({
@@ -235,7 +236,7 @@ export const UnifiedLogs = () => {
rowSelection,
columnOrder,
},
- enableMultiRowSelection: false,
+ enableMultiRowSelection: true,
columnResizeMode: 'onChange',
filterFns: { inDateRange, arrSome },
meta: { getRowClassName },
@@ -253,12 +254,10 @@ export const UnifiedLogs = () => {
getFacetedMinMaxValues: getTTableFacetedMinMaxValues(),
})
- const selectedRowKey = Object.keys(rowSelection)?.[0]
const selectedRow = useMemo(() => {
if ((isLoading || isFetching) && !flatData.length) return
-
- return table.getCoreRowModel().flatRows.find((row) => row.id === selectedRowKey)
- }, [isLoading, isFetching, flatData.length, table, selectedRowKey])
+ return table.getCoreRowModel().flatRows.find((row) => row.id === openRowId)
+ }, [isLoading, isFetching, flatData.length, table, openRowId])
// REMINDER: this is currently needed for the cmdk search
// [Joshen] This is where facets are getting dynamically loaded
@@ -321,24 +320,20 @@ export const UnifiedLogs = () => {
useEffect(() => {
if (isLoading || isFetching) return
- const selectedRowId = Object.keys(rowSelection)?.[0]
- if (selectedRowId && !selectedRow) {
- // Clear both uuid and logId when no row is selected
+ if (openRowId && !selectedRow) {
+ // Clear both uuid and logId when the open row no longer exists in data
setSearch({ id: null })
- setRowSelection({})
- } else if (selectedRowId && selectedRow) {
- setSearch({
- id: selectedRowId,
- })
+ setOpenRowId(undefined)
+ } else if (openRowId && selectedRow) {
+ setSearch({ id: openRowId })
track('unified_logs_row_clicked', { logType: selectedRow.original.log_type })
- // Don't clear rowSelection here - let it persist to maintain the selection
- } else if (!selectedRowId && search.id) {
- // Clear the URL parameter when no row is selected
+ } else if (!openRowId && search.id) {
+ // Clear the URL parameter when no row is open
setSearch({ id: null })
}
// eslint-disable-next-line react-hooks/exhaustive-deps
- }, [rowSelection, selectedRow, isLoading, isFetching])
+ }, [openRowId, selectedRow, isLoading, isFetching])
const isMobile = useIsMobile()
const [isFilterBarOpen, setIsFilterBarOpen] = useState(!isMobile)
@@ -353,6 +348,10 @@ export const UnifiedLogs = () => {
}
}, [isMobile])
+ useEffect(() => {
+ table.resetRowSelection()
+ }, [searchParameters, table])
+
return (
{
columnFilters={columnFilters}
sorting={sorting}
rowSelection={rowSelection}
+ openRowId={openRowId}
+ setOpenRowId={setOpenRowId}
columnOrder={columnOrder}
columnVisibility={columnVisibility}
searchParameters={searchParameters}
@@ -431,6 +432,8 @@ export const UnifiedLogs = () => {
/>
+
+
{
- {!!selectedRow && (
+ {!!openRowId && !!selectedRow && (
<>
>
diff --git a/apps/studio/components/interfaces/UnifiedLogs/components/Columns.tsx b/apps/studio/components/interfaces/UnifiedLogs/components/Columns.tsx
index 165712c558727..98574cd488d32 100644
--- a/apps/studio/components/interfaces/UnifiedLogs/components/Columns.tsx
+++ b/apps/studio/components/interfaces/UnifiedLogs/components/Columns.tsx
@@ -1,5 +1,5 @@
import { ColumnDef } from '@tanstack/react-table'
-import { Tooltip, TooltipContent, TooltipTrigger } from 'ui'
+import { Checkbox, Tooltip, TooltipContent, TooltipTrigger } from 'ui'
import { STATUS_CODE_LABELS } from '../UnifiedLogs.constants'
import { ColumnFilterSchema, ColumnSchema } from '../UnifiedLogs.schema'
@@ -30,7 +30,7 @@ function shouldHideColumn(data: ColumnSchema[], columnKey: keyof ColumnSchema):
}
// Generate dynamic columns based on data
-export function generateDynamicColumns(data: ColumnSchema[]): {
+export function generateDynamicColumns({ data }: { data: ColumnSchema[] }): {
columns: ColumnDef[]
columnVisibility: Record
} {
@@ -39,6 +39,32 @@ export function generateDynamicColumns(data: ColumnSchema[]): {
const hideEventMessage = shouldHideColumn(data, 'event_message')
const columns: ColumnDef[] = [
+ {
+ accessorKey: 'select',
+ header: '',
+ cell: ({ row }) => {
+ return (
+
+ row.toggleSelected(!!value)}
+ onClick={(e) => e.stopPropagation()}
+ />
+
+ )
+ },
+ enableHiding: false,
+ enableResizing: false,
+ enableSorting: false,
+ filterFn: (_row, _columnId, _filterValue) => true,
+ size: 48,
+ minSize: 48,
+ maxSize: 48,
+ meta: {
+ cellClassName: 'w-[32px]',
+ headerClassName: 'w-[32px]',
+ },
+ },
// Level column - always visible
{
accessorKey: 'level',
@@ -243,4 +269,6 @@ export function generateDynamicColumns(data: ColumnSchema[]): {
}
// Static fallback columns
-export const UNIFIED_LOGS_COLUMNS: ColumnDef[] = generateDynamicColumns([]).columns
+export const UNIFIED_LOGS_COLUMNS: ColumnDef[] = generateDynamicColumns({
+ data: [],
+}).columns
diff --git a/apps/studio/components/ui/AiAssistantDropdown.tsx b/apps/studio/components/ui/AiAssistantDropdown.tsx
index e3652414c00d2..da2c95264fd2f 100644
--- a/apps/studio/components/ui/AiAssistantDropdown.tsx
+++ b/apps/studio/components/ui/AiAssistantDropdown.tsx
@@ -1,6 +1,7 @@
import { AiAssistantSource } from 'common/telemetry-constants'
import { Chatgpt, Claude } from 'icons'
import { Check, ChevronDown, Copy } from 'lucide-react'
+import Link from 'next/link'
import { ComponentProps, ReactNode, useEffect, useState } from 'react'
import {
AiIconAnimation,
@@ -41,7 +42,8 @@ const EXTERNAL_AI_TOOLS = [
export interface AiAssistantDropdownItem {
label: string
icon?: ReactNode
- onClick: () => void
+ href?: string
+ onClick?: () => void
}
export interface AiAssistantDropdownProps {
@@ -59,7 +61,6 @@ export interface AiAssistantDropdownProps {
tooltip?: string
copyLabel?: string
showExternalAI?: boolean
- extraDropdownItems?: ReactNode
additionalDropdownItems?: AiAssistantDropdownItem[]
}
@@ -78,7 +79,6 @@ export function AiAssistantDropdown({
tooltip,
copyLabel = 'Copy prompt',
showExternalAI = false,
- extraDropdownItems,
additionalDropdownItems,
}: AiAssistantDropdownProps) {
const track = useTrack()
@@ -150,11 +150,11 @@ export function AiAssistantDropdown({
/>
- {extraDropdownItems}
{showCopied ? : }
{showCopied ? 'Copied!' : copyLabel}
+
{showExternalAI && (
<>
@@ -170,13 +170,23 @@ export function AiAssistantDropdown({
))}
>
)}
+
{additionalDropdownItems && additionalDropdownItems.length > 0 && (
<>
{additionalDropdownItems.map((item, i) => (
- {item.icon}
- {item.label}
+ {item.href ? (
+
+ {item.icon}
+ {item.label}
+
+ ) : (
+ <>
+ {item.icon}
+ {item.label}
+ >
+ )}
))}
>
diff --git a/apps/studio/components/ui/DataTable/DataTable.utils.ts b/apps/studio/components/ui/DataTable/DataTable.utils.ts
index deec18fab9730..5443a55599a40 100644
--- a/apps/studio/components/ui/DataTable/DataTable.utils.ts
+++ b/apps/studio/components/ui/DataTable/DataTable.utils.ts
@@ -86,43 +86,3 @@ export function getLevelColor(
}
}
}
-
-export function getStatusColor(value?: number | string): Record<'text' | 'bg' | 'border', string> {
- switch (value) {
- case '1':
- case 'info':
- return {
- text: 'text-blue-500',
- bg: '',
- border: 'border-blue-200 dark:border-blue-800',
- }
- case '2':
- case 'success':
- return {
- text: 'text-foreground',
- bg: '',
- border: 'border-green-200 dark:border-green-800',
- }
- case '4':
- case 'warning':
- case 'redirect':
- return {
- text: 'text-warning',
- bg: 'bg-warning-300 dark:bg-warning-200',
- border: 'border border-warning-400/50 dark:border-warning-400/50',
- }
- case '5':
- case 'error':
- return {
- text: 'text-destructive',
- bg: 'bg-destructive-300 dark:bg-destructive-300/50',
- border: 'border border-destructive-400/50 dark:border-destructive-400/50',
- }
- default:
- return {
- text: 'text-foreground',
- bg: '',
- border: '',
- }
- }
-}
diff --git a/apps/studio/components/ui/DataTable/DataTableColumn/DataTableColumnLevelIndicator.tsx b/apps/studio/components/ui/DataTable/DataTableColumn/DataTableColumnLevelIndicator.tsx
index dde560e82d98c..a4b8ed3ebcfbe 100644
--- a/apps/studio/components/ui/DataTable/DataTableColumn/DataTableColumnLevelIndicator.tsx
+++ b/apps/studio/components/ui/DataTable/DataTableColumn/DataTableColumnLevelIndicator.tsx
@@ -16,7 +16,7 @@ export const DataTableColumnLevelIndicator = ({
{
- const colors = getStatusColor(level)
+ const colorClassName = getStatusColor(level)
+
+ function getStatusColor(value?: number | string): string {
+ switch (value) {
+ case '1':
+ case 'info':
+ return 'text-blue-500'
+ case '2':
+ case 'success':
+ return 'text-foreground'
+ case '4':
+ case 'warning':
+ case 'redirect':
+ return 'text-warning'
+ case '5':
+ case 'error':
+ return 'text-destructive'
+ default:
+ return 'text-foreground'
+ }
+ }
+
if (!value) {
return
}
return (
-
diff --git a/apps/studio/components/ui/DataTable/DataTableInfinite.tsx b/apps/studio/components/ui/DataTable/DataTableInfinite.tsx
index e190f9d6deef7..221466617b09b 100644
--- a/apps/studio/components/ui/DataTable/DataTableInfinite.tsx
+++ b/apps/studio/components/ui/DataTable/DataTableInfinite.tsx
@@ -45,8 +45,8 @@ export function DataTableInfinite
({
setColumnVisibility,
searchParamsParser,
}: DataTableInfiniteProps) {
- const { table, error, isError, isLoading, isFetching } = useDataTable()
const tableRef = useRef(null)
+ const { table, error, isError, isLoading, isFetching, openRowId, setOpenRowId } = useDataTable()
const headerGroups = table.getHeaderGroups()
const headers = headerGroups[0].headers
@@ -128,7 +128,8 @@ export function DataTableInfinite({
row={row}
table={table}
searchParamsParser={searchParamsParser}
- selected={row.getIsSelected()}
+ selected={row.id === openRowId}
+ onSelect={() => setOpenRowId(row.id === openRowId ? undefined : row.id)}
/>
))
) : isLoading ? (
@@ -229,11 +230,13 @@ function DataTableRow({
table,
selected,
searchParamsParser,
+ onSelect,
}: {
row: Row
table: TTable
selected?: boolean
searchParamsParser: any
+ onSelect: () => void
}) {
useQueryState('live', searchParamsParser.live)
const rowClassName = (table.options.meta as any)?.getRowClassName?.(row)
@@ -244,11 +247,11 @@ function DataTableRow({
id={row.id}
tabIndex={0}
data-state={selected && 'selected'}
- onClick={() => row.toggleSelected()}
+ onClick={onSelect}
onKeyDown={(event) => {
if (event.key === 'Enter') {
event.preventDefault()
- row.toggleSelected()
+ onSelect()
}
}}
className={cn(rowClassName)}
diff --git a/apps/studio/components/ui/DataTable/Table.tsx b/apps/studio/components/ui/DataTable/Table.tsx
index 7b5c3d8798c0e..9f81520bbfe76 100644
--- a/apps/studio/components/ui/DataTable/Table.tsx
+++ b/apps/studio/components/ui/DataTable/Table.tsx
@@ -79,7 +79,7 @@ export const TableHead = forwardRef<
className={cn(
'text-xs! font-normal! text-foreground-lighter font-mono',
'relative select-none truncate [&>.cursor-col-resize]:last:opacity-0',
- 'text-muted-foreground h-8 px-2 text-left align-middle [&:has([role=checkbox])]:pr-0 *:[[role=checkbox]]:translate-y-[2px]',
+ 'text-muted-foreground h-9 px-2 text-left align-middle [&:has([role=checkbox])]:pr-0 *:[[role=checkbox]]:translate-y-[2px]',
className
)}
{...props}
diff --git a/apps/studio/components/ui/DataTable/providers/DataTableProvider.tsx b/apps/studio/components/ui/DataTable/providers/DataTableProvider.tsx
index 9dfd396da82c7..b60950fe331b8 100644
--- a/apps/studio/components/ui/DataTable/providers/DataTableProvider.tsx
+++ b/apps/studio/components/ui/DataTable/providers/DataTableProvider.tsx
@@ -25,6 +25,8 @@ interface DataTableStateContextType {
pagination: PaginationState
enableColumnOrdering: boolean
searchParameters: QuerySearchParamsType
+ openRowId: string | undefined
+ setOpenRowId: (id: string | undefined) => void
}
interface DataTableBaseContextType {
@@ -63,6 +65,8 @@ export function DataTableProvider({
pagination: props.pagination ?? { pageIndex: 0, pageSize: 10 },
enableColumnOrdering: props.enableColumnOrdering ?? false,
searchParameters: props.searchParameters ?? ({} as any),
+ openRowId: props.openRowId,
+ setOpenRowId: props.setOpenRowId ?? (() => {}),
}),
[props]
)
diff --git a/apps/studio/components/ui/ErrorCodeTooltip/ErrorCodeTooltip.tsx b/apps/studio/components/ui/ErrorCodeTooltip/ErrorCodeTooltip.tsx
index 13fd2f4f85072..83e5125a06f90 100644
--- a/apps/studio/components/ui/ErrorCodeTooltip/ErrorCodeTooltip.tsx
+++ b/apps/studio/components/ui/ErrorCodeTooltip/ErrorCodeTooltip.tsx
@@ -1,17 +1,8 @@
import { ExternalLink } from 'lucide-react'
import { useTheme } from 'next-themes'
import Image from 'next/image'
-import Link from 'next/link'
import { useState } from 'react'
-import {
- cn,
- DropdownMenuItem,
- DropdownMenuSeparator,
- HoverCard,
- HoverCardContent,
- HoverCardTrigger,
- InfoIcon,
-} from 'ui'
+import { cn, HoverCard, HoverCardContent, HoverCardTrigger, InfoIcon } from 'ui'
import { ShimmeringLoader } from 'ui-patterns/ShimmeringLoader'
import { getErrorCodeInfo } from './ErrorCodeTooltip.utils'
@@ -117,25 +108,19 @@ export const ErrorCodeTooltip = ({ errorCode, service, children }: ErrorCodeTool
)}
-
-
-
- Go to Docs
-
-
-
- >
- ) : undefined
- }
+ additionalDropdownItems={[
+ {
+ label: 'Go to Docs',
+ icon: ,
+ href: docsUrl,
+ },
+ ]}
/>
From 7e717fb7bc5d9ffaf0922d4a3d5279f35dda58cd Mon Sep 17 00:00:00 2001
From: "kemal.earth" <606977+kemaldotearth@users.noreply.github.com>
Date: Wed, 20 May 2026 14:42:16 +0100
Subject: [PATCH 08/14] fix(studio): selected status bg colour unified logs
(#46152)
## I have read the
[CONTRIBUTING.md](https://github.com/supabase/supabase/blob/master/CONTRIBUTING.md)
file.
YES
## What kind of change does this PR introduce?
Small visual gremlin where the status dot was blending in with the
selected state background colour. See image below.
Appreciate there's probably another PR to go in with the row select
before this goes in.
| Before | After |
|--------|--------|
| | |
## Summary by CodeRabbit
* **Style**
* Updated visual styling for successful rows in data tables to use the
selected-row variant, improving highlight consistency for
selected/successful rows.
* **Refactor**
* Standardized row class composition so each table row reliably includes
the base row grouping class alongside any custom row classes from table
metadata, reducing UI regressions and improving consistency.
[](https://app.coderabbit.ai/change-stack/supabase/supabase/pull/46152?utm_source=github_walkthrough&utm_medium=github&utm_campaign=change_stack)
---------
Co-authored-by: Joshen Lim
---
apps/studio/components/ui/DataTable/DataTable.utils.ts | 4 ++--
apps/studio/components/ui/DataTable/DataTableInfinite.tsx | 2 +-
2 files changed, 3 insertions(+), 3 deletions(-)
diff --git a/apps/studio/components/ui/DataTable/DataTable.utils.ts b/apps/studio/components/ui/DataTable/DataTable.utils.ts
index 5443a55599a40..d206a302dd8df 100644
--- a/apps/studio/components/ui/DataTable/DataTable.utils.ts
+++ b/apps/studio/components/ui/DataTable/DataTable.utils.ts
@@ -63,8 +63,8 @@ export function getLevelColor(
case 'success':
return {
text: 'text-muted',
- bg: 'bg-muted',
- border: 'border-muted',
+ bg: 'bg-muted group-data-[state=selected]/row:bg-foreground-lighter',
+ border: 'border-muted group-data-[state=selected]/row:border-foreground-lighter',
}
case 'warning':
return {
diff --git a/apps/studio/components/ui/DataTable/DataTableInfinite.tsx b/apps/studio/components/ui/DataTable/DataTableInfinite.tsx
index 221466617b09b..2656050405fe0 100644
--- a/apps/studio/components/ui/DataTable/DataTableInfinite.tsx
+++ b/apps/studio/components/ui/DataTable/DataTableInfinite.tsx
@@ -239,7 +239,7 @@ function DataTableRow({
onSelect: () => void
}) {
useQueryState('live', searchParamsParser.live)
- const rowClassName = (table.options.meta as any)?.getRowClassName?.(row)
+ const rowClassName = cn('group/row', (table.options.meta as any)?.getRowClassName?.(row))
const cells = row.getVisibleCells()
return (
From e8af602d2dc042ed069af2db936c189dab742804 Mon Sep 17 00:00:00 2001
From: Joshen Lim
Date: Wed, 20 May 2026 20:44:31 +0700
Subject: [PATCH 09/14] Joshen/debug 110 default unified logs search to event
message (#46134)
## Context
Adjusts the filter bar component to accept a `freeformDefaultProperty`,
in which entering any text in the filter bar will opt to search against
that property by default. (Property must be defined within the
`filterProperties` prop too)
Applies to unified logs, which for e.g "Event message" is a valid
filter:
I've set `freeformDefaultProperty` to be `event_message`, and hence
typing free text will opt the default action to just filtering against
that property
### Demo:
https://github.com/user-attachments/assets/287ee22d-f957-48e5-89b0-1fed159cd86a
### Other changes
- Opt to deprecate `truncateText` util from unified logs -> preference
for tailwind instead
- Event message is added as a filter field, but hidden in the side nav
(wouldn't make sense since the content is very dynamic, unlike something
similar like pathname)
- Fixes some console errors in unified logs because we were using
`.getColumn` in `DataTableSheetRowAction`
## Summary by CodeRabbit
* **New Features**
* Added an "Event message" filter (hidden by default) and set it as the
default target for freeform searches.
* **UI Improvements**
* Filter sidebar resize constraints tightened.
* Timeline chart spacing and x-axis tick behavior improved.
* Action labels and command list items no longer truncate long input
values.
* **Bug Fixes**
* More reliable resolution of target columns for row actions, improving
available filter options.
[](https://app.coderabbit.ai/change-stack/supabase/supabase/pull/46134?utm_source=github_walkthrough&utm_medium=github&utm_campaign=change_stack)
---
.../UnifiedLogs/UnifiedLogs.fields.tsx | 17 ++++
.../UnifiedLogs/components/LogsFilterBar.tsx | 1 +
.../ui/DataTable/DataTable.types.ts | 2 +
.../DataTableFilterControls.tsx | 88 ++++++++++---------
.../ui/DataTable/DataTableSheetRowAction.tsx | 6 +-
.../components/ui/DataTable/TimelineChart.tsx | 4 +-
.../src/FilterBar/CommandListItem.tsx | 4 +-
.../ui-patterns/src/FilterBar/FilterBar.tsx | 10 +++
.../src/FilterBar/FilterBarContext.tsx | 4 +
.../ui-patterns/src/FilterBar/FilterGroup.tsx | 24 ++++-
.../ui-patterns/src/FilterBar/menuItems.ts | 16 +++-
packages/ui-patterns/src/FilterBar/types.ts | 3 +
.../src/FilterBar/useCommandHandling.ts | 31 +++++++
.../ui-patterns/src/FilterBar/utils.test.ts | 25 +-----
packages/ui-patterns/src/FilterBar/utils.ts | 7 +-
15 files changed, 163 insertions(+), 79 deletions(-)
diff --git a/apps/studio/components/interfaces/UnifiedLogs/UnifiedLogs.fields.tsx b/apps/studio/components/interfaces/UnifiedLogs/UnifiedLogs.fields.tsx
index e3512b5ead005..c13ecbbbf5f1f 100644
--- a/apps/studio/components/interfaces/UnifiedLogs/UnifiedLogs.fields.tsx
+++ b/apps/studio/components/interfaces/UnifiedLogs/UnifiedLogs.fields.tsx
@@ -134,6 +134,23 @@ export const filterFields = [
)
},
},
+ {
+ label: 'Event message',
+ value: 'event_message',
+ type: 'checkbox',
+ defaultOpen: false,
+ options: [],
+ hasDynamicOptions: false,
+ hasAsyncSearch: false,
+ hidden: true,
+ component: (props: Option) => {
+ return (
+
+ {props.value}
+
+ )
+ },
+ },
] satisfies DataTableFilterField[]
export const sheetFields = [
diff --git a/apps/studio/components/interfaces/UnifiedLogs/components/LogsFilterBar.tsx b/apps/studio/components/interfaces/UnifiedLogs/components/LogsFilterBar.tsx
index d8d4d68103340..7eb6e43296768 100644
--- a/apps/studio/components/interfaces/UnifiedLogs/components/LogsFilterBar.tsx
+++ b/apps/studio/components/interfaces/UnifiedLogs/components/LogsFilterBar.tsx
@@ -85,6 +85,7 @@ export const LogsFilterBar = () => {
return (
= {
commandDisabled?: boolean
hasDynamicOptions?: boolean
hasAsyncSearch?: boolean
+ /** Defines if the filter should be present in the filter nav */
+ hidden?: boolean
}
export type DataTableCheckboxFilterField = Base & Checkbox
diff --git a/apps/studio/components/ui/DataTable/DataTableFilters/DataTableFilterControls.tsx b/apps/studio/components/ui/DataTable/DataTableFilters/DataTableFilterControls.tsx
index ee813b21790fd..e13a8906643c1 100644
--- a/apps/studio/components/ui/DataTable/DataTableFilters/DataTableFilterControls.tsx
+++ b/apps/studio/components/ui/DataTable/DataTableFilters/DataTableFilterControls.tsx
@@ -30,51 +30,53 @@ export function DataTableFilterControls({
?.filter(({ defaultOpen }) => defaultOpen)
?.map(({ value }) => value as string)}
>
- {filterFields?.map((field) => {
- const value = field.value as string
- return (
-
-
-
- {/* REMINDER: avoid the focus state to be cut due to overflow-hidden */}
- {/* REMINDER: need to move within here because of accordion height animation */}
-
- {(() => {
- switch (field.type) {
- case 'checkbox': {
- // [Joshen] Loader here so that CheckboxAsync can retrieve the data
- // immediately to be set in its react query state
- if (field.hasDynamicOptions && isLoadingCounts) {
- return
- } else if (field.hasAsyncSearch) {
- return
- } else {
- return
+ {filterFields
+ ?.filter((field) => !field.hidden)
+ .map((field) => {
+ const value = field.value as string
+ return (
+
+
+
+ {/* REMINDER: avoid the focus state to be cut due to overflow-hidden */}
+ {/* REMINDER: need to move within here because of accordion height animation */}
+
+ {(() => {
+ switch (field.type) {
+ case 'checkbox': {
+ // [Joshen] Loader here so that CheckboxAsync can retrieve the data
+ // immediately to be set in its react query state
+ if (field.hasDynamicOptions && isLoadingCounts) {
+ return
+ } else if (field.hasAsyncSearch) {
+ return
+ } else {
+ return
+ }
+ }
+ case 'slider': {
+ return
+ }
+ case 'input': {
+ return
+ }
+ case 'timerange': {
+ return
}
}
- case 'slider': {
- return
- }
- case 'input': {
- return
- }
- case 'timerange': {
- return
- }
- }
- })()}
-
-
-
- )
- })}
+ })()}
+
+
+
+ )
+ })}
)
}
diff --git a/apps/studio/components/ui/DataTable/DataTableSheetRowAction.tsx b/apps/studio/components/ui/DataTable/DataTableSheetRowAction.tsx
index e26101a1553aa..7c3f965528556 100644
--- a/apps/studio/components/ui/DataTable/DataTableSheetRowAction.tsx
+++ b/apps/studio/components/ui/DataTable/DataTableSheetRowAction.tsx
@@ -47,8 +47,12 @@ export function DataTableSheetRowAction) {
const { copy, isCopied } = useCopyToClipboard()
+
const field = !!fieldValue ? filterFields.find((f) => f.value === fieldValue) : undefined
- const column = !!fieldValue ? table.getColumn(fieldValue.toString()) : undefined
+ const column =
+ !!fieldValue && !!field
+ ? table.getAllColumns().find((c) => c.id === fieldValue.toString())
+ : undefined
function renderOptions() {
if (!field) return null
diff --git a/apps/studio/components/ui/DataTable/TimelineChart.tsx b/apps/studio/components/ui/DataTable/TimelineChart.tsx
index 236941804e8ed..fb28fc44fc0c9 100644
--- a/apps/studio/components/ui/DataTable/TimelineChart.tsx
+++ b/apps/studio/components/ui/DataTable/TimelineChart.tsx
@@ -81,7 +81,7 @@ export function TimelineChart({
({
tickLine={false}
minTickGap={32}
axisLine={false}
- // interval="preserveStartEnd"
+ interval="preserveStartEnd"
tickFormatter={(value) => {
const date = new Date(value)
if (isNaN(date.getTime())) return 'N/A'
diff --git a/packages/ui-patterns/src/FilterBar/CommandListItem.tsx b/packages/ui-patterns/src/FilterBar/CommandListItem.tsx
index 35c1e758c4dfc..a8408a288605e 100644
--- a/packages/ui-patterns/src/FilterBar/CommandListItem.tsx
+++ b/packages/ui-patterns/src/FilterBar/CommandListItem.tsx
@@ -31,9 +31,9 @@ export function CommandListItem({
)}
data-testid={`filter-menu-item-${item.value}`}
>
-
+
{includeIcon && item.icon}
- {getActionItemLabel(item)}
+ {getActionItemLabel(item)}
{item.operatorSymbol && }
diff --git a/packages/ui-patterns/src/FilterBar/FilterBar.tsx b/packages/ui-patterns/src/FilterBar/FilterBar.tsx
index 066572f1cdccf..4ffd929a0aa94 100644
--- a/packages/ui-patterns/src/FilterBar/FilterBar.tsx
+++ b/packages/ui-patterns/src/FilterBar/FilterBar.tsx
@@ -24,6 +24,14 @@ export type FilterBarProps = {
supportsOperators?: boolean
variant?: FilterBarVariant
icon?: React.ReactNode
+ /**
+ * Name of the property to use when the user commits free text from the root input. Must match
+ * a `name` in `filterProperties`. When set, the dropdown shows a "Search : \"...\""
+ * item as the first option while the user is typing. Selecting it (Enter) creates a filter
+ * `{ propertyName, operator: '=', value: typedText }`. If the property has no `=` operator,
+ * the first operator in its list is used instead.
+ */
+ freeformDefaultProperty?: string
onFilterChange: (filters: FilterGroupType) => void
/**
* Fires only on commit boundaries: menu item selected, operator/property/logical-operator
@@ -135,6 +143,7 @@ export const FilterBar = forwardRef(function Fi
supportsOperators = false,
variant = 'default',
icon,
+ freeformDefaultProperty,
},
ref
) {
@@ -152,6 +161,7 @@ export const FilterBar = forwardRef(function Fi
supportsOperators={supportsOperators}
variant={variant}
icon={icon}
+ freeformDefaultProperty={freeformDefaultProperty}
>
diff --git a/packages/ui-patterns/src/FilterBar/FilterBarContext.tsx b/packages/ui-patterns/src/FilterBar/FilterBarContext.tsx
index 1b539c9ed573e..cc0306fbce249 100644
--- a/packages/ui-patterns/src/FilterBar/FilterBarContext.tsx
+++ b/packages/ui-patterns/src/FilterBar/FilterBarContext.tsx
@@ -71,6 +71,7 @@ export type FilterBarContextValue = {
variant: FilterBarVariant
actions?: FilterBarAction[]
icon?: React.ReactNode
+ freeformDefaultProperty?: string
rootRef: React.RefObject
}
@@ -98,6 +99,7 @@ export type FilterBarRootProps = {
supportsOperators?: boolean
variant?: FilterBarVariant
icon?: React.ReactNode
+ freeformDefaultProperty?: string
}
export type FilterBarVariant = 'default' | 'pill'
@@ -120,6 +122,7 @@ export const FilterBarRoot = forwardRef(fun
supportsOperators = false,
variant = 'default',
icon,
+ freeformDefaultProperty,
}: FilterBarRootProps,
ref: React.Ref
) {
@@ -395,6 +398,7 @@ export const FilterBarRoot = forwardRef(fun
variant,
actions,
icon,
+ freeformDefaultProperty,
rootRef,
}
diff --git a/packages/ui-patterns/src/FilterBar/FilterGroup.tsx b/packages/ui-patterns/src/FilterBar/FilterGroup.tsx
index 3fcbab301955e..34d0a143c4dda 100644
--- a/packages/ui-patterns/src/FilterBar/FilterGroup.tsx
+++ b/packages/ui-patterns/src/FilterBar/FilterGroup.tsx
@@ -25,6 +25,7 @@ export function FilterGroup({ group, path }: FilterGroupProps) {
actions,
variant,
highlightedConditionPath,
+ freeformDefaultProperty,
handleInputBlur,
handleGroupFreeformFocus,
handleGroupFreeformChange,
@@ -86,6 +87,16 @@ export function FilterGroup({ group, path }: FilterGroupProps) {
return pathsEqual(conditionPath, highlightedConditionPath)
}
+ // Free-text search only applies to the root group's input — nested groups don't synthesize
+ // a "Search " item.
+ const resolvedFreeformDefaultProperty = useMemo(
+ () =>
+ path.length === 0 && freeformDefaultProperty
+ ? filterProperties.find((p) => p.name === freeformDefaultProperty)
+ : undefined,
+ [path.length, freeformDefaultProperty, filterProperties]
+ )
+
const items = useMemo(
() =>
buildPropertyItems({
@@ -93,8 +104,17 @@ export function FilterGroup({ group, path }: FilterGroupProps) {
inputValue: (isActive ? freeformText : localFreeformValue) || '',
actions,
supportsOperators,
+ freeformDefaultProperty: resolvedFreeformDefaultProperty,
}),
- [filterProperties, isActive, freeformText, localFreeformValue, actions, supportsOperators]
+ [
+ filterProperties,
+ isActive,
+ freeformText,
+ localFreeformValue,
+ actions,
+ supportsOperators,
+ resolvedFreeformDefaultProperty,
+ ]
)
const emptyPlaceholder = useMemo(
@@ -220,7 +240,7 @@ export function FilterGroup({ group, path }: FilterGroupProps) {
)}
e.preventDefault()}
diff --git a/packages/ui-patterns/src/FilterBar/menuItems.ts b/packages/ui-patterns/src/FilterBar/menuItems.ts
index bff559cfa56a7..bb58c84f5fe43 100644
--- a/packages/ui-patterns/src/FilterBar/menuItems.ts
+++ b/packages/ui-patterns/src/FilterBar/menuItems.ts
@@ -70,10 +70,23 @@ export function buildPropertyItems(params: {
inputValue: string
supportsOperators?: boolean
actions?: FilterBarAction[]
+ freeformDefaultProperty?: FilterProperty
}): MenuItem[] {
- const { filterProperties, inputValue, supportsOperators, actions } = params
+ const { filterProperties, inputValue, supportsOperators, actions, freeformDefaultProperty } =
+ params
const items: MenuItem[] = []
+ const trimmedInput = inputValue.trim()
+ if (freeformDefaultProperty && trimmedInput.length > 0) {
+ items.push({
+ value: '__freeform_search__',
+ label: `Search ${freeformDefaultProperty.label.toLowerCase()}: "${trimmedInput}"`,
+ isFreeformSearch: true,
+ freeformPropertyName: freeformDefaultProperty.name,
+ freeformValue: trimmedInput,
+ })
+ }
+
items.push(
...filterProperties
.filter((prop) => prop.label.toLowerCase().includes(inputValue.toLowerCase()))
@@ -84,7 +97,6 @@ export function buildPropertyItems(params: {
items.push({ value: 'group', label: 'New Group' })
}
- const trimmedInput = inputValue.trim()
if (actions && trimmedInput.length > 0) {
actions.forEach((action) => {
items.push({
diff --git a/packages/ui-patterns/src/FilterBar/types.ts b/packages/ui-patterns/src/FilterBar/types.ts
index eac3b5ddaf207..19056763e696a 100644
--- a/packages/ui-patterns/src/FilterBar/types.ts
+++ b/packages/ui-patterns/src/FilterBar/types.ts
@@ -99,6 +99,9 @@ export type MenuItem = {
operatorSymbol?: string
isDefaultOperator?: boolean
defaultValue?: string
+ isFreeformSearch?: boolean
+ freeformPropertyName?: string
+ freeformValue?: string
}
export type GroupedMenuItem = {
diff --git a/packages/ui-patterns/src/FilterBar/useCommandHandling.ts b/packages/ui-patterns/src/FilterBar/useCommandHandling.ts
index 4e31aa47aae8f..61119c48a9ada 100644
--- a/packages/ui-patterns/src/FilterBar/useCommandHandling.ts
+++ b/packages/ui-patterns/src/FilterBar/useCommandHandling.ts
@@ -146,6 +146,35 @@ export function useCommandHandling({
return
}
+ if (item.isFreeformSearch && item.freeformPropertyName) {
+ if (!activeInput || activeInput.type !== 'group') return
+ const property = filterProperties.find((p) => p.name === item.freeformPropertyName)
+ if (!property) return
+
+ const currentPath = activeInput.path
+ const group = findGroupByPath(activeFilters, currentPath)
+ if (!group) return
+
+ const operators = property.operators ?? ['=']
+ const defaultOperator =
+ operators.find((op) => (isFilterOperatorObject(op) ? op.value : op) === '=') ??
+ operators[0]
+ const operatorValue = isFilterOperatorObject(defaultOperator)
+ ? defaultOperator.value
+ : defaultOperator
+
+ let updatedFilters = addFilterToGroup(activeFilters, currentPath, property)
+ const newPath = [...currentPath, group.conditions.length]
+ updatedFilters = updateNestedOperator(updatedFilters, newPath, operatorValue)
+ updatedFilters = updateNestedValue(updatedFilters, newPath, item.freeformValue ?? '')
+ commitFilters(updatedFilters)
+ onFreeformTextChange('')
+ setTimeout(() => {
+ setActiveInput({ type: 'group', path: currentPath })
+ }, 0)
+ return
+ }
+
if (item.value === 'group') {
handleGroupCommand()
return
@@ -174,6 +203,8 @@ export function useCommandHandling({
activeInput,
activeFilters,
freeformText,
+ filterProperties,
+ onFreeformTextChange,
setActiveInput,
handleGroupCommand,
handleValueCommand,
diff --git a/packages/ui-patterns/src/FilterBar/utils.test.ts b/packages/ui-patterns/src/FilterBar/utils.test.ts
index e67524d7b1f8d..cafa8ac2014ae 100644
--- a/packages/ui-patterns/src/FilterBar/utils.test.ts
+++ b/packages/ui-patterns/src/FilterBar/utils.test.ts
@@ -17,7 +17,6 @@ import {
isSyncOptionsFunction,
removeFromGroup,
resolvePropertyChange,
- truncateText,
updateNestedLogicalOperator,
updateNestedOperator,
updateNestedPropertyName,
@@ -477,24 +476,6 @@ describe('FilterBar Utils', () => {
})
})
- describe('truncateText', () => {
- it('returns text unchanged if under max length', () => {
- expect(truncateText('hello', 10)).toBe('hello')
- })
-
- it('returns text unchanged if exactly max length', () => {
- expect(truncateText('hello', 5)).toBe('hello')
- })
-
- it('truncates text and adds ellipsis if over max length', () => {
- expect(truncateText('hello world', 5)).toBe('hello...')
- })
-
- it('handles empty string', () => {
- expect(truncateText('', 10)).toBe('')
- })
- })
-
describe('getActionItemLabel', () => {
it('returns original label for non-action items', () => {
const item: MenuItem = { value: 'test', label: 'Test Label' }
@@ -516,14 +497,16 @@ describe('FilterBar Utils', () => {
expect(getActionItemLabel(item)).toBe('Ask AI: "Find users"')
})
- it('truncates long input values at 30 characters', () => {
+ it('returns full input value (no truncation — CSS handles overflow)', () => {
const item: MenuItem = {
value: 'ai',
label: 'Filter by AI',
isAction: true,
actionInputValue: 'Find all users who registered in the last 30 days',
}
- expect(getActionItemLabel(item)).toBe('Ask AI: "Find all users who registered ..."')
+ expect(getActionItemLabel(item)).toBe(
+ 'Ask AI: "Find all users who registered in the last 30 days"'
+ )
})
})
diff --git a/packages/ui-patterns/src/FilterBar/utils.ts b/packages/ui-patterns/src/FilterBar/utils.ts
index 76cf3551a7cc3..c89a39e846b8a 100644
--- a/packages/ui-patterns/src/FilterBar/utils.ts
+++ b/packages/ui-patterns/src/FilterBar/utils.ts
@@ -326,14 +326,9 @@ export function groupMenuItemsByOperator(items: MenuItem[]): MenuItemGroup[] {
}))
}
-export function truncateText(text: string, maxLength: number): string {
- if (text.length <= maxLength) return text
- return text.slice(0, maxLength) + '...'
-}
-
export function getActionItemLabel(item: MenuItem): string {
if (item.isAction && item.actionInputValue) {
- return `Ask AI: "${truncateText(item.actionInputValue, 30)}"`
+ return `Ask AI: "${item.actionInputValue}"`
}
return item.label
}
From 243e079a2c44e7bbd4eb24cf0d96ce4aeae438e6 Mon Sep 17 00:00:00 2001
From: Gildas Garcia <1122076+djhi@users.noreply.github.com>
Date: Wed, 20 May 2026 15:45:32 +0200
Subject: [PATCH 10/14] chore: remove `_Shadcn_` suffix from `Command`
components (#46153)
## Problem
The `_Shadcn_` suffix isn't needed anymore on `Command` components
## Solution
- Remove the `_Shadcn_` suffix
- Simplify UI package exports
- Apply prettier
## Summary by CodeRabbit
* **Refactor**
* Simplified command component imports and exports across the UI library
by removing internal naming aliases and adopting direct component
references. Updated the public UI package barrel export to use wildcard
re-exports for cleaner API surface.
[](https://app.coderabbit.ai/change-stack/supabase/supabase/pull/46153?utm_source=github_walkthrough&utm_medium=github&utm_campaign=change_stack)
---
.../design-system/components/command-menu.tsx | 50 ++++++-------
.../default/example/combobox-demo.tsx | 32 ++++-----
.../example/combobox-dropdown-menu.tsx | 32 ++++-----
.../default/example/combobox-form.tsx | 32 ++++-----
.../default/example/combobox-popover.tsx | 32 ++++-----
.../default/example/combobox-responsive.tsx | 32 ++++-----
.../registry/default/example/command-demo.tsx | 68 +++++++++---------
.../default/example/command-dialog.tsx | 62 ++++++++--------
.../ProjectConfigVariables.ComboBox.tsx | 18 ++---
apps/docs/features/ui/InfoTooltip.tsx | 10 +--
apps/docs/features/ui/McpConfigPanel.tsx | 52 +++++++-------
apps/learn/components/command-menu.tsx | 56 +++++++--------
.../PermissionResourceSelector.tsx | 32 ++++-----
.../Account/Preferences/TimezoneSettings.tsx | 36 +++++-----
.../ContextSearchResults.shared.tsx | 6 +-
.../PolicyEditorPanel/PolicyDetailsV2.tsx | 32 ++++-----
.../Auth/RLSTester/UserSelector.tsx | 32 ++++-----
.../ThirdPartyAuthForm/AwsRegionSelector.tsx | 32 ++++-----
.../NewPaymentMethodElement.tsx | 12 ++--
.../BranchManagement/BranchSelector.tsx | 32 ++++-----
.../interfaces/Connect/ConnectDropdown.tsx | 32 ++++-----
.../ConnectSheet/FrameworkSelector.tsx | 32 ++++-----
.../Backups/PITR/TimezoneSelection.tsx | 32 ++++-----
.../Database/Indexes/CreateIndexSidePanel.tsx | 54 +++++++-------
.../DestinationForm/PublicationsComboBox.tsx | 46 ++++++------
.../CronJobs/EdgeFunctionSection.tsx | 32 ++++-----
.../Vercel/OrganizationPicker.tsx | 32 ++++-----
.../VercelGithub/ProjectLinker.tsx | 54 +++++++-------
.../Integrations/Wrappers/ColumnType.tsx | 44 ++++++------
.../Wrappers/WrapperTableEditor.tsx | 32 ++++-----
.../BillingCustomerDataForm.tsx | 12 ++--
.../Apps/CreateAppSheet/CreateAppSheet.tsx | 32 ++++-----
.../interfaces/Organization/Usage/Usage.tsx | 10 +--
.../ProjectAPIDocs/LanguageSelector.tsx | 28 ++++----
.../SecondLevelNav.ResourcePicker.tsx | 28 +++-----
.../SecondLevelNav.StoragePicker.tsx | 35 ++++------
.../ProjectHome/SnippetDropdown.tsx | 36 +++++-----
.../RealtimeFilterPopover/TableSelector.tsx | 41 +++++------
.../interfaces/Reports/MetricOptions.tsx | 36 +++++-----
.../Reports/ReportFilterPopover.tsx | 34 ++++-----
.../Reports/v2/ReportsSelectFilter.tsx | 14 +---
.../interfaces/SQLEditor/MoveQueryModal.tsx | 48 ++++++-------
.../Settings/API/ExposedFunctionSelector.tsx | 28 ++++----
.../Settings/API/ExposedSchemaSelector.tsx | 34 ++++-----
.../Settings/API/ExposedTableSelector.tsx | 28 ++++----
.../GitHubRepositoryField.tsx | 52 +++++++-------
.../Settings/Logs/LogsQueryPanel.tsx | 32 ++++-----
.../VectorBucketTableExamplesSheet.tsx | 28 ++++----
.../interfaces/Support/ProjectAndPlanInfo.tsx | 10 +--
.../ColumnEditor/ColumnType.tsx | 44 ++++++------
.../SidePanelEditor/TableEditor/Column.tsx | 36 +++++-----
.../UserDropdown/TimezoneDropdown.tsx | 36 +++++-----
.../BranchDropdownCommandContent.tsx | 70 +++++++++----------
.../layouts/AppLayout/BranchLink.tsx | 6 +-
.../layouts/AppLayout/OrgCommandItem.tsx | 6 +-
.../OrganizationDropdownCommandContent.tsx | 64 ++++++++---------
.../layouts/AppLayout/ProjectDropdown.tsx | 10 +--
.../Navigation/NavigationBar/OrgSelector.tsx | 50 ++++++-------
.../layouts/ProjectLayout/index.test.tsx | 10 +--
.../SQLEditorLayout/SqlEditor.Commands.tsx | 54 +++++++-------
.../AIAssistantChatSelector.tsx | 44 ++++++------
.../ui/AIAssistantPanel/ModelSelector.tsx | 24 +++----
.../ui/DataTable/DataTableViewOptions.tsx | 12 ++--
.../studio/components/ui/DatabaseSelector.tsx | 40 +++++------
.../components/ui/EditorPanel/EditorPanel.tsx | 52 +++++++-------
.../studio/components/ui/FunctionSelector.tsx | 48 ++++++-------
.../components/ui/Logs/LogsExplorerHeader.tsx | 32 ++++-----
.../ui/OrganizationProjectSelector.tsx | 22 +++---
.../ProjectCommandItem.tsx | 6 +-
apps/studio/components/ui/SchemaComboBox.tsx | 32 ++++-----
apps/studio/components/ui/SchemaSelector.tsx | 48 ++++++-------
.../pages/project/[ref]/functions/new.tsx | 32 ++++-----
apps/ui-library/components/command-menu.tsx | 50 ++++++-------
.../tanstack-db-generator/ComboBox.tsx | 17 ++---
apps/www/components/Pricing/UpgradePlan.tsx | 44 ++++++------
.../src/CommandMenu/api/CommandMenu.tsx | 12 ++--
.../src/CommandMenu/api/CommandMenuInput.tsx | 8 +--
.../src/CommandMenu/api/CommandMenuList.tsx | 10 +--
.../CommandMenu/internal/CommandMenuGroup.tsx | 8 +--
.../CommandMenu/internal/CommandMenuItem.tsx | 10 +--
.../prepackaged/DocsAi/DocsAiPage.tsx | 23 +++---
.../prepackaged/DocsSearch/DocsSearchPage.tsx | 26 +++----
.../components/ClientSelectDropdown.tsx | 34 ++++-----
.../src/MobileSheetNav/MobileSheetNav.tsx | 4 +-
.../src/multi-select/multi-select.tsx | 10 +--
packages/ui/index.tsx | 12 +---
86 files changed, 1320 insertions(+), 1372 deletions(-)
diff --git a/apps/design-system/components/command-menu.tsx b/apps/design-system/components/command-menu.tsx
index fbd26bea2e88d..2fa3cfee17fc4 100644
--- a/apps/design-system/components/command-menu.tsx
+++ b/apps/design-system/components/command-menu.tsx
@@ -7,12 +7,12 @@ import * as React from 'react'
import {
Button,
CommandDialog,
- CommandEmpty_Shadcn_,
- CommandGroup_Shadcn_,
- CommandInput_Shadcn_,
- CommandItem_Shadcn_,
- CommandList_Shadcn_,
- CommandSeparator_Shadcn_,
+ CommandEmpty,
+ CommandGroup,
+ CommandInput,
+ CommandItem,
+ CommandList,
+ CommandSeparator,
DialogProps,
DialogTitle,
} from 'ui'
@@ -77,13 +77,13 @@ export function CommandMenu({ ...props }: DialogProps) {
/>
Search Design System...
-
-
- No results found.
+
+
+ No results found.
{docsConfig.sidebarNav.map((group) => (
-
+
{group.items.map((navItem) => (
- {
@@ -94,30 +94,30 @@ export function CommandMenu({ ...props }: DialogProps) {
{navItem.title}
-
+
))}
-
+
))}
-
-
- runCommand(() => setTheme('light'))}>
+
+
+ runCommand(() => setTheme('light'))}>
Light
-
- runCommand(() => setTheme('dark'))}>
+
+ runCommand(() => setTheme('dark'))}>
Dark
-
- runCommand(() => setTheme('classic-dark'))}>
+
+ runCommand(() => setTheme('classic-dark'))}>
Classic dark
-
- runCommand(() => setTheme('system'))}>
+
+ runCommand(() => setTheme('system'))}>
System
-
-
-
+
+
+
>
)
diff --git a/apps/design-system/registry/default/example/combobox-demo.tsx b/apps/design-system/registry/default/example/combobox-demo.tsx
index 558d83237e4e5..b7f8fabd97817 100644
--- a/apps/design-system/registry/default/example/combobox-demo.tsx
+++ b/apps/design-system/registry/default/example/combobox-demo.tsx
@@ -4,12 +4,12 @@ import { Check, ChevronsUpDown } from 'lucide-react'
import * as React from 'react'
import {
Button,
- Command_Shadcn_,
- CommandEmpty_Shadcn_,
- CommandGroup_Shadcn_,
- CommandInput_Shadcn_,
- CommandItem_Shadcn_,
- CommandList_Shadcn_,
+ Command,
+ CommandEmpty,
+ CommandGroup,
+ CommandInput,
+ CommandItem,
+ CommandList,
Popover,
PopoverContent,
PopoverTrigger,
@@ -61,13 +61,13 @@ export default function ComboboxDemo() {
-
-
-
- No framework found.
-
+
+
+
+ No framework found.
+
{frameworks.map((framework) => (
- {
@@ -82,11 +82,11 @@ export default function ComboboxDemo() {
)}
/>
{framework.label}
-
+
))}
-
-
-
+
+
+
)
diff --git a/apps/design-system/registry/default/example/combobox-dropdown-menu.tsx b/apps/design-system/registry/default/example/combobox-dropdown-menu.tsx
index ae866941efaa7..b9885ea531b5d 100644
--- a/apps/design-system/registry/default/example/combobox-dropdown-menu.tsx
+++ b/apps/design-system/registry/default/example/combobox-dropdown-menu.tsx
@@ -4,12 +4,12 @@ import { Calendar, MoreHorizontal, Tags, Trash, User } from 'lucide-react'
import * as React from 'react'
import {
Button,
- Command_Shadcn_,
- CommandEmpty_Shadcn_,
- CommandGroup_Shadcn_,
- CommandInput_Shadcn_,
- CommandItem_Shadcn_,
- CommandList_Shadcn_,
+ Command,
+ CommandEmpty,
+ CommandGroup,
+ CommandInput,
+ CommandItem,
+ CommandList,
DropdownMenu,
DropdownMenuContent,
DropdownMenuGroup,
@@ -72,14 +72,14 @@ export default function ComboboxDropdownMenu() {
Apply label
-
-
+
+
-
- No label found.
-
+
+ No label found.
+
{labels.map((label) => (
- {
@@ -88,12 +88,12 @@ export default function ComboboxDropdownMenu() {
}}
>
{label}
-
+
))}
-
-
+
+
-
+
diff --git a/apps/design-system/registry/default/example/combobox-form.tsx b/apps/design-system/registry/default/example/combobox-form.tsx
index b83b07f07faef..b6cd2f507d110 100644
--- a/apps/design-system/registry/default/example/combobox-form.tsx
+++ b/apps/design-system/registry/default/example/combobox-form.tsx
@@ -6,12 +6,12 @@ import { useForm } from 'react-hook-form'
import { toast } from 'sonner'
import {
Button,
- Command_Shadcn_,
- CommandEmpty_Shadcn_,
- CommandGroup_Shadcn_,
- CommandInput_Shadcn_,
- CommandItem_Shadcn_,
- CommandList_Shadcn_,
+ Command,
+ CommandEmpty,
+ CommandGroup,
+ CommandInput,
+ CommandItem,
+ CommandList,
Form,
FormControl,
FormDescription,
@@ -94,13 +94,13 @@ export default function ComboboxForm() {
-
-
-
- No language found.
-
+
+
+
+ No language found.
+
{languages.map((language) => (
- {
@@ -114,11 +114,11 @@ export default function ComboboxForm() {
)}
/>
{language.label}
-
+
))}
-
-
-
+
+
+
diff --git a/apps/design-system/registry/default/example/combobox-popover.tsx b/apps/design-system/registry/default/example/combobox-popover.tsx
index 88ac417d507ba..4c2df6b951c20 100644
--- a/apps/design-system/registry/default/example/combobox-popover.tsx
+++ b/apps/design-system/registry/default/example/combobox-popover.tsx
@@ -12,12 +12,12 @@ import {
import * as React from 'react'
import {
Button,
- Command_Shadcn_,
- CommandEmpty_Shadcn_,
- CommandGroup_Shadcn_,
- CommandInput_Shadcn_,
- CommandItem_Shadcn_,
- CommandList_Shadcn_,
+ Command,
+ CommandEmpty,
+ CommandGroup,
+ CommandInput,
+ CommandItem,
+ CommandList,
Popover,
PopoverContent,
PopoverTrigger,
@@ -84,13 +84,13 @@ export default function ComboboxPopover() {
-
-
-
- No results found.
-
+
+
+
+ No results found.
+
{statuses.map((status) => (
- {
@@ -107,11 +107,11 @@ export default function ComboboxPopover() {
)}
/>
{status.label}
-
+
))}
-
-
-
+
+
+
diff --git a/apps/design-system/registry/default/example/combobox-responsive.tsx b/apps/design-system/registry/default/example/combobox-responsive.tsx
index d09a1fd62851d..90dcb2f8506df 100644
--- a/apps/design-system/registry/default/example/combobox-responsive.tsx
+++ b/apps/design-system/registry/default/example/combobox-responsive.tsx
@@ -4,12 +4,12 @@ import { Plus } from 'lucide-react'
import * as React from 'react'
import {
Button,
- Command_Shadcn_,
- CommandEmpty_Shadcn_,
- CommandGroup_Shadcn_,
- CommandInput_Shadcn_,
- CommandItem_Shadcn_,
- CommandList_Shadcn_,
+ Command,
+ CommandEmpty,
+ CommandGroup,
+ CommandInput,
+ CommandItem,
+ CommandList,
Drawer,
DrawerContent,
DrawerTrigger,
@@ -97,13 +97,13 @@ function StatusList({
setSelectedStatus: (status: Status | null) => void
}) {
return (
-
-
-
- No results found.
-
+
+
+
+ No results found.
+
{statuses.map((status) => (
- {
@@ -112,10 +112,10 @@ function StatusList({
}}
>
{status.label}
-
+
))}
-
-
-
+
+
+
)
}
diff --git a/apps/design-system/registry/default/example/command-demo.tsx b/apps/design-system/registry/default/example/command-demo.tsx
index 8589373f51dd4..b51049ab5bcf2 100644
--- a/apps/design-system/registry/default/example/command-demo.tsx
+++ b/apps/design-system/registry/default/example/command-demo.tsx
@@ -1,54 +1,54 @@
import { Calculator, Calendar, CreditCard, Settings, Smile, User } from 'lucide-react'
import {
- Command_Shadcn_,
- CommandEmpty_Shadcn_,
- CommandGroup_Shadcn_,
- CommandInput_Shadcn_,
- CommandItem_Shadcn_,
- CommandList_Shadcn_,
- CommandSeparator_Shadcn_,
- CommandShortcut_Shadcn_,
+ Command,
+ CommandEmpty,
+ CommandGroup,
+ CommandInput,
+ CommandItem,
+ CommandList,
+ CommandSeparator,
+ CommandShortcut,
} from 'ui'
export default function CommandDemo() {
return (
-
-
-
- No results found.
-
-
+
+
+
+ No results found.
+
+
Calendar
-
-
+
+
Search Emoji
-
-
+
+
Calculator
-
-
-
-
-
+
+
+
+
+
Profile
- ⌘P
-
-
+ ⌘P
+
+
Billing
- ⌘B
-
-
+ ⌘B
+
+
Settings
- ⌘S
-
-
-
-
+ ⌘S
+
+
+
+
)
}
diff --git a/apps/design-system/registry/default/example/command-dialog.tsx b/apps/design-system/registry/default/example/command-dialog.tsx
index fc9eab9b0ff60..308c3cc1ac267 100644
--- a/apps/design-system/registry/default/example/command-dialog.tsx
+++ b/apps/design-system/registry/default/example/command-dialog.tsx
@@ -4,13 +4,13 @@ import { Calculator, Calendar, CreditCard, Settings, Smile, User } from 'lucide-
import * as React from 'react'
import {
CommandDialog,
- CommandEmpty_Shadcn_,
- CommandGroup_Shadcn_,
- CommandInput_Shadcn_,
- CommandItem_Shadcn_,
- CommandList_Shadcn_,
- CommandSeparator_Shadcn_,
- CommandShortcut_Shadcn_,
+ CommandEmpty,
+ CommandGroup,
+ CommandInput,
+ CommandItem,
+ CommandList,
+ CommandSeparator,
+ CommandShortcut,
} from 'ui'
export default function CommandDialogDemo() {
@@ -37,42 +37,42 @@ export default function CommandDialogDemo() {
-
-
- No results found.
-
-
+
+
+ No results found.
+
+
Calendar
-
-
+
+
Search Emoji
-
-
+
+
Calculator
-
-
-
-
-
+
+
+
+
+
Profile
- ⌘P
-
-
+ ⌘P
+
+
Billing
- ⌘B
-
-
+ ⌘B
+
+
Settings
- ⌘S
-
-
-
+ ⌘S
+
+
+
>
)
diff --git a/apps/docs/components/ProjectConfigVariables/ProjectConfigVariables.ComboBox.tsx b/apps/docs/components/ProjectConfigVariables/ProjectConfigVariables.ComboBox.tsx
index fc8d2a50cf566..105cb3e45b6eb 100644
--- a/apps/docs/components/ProjectConfigVariables/ProjectConfigVariables.ComboBox.tsx
+++ b/apps/docs/components/ProjectConfigVariables/ProjectConfigVariables.ComboBox.tsx
@@ -1,21 +1,21 @@
+import { useIntersectionObserver } from '~/hooks/useIntersectionObserver'
import { noop } from 'lodash-es'
import { Check, ChevronsUpDown } from 'lucide-react'
import { useEffect, useRef, useState } from 'react'
import {
Button_Shadcn_ as Button,
cn,
- Command_Shadcn_ as Command,
- CommandGroup_Shadcn_ as CommandGroup,
- CommandInput_Shadcn_ as CommandInput,
- CommandItem_Shadcn_ as CommandItem,
- CommandList_Shadcn_ as CommandList,
- Popover as Popover,
- PopoverContent as PopoverContent,
- PopoverTrigger as PopoverTrigger,
+ Command,
+ CommandGroup as CommandGroup,
+ CommandInput,
+ CommandItem as CommandItem,
+ CommandList as CommandList,
+ Popover,
+ PopoverContent,
+ PopoverTrigger,
ScrollArea,
} from 'ui'
import ShimmeringLoader from 'ui-patterns/ShimmeringLoader'
-import { useIntersectionObserver } from '~/hooks/useIntersectionObserver'
export interface ComboBoxOption {
id: string
diff --git a/apps/docs/features/ui/InfoTooltip.tsx b/apps/docs/features/ui/InfoTooltip.tsx
index d8dd67b1da623..d604a0047b128 100644
--- a/apps/docs/features/ui/InfoTooltip.tsx
+++ b/apps/docs/features/ui/InfoTooltip.tsx
@@ -1,20 +1,20 @@
'use client'
+import { useBreakpoint } from 'common'
+import { InfoIcon, XIcon } from 'lucide-react'
import React, {
- type PropsWithChildren,
useCallback,
useEffect,
useId,
useRef,
useState,
+ type PropsWithChildren,
} from 'react'
-import { InfoIcon, XIcon } from 'lucide-react'
import { ErrorBoundary } from 'react-error-boundary'
-import { useBreakpoint } from 'common'
import {
Button,
cn,
- CommandEmpty_Shadcn_,
+ CommandEmpty,
Sheet,
SheetContent,
SheetHeader,
@@ -105,7 +105,7 @@ const InfoTooltip = ({
'w-full h-fit min-h-[200px] py-2 px-4'
)}
>
- }>
+ }>
diff --git a/apps/docs/features/ui/McpConfigPanel.tsx b/apps/docs/features/ui/McpConfigPanel.tsx
index e4723715f4a7d..ec2cd3c752f7b 100644
--- a/apps/docs/features/ui/McpConfigPanel.tsx
+++ b/apps/docs/features/ui/McpConfigPanel.tsx
@@ -1,5 +1,9 @@
'use client'
+import { useDebounce } from '~/hooks/useDebounce'
+import { useIntersectionObserver } from '~/hooks/useIntersectionObserver'
+import { useProjectsInfiniteQuery } from '~/lib/fetch/projects-infinite'
+import { useSendTelemetryEvent } from '~/lib/telemetry'
import { useIsLoggedIn, useIsUserLoading } from 'common'
import { Check, ChevronDown } from 'lucide-react'
import { useTheme } from 'next-themes'
@@ -8,11 +12,11 @@ import { useEffect, useMemo, useRef, useState } from 'react'
import {
Button,
cn,
- Command_Shadcn_,
- CommandGroup_Shadcn_,
- CommandInput_Shadcn_,
- CommandItem_Shadcn_,
- CommandList_Shadcn_,
+ Command,
+ CommandGroup,
+ CommandInput,
+ CommandItem,
+ CommandList,
Popover,
PopoverContent,
PopoverTrigger,
@@ -25,10 +29,6 @@ import {
type McpClient,
} from 'ui-patterns/McpUrlBuilder'
import ShimmeringLoader from 'ui-patterns/ShimmeringLoader'
-import { useDebounce } from '~/hooks/useDebounce'
-import { useIntersectionObserver } from '~/hooks/useIntersectionObserver'
-import { useProjectsInfiniteQuery } from '~/lib/fetch/projects-infinite'
-import { useSendTelemetryEvent } from '~/lib/telemetry'
type PlatformType = (typeof PLATFORMS)[number]['value']
@@ -135,8 +135,8 @@ function ProjectSelector({
)}
-
-
+ setSearch('')}
/>
-
-
+
+
{isLoading ? (
@@ -160,7 +160,7 @@ function ProjectSelector({
)}
7 ? 'h-[210px]' : ''}>
{projects?.map((project) => (
- {
@@ -178,16 +178,16 @@ function ProjectSelector({
project.ref === selectedProject?.ref ? 'opacity-100' : 'opacity-0'
)}
/>
-
+
))}
{hasNextPage && }
>
)}
-
-
-
+
+
+
)
@@ -230,11 +230,11 @@ function PlatformSelector({
-
-
-
+
+
+
{PLATFORMS.map((platform) => (
- {
@@ -252,11 +252,11 @@ function PlatformSelector({
platform.value === selectedPlatform ? 'opacity-100' : 'opacity-0'
)}
/>
-
+
))}
-
-
-
+
+
+
)
diff --git a/apps/learn/components/command-menu.tsx b/apps/learn/components/command-menu.tsx
index d764ce7e38f4b..75f055f9a8f2f 100644
--- a/apps/learn/components/command-menu.tsx
+++ b/apps/learn/components/command-menu.tsx
@@ -4,21 +4,21 @@ import { CircleIcon, LaptopIcon, MoonIcon, SunIcon } from 'lucide-react'
import { useTheme } from 'next-themes'
import { useRouter } from 'next/navigation'
import * as React from 'react'
-
-import { COMMAND_ITEMS } from '@/config/docs'
-import { cn } from '@/lib/utils'
import {
Button,
CommandDialog,
- CommandEmpty_Shadcn_,
- CommandGroup_Shadcn_,
- CommandInput_Shadcn_,
- CommandItem_Shadcn_,
- CommandList_Shadcn_,
- CommandSeparator_Shadcn_,
+ CommandEmpty,
+ CommandGroup,
+ CommandInput,
+ CommandItem,
+ CommandList,
+ CommandSeparator,
DialogProps,
} from 'ui'
+import { COMMAND_ITEMS } from '@/config/docs'
+import { cn } from '@/lib/utils'
+
export function CommandMenu({ ...props }: DialogProps) {
const router = useRouter()
const [open, setOpen] = React.useState(false)
@@ -69,12 +69,12 @@ export function CommandMenu({ ...props }: DialogProps) {
-
-
- No results found.
-
+
+
+ No results found.
+
{COMMAND_ITEMS.map((navItem) => (
- runCommand(() => router.push(navItem.href as string))}
@@ -83,29 +83,29 @@ export function CommandMenu({ ...props }: DialogProps) {
{navItem.label}
-
+
))}
-
-
-
- runCommand(() => setTheme('light'))}>
+
+
+
+ runCommand(() => setTheme('light'))}>
Light
-
- runCommand(() => setTheme('dark'))}>
+
+ runCommand(() => setTheme('dark'))}>
Dark
-
- runCommand(() => setTheme('classic-dark'))}>
+
+ runCommand(() => setTheme('classic-dark'))}>
Classic dark
-
- runCommand(() => setTheme('system'))}>
+
+ runCommand(() => setTheme('system'))}>
System
-
-
-
+
+
+
>
)
diff --git a/apps/studio/components/interfaces/Account/AccessTokens/Scoped/Form/Permissions/PermissionResourceSelector.tsx b/apps/studio/components/interfaces/Account/AccessTokens/Scoped/Form/Permissions/PermissionResourceSelector.tsx
index 8f6416c71a144..f1d2e54c9d2ca 100644
--- a/apps/studio/components/interfaces/Account/AccessTokens/Scoped/Form/Permissions/PermissionResourceSelector.tsx
+++ b/apps/studio/components/interfaces/Account/AccessTokens/Scoped/Form/Permissions/PermissionResourceSelector.tsx
@@ -3,12 +3,12 @@ import { Path, PathValue } from 'react-hook-form'
import {
Button,
Checkbox,
- Command_Shadcn_,
- CommandEmpty_Shadcn_,
- CommandGroup_Shadcn_,
- CommandInput_Shadcn_,
- CommandItem_Shadcn_,
- CommandList_Shadcn_,
+ Command,
+ CommandEmpty,
+ CommandGroup,
+ CommandInput,
+ CommandItem,
+ CommandList,
Popover,
PopoverContent,
PopoverTrigger,
@@ -46,19 +46,19 @@ export const PermissionResourceSelector =
-
-
-
- No resources found.
+
+
+
+ No resources found.
-
+
{ACCESS_TOKEN_RESOURCES.map((resource) => {
const isChecked = permissionRows.some(
(row: PermissionRow) => row.resource === resource.resource
)
return (
- handleToggleResource(resource)}
@@ -77,13 +77,13 @@ export const PermissionResourceSelector =
-
+
)
})}
-
-
-
+
+
+
)
diff --git a/apps/studio/components/interfaces/Account/Preferences/TimezoneSettings.tsx b/apps/studio/components/interfaces/Account/Preferences/TimezoneSettings.tsx
index 2430bf3bdee93..63a318f171bd4 100644
--- a/apps/studio/components/interfaces/Account/Preferences/TimezoneSettings.tsx
+++ b/apps/studio/components/interfaces/Account/Preferences/TimezoneSettings.tsx
@@ -6,12 +6,12 @@ import {
Card,
CardContent,
cn,
- Command_Shadcn_,
- CommandEmpty_Shadcn_,
- CommandGroup_Shadcn_,
- CommandInput_Shadcn_,
- CommandItem_Shadcn_,
- CommandList_Shadcn_,
+ Command,
+ CommandEmpty,
+ CommandGroup,
+ CommandInput,
+ CommandItem,
+ CommandList,
Popover,
PopoverContent,
PopoverTrigger,
@@ -103,13 +103,13 @@ export const TimezoneSettings = () => {
-
-
-
- No timezones found
-
+
+
+
+ No timezones found
+
- handleSelect('')}
@@ -126,12 +126,12 @@ export const TimezoneSettings = () => {
isAutoDetected ? 'opacity-100' : 'opacity-0'
)}
/>
-
+
{TIMEZONES_BY_IANA.map((entry) => {
const ianaName = entry.utc[0]
const isSelected = !isAutoDetected && storedTimezone === ianaName
return (
- {
isSelected ? 'opacity-100' : 'opacity-0'
)}
/>
-
+
)
})}
-
-
-
+
+
+
diff --git a/apps/studio/components/interfaces/App/CommandMenu/ContextSearchResults.shared.tsx b/apps/studio/components/interfaces/App/CommandMenu/ContextSearchResults.shared.tsx
index 3eaf23408efdb..d798f407c50c5 100644
--- a/apps/studio/components/interfaces/App/CommandMenu/ContextSearchResults.shared.tsx
+++ b/apps/studio/components/interfaces/App/CommandMenu/ContextSearchResults.shared.tsx
@@ -1,6 +1,6 @@
'use client'
-import { cn, CommandList_Shadcn_ } from 'ui'
+import { cn, CommandList } from 'ui'
import { ShimmeringLoader } from 'ui-patterns'
import { TextHighlighter } from 'ui-patterns/CommandMenu'
import { CommandMenuGroup } from 'ui-patterns/CommandMenu/internal/CommandMenuGroup'
@@ -86,7 +86,7 @@ export function ResultsList({
})
return (
-
))}
-
+
)
}
diff --git a/apps/studio/components/interfaces/Auth/Policies/PolicyEditorPanel/PolicyDetailsV2.tsx b/apps/studio/components/interfaces/Auth/Policies/PolicyEditorPanel/PolicyDetailsV2.tsx
index ca41b17194ab0..01340314da6b2 100644
--- a/apps/studio/components/interfaces/Auth/Policies/PolicyEditorPanel/PolicyDetailsV2.tsx
+++ b/apps/studio/components/interfaces/Auth/Policies/PolicyEditorPanel/PolicyDetailsV2.tsx
@@ -11,12 +11,12 @@ import { UseFormReturn } from 'react-hook-form'
import {
Button,
cn,
- Command_Shadcn_,
- CommandEmpty_Shadcn_,
- CommandGroup_Shadcn_,
- CommandInput_Shadcn_,
- CommandItem_Shadcn_,
- CommandList_Shadcn_,
+ Command,
+ CommandEmpty,
+ CommandGroup,
+ CommandInput,
+ CommandItem,
+ CommandList,
FormControl,
FormField,
FormItem,
@@ -182,14 +182,14 @@ export const PolicyDetailsV2 = ({
align="start"
sameWidthAsTrigger
>
-
-
- event.stopPropagation()}>
- No tables found
-
+
+
+ event.stopPropagation()}>
+ No tables found
+
7 ? 'h-[200px]' : ''}>
{(tables ?? []).map((table) => (
- {
@@ -205,12 +205,12 @@ export const PolicyDetailsV2 = ({
{field.value === table.name ? : ''}
{table.name}
-
+
))}
-
-
-
+
+
+
diff --git a/apps/studio/components/interfaces/Auth/RLSTester/UserSelector.tsx b/apps/studio/components/interfaces/Auth/RLSTester/UserSelector.tsx
index 17daee2762cfe..bd26666b3da96 100644
--- a/apps/studio/components/interfaces/Auth/RLSTester/UserSelector.tsx
+++ b/apps/studio/components/interfaces/Auth/RLSTester/UserSelector.tsx
@@ -6,12 +6,12 @@ import { toast } from 'sonner'
import {
Button,
cn,
- Command_Shadcn_,
- CommandEmpty_Shadcn_,
- CommandGroup_Shadcn_,
- CommandInput_Shadcn_,
- CommandItem_Shadcn_,
- CommandList_Shadcn_,
+ Command,
+ CommandEmpty,
+ CommandGroup,
+ CommandInput,
+ CommandItem,
+ CommandList,
Popover,
PopoverContent,
PopoverTrigger,
@@ -82,8 +82,8 @@ export const UserSelector = () => {
-
-
+ {
Failed to fetch users: {error.message}
) : (
- No user found
+ No user found
)}
-
+
{isPending && (
@@ -107,11 +107,11 @@ export const UserSelector = () => {
)}
{isSuccess && (
-
+
7 ? 'h-full md:h-[210px]' : ''}>
{users.map((user) => {
return (
- {
{impersonatingUser?.id === user.id && }
-
+
)
})}
-
+
)}
-
-
+
+
diff --git a/apps/studio/components/interfaces/Auth/ThirdPartyAuthForm/AwsRegionSelector.tsx b/apps/studio/components/interfaces/Auth/ThirdPartyAuthForm/AwsRegionSelector.tsx
index f6682a1b1874a..6cbbdfab02017 100644
--- a/apps/studio/components/interfaces/Auth/ThirdPartyAuthForm/AwsRegionSelector.tsx
+++ b/apps/studio/components/interfaces/Auth/ThirdPartyAuthForm/AwsRegionSelector.tsx
@@ -3,12 +3,12 @@ import { useId, useState } from 'react'
import {
Button,
cn,
- Command_Shadcn_,
- CommandEmpty_Shadcn_,
- CommandGroup_Shadcn_,
- CommandInput_Shadcn_,
- CommandItem_Shadcn_,
- CommandList_Shadcn_,
+ Command,
+ CommandEmpty,
+ CommandGroup,
+ CommandInput,
+ CommandItem,
+ CommandList,
FormControl,
Popover,
PopoverContent,
@@ -78,14 +78,14 @@ export const AwsRegionSelector = ({
-
-
-
- No regions found.
-
+
+
+
+ No regions found.
+
{AWS_IDP_REGIONS.map((option) => (
- {
@@ -97,12 +97,12 @@ export const AwsRegionSelector = ({
className={cn('mr-2 h-4 w-4', option === value ? 'opacity-100' : 'opacity-0')}
/>
{option}
-
+
))}
-
-
-
+
+
+
)
diff --git a/apps/studio/components/interfaces/Billing/Payment/PaymentMethods/NewPaymentMethodElement.tsx b/apps/studio/components/interfaces/Billing/Payment/PaymentMethods/NewPaymentMethodElement.tsx
index 8316091929190..6c6abcc3d92b7 100644
--- a/apps/studio/components/interfaces/Billing/Payment/PaymentMethods/NewPaymentMethodElement.tsx
+++ b/apps/studio/components/interfaces/Billing/Payment/PaymentMethods/NewPaymentMethodElement.tsx
@@ -20,12 +20,12 @@ import {
Button,
Checkbox,
cn,
- Command_Shadcn_ as Command,
- CommandEmpty_Shadcn_ as CommandEmpty,
- CommandGroup_Shadcn_ as CommandGroup,
- CommandInput_Shadcn_ as CommandInput,
- CommandItem_Shadcn_ as CommandItem,
- CommandList_Shadcn_ as CommandList,
+ Command,
+ CommandEmpty,
+ CommandGroup,
+ CommandInput,
+ CommandItem,
+ CommandList,
FormControl,
FormField,
FormItem,
diff --git a/apps/studio/components/interfaces/BranchManagement/BranchSelector.tsx b/apps/studio/components/interfaces/BranchManagement/BranchSelector.tsx
index 7fcc00cc2e959..544de78c274f0 100644
--- a/apps/studio/components/interfaces/BranchManagement/BranchSelector.tsx
+++ b/apps/studio/components/interfaces/BranchManagement/BranchSelector.tsx
@@ -1,12 +1,12 @@
import { Check, GitMerge, Shield } from 'lucide-react'
import { useState } from 'react'
import {
- Command_Shadcn_,
- CommandEmpty_Shadcn_,
- CommandGroup_Shadcn_,
- CommandInput_Shadcn_,
- CommandItem_Shadcn_,
- CommandList_Shadcn_,
+ Command,
+ CommandEmpty,
+ CommandGroup,
+ CommandInput,
+ CommandItem,
+ CommandList,
Popover,
PopoverContent,
PopoverTrigger,
@@ -68,14 +68,14 @@ export const BranchSelector = ({
-
-
-
- No available branches found
-
+
+
+
+ No available branches found
+
{availableBranches.map((branch) => (
- Synced to a Git branch}
{branch.review_requested_at && Merge request opened }
-
+
))}
-
-
-
+
+
+
)
diff --git a/apps/studio/components/interfaces/Connect/ConnectDropdown.tsx b/apps/studio/components/interfaces/Connect/ConnectDropdown.tsx
index 70a25816e18ba..a2a0b30e9b015 100644
--- a/apps/studio/components/interfaces/Connect/ConnectDropdown.tsx
+++ b/apps/studio/components/interfaces/Connect/ConnectDropdown.tsx
@@ -3,12 +3,12 @@ import { useState } from 'react'
import {
Button,
cn,
- Command_Shadcn_,
- CommandEmpty_Shadcn_,
- CommandGroup_Shadcn_,
- CommandInput_Shadcn_,
- CommandItem_Shadcn_,
- CommandList_Shadcn_,
+ Command,
+ CommandEmpty,
+ CommandGroup,
+ CommandInput,
+ CommandItem,
+ CommandList,
Popover,
PopoverContent,
PopoverTrigger,
@@ -73,13 +73,13 @@ export const ConnectDropdown = ({
-
-
-
- No results found.
-
+
+
+
+ No results found.
+
{items.map((item) => (
- {
@@ -102,11 +102,11 @@ export const ConnectDropdown = ({
size={15}
className={cn('ml-auto ', item.key === state ? 'opacity-100' : 'opacity-0')}
/>
-
+
))}
-
-
-
+
+
+
)
diff --git a/apps/studio/components/interfaces/ConnectSheet/FrameworkSelector.tsx b/apps/studio/components/interfaces/ConnectSheet/FrameworkSelector.tsx
index 1d372e1bdf22a..1bf01b509d241 100644
--- a/apps/studio/components/interfaces/ConnectSheet/FrameworkSelector.tsx
+++ b/apps/studio/components/interfaces/ConnectSheet/FrameworkSelector.tsx
@@ -3,12 +3,12 @@ import { useState } from 'react'
import {
Button,
cn,
- Command_Shadcn_,
- CommandEmpty_Shadcn_,
- CommandGroup_Shadcn_,
- CommandInput_Shadcn_,
- CommandItem_Shadcn_,
- CommandList_Shadcn_,
+ Command,
+ CommandEmpty,
+ CommandGroup,
+ CommandInput,
+ CommandItem,
+ CommandList,
Popover,
PopoverContent,
PopoverTrigger,
@@ -64,13 +64,13 @@ export const FrameworkSelector = ({
align="start"
onOpenAutoFocus={(e) => e.preventDefault()}
>
-
-
-
- No results found.
-
+
+
+
+ No results found.
+
{items.map((item) => (
- handleSelect(item.key)}
@@ -82,11 +82,11 @@ export const FrameworkSelector = ({
size={15}
className={cn('ml-auto', item.key === value ? 'opacity-100' : 'opacity-0')}
/>
-
+
))}
-
-
-
+
+
+
)
diff --git a/apps/studio/components/interfaces/Database/Backups/PITR/TimezoneSelection.tsx b/apps/studio/components/interfaces/Database/Backups/PITR/TimezoneSelection.tsx
index a0a8d24f945bc..028bd48a27c1f 100644
--- a/apps/studio/components/interfaces/Database/Backups/PITR/TimezoneSelection.tsx
+++ b/apps/studio/components/interfaces/Database/Backups/PITR/TimezoneSelection.tsx
@@ -3,12 +3,12 @@ import { useId, useState } from 'react'
import {
Button,
cn,
- Command_Shadcn_,
- CommandEmpty_Shadcn_,
- CommandGroup_Shadcn_,
- CommandInput_Shadcn_,
- CommandItem_Shadcn_,
- CommandList_Shadcn_,
+ Command,
+ CommandEmpty,
+ CommandGroup,
+ CommandInput,
+ CommandItem,
+ CommandList,
Popover,
PopoverContent,
PopoverTrigger,
@@ -51,14 +51,14 @@ export const TimezoneSelection = ({
-
-
-
- No timezones found...
-
+
+
+
+ No timezones found...
+
{timezoneOptions.map((option) => (
- {
@@ -78,12 +78,12 @@ export const TimezoneSelection = ({
selectedTimezone.text === option ? 'opacity-100' : 'opacity-0'
)}
/>
-
+
))}
-
-
-
+
+
+
diff --git a/apps/studio/components/interfaces/Database/Indexes/CreateIndexSidePanel.tsx b/apps/studio/components/interfaces/Database/Indexes/CreateIndexSidePanel.tsx
index 68e89737b6472..270350ebba93f 100644
--- a/apps/studio/components/interfaces/Database/Indexes/CreateIndexSidePanel.tsx
+++ b/apps/studio/components/interfaces/Database/Indexes/CreateIndexSidePanel.tsx
@@ -5,12 +5,12 @@ import { toast } from 'sonner'
import {
Button,
cn,
- Command_Shadcn_,
- CommandEmpty_Shadcn_,
- CommandGroup_Shadcn_,
- CommandInput_Shadcn_,
- CommandItem_Shadcn_,
- CommandList_Shadcn_,
+ Command,
+ CommandEmpty,
+ CommandGroup,
+ CommandInput,
+ CommandItem,
+ CommandList,
Popover,
PopoverContent,
PopoverTrigger,
@@ -195,20 +195,20 @@ CREATE INDEX ON "${selectedSchema}"."${selectedEntity}" USING ${selectedIndexTyp
-
-
+
- 7 && 'max-h-[210px]! overflow-y-auto')}
onWheel={(event) => event.stopPropagation()}
>
- No schemas found
-
+ No schemas found
+
{(schemas ?? []).map((schema) => (
- {
@@ -222,11 +222,11 @@ CREATE INDEX ON "${selectedSchema}"."${selectedEntity}" USING ${selectedIndexTyp
{selectedSchema === schema.name && (
)}
-
+
))}
-
-
-
+
+
+
@@ -264,17 +264,17 @@ CREATE INDEX ON "${selectedSchema}"."${selectedEntity}" USING ${selectedIndexTyp
{/* [Terry] shouldFilter context:
https://github.com/pacocoursey/cmdk/issues/267#issuecomment-2252717107 */}
-
-
+
- 7 && 'max-h-[210px]! overflow-y-auto')}
onWheel={(event) => event.stopPropagation()}
>
-
+
{isLoadingEntities ? (
@@ -283,10 +283,10 @@ CREATE INDEX ON "${selectedSchema}"."${selectedEntity}" USING ${selectedIndexTyp
) : (
'No tables found'
)}
-
-
+
+
{entityTypes.map((entity) => (
- {
@@ -302,11 +302,11 @@ CREATE INDEX ON "${selectedSchema}"."${selectedEntity}" USING ${selectedIndexTyp
{selectedEntity === entity.name && (
)}
-
+
))}
-
-
-
+
+
+
diff --git a/apps/studio/components/interfaces/Database/Replication/DestinationPanel/DestinationForm/PublicationsComboBox.tsx b/apps/studio/components/interfaces/Database/Replication/DestinationPanel/DestinationForm/PublicationsComboBox.tsx
index 158a21ab7b4cb..dd4e9fea9a34a 100644
--- a/apps/studio/components/interfaces/Database/Replication/DestinationPanel/DestinationForm/PublicationsComboBox.tsx
+++ b/apps/studio/components/interfaces/Database/Replication/DestinationPanel/DestinationForm/PublicationsComboBox.tsx
@@ -5,13 +5,13 @@ import {
Badge,
Button,
cn,
- Command_Shadcn_,
- CommandEmpty_Shadcn_,
- CommandGroup_Shadcn_,
- CommandInput_Shadcn_,
- CommandItem_Shadcn_,
- CommandList_Shadcn_,
- CommandSeparator_Shadcn_,
+ Command,
+ CommandEmpty,
+ CommandGroup,
+ CommandInput,
+ CommandItem,
+ CommandList,
+ CommandSeparator,
Popover,
PopoverContent,
PopoverTrigger,
@@ -74,8 +74,8 @@ export const PublicationsComboBox = ({
-
-
+
-
-
+
+
{isLoadingPublications ? (
@@ -96,9 +96,9 @@ export const PublicationsComboBox = ({
) : (
'No publications found'
)}
-
+
-
+
{publications.length === 0 && (
No publications available
@@ -106,7 +106,7 @@ export const PublicationsComboBox = ({
)}
7 ? 'h-[210px]' : ''}>
{publications.map((pub) => (
- {
@@ -128,25 +128,25 @@ export const PublicationsComboBox = ({
)}
-
+
))}
-
+
-
+
-
-
+
New publication
-
-
-
-
+
+
+
+
)
diff --git a/apps/studio/components/interfaces/Integrations/CronJobs/EdgeFunctionSection.tsx b/apps/studio/components/interfaces/Integrations/CronJobs/EdgeFunctionSection.tsx
index 774959c90064e..d14d8bd5f7e26 100644
--- a/apps/studio/components/interfaces/Integrations/CronJobs/EdgeFunctionSection.tsx
+++ b/apps/studio/components/interfaces/Integrations/CronJobs/EdgeFunctionSection.tsx
@@ -6,12 +6,12 @@ import { UseFormReturn } from 'react-hook-form'
import {
Button,
cn,
- Command_Shadcn_,
- CommandEmpty_Shadcn_,
- CommandGroup_Shadcn_,
- CommandInput_Shadcn_,
- CommandItem_Shadcn_,
- CommandList_Shadcn_,
+ Command,
+ CommandEmpty,
+ CommandGroup,
+ CommandInput,
+ CommandItem,
+ CommandList,
FormControl,
FormField,
FormItem,
@@ -152,15 +152,15 @@ export const EdgeFunctionSection = ({ form }: HTTPRequestFieldsProps) => {
-
-
-
- No edge function found.
-
+
+
+
+ No edge function found.
+
7 ? 'h-[210px]' : ''}>
{edgeFunctions.map((fn) => {
return (
- {
@@ -175,13 +175,13 @@ export const EdgeFunctionSection = ({ form }: HTTPRequestFieldsProps) => {
)}
/>
{fn.name}
-
+
)
})}
-
-
-
+
+
+
diff --git a/apps/studio/components/interfaces/Integrations/Vercel/OrganizationPicker.tsx b/apps/studio/components/interfaces/Integrations/Vercel/OrganizationPicker.tsx
index 6cbda52b97e02..e342673612245 100644
--- a/apps/studio/components/interfaces/Integrations/Vercel/OrganizationPicker.tsx
+++ b/apps/studio/components/interfaces/Integrations/Vercel/OrganizationPicker.tsx
@@ -4,12 +4,12 @@ import {
Badge,
Button,
cn,
- Command_Shadcn_,
- CommandEmpty_Shadcn_,
- CommandGroup_Shadcn_,
- CommandInput_Shadcn_,
- CommandItem_Shadcn_,
- CommandList_Shadcn_,
+ Command,
+ CommandEmpty,
+ CommandGroup,
+ CommandInput,
+ CommandItem,
+ CommandList,
Popover,
PopoverContent,
PopoverTrigger,
@@ -85,14 +85,14 @@ const OrganizationPicker = ({
-
-
-
- No results found.
-
+
+
+
+ No results found.
+
{organizationsData?.map((org) => {
return (
- Integration Installed
)}
-
+
)
})}
-
-
-
+
+
+
>
diff --git a/apps/studio/components/interfaces/Integrations/VercelGithub/ProjectLinker.tsx b/apps/studio/components/interfaces/Integrations/VercelGithub/ProjectLinker.tsx
index f08401a8858dc..4a790b302e592 100644
--- a/apps/studio/components/interfaces/Integrations/VercelGithub/ProjectLinker.tsx
+++ b/apps/studio/components/interfaces/Integrations/VercelGithub/ProjectLinker.tsx
@@ -7,13 +7,13 @@ import {
Badge,
Button,
cn,
- Command_Shadcn_,
- CommandEmpty_Shadcn_,
- CommandGroup_Shadcn_,
- CommandInput_Shadcn_,
- CommandItem_Shadcn_,
- CommandList_Shadcn_,
- CommandSeparator_Shadcn_,
+ Command,
+ CommandEmpty,
+ CommandGroup,
+ CommandInput,
+ CommandItem,
+ CommandList,
+ CommandSeparator,
Popover,
PopoverContent,
PopoverTrigger,
@@ -262,8 +262,8 @@ const ProjectLinker = ({
renderActions={() => {
return (
projectCreationEnabled && (
-
-
+ {
setOpenProjectsDropdown(false)
@@ -281,8 +281,8 @@ const ProjectLinker = ({
Create a new project
-
-
+
+
)
)
}}
@@ -324,14 +324,14 @@ const ProjectLinker = ({
-
-
-
- No results found.
-
+
+
+
+ No results found.
+
{foreignProjects.map((project, i) => {
return (
-
{project.name}
-
+
)
})}
{foreignProjects.length === 0 && (
- No results found.
+ No results found.
)}
-
+
{mode === 'GitHub' && (
<>
-
-
-
+
+ openInstallGitHubIntegrationWindow('install')}
>
Add GitHub Repositories
-
-
+
+
>
)}
-
-
+
+
diff --git a/apps/studio/components/interfaces/Integrations/Wrappers/ColumnType.tsx b/apps/studio/components/interfaces/Integrations/Wrappers/ColumnType.tsx
index e258d44edc6c9..634cc26a74f2b 100644
--- a/apps/studio/components/interfaces/Integrations/Wrappers/ColumnType.tsx
+++ b/apps/studio/components/interfaces/Integrations/Wrappers/ColumnType.tsx
@@ -17,13 +17,13 @@ import {
AlertTitle,
Button,
cn,
- Command_Shadcn_,
- CommandEmpty_Shadcn_,
- CommandGroup_Shadcn_,
- CommandInput_Shadcn_,
- CommandItem_Shadcn_,
- CommandList_Shadcn_,
- CommandSeparator_Shadcn_,
+ Command,
+ CommandEmpty,
+ CommandGroup,
+ CommandInput,
+ CommandItem,
+ CommandList,
+ CommandSeparator,
CriticalIcon,
FormControl,
FormField,
@@ -159,20 +159,20 @@ export const ColumnType = ({
-
-
+
- Type not found.
+ Type not found.
-
+
-
+
{POSTGRES_DATA_TYPE_OPTIONS.map((option: PostgresDataTypeOption) => (
-
-
+
))}
-
+
{enumTypes.length > 0 && (
<>
-
-
+
+
{enumTypes.map((option) => (
-
)}
-
+
))}
-
+
>
)}
-
-
+
+
{showRecommendation && recommendation !== undefined && (
diff --git a/apps/studio/components/interfaces/Integrations/Wrappers/WrapperTableEditor.tsx b/apps/studio/components/interfaces/Integrations/Wrappers/WrapperTableEditor.tsx
index 12afee2585651..ae230c6fe1091 100644
--- a/apps/studio/components/interfaces/Integrations/Wrappers/WrapperTableEditor.tsx
+++ b/apps/studio/components/interfaces/Integrations/Wrappers/WrapperTableEditor.tsx
@@ -12,12 +12,12 @@ import {
import {
Button,
cn,
- Command_Shadcn_,
- CommandEmpty_Shadcn_,
- CommandGroup_Shadcn_,
- CommandInput_Shadcn_,
- CommandItem_Shadcn_,
- CommandList_Shadcn_,
+ Command,
+ CommandEmpty,
+ CommandGroup,
+ CommandInput,
+ CommandItem,
+ CommandList,
Form,
FormControl,
FormField,
@@ -136,14 +136,14 @@ const WrapperTableEditor = ({
-
-
-
- No targets found
-
+
+
+
+ No targets found
+
7 ? 'h-[200px]' : ''}>
{(tables ?? []).map((table, i) => (
- {
@@ -162,12 +162,12 @@ const WrapperTableEditor = ({
{String(i) === selectedTableIndex && (
)}
-
+
))}
-
-
-
+
+
+
diff --git a/apps/studio/components/interfaces/Organization/BillingSettings/BillingCustomerData/BillingCustomerDataForm.tsx b/apps/studio/components/interfaces/Organization/BillingSettings/BillingCustomerData/BillingCustomerDataForm.tsx
index a91acb83ca6d8..522214d7b79b4 100644
--- a/apps/studio/components/interfaces/Organization/BillingSettings/BillingCustomerData/BillingCustomerDataForm.tsx
+++ b/apps/studio/components/interfaces/Organization/BillingSettings/BillingCustomerData/BillingCustomerDataForm.tsx
@@ -10,12 +10,12 @@ import { UseFormReturn } from 'react-hook-form'
import {
Button,
cn,
- Command_Shadcn_ as Command,
- CommandEmpty_Shadcn_ as CommandEmpty,
- CommandGroup_Shadcn_ as CommandGroup,
- CommandInput_Shadcn_ as CommandInput,
- CommandItem_Shadcn_ as CommandItem,
- CommandList_Shadcn_ as CommandList,
+ Command,
+ CommandEmpty,
+ CommandGroup,
+ CommandInput,
+ CommandItem,
+ CommandList,
FormControl,
FormField,
FormMessage,
diff --git a/apps/studio/components/interfaces/Organization/PrivateApps/Apps/CreateAppSheet/CreateAppSheet.tsx b/apps/studio/components/interfaces/Organization/PrivateApps/Apps/CreateAppSheet/CreateAppSheet.tsx
index 1128f408b194e..5f603fa83c46a 100644
--- a/apps/studio/components/interfaces/Organization/PrivateApps/Apps/CreateAppSheet/CreateAppSheet.tsx
+++ b/apps/studio/components/interfaces/Organization/PrivateApps/Apps/CreateAppSheet/CreateAppSheet.tsx
@@ -5,12 +5,12 @@ import { toast } from 'sonner'
import {
Button,
Checkbox,
- Command_Shadcn_,
- CommandEmpty_Shadcn_,
- CommandGroup_Shadcn_,
- CommandInput_Shadcn_,
- CommandItem_Shadcn_,
- CommandList_Shadcn_,
+ Command,
+ CommandEmpty,
+ CommandGroup,
+ CommandInput,
+ CommandItem,
+ CommandList,
Input,
Popover,
PopoverContent,
@@ -206,14 +206,14 @@ export function CreateAppSheet({ visible, onClose, onCreated }: CreateAppSheetPr
-
-
-
- No permissions found.
-
+
+
+
+ No permissions found.
+
{PERMISSIONS.map((perm) => (
- toggle(perm.id)}
@@ -230,12 +230,12 @@ export function CreateAppSheet({ visible, onClose, onCreated }: CreateAppSheetPr
{perm.label}
-
+
))}
-
-
-
+
+
+
diff --git a/apps/studio/components/interfaces/Organization/Usage/Usage.tsx b/apps/studio/components/interfaces/Organization/Usage/Usage.tsx
index 4c0c21f4a8c8f..f9221c0ae2ff5 100644
--- a/apps/studio/components/interfaces/Organization/Usage/Usage.tsx
+++ b/apps/studio/components/interfaces/Organization/Usage/Usage.tsx
@@ -5,7 +5,7 @@ import { Check, ChevronDown } from 'lucide-react'
import Link from 'next/link'
import { useQueryState } from 'nuqs'
import { useMemo, useState } from 'react'
-import { Button, cn, CommandGroup_Shadcn_, CommandItem_Shadcn_ } from 'ui'
+import { Button, cn, CommandGroup, CommandItem } from 'ui'
import { Admonition } from 'ui-patterns'
import { ShimmeringLoader } from 'ui-patterns/ShimmeringLoader'
@@ -191,8 +191,8 @@ export const Usage = () => {
)
}}
renderActions={() => (
-
-
+ {
setOpenProjectSelector(false)
@@ -205,8 +205,8 @@ export const Usage = () => {
>
All projects
{!selectedProjectRef && }
-
-
+
+
)}
/>
diff --git a/apps/studio/components/interfaces/ProjectAPIDocs/LanguageSelector.tsx b/apps/studio/components/interfaces/ProjectAPIDocs/LanguageSelector.tsx
index ca77123d88555..1f4b2119ec691 100644
--- a/apps/studio/components/interfaces/ProjectAPIDocs/LanguageSelector.tsx
+++ b/apps/studio/components/interfaces/ProjectAPIDocs/LanguageSelector.tsx
@@ -2,10 +2,10 @@ import { ChevronDown, Terminal } from 'lucide-react'
import { useState } from 'react'
import {
Button,
- Command_Shadcn_,
- CommandGroup_Shadcn_,
- CommandItem_Shadcn_,
- CommandList_Shadcn_,
+ Command,
+ CommandGroup,
+ CommandItem,
+ CommandList,
Popover,
PopoverContent,
PopoverTrigger,
@@ -58,26 +58,26 @@ const LanguageSelector = ({ simplifiedVersion = false }: LanguageSelectorProps)
-
-
-
-
+
+
+ updateLanguage('js')}
onClick={() => updateLanguage('js')}
>
Javascript
-
-
+ updateLanguage('bash')}
onClick={() => updateLanguage('bash')}
>
Bash
-
-
-
-
+
+
+
+
diff --git a/apps/studio/components/interfaces/ProjectAPIDocs/SecondLevelNav.ResourcePicker.tsx b/apps/studio/components/interfaces/ProjectAPIDocs/SecondLevelNav.ResourcePicker.tsx
index a0f04bcfd681c..dd30ddfade3eb 100644
--- a/apps/studio/components/interfaces/ProjectAPIDocs/SecondLevelNav.ResourcePicker.tsx
+++ b/apps/studio/components/interfaces/ProjectAPIDocs/SecondLevelNav.ResourcePicker.tsx
@@ -1,10 +1,4 @@
-import {
- cn,
- Command_Shadcn_,
- CommandGroup_Shadcn_,
- CommandItem_Shadcn_,
- CommandList_Shadcn_,
-} from 'ui'
+import { cn, Command, CommandGroup, CommandItem, CommandList } from 'ui'
import type { ResourcePickerRenderProps } from './SecondLevelNav.Layout'
@@ -28,18 +22,18 @@ export const ResourcePickerList = ({
}
return (
-
-
-
+
+
+
{items.length === 0 && (
-
+
{emptyMessage}
-
+
)}
{items.map((item) => {
const isActive = item.name === selectedResource
return (
- handleSelect(item.name)}
>
{item.name}
-
+
)
})}
-
-
-
+
+
+
)
}
diff --git a/apps/studio/components/interfaces/ProjectAPIDocs/SecondLevelNav.StoragePicker.tsx b/apps/studio/components/interfaces/ProjectAPIDocs/SecondLevelNav.StoragePicker.tsx
index 3433213358d3e..60cdc1e505f92 100644
--- a/apps/studio/components/interfaces/ProjectAPIDocs/SecondLevelNav.StoragePicker.tsx
+++ b/apps/studio/components/interfaces/ProjectAPIDocs/SecondLevelNav.StoragePicker.tsx
@@ -1,15 +1,7 @@
import { keepPreviousData } from '@tanstack/react-query'
import { useDebounce, useIntersectionObserver } from '@uidotdev/usehooks'
import { useEffect, useMemo, useRef, useState } from 'react'
-import {
- cn,
- Command_Shadcn_,
- CommandEmpty_Shadcn_,
- CommandGroup_Shadcn_,
- CommandInput_Shadcn_,
- CommandItem_Shadcn_,
- CommandList_Shadcn_,
-} from 'ui'
+import { cn, Command, CommandEmpty, CommandGroup, CommandInput, CommandItem, CommandList } from 'ui'
import type { ResourcePickerRenderProps } from './SecondLevelNav.Layout'
import { usePaginatedBucketsQuery } from '@/data/storage/buckets-query'
@@ -101,22 +93,19 @@ export const StorageResourceList = ({
rawQuery.length > 0 ? 'No buckets found for this search' : 'No buckets available'
return (
-
-
+ setSearch('')}
/>
-
-
+
+
{emptyMessage}
-
-
+
+
{isFetching && buckets.length === 0 ? (
Loading buckets...
) : (
@@ -124,7 +113,7 @@ export const StorageResourceList = ({
{buckets.map((bucket) => {
const isActive = bucket.name === selectedResource
return (
- handleSelect(bucket.name)}
>
{bucket.name}
-
+
)
})}
{hasNextPage &&
}
)}
-
+
{isFetchingNextPage && (
Loading more buckets...
)}
-
-
+
+
)
}
diff --git a/apps/studio/components/interfaces/ProjectHome/SnippetDropdown.tsx b/apps/studio/components/interfaces/ProjectHome/SnippetDropdown.tsx
index 5fefc1ce49139..fc197b0752628 100644
--- a/apps/studio/components/interfaces/ProjectHome/SnippetDropdown.tsx
+++ b/apps/studio/components/interfaces/ProjectHome/SnippetDropdown.tsx
@@ -3,11 +3,11 @@ import { useDebounce, useIntersectionObserver } from '@uidotdev/usehooks'
import { Plus } from 'lucide-react'
import { ReactNode, useEffect, useMemo, useRef, useState } from 'react'
import {
- Command_Shadcn_,
- CommandGroup_Shadcn_,
- CommandInput_Shadcn_,
- CommandItem_Shadcn_,
- CommandList_Shadcn_,
+ Command,
+ CommandGroup,
+ CommandInput,
+ CommandItem,
+ CommandList,
DropdownMenu,
DropdownMenuContent,
DropdownMenuTrigger,
@@ -91,8 +91,8 @@ export const SnippetDropdown = ({
align={align}
className={['w-80 p-0', className].filter(Boolean).join(' ')}
>
-
-
+ setSearch('')}
/>
-
+
{isLoading ? (
Loading...
) : search.length > 0 && snippets.length === 0 ? (
No snippets found
) : (
-
+
7 ? 'h-[210px]' : ''}>
{snippets.map((snippet) => (
- onSelect({ id: snippet.id, name: snippet.name })}
>
{snippet.name}
-
+
))}
{hasNextPage && (
@@ -124,13 +124,13 @@ export const SnippetDropdown = ({
)}
-
+
)}
-
-
+ {
setOpen(false)
@@ -142,10 +142,10 @@ export const SnippetDropdown = ({
Create snippet
-
-
-
-
+
+
+
+
)
diff --git a/apps/studio/components/interfaces/Realtime/Inspector/RealtimeFilterPopover/TableSelector.tsx b/apps/studio/components/interfaces/Realtime/Inspector/RealtimeFilterPopover/TableSelector.tsx
index b6ed1cb238f45..8d8b07df62e85 100644
--- a/apps/studio/components/interfaces/Realtime/Inspector/RealtimeFilterPopover/TableSelector.tsx
+++ b/apps/studio/components/interfaces/Realtime/Inspector/RealtimeFilterPopover/TableSelector.tsx
@@ -6,12 +6,12 @@ import {
AlertDescription,
AlertTitle,
Button,
- Command_Shadcn_,
- CommandEmpty_Shadcn_,
- CommandGroup_Shadcn_,
- CommandInput_Shadcn_,
- CommandItem_Shadcn_,
- CommandList_Shadcn_,
+ Command,
+ CommandEmpty,
+ CommandGroup,
+ CommandInput,
+ CommandItem,
+ CommandList,
Popover,
PopoverContent,
PopoverTrigger,
@@ -101,12 +101,9 @@ const TableSelector = ({
-
- searchTables(str)}
- />
-
+
+ searchTables(str)} />
+
{isLoading && (
@@ -128,13 +125,11 @@ const TableSelector = ({
{isSuccess && (
<>
-
+
7 ? 'h-[210px]' : ''}>
- {entities.length === 0 && (
- No tables found
- )}
+ {entities.length === 0 && No tables found }
{!searchInput && (
- {
@@ -150,10 +145,10 @@ const TableSelector = ({
{selectedSchemaName === '*' && (
)}
-
+
)}
{entities?.map((table) => (
- {
@@ -169,14 +164,14 @@ const TableSelector = ({
{selectedSchemaName === table.name && (
)}
-
+
))}
-
+
>
)}
-
-
+
+
diff --git a/apps/studio/components/interfaces/Reports/MetricOptions.tsx b/apps/studio/components/interfaces/Reports/MetricOptions.tsx
index 831f2eead538a..d6066f2f98794 100644
--- a/apps/studio/components/interfaces/Reports/MetricOptions.tsx
+++ b/apps/studio/components/interfaces/Reports/MetricOptions.tsx
@@ -3,11 +3,11 @@ import { useParams } from 'common'
import { Home, Plus } from 'lucide-react'
import { useState } from 'react'
import {
- Command_Shadcn_,
- CommandGroup_Shadcn_,
- CommandInput_Shadcn_,
- CommandItem_Shadcn_,
- CommandList_Shadcn_,
+ Command,
+ CommandGroup,
+ CommandInput,
+ CommandItem,
+ CommandList,
DropdownMenuCheckboxItem,
DropdownMenuPortal,
DropdownMenuSub,
@@ -118,14 +118,14 @@ export const MetricOptions = ({ config, handleChartSelection }: MetricOptionsPro
-
-
+
-
+
{isLoading ? (
@@ -136,9 +136,9 @@ export const MetricOptions = ({ config, handleChartSelection }: MetricOptionsPro
No snippets found
) : null}
-
+
{snippets?.map((snippet) => (
-
{snippet.name}
-
+
))}
-
-
+
+
-
-
+ {
editorPanelState.openAsNew()
@@ -182,9 +182,9 @@ export const MetricOptions = ({ config, handleChartSelection }: MetricOptionsPro
Create snippet
-
-
-
+
+
+
diff --git a/apps/studio/components/interfaces/Reports/ReportFilterPopover.tsx b/apps/studio/components/interfaces/Reports/ReportFilterPopover.tsx
index 1d76a03b68285..da04534450472 100644
--- a/apps/studio/components/interfaces/Reports/ReportFilterPopover.tsx
+++ b/apps/studio/components/interfaces/Reports/ReportFilterPopover.tsx
@@ -4,12 +4,12 @@ import { KeyboardEvent, useCallback, useEffect, useMemo, useState } from 'react'
import {
Button,
cn,
- Command_Shadcn_,
- CommandEmpty_Shadcn_,
- CommandGroup_Shadcn_,
- CommandInput_Shadcn_,
- CommandItem_Shadcn_,
- CommandList_Shadcn_,
+ Command,
+ CommandEmpty,
+ CommandGroup,
+ CommandInput,
+ CommandItem,
+ CommandList,
Input,
Popover,
PopoverContent,
@@ -79,8 +79,8 @@ const FilterableInput = ({
return (
-
-
+ 0 && 'opacity-100 pointer-events-auto'
)}
>
-
-
+
+
No matching options found. Press Enter to use "{inputValue}"
-
-
+
+
{safeOptions.map((option, index) => (
- handleOptionSelect(option)}
className="px-3 py-2 text-sm cursor-pointer"
>
{option}
-
+
))}
-
-
+
+
-
+
{isOpen && setIsOpen(false)} />}
)
diff --git a/apps/studio/components/interfaces/Reports/v2/ReportsSelectFilter.tsx b/apps/studio/components/interfaces/Reports/v2/ReportsSelectFilter.tsx
index fd06a093715d6..fe867b3c25648 100644
--- a/apps/studio/components/interfaces/Reports/v2/ReportsSelectFilter.tsx
+++ b/apps/studio/components/interfaces/Reports/v2/ReportsSelectFilter.tsx
@@ -4,15 +4,7 @@ import { Label } from '@ui/components/shadcn/ui/label'
import { Popover, PopoverContent, PopoverTrigger } from '@ui/components/shadcn/ui/popover'
import { ChevronDown } from 'lucide-react'
import { useEffect, useState } from 'react'
-import {
- Button,
- cn,
- Command_Shadcn_ as Command,
- CommandEmpty_Shadcn_ as CommandEmpty,
- CommandInput_Shadcn_ as CommandInput,
- CommandItem_Shadcn_,
- CommandList_Shadcn_ as CommandList,
-} from 'ui'
+import { Button, cn, Command, CommandEmpty, CommandInput, CommandItem, CommandList } from 'ui'
import { z } from 'zod'
export interface ReportSelectOption {
@@ -95,7 +87,7 @@ export const ReportsSelectFilter = ({
No options found.
{options.map((option) => (
-
+
-
+
))}
diff --git a/apps/studio/components/interfaces/SQLEditor/MoveQueryModal.tsx b/apps/studio/components/interfaces/SQLEditor/MoveQueryModal.tsx
index c34f80e90796b..981f001b6b7f1 100644
--- a/apps/studio/components/interfaces/SQLEditor/MoveQueryModal.tsx
+++ b/apps/studio/components/interfaces/SQLEditor/MoveQueryModal.tsx
@@ -7,13 +7,13 @@ import { useForm } from 'react-hook-form'
import { toast } from 'sonner'
import {
Button,
- Command_Shadcn_,
- CommandEmpty_Shadcn_,
- CommandGroup_Shadcn_,
- CommandInput_Shadcn_,
- CommandItem_Shadcn_,
- CommandList_Shadcn_,
- CommandSeparator_Shadcn_,
+ Command,
+ CommandEmpty,
+ CommandGroup,
+ CommandInput,
+ CommandItem,
+ CommandList,
+ CommandSeparator,
Dialog,
DialogContent,
DialogDescription,
@@ -252,13 +252,13 @@ export const MoveQueryModal = ({ visible, snippets = [], onClose }: MoveQueryMod
-
-
-
- No folders found
-
+
+
+
+ No folders found
+
6 ? 'h-[210px]' : ''}>
-
{selectedId === 'root' && }
-
+
{folders?.map((folder) => (
-
{folder.id === selectedId && }
-
+
))}
-
-
-
-
+
+
+ {
setOpen(false)
@@ -319,10 +319,10 @@ export const MoveQueryModal = ({ visible, snippets = [], onClose }: MoveQueryMod
>
New folder
-
-
-
-
+
+
+
+
diff --git a/apps/studio/components/interfaces/Settings/API/ExposedFunctionSelector.tsx b/apps/studio/components/interfaces/Settings/API/ExposedFunctionSelector.tsx
index e7f1cee472e15..3e8041fa35f1c 100644
--- a/apps/studio/components/interfaces/Settings/API/ExposedFunctionSelector.tsx
+++ b/apps/studio/components/interfaces/Settings/API/ExposedFunctionSelector.tsx
@@ -5,11 +5,11 @@ import { useEffect, useMemo, useRef, useState } from 'react'
import {
Button,
cn,
- Command_Shadcn_,
- CommandGroup_Shadcn_,
- CommandInput_Shadcn_,
- CommandItem_Shadcn_,
- CommandList_Shadcn_,
+ Command,
+ CommandGroup,
+ CommandInput,
+ CommandItem,
+ CommandList,
Popover,
PopoverContent,
PopoverTrigger,
@@ -126,15 +126,15 @@ export const ExposedFunctionSelector = ({
align="start"
sameWidthAsTrigger
>
-
-
+
-
-
+
+
{isPending ? (
<>
@@ -179,7 +179,7 @@ export const ExposedFunctionSelector = ({
})
return (
-
-
+
)
})}
@@ -278,9 +278,9 @@ export const ExposedFunctionSelector = ({
>
)}
-
-
-
+
+
+
)
diff --git a/apps/studio/components/interfaces/Settings/API/ExposedSchemaSelector.tsx b/apps/studio/components/interfaces/Settings/API/ExposedSchemaSelector.tsx
index 396ef368cfa02..596d9541816df 100644
--- a/apps/studio/components/interfaces/Settings/API/ExposedSchemaSelector.tsx
+++ b/apps/studio/components/interfaces/Settings/API/ExposedSchemaSelector.tsx
@@ -3,12 +3,12 @@ import { useMemo, useState } from 'react'
import {
Button,
cn,
- Command_Shadcn_,
- CommandEmpty_Shadcn_,
- CommandGroup_Shadcn_,
- CommandInput_Shadcn_,
- CommandItem_Shadcn_,
- CommandList_Shadcn_,
+ Command,
+ CommandEmpty,
+ CommandGroup,
+ CommandInput,
+ CommandItem,
+ CommandList,
Popover,
PopoverContent,
PopoverTrigger,
@@ -85,10 +85,10 @@ export const ExposedSchemaSelector = ({
align="start"
sameWidthAsTrigger
>
-
-
-
-
+
+
+
+
{isPending ? (
<>
@@ -104,17 +104,17 @@ export const ExposedSchemaSelector = ({
) : (
<>
-
+
No schemas found
-
+
7 ? 'h-[210px]' : ''}>
{schemas.map((schema) => {
const isExposed = selectedSet.has(schema.name)
return (
- }
{schema.name}
-
+
)
})}
>
)}
-
-
-
+
+
+
)
diff --git a/apps/studio/components/interfaces/Settings/API/ExposedTableSelector.tsx b/apps/studio/components/interfaces/Settings/API/ExposedTableSelector.tsx
index e7ecfd3411b7b..21695b9105a14 100644
--- a/apps/studio/components/interfaces/Settings/API/ExposedTableSelector.tsx
+++ b/apps/studio/components/interfaces/Settings/API/ExposedTableSelector.tsx
@@ -5,11 +5,11 @@ import { useEffect, useMemo, useRef, useState } from 'react'
import {
Button,
cn,
- Command_Shadcn_,
- CommandGroup_Shadcn_,
- CommandInput_Shadcn_,
- CommandItem_Shadcn_,
- CommandList_Shadcn_,
+ Command,
+ CommandGroup,
+ CommandInput,
+ CommandItem,
+ CommandList,
Popover,
PopoverContent,
PopoverTrigger,
@@ -120,15 +120,15 @@ export const ExposedTableSelector = ({
align="start"
sameWidthAsTrigger
>
-
-
+
-
-
+
+
{isPending ? (
<>
@@ -173,7 +173,7 @@ export const ExposedTableSelector = ({
})
return (
-
-
+
)
})}
@@ -272,9 +272,9 @@ export const ExposedTableSelector = ({
>
)}
-
-
-
+
+
+
)
diff --git a/apps/studio/components/interfaces/Settings/Integrations/GithubIntegration/GitHubRepositoryField.tsx b/apps/studio/components/interfaces/Settings/Integrations/GithubIntegration/GitHubRepositoryField.tsx
index e76a04a69dc07..0fda2c6dfee72 100644
--- a/apps/studio/components/interfaces/Settings/Integrations/GithubIntegration/GitHubRepositoryField.tsx
+++ b/apps/studio/components/interfaces/Settings/Integrations/GithubIntegration/GitHubRepositoryField.tsx
@@ -3,13 +3,13 @@ import { useMemo, useState, type ComponentProps, type ReactNode } from 'react'
import type { FieldValues, Path, UseFormReturn } from 'react-hook-form'
import {
Button,
- Command_Shadcn_,
- CommandEmpty_Shadcn_,
- CommandGroup_Shadcn_,
- CommandInput_Shadcn_,
- CommandItem_Shadcn_,
- CommandList_Shadcn_,
- CommandSeparator_Shadcn_,
+ Command,
+ CommandEmpty,
+ CommandGroup,
+ CommandInput,
+ CommandItem,
+ CommandList,
+ CommandSeparator,
FormControl,
FormField,
Popover,
@@ -174,14 +174,14 @@ export const GitHubRepositoryField = ({
-
-
-
- No repositories found.
+
+
+
+ No repositories found.
{repositories.length > 0 ? (
-
+
{repositories.map((repo) => (
- ({
{repo.name}
-
+
))}
-
+
) : null}
-
-
+ {
setIsRepoSelectorOpen(false)
@@ -222,13 +222,13 @@ export const GitHubRepositoryField = ({
>
Add GitHub Repositories
-
-
+
+
{hasPartialResponseDueToSSO && (
<>
-
-
-
+
+ {
setIsRepoSelectorOpen(false)
@@ -239,12 +239,12 @@ export const GitHubRepositoryField = ({
Re-authorize GitHub with SSO to show all repositories
-
-
+
+
>
)}
-
-
+
+
)}
diff --git a/apps/studio/components/interfaces/Settings/Logs/LogsQueryPanel.tsx b/apps/studio/components/interfaces/Settings/Logs/LogsQueryPanel.tsx
index b7fab29a9ff48..1fa3d8900a7a4 100644
--- a/apps/studio/components/interfaces/Settings/Logs/LogsQueryPanel.tsx
+++ b/apps/studio/components/interfaces/Settings/Logs/LogsQueryPanel.tsx
@@ -7,12 +7,12 @@ import {
Badge,
Button,
cn,
- Command_Shadcn_,
- CommandEmpty_Shadcn_,
- CommandGroup_Shadcn_,
- CommandInput_Shadcn_,
- CommandItem_Shadcn_,
- CommandList_Shadcn_,
+ Command,
+ CommandEmpty,
+ CommandGroup,
+ CommandInput,
+ CommandItem,
+ CommandList,
copyToClipboard,
DropdownMenu,
DropdownMenuContent,
@@ -280,13 +280,13 @@ const LogsQueryPanel = ({
-
-
-
- No source found.
-
+
+
+
+ No source found.
+
{logConstants.schemas.map((schema) => (
- {
@@ -301,11 +301,11 @@ const LogsQueryPanel = ({
)}
/>
{schema.name}
-
+
))}
-
-
-
+
+
+
-
-
-
-
+
+
+ onLanguageChange('sql')}
onClick={() => onLanguageChange('sql')}
>
SQL
-
-
+ onLanguageChange('javascript')}
onClick={() => onLanguageChange('javascript')}
>
JavaScript
-
-
-
-
+
+
+
+
diff --git a/apps/studio/components/interfaces/Support/ProjectAndPlanInfo.tsx b/apps/studio/components/interfaces/Support/ProjectAndPlanInfo.tsx
index af6ef46f85790..983c187e708d1 100644
--- a/apps/studio/components/interfaces/Support/ProjectAndPlanInfo.tsx
+++ b/apps/studio/components/interfaces/Support/ProjectAndPlanInfo.tsx
@@ -6,7 +6,7 @@ import { Check, ChevronsUpDown, ExternalLink } from 'lucide-react'
import Link from 'next/link'
import type { UseFormReturn } from 'react-hook-form'
import { toast } from 'sonner'
-import { Button, cn, CommandGroup_Shadcn_, CommandItem_Shadcn_, FormControl, FormField } from 'ui'
+import { Button, cn, CommandGroup, CommandItem, FormControl, FormField } from 'ui'
import { Admonition } from 'ui-patterns'
import { FormItemLayout } from 'ui-patterns/form/FormItemLayout/FormItemLayout'
import ShimmeringLoader from 'ui-patterns/ShimmeringLoader'
@@ -99,8 +99,8 @@ function ProjectSelector({ form, orgSlug, projectRef }: ProjectSelectorProps) {
)
}}
renderActions={(setOpen) => (
-
-
+ {
field.onChange(NO_PROJECT_MARKER)
@@ -111,8 +111,8 @@ function ProjectSelector({ form, orgSlug, projectRef }: ProjectSelectorProps) {
No specific project
-
-
+
+
)}
/>
diff --git a/apps/studio/components/interfaces/TableGridEditor/SidePanelEditor/ColumnEditor/ColumnType.tsx b/apps/studio/components/interfaces/TableGridEditor/SidePanelEditor/ColumnEditor/ColumnType.tsx
index 887951359dce3..b01df7bc81bf1 100644
--- a/apps/studio/components/interfaces/TableGridEditor/SidePanelEditor/ColumnEditor/ColumnType.tsx
+++ b/apps/studio/components/interfaces/TableGridEditor/SidePanelEditor/ColumnEditor/ColumnType.tsx
@@ -17,13 +17,13 @@ import {
AlertTitle,
Button,
cn,
- Command_Shadcn_,
- CommandEmpty_Shadcn_,
- CommandGroup_Shadcn_,
- CommandInput_Shadcn_,
- CommandItem_Shadcn_,
- CommandList_Shadcn_,
- CommandSeparator_Shadcn_,
+ Command,
+ CommandEmpty,
+ CommandGroup,
+ CommandInput,
+ CommandItem,
+ CommandList,
+ CommandSeparator,
CriticalIcon,
Input,
InputGroup,
@@ -209,22 +209,22 @@ const ColumnType = ({
-
-
+
- Type not found.
+ Type not found.
-
+
-
+
{POSTGRES_DATA_TYPE_OPTIONS.map((option: PostgresDataTypeOption) => {
const isSelected = matchesBuiltin(option.name, value)
return (
-
{isSelected ? : ''}
-
+
)
})}
-
+
{enumTypes.length > 0 && (
<>
-
-
+
+
{enumTypes.map((option) => {
const isSelected = matchesEnum(option, value)
return (
-
)}
-
+
)
})}
-
+
>
)}
-
-
+
+
diff --git a/apps/studio/components/interfaces/TableGridEditor/SidePanelEditor/TableEditor/Column.tsx b/apps/studio/components/interfaces/TableGridEditor/SidePanelEditor/TableEditor/Column.tsx
index 9bb7473f3b3f7..d203b1232eacd 100644
--- a/apps/studio/components/interfaces/TableGridEditor/SidePanelEditor/TableEditor/Column.tsx
+++ b/apps/studio/components/interfaces/TableGridEditor/SidePanelEditor/TableEditor/Column.tsx
@@ -7,11 +7,11 @@ import {
Button,
Checkbox,
cn,
- Command_Shadcn_,
- CommandGroup_Shadcn_,
- CommandItem_Shadcn_,
- CommandList_Shadcn_,
- CommandSeparator_Shadcn_,
+ Command,
+ CommandGroup,
+ CommandItem,
+ CommandList,
+ CommandSeparator,
Input,
Popover,
PopoverContent,
@@ -167,16 +167,16 @@ export const Column = ({
Involved in {relations.length} foreign key{relations.length > 1 ? 's' : ''}
-
-
-
+
+
+
{relations.map((relation, idx) => {
const key = String(relation?.id ?? `${column.id}-relation-${idx}`)
const status = getRelationStatus(relation)
if (status === 'REMOVE') return null
return (
-
)}
-
+
)
})}
-
-
-
-
+
+
+ onEditForeignKey()}
onClick={() => onEditForeignKey()}
>
Add foreign key relation
-
-
-
-
+
+
+
+
)}
diff --git a/apps/studio/components/interfaces/UserDropdown/TimezoneDropdown.tsx b/apps/studio/components/interfaces/UserDropdown/TimezoneDropdown.tsx
index f6e7cf989be95..16fcc29ce996c 100644
--- a/apps/studio/components/interfaces/UserDropdown/TimezoneDropdown.tsx
+++ b/apps/studio/components/interfaces/UserDropdown/TimezoneDropdown.tsx
@@ -2,12 +2,12 @@ import { CheckIcon } from 'lucide-react'
import { useMemo, useState } from 'react'
import {
cn,
- Command_Shadcn_,
- CommandEmpty_Shadcn_,
- CommandGroup_Shadcn_,
- CommandInput_Shadcn_,
- CommandItem_Shadcn_,
- CommandList_Shadcn_,
+ Command,
+ CommandEmpty,
+ CommandGroup,
+ CommandInput,
+ CommandItem,
+ CommandList,
DropdownMenuPortal,
DropdownMenuSub,
DropdownMenuSubContent,
@@ -59,13 +59,13 @@ export const TimezoneDropdown = () => {
-
-
-
- No timezones found
-
+
+
+
+ No timezones found
+
- handleSelect('')}
@@ -80,12 +80,12 @@ export const TimezoneDropdown = () => {
isAutoDetected ? 'opacity-100' : 'opacity-0'
)}
/>
-
+
{TIMEZONES_BY_IANA.map((entry) => {
const ianaName = entry.utc[0]
const isSelected = !isAutoDetected && storedTimezone === ianaName
return (
- {
isSelected ? 'opacity-100' : 'opacity-0'
)}
/>
-
+
)
})}
-
-
-
+
+
+
diff --git a/apps/studio/components/layouts/AppLayout/BranchDropdownCommandContent.tsx b/apps/studio/components/layouts/AppLayout/BranchDropdownCommandContent.tsx
index 216164c180f4d..54a044c8e8bdb 100644
--- a/apps/studio/components/layouts/AppLayout/BranchDropdownCommandContent.tsx
+++ b/apps/studio/components/layouts/AppLayout/BranchDropdownCommandContent.tsx
@@ -3,13 +3,13 @@ import Link from 'next/link'
import {
Button,
cn,
- Command_Shadcn_,
- CommandEmpty_Shadcn_,
- CommandGroup_Shadcn_,
- CommandInput_Shadcn_,
- CommandItem_Shadcn_,
- CommandList_Shadcn_,
- CommandSeparator_Shadcn_,
+ Command,
+ CommandEmpty,
+ CommandGroup,
+ CommandInput,
+ CommandItem,
+ CommandList,
+ CommandSeparator,
ScrollArea,
} from 'ui'
@@ -46,7 +46,7 @@ export function BranchDropdownCommandContent({
if (embedded) {
return (
-
+
{isBranchingEnabled && (
-
+
)}
-
- {isBranchingEnabled && No branches found }
-
+
+ {isBranchingEnabled && No branches found }
+
{branchList.map((branch) => (
))}
-
-
-
+
+
+
)
}
return (
-
- {isBranchingEnabled && }
-
- {isBranchingEnabled && No branches found }
-
+
+ {isBranchingEnabled && }
+
+ {isBranchingEnabled && No branches found }
+
{branchList.map((branch) => (
))}
-
+
-
+
-
-
+ {
track('branch_selector_create_clicked')
@@ -148,8 +148,8 @@ export function BranchDropdownCommandContent({
Create branch
-
-
+ {
track('branch_selector_manage_clicked')
@@ -163,13 +163,13 @@ export function BranchDropdownCommandContent({
Manage branches
-
-
+
+
-
+
-
-
+ {
onClose()
@@ -190,9 +190,9 @@ export function BranchDropdownCommandContent({
Join GitHub Discussion
-
-
-
-
+
+
+
+
)
}
diff --git a/apps/studio/components/layouts/AppLayout/BranchLink.tsx b/apps/studio/components/layouts/AppLayout/BranchLink.tsx
index 32cdce43d41e2..aa65952f733f0 100644
--- a/apps/studio/components/layouts/AppLayout/BranchLink.tsx
+++ b/apps/studio/components/layouts/AppLayout/BranchLink.tsx
@@ -1,7 +1,7 @@
import { Check, Shield } from 'lucide-react'
import Link from 'next/link'
import { useRouter } from 'next/router'
-import { CommandItem_Shadcn_ } from 'ui'
+import { CommandItem } from 'ui'
import { sanitizeRoute } from './ProjectDropdown.utils'
import type { Branch } from '@/data/branches/branches-query'
@@ -22,7 +22,7 @@ export function BranchLink({ branch, isSelected, onClose }: BranchLinkProps) {
return (
- {
@@ -38,7 +38,7 @@ export function BranchLink({ branch, isSelected, onClose }: BranchLinkProps) {
{branch.name}
{isSelected && }
-
+
)
}
diff --git a/apps/studio/components/layouts/AppLayout/OrgCommandItem.tsx b/apps/studio/components/layouts/AppLayout/OrgCommandItem.tsx
index cfd09ee9d2703..a4a0e71224830 100644
--- a/apps/studio/components/layouts/AppLayout/OrgCommandItem.tsx
+++ b/apps/studio/components/layouts/AppLayout/OrgCommandItem.tsx
@@ -1,6 +1,6 @@
import { Check } from 'lucide-react'
import Link from 'next/link'
-import { cn, CommandItem_Shadcn_ } from 'ui'
+import { cn, CommandItem } from 'ui'
import PartnerIcon from '@/components/ui/PartnerIcon'
import type { Organization } from '@/types'
@@ -25,7 +25,7 @@ export function OrgCommandItem({
const href = hasRouteSlug ? routePathname.replace('[slug]', org.slug) : `/org/${org.slug}`
return (
-
{org.slug === selectedSlug && }
-
+
)
}
diff --git a/apps/studio/components/layouts/AppLayout/OrganizationDropdownCommandContent.tsx b/apps/studio/components/layouts/AppLayout/OrganizationDropdownCommandContent.tsx
index 78a395fa35ed4..3eb12d3705cb3 100644
--- a/apps/studio/components/layouts/AppLayout/OrganizationDropdownCommandContent.tsx
+++ b/apps/studio/components/layouts/AppLayout/OrganizationDropdownCommandContent.tsx
@@ -3,13 +3,13 @@ import Link from 'next/link'
import {
Button,
cn,
- Command_Shadcn_,
- CommandEmpty_Shadcn_,
- CommandGroup_Shadcn_,
- CommandInput_Shadcn_,
- CommandItem_Shadcn_,
- CommandList_Shadcn_,
- CommandSeparator_Shadcn_,
+ Command,
+ CommandEmpty,
+ CommandGroup,
+ CommandInput,
+ CommandItem,
+ CommandList,
+ CommandSeparator,
ScrollArea,
} from 'ui'
@@ -55,7 +55,7 @@ export function OrganizationDropdownCommandContent({
if (embedded) {
return (
-
+
)}
-
-
- No organizations found
- {orgList}
-
-
+
+ No organizations found
+ {orgList}
+
+
)
}
return (
-
-
-
- No organizations found
-
+
+
+
+ No organizations found
+
7 ? 'md:h-[210px]' : ''}>
{orgList}
-
-
-
- onClose()}>
+
+
+
+ onClose()}>
All Organizations
-
-
+
+
{organizationCreationEnabled && (
<>
-
-
- onClose()}>
+
+
+ onClose()}>
New organization
-
-
+
+
>
)}
-
-
+
+
)
}
diff --git a/apps/studio/components/layouts/AppLayout/ProjectDropdown.tsx b/apps/studio/components/layouts/AppLayout/ProjectDropdown.tsx
index 14acd11c4512e..671c6947e46cb 100644
--- a/apps/studio/components/layouts/AppLayout/ProjectDropdown.tsx
+++ b/apps/studio/components/layouts/AppLayout/ProjectDropdown.tsx
@@ -4,7 +4,7 @@ import Link from 'next/link'
import { useRouter } from 'next/router'
import type { ComponentProps } from 'react'
import { useState } from 'react'
-import { Button, CommandGroup_Shadcn_, CommandItem_Shadcn_ } from 'ui'
+import { Button, CommandGroup, CommandItem } from 'ui'
import { ShimmeringLoader } from 'ui-patterns'
import { AppLayoutDropdownTriggerButton } from './AppLayoutDropdown'
@@ -55,8 +55,8 @@ function ProjectDropdownNewProjectActions({
}
return (
-
-
+ {
onClose()
@@ -68,8 +68,8 @@ function ProjectDropdownNewProjectActions({
New project
-
-
+
+
)
}
diff --git a/apps/studio/components/layouts/Navigation/NavigationBar/OrgSelector.tsx b/apps/studio/components/layouts/Navigation/NavigationBar/OrgSelector.tsx
index d6a9f12c61845..fb9f3e09b7242 100644
--- a/apps/studio/components/layouts/Navigation/NavigationBar/OrgSelector.tsx
+++ b/apps/studio/components/layouts/Navigation/NavigationBar/OrgSelector.tsx
@@ -4,13 +4,13 @@ import Link from 'next/link'
import { useRouter } from 'next/router'
import { useState } from 'react'
import {
- Command_Shadcn_,
- CommandEmpty_Shadcn_,
- CommandGroup_Shadcn_,
- CommandInput_Shadcn_,
- CommandItem_Shadcn_,
- CommandList_Shadcn_,
- CommandSeparator_Shadcn_,
+ Command,
+ CommandEmpty,
+ CommandGroup,
+ CommandInput,
+ CommandItem,
+ CommandList,
+ CommandSeparator,
Popover,
PopoverContent,
PopoverTrigger,
@@ -107,11 +107,11 @@ export function OrgSelector() {
{triggerButton}
-
-
-
- No organizations found
-
+
+
+
+ No organizations found
+
7 ? 'h-full md:h-[210px]' : ''}
>
@@ -126,10 +126,10 @@ export function OrgSelector() {
/>
))}
-
-
-
-
+
+
+ {
setOpen(false)
@@ -140,13 +140,13 @@ export function OrgSelector() {
All Organizations
-
-
+
+
{organizationCreationEnabled && (
<>
-
-
-
+
+ {
setOpen(false)
@@ -158,12 +158,12 @@ export function OrgSelector() {
New organization
-
-
+
+
>
)}
-
-
+
+
diff --git a/apps/studio/components/layouts/ProjectLayout/index.test.tsx b/apps/studio/components/layouts/ProjectLayout/index.test.tsx
index da21a6aed34bc..bff3522e1d0ff 100644
--- a/apps/studio/components/layouts/ProjectLayout/index.test.tsx
+++ b/apps/studio/components/layouts/ProjectLayout/index.test.tsx
@@ -96,11 +96,11 @@ vi.mock('ui', () => ({
Alert: ({ children, ...props }: any) => {children}
,
AlertDescription: ({ children, ...props }: any) => {children}
,
AlertTitle: ({ children, ...props }: any) => {children}
,
- CommandInput_Shadcn_: { displayName: 'CommandInput' },
- Command_Shadcn_: { displayName: 'Command' },
- CommandGroup_Shadcn_: { displayName: 'CommandGroup' },
- CommandItem_Shadcn_: { displayName: 'CommandItem' },
- CommandList_Shadcn_: { displayName: 'CommandList' },
+ CommandInput: { displayName: 'CommandInput' },
+ Command: { displayName: 'Command' },
+ CommandGroup: { displayName: 'CommandGroup' },
+ CommandItem: { displayName: 'CommandItem' },
+ CommandList: { displayName: 'CommandList' },
LogoLoader: () =>
,
ResizableHandle: (props: any) =>
,
ResizablePanel: ({ children, ...props }: any) => {children}
,
diff --git a/apps/studio/components/layouts/SQLEditorLayout/SqlEditor.Commands.tsx b/apps/studio/components/layouts/SQLEditorLayout/SqlEditor.Commands.tsx
index 01b5961e2c006..df8be38a8f1d9 100644
--- a/apps/studio/components/layouts/SQLEditorLayout/SqlEditor.Commands.tsx
+++ b/apps/studio/components/layouts/SQLEditorLayout/SqlEditor.Commands.tsx
@@ -4,13 +4,7 @@ import { useParams } from 'common'
import { AlertTriangle, Code, Loader2, Table2 } from 'lucide-react'
import { useRouter } from 'next/navigation'
import { useEffect, useMemo, useRef } from 'react'
-import {
- cn,
- CommandEmpty_Shadcn_,
- CommandGroup_Shadcn_,
- CommandItem_Shadcn_,
- CommandList_Shadcn_,
-} from 'ui'
+import { cn, CommandEmpty, CommandGroup, CommandItem, CommandList } from 'ui'
import { CodeBlock } from 'ui-patterns/CodeBlock'
import type { CommandOptions } from 'ui-patterns/CommandMenu'
import {
@@ -166,17 +160,17 @@ function EmptyState({
return (
No snippets found.
-
-
-
+
+ router.push(`/project/${projectRef ?? '_'}/sql/new`)}
>
{canCreateNew ? 'Create new snippet' : 'Run new SQL'}
-
-
-
+
+
+
)
}
@@ -198,16 +192,16 @@ function SnippetSelector({
return (
-
{!!snippets && snippets.length > 0 && (
-
+
{snippets.map((snippet) => (
- void router.push(`/project/${projectRef ?? '_'}/sql/${snippet.id}`)}
>
{snippet.name}
-
+
))}
-
+
)}
{canCreateNew && (
-
-
+ router.push(`/project/${projectRef ?? '_'}/sql/new`)}
forceMount={true}
>
Create new snippet
-
-
+
+
)}
-
+
-
+
{isLoading && }
{isError && }
{isSuccess && (
<>
-
-
+
+
{tables?.map((table) => (
-
{`${table.schema}.${table.name}`}
-
+
))}
-
+
>
)}
-
+
)
}
diff --git a/apps/studio/components/ui/AIAssistantPanel/AIAssistantChatSelector.tsx b/apps/studio/components/ui/AIAssistantPanel/AIAssistantChatSelector.tsx
index 742497e6e0be0..5415702eaf60b 100644
--- a/apps/studio/components/ui/AIAssistantPanel/AIAssistantChatSelector.tsx
+++ b/apps/studio/components/ui/AIAssistantPanel/AIAssistantChatSelector.tsx
@@ -3,13 +3,13 @@ import { useState } from 'react'
import {
Button,
cn,
- Command_Shadcn_,
- CommandEmpty_Shadcn_,
- CommandGroup_Shadcn_,
- CommandInput_Shadcn_,
- CommandItem_Shadcn_,
- CommandList_Shadcn_,
- CommandSeparator_Shadcn_,
+ Command,
+ CommandEmpty,
+ CommandGroup,
+ CommandInput,
+ CommandItem,
+ CommandList,
+ CommandSeparator,
Input,
Popover,
PopoverContent,
@@ -97,15 +97,15 @@ export const AIAssistantChatSelector = ({ disabled = false }: AIAssistantChatSel
-
-
-
- No chats found.
-
+
+
+
+ No chats found.
+
4 ? 'h-40' : ''}>
{/* @ts-ignore */}
{chats.map(([id, chat]) => (
- handleSelectChat(id)}
@@ -185,13 +185,13 @@ export const AIAssistantChatSelector = ({ disabled = false }: AIAssistantChatSel
)}
)}
-
+
))}
-
-
-
-
+
+
+ {
snap.newChat()
@@ -205,10 +205,10 @@ export const AIAssistantChatSelector = ({ disabled = false }: AIAssistantChatSel
>
Start a new chat
-
-
-
-
+
+
+
+
)
diff --git a/apps/studio/components/ui/AIAssistantPanel/ModelSelector.tsx b/apps/studio/components/ui/AIAssistantPanel/ModelSelector.tsx
index f9c4740b9a02c..8e7817dad49ab 100644
--- a/apps/studio/components/ui/AIAssistantPanel/ModelSelector.tsx
+++ b/apps/studio/components/ui/AIAssistantPanel/ModelSelector.tsx
@@ -4,10 +4,10 @@ import { useState } from 'react'
import {
Badge,
Button,
- Command_Shadcn_,
- CommandGroup_Shadcn_,
- CommandItem_Shadcn_,
- CommandList_Shadcn_,
+ Command,
+ CommandGroup,
+ CommandItem,
+ CommandList,
Popover,
PopoverContent,
PopoverTrigger,
@@ -64,11 +64,11 @@ export const ModelSelector = ({ selectedModel, onSelectModel }: ModelSelectorPro
-
-
-
+
+
+
{ASSISTANT_MODELS.map((m) => (
-
)}
-
+
))}
-
-
-
+
+
+
)
diff --git a/apps/studio/components/ui/DataTable/DataTableViewOptions.tsx b/apps/studio/components/ui/DataTable/DataTableViewOptions.tsx
index c61a2b80365c9..dc92700e354e7 100644
--- a/apps/studio/components/ui/DataTable/DataTableViewOptions.tsx
+++ b/apps/studio/components/ui/DataTable/DataTableViewOptions.tsx
@@ -2,12 +2,12 @@ import { GripVertical, Settings2 } from 'lucide-react'
import { useId, useMemo, useState } from 'react'
import {
Checkbox,
- Command_Shadcn_ as Command,
- CommandEmpty_Shadcn_ as CommandEmpty,
- CommandGroup_Shadcn_ as CommandGroup,
- CommandInput_Shadcn_ as CommandInput,
- CommandItem_Shadcn_ as CommandItem,
- CommandList_Shadcn_ as CommandList,
+ Command,
+ CommandEmpty,
+ CommandGroup,
+ CommandInput,
+ CommandItem,
+ CommandList,
Popover,
PopoverContent,
PopoverTrigger,
diff --git a/apps/studio/components/ui/DatabaseSelector.tsx b/apps/studio/components/ui/DatabaseSelector.tsx
index 59796bb70e78e..71ed1313537d9 100644
--- a/apps/studio/components/ui/DatabaseSelector.tsx
+++ b/apps/studio/components/ui/DatabaseSelector.tsx
@@ -9,10 +9,10 @@ import {
Button,
ButtonProps,
cn,
- Command_Shadcn_,
- CommandGroup_Shadcn_,
- CommandItem_Shadcn_,
- CommandList_Shadcn_,
+ Command,
+ CommandGroup,
+ CommandItem,
+ CommandList,
Popover,
PopoverContent,
PopoverTrigger,
@@ -123,12 +123,12 @@ export const DatabaseSelector = ({
-
-
+
+
{additionalOptions.length > 0 && (
-
+
{additionalOptions.map((option) => (
- {option.name}
{option.id === selectedDatabaseId && }
-
+
))}
-
+
)}
-
+
7 ? 'h-[210px]' : ''}>
{sortedDatabases?.map((database) => {
const region = formatDatabaseRegion(database.region)
@@ -185,7 +185,7 @@ export const DatabaseSelector = ({
}
return (
-
{database.identifier === selectedDatabaseId && }
-
+
)
})}
-
+
{IS_PLATFORM && infrastructureReadReplicas && (
-
-
+ {
setOpen(false)
@@ -235,11 +235,11 @@ export const DatabaseSelector = ({
Create a new read replica
-
-
+
+
)}
-
-
+
+
)
diff --git a/apps/studio/components/ui/EditorPanel/EditorPanel.tsx b/apps/studio/components/ui/EditorPanel/EditorPanel.tsx
index afbecfa636311..87a4f2a8b1364 100644
--- a/apps/studio/components/ui/EditorPanel/EditorPanel.tsx
+++ b/apps/studio/components/ui/EditorPanel/EditorPanel.tsx
@@ -19,12 +19,12 @@ import { useEffect, useRef, useState } from 'react'
import {
Button,
cn,
- Command_Shadcn_,
- CommandEmpty_Shadcn_,
- CommandGroup_Shadcn_,
- CommandInput_Shadcn_,
- CommandItem_Shadcn_,
- CommandList_Shadcn_,
+ Command,
+ CommandEmpty,
+ CommandGroup,
+ CommandInput,
+ CommandItem,
+ CommandList,
HoverCard,
HoverCardContent,
HoverCardTrigger,
@@ -330,23 +330,23 @@ export const EditorPanel = () => {
>
-
-
+
-
+
{isLoadingSnippets ? (
Loading snippets...
) : (
- No snippets found.
+ No snippets found.
)}
-
+
{(snippetsData?.content ?? []).map((snippet) => (
- {
}}
>
{snippet.name}
-
+
))}
-
-
-
+
+
+
{templates.length > 0 && (
@@ -379,15 +379,15 @@ export const EditorPanel = () => {
-
-
-
- No templates found.
-
+
+
+
+ No templates found.
+
{templates.map((template) => (
- onSelectTemplate(template.content)}
className="cursor-pointer"
@@ -406,7 +406,7 @@ export const EditorPanel = () => {
-
+
{
))}
-
-
-
+
+
+
)}
diff --git a/apps/studio/components/ui/FunctionSelector.tsx b/apps/studio/components/ui/FunctionSelector.tsx
index bb99e250b855b..19c206746e4e3 100644
--- a/apps/studio/components/ui/FunctionSelector.tsx
+++ b/apps/studio/components/ui/FunctionSelector.tsx
@@ -9,13 +9,13 @@ import {
AlertDescription,
AlertTitle,
Button,
- Command_Shadcn_,
- CommandEmpty_Shadcn_,
- CommandGroup_Shadcn_,
- CommandInput_Shadcn_,
- CommandItem_Shadcn_,
- CommandList_Shadcn_,
- CommandSeparator_Shadcn_,
+ Command,
+ CommandEmpty,
+ CommandGroup,
+ CommandInput,
+ CommandItem,
+ CommandList,
+ CommandSeparator,
Popover,
PopoverContent,
PopoverTrigger,
@@ -123,25 +123,25 @@ const FunctionSelector = ({
-
-
-
+
+ event.stopPropagation() : undefined}
>
- No functions found
-
+ No functions found
+
7 ? 'h-[210px]' : ''}>
{!functions.length && (
-
{noResultsLabel}
-
+
)}
{functions.map((func) => (
-
)}
-
+
))}
-
-
-
-
+
+
+ {
setOpen(false)
@@ -182,10 +182,10 @@ const FunctionSelector = ({
New function
-
-
-
-
+
+
+
+
)}
diff --git a/apps/studio/components/ui/Logs/LogsExplorerHeader.tsx b/apps/studio/components/ui/Logs/LogsExplorerHeader.tsx
index d03bb0816cf3d..8f530ad80361d 100644
--- a/apps/studio/components/ui/Logs/LogsExplorerHeader.tsx
+++ b/apps/studio/components/ui/Logs/LogsExplorerHeader.tsx
@@ -5,12 +5,12 @@ import { logConstants } from 'shared-data'
import {
Button,
cn,
- Command_Shadcn_,
- CommandEmpty_Shadcn_,
- CommandGroup_Shadcn_,
- CommandInput_Shadcn_,
- CommandItem_Shadcn_,
- CommandList_Shadcn_,
+ Command,
+ CommandEmpty,
+ CommandGroup,
+ CommandInput,
+ CommandItem,
+ CommandList,
copyToClipboard,
Popover,
PopoverContent,
@@ -115,13 +115,13 @@ const LogsExplorerHeader = ({ subtitle }: LogsExplorerHeaderProps) => {
-
-
-
- No source found.
-
+
+
+
+ No source found.
+
{logConstants.schemas.map((schema) => (
- {
@@ -136,11 +136,11 @@ const LogsExplorerHeader = ({ subtitle }: LogsExplorerHeaderProps) => {
)}
/>
{schema.name}
-
+
))}
-
-
-
+
+
+
@@ -226,7 +226,7 @@ export const OrganizationProjectSelector = ({
{renderActions(setOpen, { embedded: true })}
)}
-
-
-
+
{renderListContent()}
-
+
{!!renderActions && !embedded && (
<>
{renderActions(setOpen)}
>
)}
-
-
+
+
)
if (embedded) {
diff --git a/apps/studio/components/ui/OrganizationProjectSelector/ProjectCommandItem.tsx b/apps/studio/components/ui/OrganizationProjectSelector/ProjectCommandItem.tsx
index 1f7b39463aea3..d9076d799362e 100644
--- a/apps/studio/components/ui/OrganizationProjectSelector/ProjectCommandItem.tsx
+++ b/apps/studio/components/ui/OrganizationProjectSelector/ProjectCommandItem.tsx
@@ -1,6 +1,6 @@
import { Check } from 'lucide-react'
import { ReactNode } from 'react'
-import { cn, CommandItem_Shadcn_ } from 'ui'
+import { cn, CommandItem } from 'ui'
import type { OrgProject } from '@/data/projects/org-projects-infinite-query'
@@ -31,7 +31,7 @@ export function ProjectCommandItem({
const disabled = isOptionDisabled?.(project) ?? false
return (
- }
)}
-
+
)
}
diff --git a/apps/studio/components/ui/SchemaComboBox.tsx b/apps/studio/components/ui/SchemaComboBox.tsx
index 673f41754ac63..ce0f5f0fc9f98 100644
--- a/apps/studio/components/ui/SchemaComboBox.tsx
+++ b/apps/studio/components/ui/SchemaComboBox.tsx
@@ -5,12 +5,12 @@ import {
AlertDescription,
AlertTitle,
Button,
- Command_Shadcn_,
- CommandEmpty_Shadcn_,
- CommandGroup_Shadcn_,
- CommandInput_Shadcn_,
- CommandItem_Shadcn_,
- CommandList_Shadcn_,
+ Command,
+ CommandEmpty,
+ CommandGroup,
+ CommandInput,
+ CommandItem,
+ CommandList,
Popover,
PopoverContent,
PopoverTrigger,
@@ -108,14 +108,14 @@ export const SchemaComboBox = ({
-
-
-
- No schemas found
-
+
+
+
+ No schemas found
+
7 ? 'h-[210px]' : ''}>
{schemas?.map((schema) => (
- toggleSchema(schema.name)}
@@ -125,12 +125,12 @@ export const SchemaComboBox = ({
{selectedSchemas.includes(schema.name) && (
)}
-
+
))}
-
-
-
+
+
+
)}
diff --git a/apps/studio/components/ui/SchemaSelector.tsx b/apps/studio/components/ui/SchemaSelector.tsx
index 8426adf79e1d9..bc7832fe38c40 100644
--- a/apps/studio/components/ui/SchemaSelector.tsx
+++ b/apps/studio/components/ui/SchemaSelector.tsx
@@ -6,13 +6,13 @@ import {
AlertDescription,
AlertTitle,
Button,
- Command_Shadcn_,
- CommandEmpty_Shadcn_,
- CommandGroup_Shadcn_,
- CommandInput_Shadcn_,
- CommandItem_Shadcn_,
- CommandList_Shadcn_,
- CommandSeparator_Shadcn_,
+ Command,
+ CommandEmpty,
+ CommandGroup,
+ CommandInput,
+ CommandItem,
+ CommandList,
+ CommandSeparator,
Popover,
PopoverContent,
PopoverTrigger,
@@ -149,16 +149,16 @@ export const SchemaSelector = forwardRef(
align={align}
sameWidthAsTrigger
>
-
-
-
+
+ event.stopPropagation() : undefined}
>
- No schemas found
-
+ No schemas found
+
7 ? 'h-[210px]' : ''}>
{supportSelectAll && (
- {
@@ -174,10 +174,10 @@ export const SchemaSelector = forwardRef(
{selectedSchemaName === '*' && (
)}
-
+
)}
{schemas.map((schema) => (
- {
@@ -193,15 +193,15 @@ export const SchemaSelector = forwardRef(
{selectedSchemaName === schema.name && (
)}
-
+
))}
-
+
{onSelectCreateSchema !== undefined && canCreateSchemas && (
<>
-
-
-
+
+ {
onSelectCreateSchema()
@@ -214,12 +214,12 @@ export const SchemaSelector = forwardRef(
>
Create a new schema
-
-
+
+
>
)}
-
-
+
+
)}
diff --git a/apps/studio/pages/project/[ref]/functions/new.tsx b/apps/studio/pages/project/[ref]/functions/new.tsx
index 61bb1bd2011bf..6cb09a857df3b 100644
--- a/apps/studio/pages/project/[ref]/functions/new.tsx
+++ b/apps/studio/pages/project/[ref]/functions/new.tsx
@@ -10,12 +10,12 @@ import {
AiIconAnimation,
Button,
cn,
- Command_Shadcn_,
- CommandEmpty_Shadcn_,
- CommandGroup_Shadcn_,
- CommandInput_Shadcn_,
- CommandItem_Shadcn_,
- CommandList_Shadcn_,
+ Command,
+ CommandEmpty,
+ CommandGroup,
+ CommandInput,
+ CommandItem,
+ CommandList,
Form,
FormControl,
FormField,
@@ -313,13 +313,13 @@ const NewFunctionPage = () => {
-
-
-
- No templates found.
-
+
+
+
+ No templates found.
+
{templates.map((template) => (
- {
{template.description}
-
+
))}
-
-
-
+
+
+
-
-
- No results found.
-
+
+
+ No results found.
+
{COMMAND_ITEMS.map((navItem) => (
- runCommand(() => router.push(navItem.href as string))}
@@ -83,29 +83,29 @@ export function CommandMenu({ ...props }: DialogProps) {
{navItem.label}
-
+
))}
-
-
-
- runCommand(() => setTheme('light'))}>
+
+
+
+ runCommand(() => setTheme('light'))}>
Light
-
- runCommand(() => setTheme('dark'))}>
+
+ runCommand(() => setTheme('dark'))}>
Dark
-
- runCommand(() => setTheme('classic-dark'))}>
+
+ runCommand(() => setTheme('classic-dark'))}>
Classic dark
-
- runCommand(() => setTheme('system'))}>
+
+ runCommand(() => setTheme('system'))}>
System
-
-
-
+
+
+
>
)
diff --git a/apps/ui-library/components/tanstack-db-generator/ComboBox.tsx b/apps/ui-library/components/tanstack-db-generator/ComboBox.tsx
index 208ab15dc9c43..cb5009d850ebc 100644
--- a/apps/ui-library/components/tanstack-db-generator/ComboBox.tsx
+++ b/apps/ui-library/components/tanstack-db-generator/ComboBox.tsx
@@ -6,17 +6,18 @@ import { useEffect, useRef, useState } from 'react'
import {
Button_Shadcn_ as Button,
cn,
- Command_Shadcn_ as Command,
- CommandGroup_Shadcn_ as CommandGroup,
- CommandInput_Shadcn_ as CommandInput,
- CommandItem_Shadcn_ as CommandItem,
- CommandList_Shadcn_ as CommandList,
- Popover as Popover,
- PopoverContent as PopoverContent,
- PopoverTrigger as PopoverTrigger,
+ Command,
+ CommandGroup as CommandGroup,
+ CommandInput,
+ CommandItem as CommandItem,
+ CommandList as CommandList,
+ Popover,
+ PopoverContent,
+ PopoverTrigger,
ScrollArea,
} from 'ui'
import ShimmeringLoader from 'ui-patterns/ShimmeringLoader'
+
import { useIntersectionObserver } from '@/hooks/useIntersectionObserver'
export interface ComboBoxOption {
diff --git a/apps/www/components/Pricing/UpgradePlan.tsx b/apps/www/components/Pricing/UpgradePlan.tsx
index d037156736776..2c7b0d6297ded 100644
--- a/apps/www/components/Pricing/UpgradePlan.tsx
+++ b/apps/www/components/Pricing/UpgradePlan.tsx
@@ -9,13 +9,13 @@ import {
Button,
ButtonProps,
cn,
- Command_Shadcn_,
- CommandEmpty_Shadcn_,
- CommandGroup_Shadcn_,
- CommandInput_Shadcn_,
- CommandItem_Shadcn_,
- CommandList_Shadcn_,
- CommandSeparator_Shadcn_,
+ Command,
+ CommandEmpty,
+ CommandGroup,
+ CommandInput,
+ CommandItem,
+ CommandList,
+ CommandSeparator,
Dialog,
DialogClose,
DialogContent,
@@ -81,13 +81,13 @@ const UpgradePlan = ({ organizations = [], onClick, size = 'large', planId }: Up
-
-
-
- No organizations found.
-
+
+
+
+ No organizations found.
+
{organizations.map((organization) => (
- {
@@ -103,12 +103,12 @@ const UpgradePlan = ({ organizations = [], onClick, size = 'large', planId }: Up
)}
/>
{organization.name}
-
+
))}
-
-
-
-
+
+
+ {
setValue(currentValue === value ? '' : currentValue)
@@ -123,10 +123,10 @@ const UpgradePlan = ({ organizations = [], onClick, size = 'large', planId }: Up
)}
/>
Create a new organization
-
-
-
-
+
+
+
+
diff --git a/packages/ui-patterns/src/CommandMenu/api/CommandMenu.tsx b/packages/ui-patterns/src/CommandMenu/api/CommandMenu.tsx
index bc0ab4c55fc03..bb2cbbee04c7a 100644
--- a/packages/ui-patterns/src/CommandMenu/api/CommandMenu.tsx
+++ b/packages/ui-patterns/src/CommandMenu/api/CommandMenu.tsx
@@ -10,7 +10,7 @@ import { ErrorBoundary } from 'react-error-boundary'
import {
Button,
cn,
- Command_Shadcn_,
+ Command,
Dialog,
DialogContent,
DialogDescription,
@@ -50,11 +50,11 @@ function Breadcrumb({ className }: { className?: string }) {
}
const CommandWrapper = forwardRef<
- React.ElementRef,
- React.ComponentPropsWithoutRef
+ React.ElementRef,
+ React.ComponentPropsWithoutRef
>(({ children, className, ...props }, ref) => {
return (
-
{children}
-
+
)
})
-CommandWrapper.displayName = Command_Shadcn_.displayName
+CommandWrapper.displayName = Command.displayName
function CommandError({ resetErrorBoundary }: { resetErrorBoundary: () => void }) {
return (
diff --git a/packages/ui-patterns/src/CommandMenu/api/CommandMenuInput.tsx b/packages/ui-patterns/src/CommandMenu/api/CommandMenuInput.tsx
index 8f3c33c1a669c..79036c8894de7 100644
--- a/packages/ui-patterns/src/CommandMenu/api/CommandMenuInput.tsx
+++ b/packages/ui-patterns/src/CommandMenu/api/CommandMenuInput.tsx
@@ -3,7 +3,7 @@
import { useBreakpoint, useDebounce } from 'common'
import { forwardRef, useCallback, useEffect, useRef, useState } from 'react'
import type React from 'react'
-import { cn, CommandInput_Shadcn_ } from 'ui'
+import { cn, CommandInput } from 'ui'
import { useQuery, useSetQuery } from './hooks/queryHooks'
import { useCommandMenuTelemetryContext } from './hooks/useCommandMenuTelemetryContext'
@@ -42,8 +42,8 @@ function useFocusInputOnWiderScreens(ref: React.ForwardedRef)
}
const CommandMenuInput = forwardRef<
- React.ElementRef,
- React.ComponentPropsWithoutRef
+ React.ElementRef,
+ React.ComponentPropsWithoutRef
>(({ className, ...props }, ref) => {
const inputRef = useFocusInputOnWiderScreens(ref)
@@ -113,7 +113,7 @@ const CommandMenuInput = forwardRef<
return (
- ,
- React.ComponentPropsWithoutRef
+ React.ElementRef,
+ React.ComponentPropsWithoutRef
>(({ className, ...props }, ref) => {
const commandSections = useCommands()
const query = useQuery()
@@ -26,7 +26,7 @@ const CommandMenuList = forwardRef<
}
return (
-
)
})}
-
+
)
})
CommandMenuList.displayName = 'CommandMenuList'
diff --git a/packages/ui-patterns/src/CommandMenu/internal/CommandMenuGroup.tsx b/packages/ui-patterns/src/CommandMenu/internal/CommandMenuGroup.tsx
index c100b155ef2b5..4d4acf40d4966 100644
--- a/packages/ui-patterns/src/CommandMenu/internal/CommandMenuGroup.tsx
+++ b/packages/ui-patterns/src/CommandMenu/internal/CommandMenuGroup.tsx
@@ -1,14 +1,14 @@
'use client'
import { forwardRef } from 'react'
-import { cn, CommandGroup_Shadcn_ } from 'ui'
+import { cn, CommandGroup } from 'ui'
const CommandMenuGroup = forwardRef<
- React.ElementRef,
- React.ComponentPropsWithoutRef
+ React.ElementRef,
+ React.ComponentPropsWithoutRef
>(({ className, ...props }, ref) => {
return (
- {
+interface CommandItemProps extends React.ComponentPropsWithoutRef {
command: ICommand
}
const CommandMenuItem = forwardRef<
- React.ElementRef,
+ React.ElementRef,
PropsWithChildren
>(({ children, className, command: _command, ...props }, ref) => {
const router = useCrossCompatRouter()
@@ -95,7 +95,7 @@ const CommandMenuItem = forwardRef<
}
return (
-
{command.badge?.()}
-
+
)
})
CommandMenuItem.displayName = 'CommandMenuItem'
diff --git a/packages/ui-patterns/src/CommandMenu/prepackaged/DocsAi/DocsAiPage.tsx b/packages/ui-patterns/src/CommandMenu/prepackaged/DocsAi/DocsAiPage.tsx
index 0d13efe3da31f..f77a11be38c3f 100644
--- a/packages/ui-patterns/src/CommandMenu/prepackaged/DocsAi/DocsAiPage.tsx
+++ b/packages/ui-patterns/src/CommandMenu/prepackaged/DocsAi/DocsAiPage.tsx
@@ -5,14 +5,7 @@ import { User } from 'lucide-react'
import { Fragment, useCallback, useEffect, useRef, useState } from 'react'
import ReactMarkdown from 'react-markdown'
import remarkGfm from 'remark-gfm'
-import {
- AiIconAnimation,
- Button,
- cn,
- CommandGroup_Shadcn_,
- CommandItem_Shadcn_,
- CommandList_Shadcn_,
-} from 'ui'
+import { AiIconAnimation, Button, cn, CommandGroup, CommandItem, CommandList } from 'ui'
import { markdownComponents } from 'ui-patterns/Markdown'
import { StatusIcon } from 'ui/src/components/StatusIcon'
@@ -195,7 +188,7 @@ function AiMessages({ messages }: { messages: Array }) {
error. This display doesn't actually need the Command Menu, but it's
needed for the empty state to work with the input, so this is a somewhat
hacktastic way of making it not error. */}
-
+
void
const query = useQuery()
return (
-
-
+ void
{questions.map((question) => {
const key = question.replace(/\s+/g, '_')
return (
- {
if (!query) {
@@ -312,11 +305,11 @@ function EmptyState({ handleSubmit }: { handleSubmit: (message: string) => void
>
{question}
-
+
)
})}
-
-
+
+
)
}
diff --git a/packages/ui-patterns/src/CommandMenu/prepackaged/DocsSearch/DocsSearchPage.tsx b/packages/ui-patterns/src/CommandMenu/prepackaged/DocsSearch/DocsSearchPage.tsx
index 00bf0ab4d74ea..ba7454ba5c4d9 100644
--- a/packages/ui-patterns/src/CommandMenu/prepackaged/DocsSearch/DocsSearchPage.tsx
+++ b/packages/ui-patterns/src/CommandMenu/prepackaged/DocsSearch/DocsSearchPage.tsx
@@ -8,7 +8,7 @@ import {
} from 'common'
import { Book, ChevronRight, Github, Hash, Loader2, MessageSquare, Search } from 'lucide-react'
import { useCallback, useEffect, useRef } from 'react'
-import { Button, cn, CommandGroup_Shadcn_, CommandItem_Shadcn_, CommandList_Shadcn_ } from 'ui'
+import { Button, cn, CommandGroup, CommandItem, CommandList } from 'ui'
import { StatusIcon } from 'ui/src/components/StatusIcon'
import {
@@ -193,18 +193,18 @@ const DocsSearchPage = () => {
-
+
{hasResults &&
('results' in state ? state.results : state.staleResults).map((page, i) => {
return (
-
- {
@@ -227,11 +227,11 @@ const DocsSearchPage = () => {
-
+
{page.sections.length > 0 && (
{page.sections.map((section, i) => (
- {
-
+
))}
)}
-
+
)
})}
{state.status === 'initial' && (
-
+
{questions.map((question) => {
const key = question.replace(/\s+/g, '_')
return (
- {
@@ -287,10 +287,10 @@ const DocsSearchPage = () => {
>
{question}
-
+
)
})}
-
+
)}
{state.status === 'loading' && state.staleResults.length === 0 && (
@@ -319,7 +319,7 @@ const DocsSearchPage = () => {
)}
-
+
)
}
diff --git a/packages/ui-patterns/src/McpUrlBuilder/components/ClientSelectDropdown.tsx b/packages/ui-patterns/src/McpUrlBuilder/components/ClientSelectDropdown.tsx
index 288d14726f10d..14fde11eb2004 100644
--- a/packages/ui-patterns/src/McpUrlBuilder/components/ClientSelectDropdown.tsx
+++ b/packages/ui-patterns/src/McpUrlBuilder/components/ClientSelectDropdown.tsx
@@ -5,12 +5,12 @@ import { useState } from 'react'
import {
Button,
cn,
- Command_Shadcn_,
- CommandEmpty_Shadcn_,
- CommandGroup_Shadcn_,
- CommandInput_Shadcn_,
- CommandItem_Shadcn_,
- CommandList_Shadcn_,
+ Command,
+ CommandEmpty,
+ CommandGroup,
+ CommandInput,
+ CommandItem,
+ CommandList,
Popover,
PopoverContent,
PopoverTrigger,
@@ -50,7 +50,7 @@ export const ClientSelectDropdown = ({
function renderClient(client: McpClient) {
return (
- onSelectClient(client.key)}
@@ -71,7 +71,7 @@ export const ClientSelectDropdown = ({
size={15}
className={cn('ml-auto', client.key === selectedClient.key ? 'opacity-100' : 'opacity-0')}
/>
-
+
)
}
@@ -109,21 +109,21 @@ export const ClientSelectDropdown = ({
-
-
-
- No results found.
+
+
+
+ No results found.
{groups ? (
groups.map((group) => (
-
+
{group.clients.map(renderClient)}
-
+
))
) : (
- {clients.map(renderClient)}
+ {clients.map(renderClient)}
)}
-
-
+
+
)
diff --git a/packages/ui-patterns/src/MobileSheetNav/MobileSheetNav.tsx b/packages/ui-patterns/src/MobileSheetNav/MobileSheetNav.tsx
index d683197688b06..3d29ab996f133 100644
--- a/packages/ui-patterns/src/MobileSheetNav/MobileSheetNav.tsx
+++ b/packages/ui-patterns/src/MobileSheetNav/MobileSheetNav.tsx
@@ -4,7 +4,7 @@ import { useRouter } from 'next/router'
import { useEffect } from 'react'
import { ErrorBoundary } from 'react-error-boundary'
import { useWindowSize } from 'react-use'
-import { CommandEmpty_Shadcn_, Sheet, SheetContent } from 'ui'
+import { CommandEmpty, Sheet, SheetContent } from 'ui'
import { cn } from 'ui/src/lib/utils'
const MobileSheetNav: React.FC<{
@@ -53,7 +53,7 @@ const MobileSheetNav: React.FC<{
className
)}
>
- }>{children}
+ }>{children}
)
diff --git a/packages/ui-patterns/src/multi-select/multi-select.tsx b/packages/ui-patterns/src/multi-select/multi-select.tsx
index 4311a2aee1f45..837e273e2b9d7 100644
--- a/packages/ui-patterns/src/multi-select/multi-select.tsx
+++ b/packages/ui-patterns/src/multi-select/multi-select.tsx
@@ -8,11 +8,11 @@ import React, { isValidElement, ReactElement, useEffect } from 'react'
import {
Badge,
cn,
- Command_Shadcn_ as Command,
- CommandEmpty_Shadcn_ as CommandEmpty,
- CommandInput_Shadcn_ as CommandInput,
- CommandItem_Shadcn_ as CommandItem,
- CommandList_Shadcn_ as CommandList,
+ Command as Command,
+ CommandEmpty as CommandEmpty,
+ CommandInput as CommandInput,
+ CommandItem as CommandItem,
+ CommandList as CommandList,
Popover,
PopoverAnchor,
PopoverContent,
diff --git a/packages/ui/index.tsx b/packages/ui/index.tsx
index c39bd29b88d38..0ad715c9a9982 100644
--- a/packages/ui/index.tsx
+++ b/packages/ui/index.tsx
@@ -63,17 +63,7 @@ export * from './src/components/shadcn/ui/toggle-group'
export * from './src/components/shadcn/ui/toggle'
export * from './src/components/shadcn/ui/card'
-export {
- Command as Command_Shadcn_,
- CommandDialog as CommandDialog,
- CommandInput as CommandInput_Shadcn_,
- CommandList as CommandList_Shadcn_,
- CommandEmpty as CommandEmpty_Shadcn_,
- CommandGroup as CommandGroup_Shadcn_,
- CommandItem as CommandItem_Shadcn_,
- CommandShortcut as CommandShortcut_Shadcn_,
- CommandSeparator as CommandSeparator_Shadcn_,
-} from './src/components/shadcn/ui/command'
+export * from './src/components/shadcn/ui/command'
export * from './src/components/shadcn/ui/context-menu'
From 3c5a5a45ca7fb406364b1eb5e41aa41c28088393 Mon Sep 17 00:00:00 2001
From: Pedro Rodrigues <44656907+Rodriguespn@users.noreply.github.com>
Date: Wed, 20 May 2026 15:06:55 +0100
Subject: [PATCH 11/14] chore(docs): add GitHub Copilot CLI to MCP client list
(#46150)
## Summary
- Adds GitHub Copilot CLI as a new MCP client option in the AI Agent CLI
group (positioned after Gemini CLI)
- Includes light and dark mode SVG icons sourced from official GitHub
Copilot brand assets
- Setup instructions follow the `copilot mcp add --transport http
supabase ""` command, with authentication via `copilot -i /mcp`
- Adds `CopilotMcpConfig` type and wires up the icon asset mapping
Closes
[AI-768](https://linear.app/supabase/issue/AI-768/add-github-copilot-mcp-setup-instructions-to-docs)
## Summary by CodeRabbit
* **New Features**
* Added support for GitHub Copilot CLI MCP configuration, including
setup and authentication instructions.
* Updated AI Agent CLI client group to include Copilot CLI.
* Added theme-aware iconography for Copilot CLI integration.
[](https://app.coderabbit.ai/change-stack/supabase/supabase/pull/46150?utm_source=github_walkthrough&utm_medium=github&utm_campaign=change_stack)
Co-authored-by: Claude Sonnet 4.6
---
.../assets/copilot-icon-dark.svg | 17 ++++++
.../src/McpUrlBuilder/assets/copilot-icon.svg | 17 ++++++
.../src/McpUrlBuilder/constants.tsx | 57 ++++++++++++++++++-
.../ui-patterns/src/McpUrlBuilder/types.ts | 10 ++++
.../src/McpUrlBuilder/utils/mcpIconAssets.ts | 3 +
5 files changed, 103 insertions(+), 1 deletion(-)
create mode 100755 packages/ui-patterns/src/McpUrlBuilder/assets/copilot-icon-dark.svg
create mode 100755 packages/ui-patterns/src/McpUrlBuilder/assets/copilot-icon.svg
diff --git a/packages/ui-patterns/src/McpUrlBuilder/assets/copilot-icon-dark.svg b/packages/ui-patterns/src/McpUrlBuilder/assets/copilot-icon-dark.svg
new file mode 100755
index 0000000000000..0411bb1685898
--- /dev/null
+++ b/packages/ui-patterns/src/McpUrlBuilder/assets/copilot-icon-dark.svg
@@ -0,0 +1,17 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/packages/ui-patterns/src/McpUrlBuilder/assets/copilot-icon.svg b/packages/ui-patterns/src/McpUrlBuilder/assets/copilot-icon.svg
new file mode 100755
index 0000000000000..300c0caa0c900
--- /dev/null
+++ b/packages/ui-patterns/src/McpUrlBuilder/assets/copilot-icon.svg
@@ -0,0 +1,17 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/packages/ui-patterns/src/McpUrlBuilder/constants.tsx b/packages/ui-patterns/src/McpUrlBuilder/constants.tsx
index eeecf578c7426..6b73ce26f257e 100644
--- a/packages/ui-patterns/src/McpUrlBuilder/constants.tsx
+++ b/packages/ui-patterns/src/McpUrlBuilder/constants.tsx
@@ -6,6 +6,7 @@ import type {
AntigravityMcpConfig,
ClaudeCodeMcpConfig,
CodexMcpConfig,
+ CopilotMcpConfig,
FactoryMcpConfig,
GeminiMcpConfig,
GooseMcpConfig,
@@ -309,6 +310,60 @@ export const MCP_CLIENTS: McpClient[] = [
)
},
},
+ {
+ key: 'copilot-cli',
+ label: 'GitHub Copilot',
+ icon: 'copilot',
+ hasDistinctDarkIcon: true,
+ configFile: '~/.copilot/mcp-config.json',
+ externalDocsUrl:
+ 'https://docs.github.com/en/copilot/how-tos/copilot-cli/customize-copilot/add-mcp-servers',
+ transformConfig: (config): CopilotMcpConfig => {
+ return {
+ mcpServers: {
+ supabase: {
+ type: 'http',
+ url: config.mcpServers.supabase.url,
+ },
+ },
+ }
+ },
+ primaryInstructions: (_config, onCopy) => {
+ const config = _config as CopilotMcpConfig
+ const command = `copilot mcp add --transport http supabase "${config.mcpServers.supabase.url}"`
+ return (
+
+
+ Add the MCP server to your GitHub Copilot config using the command line:
+
+
onCopy('command')}
+ />
+
+ )
+ },
+ alternateInstructions: (_config, onCopy) => (
+
+
+ After configuring the MCP server, authenticate by running:
+
+
onCopy('command')}
+ />
+
+ Follow the on-screen instructions to complete the authentication flow.
+
+
+ ),
+ },
{
key: 'antigravity',
label: 'Antigravity',
@@ -576,7 +631,7 @@ export const MCP_CLIENTS: McpClient[] = [
export const MCP_CLIENT_GROUPS = [
{
heading: 'AI Agent CLI',
- keys: ['claude-code', 'codex', 'gemini-cli', 'opencode', 'factory'],
+ keys: ['claude-code', 'codex', 'gemini-cli', 'copilot-cli', 'opencode', 'factory'],
},
{
heading: 'Web Clients',
diff --git a/packages/ui-patterns/src/McpUrlBuilder/types.ts b/packages/ui-patterns/src/McpUrlBuilder/types.ts
index 8d7cb59ed4425..3b19577127071 100644
--- a/packages/ui-patterns/src/McpUrlBuilder/types.ts
+++ b/packages/ui-patterns/src/McpUrlBuilder/types.ts
@@ -166,10 +166,20 @@ export interface AntigravityMcpConfig {
}
}
+export interface CopilotMcpConfig extends McpClientBaseConfig {
+ mcpServers: {
+ supabase: {
+ type: 'http'
+ url: string
+ }
+ }
+}
+
// Union of all possible config types
export type McpClientConfig =
| AntigravityMcpConfig
| ClaudeCodeMcpConfig
+ | CopilotMcpConfig
| ClaudeDesktopMcpConfig
| CodexMcpConfig
| CursorMcpConfig
diff --git a/packages/ui-patterns/src/McpUrlBuilder/utils/mcpIconAssets.ts b/packages/ui-patterns/src/McpUrlBuilder/utils/mcpIconAssets.ts
index 9641d13370bba..59bbd0232dc85 100644
--- a/packages/ui-patterns/src/McpUrlBuilder/utils/mcpIconAssets.ts
+++ b/packages/ui-patterns/src/McpUrlBuilder/utils/mcpIconAssets.ts
@@ -2,6 +2,8 @@
import antigravityIcon from '../assets/antigravity-icon.svg'
import claudeIcon from '../assets/claude-icon.svg'
+import copilotDarkIcon from '../assets/copilot-icon-dark.svg'
+import copilotIcon from '../assets/copilot-icon.svg'
import cursorIcon from '../assets/cursor-icon.svg'
import factoryDarkIcon from '../assets/factory-icon-dark.svg'
import factoryIcon from '../assets/factory-icon.svg'
@@ -27,6 +29,7 @@ type McpClientIconAsset = {
const MCP_CLIENT_ICON_ASSETS = {
antigravity: { light: antigravityIcon, dark: antigravityIcon },
claude: { light: claudeIcon, dark: claudeIcon },
+ copilot: { light: copilotIcon, dark: copilotDarkIcon },
cursor: { light: cursorIcon, dark: cursorIcon },
factory: { light: factoryIcon, dark: factoryDarkIcon },
'gemini-cli': { light: geminiCliIcon, dark: geminiCliIcon },
From 69b22d37cde059dcd0fa9a33016b0932e2e91843 Mon Sep 17 00:00:00 2001
From: Jordi Enric <37541088+jordienr@users.noreply.github.com>
Date: Wed, 20 May 2026 17:01:24 +0200
Subject: [PATCH 12/14] fix(studio): parse auth log event_message JSON for
human-readable display DEBUG-111 (#46147)
## Problem
Auth log entries store metadata as a stringified JSON object in the
`event_message` field (e.g. `{"msg":"user signed
in","level":"info","status":200,"path":"/auth/v1/token"}`). The
dashboard was rendering this raw JSON string in the event message column
instead of a human-readable message.
## Fix
Added `parseAuthLogEventMessage` utility to `UnifiedLogs.utils.ts` that
JSON-parses the `event_message` value and extracts the `msg` field,
falling back to the `error` field, then the original raw string. The raw
string fallback ensures self-hosted versions with different log formats
continue to render without breaking between releases.
Applied in two places:
- `UnifiedLogs/components/Columns.tsx`: event_message column for
`log_type === 'auth'` rows
- `Settings/Logs/LogColumnRenderers/AuthColumnRenderer.tsx`:
event_message fallback when `metadata.msg` is absent
## How to test
1. Open the Supabase dashboard and navigate to Logs > Auth Logs
2. Verify that log entries show a plain message (e.g. "login attempt",
"invalid password") in the event message column instead of a raw JSON
string
3. Navigate to the unified logs view and filter to auth logs only
4. Verify the event message column shows the same human-readable
messages
5. Confirm that non-auth log types (edge, postgres, etc.) are unaffected
6. Expected result: auth log entries show readable messages; all other
log sources are unchanged
## Summary by CodeRabbit
* **Bug Fixes**
* Auth log messages now display in a more readable, human-friendly
format by intelligently parsing message data.
* **Refactor**
* Removed tooltip functionality from the pathname column in logs view
for streamlined display.
[](https://app.coderabbit.ai/change-stack/supabase/supabase/pull/46147?utm_source=github_walkthrough&utm_medium=github&utm_campaign=change_stack)
---------
Co-authored-by: Claude Sonnet 4.6
Co-authored-by: Joshen Lim
---
.../LogColumnRenderers/AuthColumnRenderer.tsx | 3 +-
.../UnifiedLogs/UnifiedLogs.utils.ts | 22 ++++++++
.../UnifiedLogs/components/Columns.tsx | 12 ++---
.../components/TextWithTooltip.tsx | 53 -------------------
4 files changed, 29 insertions(+), 61 deletions(-)
delete mode 100644 apps/studio/components/interfaces/UnifiedLogs/components/TextWithTooltip.tsx
diff --git a/apps/studio/components/interfaces/Settings/Logs/LogColumnRenderers/AuthColumnRenderer.tsx b/apps/studio/components/interfaces/Settings/Logs/LogColumnRenderers/AuthColumnRenderer.tsx
index 5e7ac8a052b2d..9e6b01953b7b1 100644
--- a/apps/studio/components/interfaces/Settings/Logs/LogColumnRenderers/AuthColumnRenderer.tsx
+++ b/apps/studio/components/interfaces/Settings/Logs/LogColumnRenderers/AuthColumnRenderer.tsx
@@ -4,6 +4,7 @@ import { TimestampInfo } from 'ui-patterns/TimestampInfo'
import type { LogData } from '../Logs.types'
import { RowLayout, SeverityFormatter, TextFormatter } from '../LogsFormatters'
import { defaultRenderCell } from './DefaultPreviewColumnRenderer'
+import { parseAuthLogEventMessage } from '@/components/interfaces/UnifiedLogs/UnifiedLogs.utils'
const columns: Column[] = [
{
@@ -23,7 +24,7 @@ const columns: Column[] = [
className="w-full"
value={`${props.row.path ? props.row.path + ' | ' : ''}${
// not all log events have metadata.msg
- (props.row.msg as string)?.trim() || props.row.event_message
+ (props.row.msg as string)?.trim() || parseAuthLogEventMessage(props.row.event_message)
}`}
/>
diff --git a/apps/studio/components/interfaces/UnifiedLogs/UnifiedLogs.utils.ts b/apps/studio/components/interfaces/UnifiedLogs/UnifiedLogs.utils.ts
index 7cd29dbc9ec69..78c96b0ce832c 100644
--- a/apps/studio/components/interfaces/UnifiedLogs/UnifiedLogs.utils.ts
+++ b/apps/studio/components/interfaces/UnifiedLogs/UnifiedLogs.utils.ts
@@ -115,3 +115,25 @@ export function formatServiceTypeForDisplay(serviceType: string): string {
return specialCases[serviceType.toLowerCase()] || serviceType
}
+
+/**
+ * Parses an auth log event_message that may be a stringified JSON object.
+ * Auth log entries store metadata as JSON in event_message (e.g. {"msg":"...","level":"info"}).
+ * Extracts the human-readable msg field, falling back to error, then the raw string.
+ * The fallback ensures self-hosted versions with different formats still render correctly.
+ */
+export function parseAuthLogEventMessage(value: string | undefined): string | undefined {
+ if (!value) return value
+ try {
+ const parsed = JSON.parse(value)
+ if (parsed && typeof parsed === 'object') {
+ const msg = parsed.msg
+ const err = parsed.error
+ if (typeof msg === 'string' && msg.trim()) return msg
+ if (typeof err === 'string' && err.trim()) return err
+ }
+ return value
+ } catch {
+ return value
+ }
+}
diff --git a/apps/studio/components/interfaces/UnifiedLogs/components/Columns.tsx b/apps/studio/components/interfaces/UnifiedLogs/components/Columns.tsx
index 98574cd488d32..544261a58e432 100644
--- a/apps/studio/components/interfaces/UnifiedLogs/components/Columns.tsx
+++ b/apps/studio/components/interfaces/UnifiedLogs/components/Columns.tsx
@@ -3,9 +3,9 @@ import { Checkbox, Tooltip, TooltipContent, TooltipTrigger } from 'ui'
import { STATUS_CODE_LABELS } from '../UnifiedLogs.constants'
import { ColumnFilterSchema, ColumnSchema } from '../UnifiedLogs.schema'
+import { parseAuthLogEventMessage } from '../UnifiedLogs.utils'
import { HoverCardTimestamp } from './HoverCardTimestamp'
import { LogTypeIcon } from './LogTypeIcon'
-import { TextWithTooltip } from './TextWithTooltip'
import { DataTableColumnLevelIndicator } from '@/components/ui/DataTable/DataTableColumn/DataTableColumnLevelIndicator'
import { DataTableColumnStatusCode } from '@/components/ui/DataTable/DataTableColumn/DataTableColumnStatusCode'
@@ -205,7 +205,7 @@ export function generateDynamicColumns({ data }: { data: ColumnSchema[] }): {
header: 'Pathname',
cell: ({ row }) => {
const value = row.getValue('pathname') ?? ''
- return
+ return value
},
enableSorting: false,
enableResizing: false,
@@ -223,7 +223,9 @@ export function generateDynamicColumns({ data }: { data: ColumnSchema[] }): {
header: 'Event message',
cell: ({ row }) => {
const value = row.getValue('event_message')
+ const logType = row.original.log_type
const logCount = row.original.log_count
+ const displayMessage = logType === 'auth' ? parseAuthLogEventMessage(value) : value
return (
@@ -239,11 +241,7 @@ export function generateDynamicColumns({ data }: { data: ColumnSchema[] }): {
)}
- {value && (
-
-
-
- )}
+ {displayMessage && {displayMessage} }
)
},
diff --git a/apps/studio/components/interfaces/UnifiedLogs/components/TextWithTooltip.tsx b/apps/studio/components/interfaces/UnifiedLogs/components/TextWithTooltip.tsx
deleted file mode 100644
index fae42e933ac5c..0000000000000
--- a/apps/studio/components/interfaces/UnifiedLogs/components/TextWithTooltip.tsx
+++ /dev/null
@@ -1,53 +0,0 @@
-import { useEffect, useRef, useState } from 'react'
-import { cn, Tooltip, TooltipContent, TooltipPortal, TooltipProvider, TooltipTrigger } from 'ui'
-
-interface TextWithTooltipProps {
- text: string | number
- className?: string
-}
-
-export function TextWithTooltip({ text, className }: TextWithTooltipProps) {
- const [isTruncated, setIsTruncated] = useState(false)
- const textRef = useRef(null)
-
- useEffect(() => {
- const checkTruncation = () => {
- if (textRef.current) {
- const { scrollWidth, clientWidth } = textRef.current
- setIsTruncated(scrollWidth > clientWidth)
- }
- }
-
- const resizeObserver = new ResizeObserver(() => {
- checkTruncation()
- })
-
- if (textRef.current) {
- resizeObserver.observe(textRef.current)
- }
-
- checkTruncation()
-
- return () => {
- resizeObserver.disconnect()
- }
- }, [])
-
- return (
-
-
-
-
- {text}
-
-
-
- {text}
-
-
-
- )
-}
From c8e1eb18362878e7b383634ad0313e68ea6e5d08 Mon Sep 17 00:00:00 2001
From: Joshen Lim
Date: Wed, 20 May 2026 22:14:05 +0700
Subject: [PATCH 13/14] Support click drag to highlight time range in timeline
chart unified logs (#46149)
## Context
As per PR title - supports click drag to highlight a specific time range
in the TimelineChart of unified logs as such:
Also adjusts the chart highlight behaviour which affects the database
report charts to clear the highlighted area when clicking outside of it
### Demo
https://github.com/user-attachments/assets/5084fc04-49a7-4b41-94be-b4edb1bef3ce
## Summary by CodeRabbit
* **New Features**
* Added Escape key support to dismiss chart highlights
* **Improvements**
* Clear chart selections when clicking outside the menu while preserving
chart interactions
* Time-range filters now apply to the intended column for more accurate
zooms
* Tooltip and highlight rendering refined; reference highlight styling
adapts to dark mode
* Unified chart highlight interactions for more consistent selection and
zoom behavior
[](https://app.coderabbit.ai/change-stack/supabase/supabase/pull/46149?utm_source=github_walkthrough&utm_medium=github&utm_campaign=change_stack)
---
.../interfaces/UnifiedLogs/UnifiedLogs.tsx | 1 +
.../ui/Charts/ChartHighlightActions.tsx | 12 +-
.../components/ui/DataTable/TimelineChart.tsx | 208 ++++++++++--------
3 files changed, 125 insertions(+), 96 deletions(-)
diff --git a/apps/studio/components/interfaces/UnifiedLogs/UnifiedLogs.tsx b/apps/studio/components/interfaces/UnifiedLogs/UnifiedLogs.tsx
index a06406666aa2e..36d30b0791606 100644
--- a/apps/studio/components/interfaces/UnifiedLogs/UnifiedLogs.tsx
+++ b/apps/studio/components/interfaces/UnifiedLogs/UnifiedLogs.tsx
@@ -428,6 +428,7 @@ export const UnifiedLogs = () => {
isFetchingCharts && 'opacity-60 transition-opacity duration-150'
)}
columnId="timestamp"
+ filterColumnId="date"
chartConfig={filteredChartConfig}
/>
diff --git a/apps/studio/components/ui/Charts/ChartHighlightActions.tsx b/apps/studio/components/ui/Charts/ChartHighlightActions.tsx
index 2babb10d0f65b..ddc0460555e09 100644
--- a/apps/studio/components/ui/Charts/ChartHighlightActions.tsx
+++ b/apps/studio/components/ui/Charts/ChartHighlightActions.tsx
@@ -90,7 +90,17 @@ export const ChartHighlightActions = ({
top: chartHighlight?.popoverPosition?.y + 'px' || 0,
}}
/>
-
+ clearHighlight?.()}
+ onInteractOutside={(e) => {
+ const target = e.target as Element | null
+ // If the user clicked on a chart, handleMouseDown will manage the new selection.
+ // Calling clearHighlight here would race with it and clobber the new state.
+ if (target?.closest('.recharts-wrapper')) return
+ clearHighlight?.()
+ }}
+ >
{formatChartDate(selectedRangeStart!, 'MMM D, H:mm')}
diff --git a/apps/studio/components/ui/DataTable/TimelineChart.tsx b/apps/studio/components/ui/DataTable/TimelineChart.tsx
index fb28fc44fc0c9..64524e9cc1d56 100644
--- a/apps/studio/components/ui/DataTable/TimelineChart.tsx
+++ b/apps/studio/components/ui/DataTable/TimelineChart.tsx
@@ -1,10 +1,16 @@
import { format } from 'date-fns'
-import { useMemo, useState } from 'react'
+import { SearchIcon } from 'lucide-react'
+import { useTheme } from 'next-themes'
+import { useMemo } from 'react'
import { Bar, BarChart, CartesianGrid, ReferenceArea, XAxis } from 'recharts'
-import type { CategoricalChartFunc } from 'recharts/types/chart/generateCategoricalChart'
import { ChartConfig, ChartContainer, ChartTooltip, ChartTooltipContent, cn } from 'ui'
import { useDataTable } from './providers/DataTableProvider'
+import {
+ ChartHighlightAction,
+ ChartHighlightActions,
+} from '@/components/ui/Charts/ChartHighlightActions'
+import { useChartHighlight } from '@/components/ui/Charts/useChartHighlight'
export type BaseChartSchema = { timestamp: number; [key: string]: number }
export const description = 'A stacked bar chart'
@@ -16,6 +22,11 @@ interface TimelineChartProps {
* TBD: if using keyof TData to be closer to the data table props
*/
columnId: string
+ /**
+ * Optional override for the column id used when applying the time range filter.
+ * Defaults to `columnId` if not provided.
+ */
+ filterColumnId?: string
/**
* Same data as of the InfiniteQueryMeta.
*/
@@ -27,12 +38,18 @@ export function TimelineChart({
data,
className,
columnId,
+ filterColumnId,
chartConfig,
}: TimelineChartProps) {
+ const resolvedFilterColumnId = filterColumnId ?? columnId
+ const { resolvedTheme } = useTheme()
+ const isDarkMode = resolvedTheme?.includes('dark')
+
const { table } = useDataTable()
- const [refAreaLeft, setRefAreaLeft] = useState(null)
- const [refAreaRight, setRefAreaRight] = useState(null)
- const [isSelecting, setIsSelecting] = useState(false)
+ const chartHighlight = useChartHighlight()
+
+ const showHighlight =
+ chartHighlight?.left && chartHighlight?.right && chartHighlight?.left !== chartHighlight?.right
// REMINDER: date has to be a string for tooltip label to work - don't ask me why
const chart = useMemo(
@@ -52,101 +69,102 @@ export function TimelineChart({
return { interval, period: calculatePeriod(interval) }
}, [data])
- const handleMouseDown: CategoricalChartFunc = (e) => {
- if (e.activeLabel) {
- setRefAreaLeft(e.activeLabel)
- setIsSelecting(true)
- }
- }
-
- const handleMouseMove: CategoricalChartFunc = (e) => {
- if (isSelecting && e.activeLabel) {
- setRefAreaRight(e.activeLabel)
- }
- }
-
- const handleMouseUp: CategoricalChartFunc = () => {
- if (refAreaLeft && refAreaRight) {
- const [left, right] = [refAreaLeft, refAreaRight].sort(
- (a, b) => new Date(a).getTime() - new Date(b).getTime()
- )
- table.getColumn(columnId)?.setFilterValue([new Date(left), new Date(right)])
- }
- setRefAreaLeft(null)
- setRefAreaRight(null)
- setIsSelecting(false)
- }
+ const highlightActions: ChartHighlightAction[] = useMemo(
+ () => [
+ {
+ id: 'zoom-in',
+ label: 'Filter logs to selected range',
+ icon: ,
+ onSelect: ({ start, end, clear }) => {
+ const [left, right] = [start, end].sort(
+ (a, b) => new Date(a).getTime() - new Date(b).getTime()
+ )
+ table.getColumn(resolvedFilterColumnId)?.setFilterValue([new Date(left), new Date(right)])
+ clear()
+ },
+ },
+ ],
+ [table, resolvedFilterColumnId]
+ )
return (
-
-
+
-
- {
- const date = new Date(value)
- if (isNaN(date.getTime())) return 'N/A'
- if (timerange.period === '10m') {
- return format(date, 'HH:mm:ss')
- } else if (timerange.period === '1d') {
- return format(date, 'HH:mm')
- } else if (timerange.period === '1w') {
- return format(date, 'LLL dd HH:mm')
- }
- return format(date, 'LLL dd, y')
+ {
+ if (activeTooltipIndex === undefined || activeTooltipIndex === null) return
+ chartHighlight.handleMouseDown({ activeLabel, coordinates: activeLabel })
}}
- />
- {
- const date = new Date(value)
- if (isNaN(date.getTime())) return 'N/A'
- if (timerange.period === '10m') {
- return format(date, 'LLL dd, HH:mm:ss')
- }
- return format(date, 'LLL dd, y HH:mm')
- }}
- />
- }
- />
- {/* TODO: we could use the `{timestamp, ...rest} = data[0]` to dynamically create the bars but that would mean the order can be very much random */}
-
-
-
- {refAreaLeft && refAreaRight && (
- {
+ if (activeTooltipIndex === undefined || activeTooltipIndex === null) return
+ chartHighlight.handleMouseMove({ activeLabel, coordinates: activeLabel })
+ }}
+ onMouseUp={chartHighlight.handleMouseUp}
+ style={{ cursor: 'crosshair' }}
+ >
+
+ {
+ const date = new Date(value)
+ if (isNaN(date.getTime())) return 'N/A'
+ if (timerange.period === '10m') {
+ return format(date, 'HH:mm:ss')
+ } else if (timerange.period === '1d') {
+ return format(date, 'HH:mm')
+ } else if (timerange.period === '1w') {
+ return format(date, 'LLL dd HH:mm')
+ }
+ return format(date, 'LLL dd, y')
+ }}
/>
- )}
-
-
+ {!chartHighlight.popoverPosition && (
+ {
+ const date = new Date(value)
+ if (isNaN(date.getTime())) return 'N/A'
+ if (timerange.period === '10m') {
+ return format(date, 'LLL dd, HH:mm:ss')
+ }
+ return format(date, 'LLL dd, y HH:mm')
+ }}
+ />
+ }
+ />
+ )}
+ {/* TODO: we could use the `{timestamp, ...rest} = data[0]` to dynamically create the bars but that would mean the order can be very much random */}
+
+
+
+ {showHighlight && (
+
+ )}
+
+
+
+
)
}
From 0283d92505fb4312c6abbd77251c210229f564d2 Mon Sep 17 00:00:00 2001
From: Gildas Garcia <1122076+djhi@users.noreply.github.com>
Date: Wed, 20 May 2026 17:33:03 +0200
Subject: [PATCH 14/14] fix: allow users to remove missing schemas from the
data API (#46169)
## Problem
Exposed schemas (from the Data API) that have been deleted manually (for
instance, using the SQL editor) are still present in the Data API
setting, crashing Postgrest clients. However, the Data API setting does
not show them anymore preventing users from fixing the issue.
## Solution
- Detect missing schemas and show users an error message
- Make missing schema visually distinct
- Allow users to unselect them and update the Data API settings
## How to test
- Create a new schema
- Verify that it is exposed (expose it if necessary) in the Data API
settings
- Delete the schema using the SQL editor
- Verify that you can unselect it from the Data API settings
## Screenshots
## Summary by CodeRabbit
* **Bug Fixes**
* Dropdown for exposed API schemas now shows selected schemas that no
longer exist and labels them "This schema does not exist", allowing
users to toggle them.
* "Exposed schemas" field now shows an inline validation/error message
when selected schemas are unavailable to help resolve configuration
issues.
[](https://app.coderabbit.ai/change-stack/supabase/supabase/pull/46169?utm_source=github_walkthrough&utm_medium=github&utm_campaign=change_stack)
---
.../Settings/API/ExposedSchemaSelector.tsx | 25 +++++++++++++++++++
.../Settings/API/PostgrestConfig.tsx | 8 ++++++
2 files changed, 33 insertions(+)
diff --git a/apps/studio/components/interfaces/Settings/API/ExposedSchemaSelector.tsx b/apps/studio/components/interfaces/Settings/API/ExposedSchemaSelector.tsx
index 596d9541816df..db77567e9ce5c 100644
--- a/apps/studio/components/interfaces/Settings/API/ExposedSchemaSelector.tsx
+++ b/apps/studio/components/interfaces/Settings/API/ExposedSchemaSelector.tsx
@@ -57,6 +57,11 @@ export const ExposedSchemaSelector = ({
[allSchemas]
)
+ const missingExposedSchema = useMemo(
+ () => selectedSchemas.filter((schema) => !schemas.some((s) => s.name === schema)),
+ [schemas, selectedSchemas]
+ )
+
const selectedSet = useMemo(() => new Set(selectedSchemas), [selectedSchemas])
const selectedCount = schemas.filter((s) => selectedSet.has(s.name)).length
@@ -110,6 +115,26 @@ export const ExposedSchemaSelector = ({
7 ? 'h-[210px]' : ''}>
+ {missingExposedSchema.map((schema) => (
+ {
+ onToggleSchema(schema)
+ }}
+ >
+
+
+
+ {schema}
+
+
+ This schema does not exist
+
+
+
+ ))}
{schemas.map((schema) => {
const isExposed = selectedSet.has(schema.name)
diff --git a/apps/studio/components/interfaces/Settings/API/PostgrestConfig.tsx b/apps/studio/components/interfaces/Settings/API/PostgrestConfig.tsx
index c1d3fcdaf0e13..c62cad5a5a2d5 100644
--- a/apps/studio/components/interfaces/Settings/API/PostgrestConfig.tsx
+++ b/apps/studio/components/interfaces/Settings/API/PostgrestConfig.tsx
@@ -260,6 +260,11 @@ export const PostgrestConfig = () => {
name: 'functionNamesToRemove',
})
+ const missingExposedSchema = useMemo(
+ () => watchedDbSchema.filter((schema) => !allSchemas.some((s) => s.name === schema)),
+ [allSchemas, watchedDbSchema]
+ )
+
return (
@@ -282,6 +287,9 @@ export const PostgrestConfig = () => {
layout="flex-row-reverse"
label="Exposed schemas"
description="Select schemas to include in the Data API. Schemas must be included before tables can be exposed."
+ error={
+ missingExposedSchema.length > 0 ? 'Some exposed schemas are missing' : null
+ }
>