From 0c46c33861fb60dace237f03161b5f0b3d049b69 Mon Sep 17 00:00:00 2001 From: Gildas Garcia <1122076+djhi@users.noreply.github.com> Date: Wed, 20 May 2026 12:25:10 +0200 Subject: [PATCH 01/14] chore: improve field reference everywhere in logs explorer (#46143) ## Problem #45828 only fixed some screens. ## Solution Fix all of them by fixing the `LogsExplorerHeader` ## Screenshots Before: image After: image ## Summary by CodeRabbit * **New Features** * Schema selection now features a searchable dropdown interface, replacing the previous tabbed layout for improved ease of navigation and discovery. [![Review Change Stack](https://storage.googleapis.com/coderabbit_public_assets/review-stack-in-coderabbit-ui.svg)](https://app.coderabbit.ai/change-stack/supabase/supabase/pull/46143?utm_source=github_walkthrough&utm_medium=github&utm_campaign=change_stack) --- .../components/ui/Logs/LogsExplorerHeader.tsx | 104 ++++++++++++------ 1 file changed, 70 insertions(+), 34 deletions(-) diff --git a/apps/studio/components/ui/Logs/LogsExplorerHeader.tsx b/apps/studio/components/ui/Logs/LogsExplorerHeader.tsx index 5e6cf2c0caac3..d03bb0816cf3d 100644 --- a/apps/studio/components/ui/Logs/LogsExplorerHeader.tsx +++ b/apps/studio/components/ui/Logs/LogsExplorerHeader.tsx @@ -1,12 +1,21 @@ -import { BookOpen, Check, Copy, ExternalLink, List, X } from 'lucide-react' +import { BookOpen, Check, ChevronsUpDown, Copy, ExternalLink, List, X } from 'lucide-react' import Link from 'next/link' import { useState } from 'react' import { logConstants } from 'shared-data' import { Button, + cn, + Command_Shadcn_, + CommandEmpty_Shadcn_, + CommandGroup_Shadcn_, + CommandInput_Shadcn_, + CommandItem_Shadcn_, + CommandList_Shadcn_, copyToClipboard, + Popover, + PopoverContent, + PopoverTrigger, SidePanel, - Tabs, Tooltip, TooltipContent, TooltipTrigger, @@ -23,6 +32,8 @@ export interface LogsExplorerHeaderProps { const LogsExplorerHeader = ({ subtitle }: LogsExplorerHeaderProps) => { const [showReference, setShowReference] = useState(false) + const [open, setOpen] = useState(false) + const [selectedSchema, setSelectedSchema] = useState(logConstants.schemas[0]) return (
@@ -89,38 +100,63 @@ const LogsExplorerHeader = ({ subtitle }: LogsExplorerHeaderProps) => {
- - {logConstants.schemas.map((schema) => ( - - - Path - , - - Type - , - ]} - body={schema.fields - .sort((a: any, b: any) => a.path - b.path) - .map((field) => ( - - ))} - /> - - ))} - +
+ + + + + + + + + No source found. + + {logConstants.schemas.map((schema) => ( + { + setSelectedSchema(schema) + setOpen(false) + }} + > + + {schema.name} + + ))} + + + + + +
+ Path + , + + Type + , + ]} + body={selectedSchema.fields.map((field) => ( + + ))} + /> + From df77fc901187d6bcd8ac3164e4264a3ac9833127 Mon Sep 17 00:00:00 2001 From: Danny White <3104761+dnywh@users.noreply.github.com> Date: Wed, 20 May 2026 20:26:02 +1000 Subject: [PATCH 02/14] fix(cli): resolve infinite loader on device code screen (#46137) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit ## Summary Follow-up fix for [#46120](https://github.com/supabase/supabase/pull/46120). PR #46120 correctly guarded against duplicate `POST /platform/cli/login` calls using a `useRef`, but left `navigate` in the `useEffect` deps array. Because the parent passes an inline lambda, `navigate` gets a new reference on every render. This causes React to: 1. Run the effect cleanup mid-flight (setting `isActive = false`) 2. Re-run the effect, which hits the session-id ref guard and returns early When step 1 happens while the POST is in-flight, the response arrives with `isActive === false`, silently drops the `navigate(...)` call, and leaves status stuck at `{ _tag: 'loading' }` — the infinite spinner reported in Slack. ## Fix Store `navigate` in a ref (updated each render) and call `navigateRef.current(...)` inside `createSession`. Remove `navigate` from the deps array so parent re-renders never trigger a cleanup while the POST is in-flight. ```ts const navigateRef = useRef(navigate) navigateRef.current = navigate // always up to date, never a dep ``` All 7 existing CLI login unit tests pass, including the "POSTs exactly once even when parent re-renders" regression test. ## Test plan - [ ] Run `pnpm test:studio tests/pages/cli-login.test.tsx` — all 7 tests pass - [ ] Browser: `supabase login` flow completes and shows the verification code screen without hanging on the loader - [ ] DevTools Network: exactly one `POST /platform/cli/login` fires per login attempt 🤖 Generated with [Claude Code](https://claude.com/claude-code) ## Summary by CodeRabbit * **Bug Fixes** * Improved CLI login navigation reliability when parent components update during session creation. * **Style** * Adjusted loading indicator styling on the CLI login screen. [![Review Change Stack](https://storage.googleapis.com/coderabbit_public_assets/review-stack-in-coderabbit-ui.svg)](https://app.coderabbit.ai/change-stack/supabase/supabase/pull/46137?utm_source=github_walkthrough&utm_medium=github&utm_campaign=change_stack) --------- Co-authored-by: Claude Sonnet 4.6 Co-authored-by: Gildas Garcia <1122076+djhi@users.noreply.github.com> --- apps/studio/pages/cli/login.tsx | 10 ++- apps/studio/tests/pages/cli/login.test.tsx | 78 ++++++++++++++++++++++ 2 files changed, 85 insertions(+), 3 deletions(-) create mode 100644 apps/studio/tests/pages/cli/login.test.tsx diff --git a/apps/studio/pages/cli/login.tsx b/apps/studio/pages/cli/login.tsx index 5c9e88f0bc724..e87e1885478dc 100644 --- a/apps/studio/pages/cli/login.tsx +++ b/apps/studio/pages/cli/login.tsx @@ -18,6 +18,7 @@ import CopyButton from '@/components/ui/CopyButton' import { InlineLink } from '@/components/ui/InlineLink' import { createCliLoginSession } from '@/data/cli/login' import { withAuth } from '@/hooks/misc/withAuth' +import { useStaticEffectEvent } from '@/hooks/useStaticEffectEvent' import { buildStudioPageTitle } from '@/lib/page-title' import { useProfile } from '@/lib/profile' import type { NextPageWithLayout } from '@/types' @@ -99,7 +100,7 @@ export const CliLoginScreen = ({ publicKey, tokenName, deviceCode, - navigate, + navigate: navigateProp, }: { isLoggedIn: boolean routerReady: boolean @@ -112,6 +113,9 @@ export const CliLoginScreen = ({ const { profile } = useProfile() const [status, setStatus] = useState({ _tag: 'loading' }) const startedForSessionIdRef = useRef(undefined) + // Keep navigate in a ref so changing the prop never re-triggers the effect + // or cancels an in-flight POST via the isActive cleanup. + const navigate = useStaticEffectEvent(navigateProp) const displayName = profile?.primary_email ?? profile?.username useEffect(() => { @@ -163,7 +167,7 @@ export const CliLoginScreen = ({ return () => { isActive = false } - }, [deviceCode, isLoggedIn, navigate, publicKey, routerReady, sessionId, tokenName]) + }, [deviceCode, isLoggedIn, publicKey, routerReady, sessionId, tokenName, navigate]) if (status._tag === 'loading') { return ( @@ -174,7 +178,7 @@ export const CliLoginScreen = ({
- +
diff --git a/apps/studio/tests/pages/cli/login.test.tsx b/apps/studio/tests/pages/cli/login.test.tsx new file mode 100644 index 0000000000000..0f931d3bb1861 --- /dev/null +++ b/apps/studio/tests/pages/cli/login.test.tsx @@ -0,0 +1,78 @@ +import { waitFor } from '@testing-library/dom' +import { expect, test, vi } from 'vitest' + +import * as cliLogin from '@/data/cli/login' +import { ProfileContextType } from '@/lib/profile' +import { CliLoginScreen } from '@/pages/cli/login' +import { customRender } from '@/tests/lib/custom-render' + +const DEFAULT_PROFILE_CONTEXT: ProfileContextType = { + profile: { + id: 1, + auth0_id: 'auth0|test', + gotrue_id: 'gotrue-test', + username: 'testuser', + primary_email: 'test@example.com', + first_name: null, + last_name: null, + mobile: null, + is_alpha_user: false, + is_sso_user: false, + disabled_features: [], + free_project_limit: null, + }, + error: null, + isLoading: false, + isError: false, + isSuccess: true, +} + +test('still navigates after parent re-renders during an in-flight POST', async () => { + // Resolve manually so we can inject a re-render while the POST is in flight. + let resolveSession: (value: { nonce: string }) => void = () => {} + const createCliLoginSessionMock = vi.spyOn(cliLogin, 'createCliLoginSession').mockImplementation( + () => + new Promise<{ nonce: string }>((resolve) => { + resolveSession = resolve + }) + ) + const initialNavigate = vi.fn() + const { rerender } = customRender( + , + { profileContext: DEFAULT_PROFILE_CONTEXT } + ) + + await waitFor(() => { + expect(createCliLoginSessionMock).toHaveBeenCalledTimes(1) + }) + + // Parent re-renders mid-POST with a brand-new navigate ref. This was the + // production hang: the cleanup would invalidate the success handler and + // the ref guard would skip the retry, leaving the screen on the loader. + const laterNavigate = vi.fn() + rerender( + + ) + + resolveSession({ nonce: 'ABCDEFGH12345678' }) + + await waitFor(() => { + expect(laterNavigate).toHaveBeenCalledWith('/cli/login?device_code=ABCDEFGH') + }) + expect(initialNavigate).not.toHaveBeenCalled() + expect(createCliLoginSessionMock).toHaveBeenCalledTimes(1) +}) From 1ef80fec2358b9b3c45e819654c1dd738697adc6 Mon Sep 17 00:00:00 2001 From: Mert YEREKAPAN <33198490+myerekapan@users.noreply.github.com> Date: Wed, 20 May 2026 12:38:04 +0200 Subject: [PATCH 03/14] chore(studio): remove HeaderUpgradeButton experiment code (#46144) ## Summary - Removes the `HeaderUpgradeButton` component, all call sites, and the `HeaderUpgradeCtaClickedEvent` telemetry type. The GROWTH-615 header upgrade CTA experiment ended on Apr 29. - Fixes the `Flag key "headerUpgradeCta" does not exist in PostHog flag store` console errors that were logging on every render. PostHog drops disabled flags from `/feature-flags` responses, so the still-mounted consumer logged a missing-flag warning continuously. Removing the consumer lets the flag be safely disabled again. Context: [Slack thread](https://supabase.slack.com/archives/C07P3AU3J2D/p1779250648219089?thread_ts=1779166940.445709&cid=C07P3AU3J2D) ## Test plan - [x] `pnpm dev:studio`, open the dashboard, confirm no `headerUpgradeCta` warning in the browser console - [x] Desktop header still renders correctly (the button was hidden behind the `test` variant; visually nothing changes for users since rollout was 100/0 control) - [x] Mobile nav bar still renders with `UserDropdown` to the right of the org/project selector ## Summary by CodeRabbit * **Chores** * Removed the upgrade call-to-action button from the navigation header in both desktop and mobile layouts. [![Review Change Stack](https://storage.googleapis.com/coderabbit_public_assets/review-stack-in-coderabbit-ui.svg)](https://app.coderabbit.ai/change-stack/supabase/supabase/pull/46144?utm_source=github_walkthrough&utm_medium=github&utm_campaign=change_stack) --- .../LayoutHeader/HeaderUpgradeButton.tsx | 37 ------------------- .../Navigation/LayoutHeader/LayoutHeader.tsx | 2 - .../NavigationBar/MobileNavigationBar.tsx | 2 - packages/common/telemetry-constants.ts | 13 ------- 4 files changed, 54 deletions(-) delete mode 100644 apps/studio/components/layouts/Navigation/LayoutHeader/HeaderUpgradeButton.tsx diff --git a/apps/studio/components/layouts/Navigation/LayoutHeader/HeaderUpgradeButton.tsx b/apps/studio/components/layouts/Navigation/LayoutHeader/HeaderUpgradeButton.tsx deleted file mode 100644 index e4de5957c25f2..0000000000000 --- a/apps/studio/components/layouts/Navigation/LayoutHeader/HeaderUpgradeButton.tsx +++ /dev/null @@ -1,37 +0,0 @@ -import { UpgradePlanButton } from '@/components/ui/UpgradePlanButton' -import { useSelectedOrganizationQuery } from '@/hooks/misc/useSelectedOrganization' -import { useTrackExperimentExposure } from '@/hooks/misc/useTrackExperimentExposure' -import { usePHFlag } from '@/hooks/ui/useFlag' -import { useTrack } from '@/lib/telemetry/track' - -const EXPERIMENT_FLAG_KEY = 'headerUpgradeCta' -const EXPERIMENT_EXPOSURE_NAME = 'header_upgrade_cta' -type HeaderUpgradeCtaVariant = 'control' | 'test' - -interface HeaderUpgradeButtonProps { - className?: string -} - -export const HeaderUpgradeButton = ({ className }: HeaderUpgradeButtonProps) => { - const track = useTrack() - const { data: organization } = useSelectedOrganizationQuery() - const flagValue = usePHFlag(EXPERIMENT_FLAG_KEY) - - const isFreePlan = organization?.plan?.id === 'free' - const isInExperiment = flagValue === 'control' || flagValue === 'test' - const showButton = flagValue === 'test' - - const variant = isFreePlan && isInExperiment ? (flagValue as string) : undefined - useTrackExperimentExposure(EXPERIMENT_EXPOSURE_NAME, variant) - - if (!isFreePlan) return null - if (!showButton) return null - - const handleClick = () => { - track('header_upgrade_cta_clicked') - } - - return ( - - ) -} diff --git a/apps/studio/components/layouts/Navigation/LayoutHeader/LayoutHeader.tsx b/apps/studio/components/layouts/Navigation/LayoutHeader/LayoutHeader.tsx index 1d05bc775c407..516c8f72e640d 100644 --- a/apps/studio/components/layouts/Navigation/LayoutHeader/LayoutHeader.tsx +++ b/apps/studio/components/layouts/Navigation/LayoutHeader/LayoutHeader.tsx @@ -10,7 +10,6 @@ import { CommandMenuTriggerInput } from 'ui-patterns' import { BreadcrumbsView } from './BreadcrumbsView' import { FeedbackDropdown } from './FeedbackDropdown/FeedbackDropdown' -import { HeaderUpgradeButton } from './HeaderUpgradeButton' import { HomeIcon } from './HomeIcon' import { LocalVersionPopover } from './LocalVersionPopover' import { MergeRequestButton } from './MergeRequestButton' @@ -253,7 +252,6 @@ export const LayoutHeader = ({ )}
- ) : ( diff --git a/apps/studio/components/layouts/Navigation/NavigationBar/MobileNavigationBar.tsx b/apps/studio/components/layouts/Navigation/NavigationBar/MobileNavigationBar.tsx index 18c4d1e2ea686..a3b25512ba424 100644 --- a/apps/studio/components/layouts/Navigation/NavigationBar/MobileNavigationBar.tsx +++ b/apps/studio/components/layouts/Navigation/NavigationBar/MobileNavigationBar.tsx @@ -5,7 +5,6 @@ import { useState } from 'react' import { Button, cn } from 'ui' import { MobileSheetNav } from 'ui-patterns' -import { HeaderUpgradeButton } from '../LayoutHeader/HeaderUpgradeButton' import { HomeIcon } from '../LayoutHeader/HomeIcon' import { useMobileSheet } from './MobileSheetContext' import { OrgSelector } from './OrgSelector' @@ -71,7 +70,6 @@ const MobileNavigationBar = ({ )}
- {IS_PLATFORM && } {IS_PLATFORM ? : } {!hideMobileMenu && ( + ) : undefined + } + />
From 84484be46d112a0bbfe62513ba66deb4d5eb5b5b Mon Sep 17 00:00:00 2001 From: Joshen Lim 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 image ## 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 [![Review Change Stack](https://storage.googleapis.com/coderabbit_public_assets/review-stack-in-coderabbit-ui.svg)](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 (
-
+
{value}
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 | |--------|--------| | Screenshot 2026-05-20 at 09 34 10 | Screenshot 2026-05-20 at 12 51
14 | ## 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. [![Review Change Stack](https://storage.googleapis.com/coderabbit_public_assets/review-stack-in-coderabbit-ui.svg)](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: image I've set `freeformDefaultProperty` to be `event_message`, and hence typing free text will opt the default action to just filtering against that property image ### 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. [![Review Change Stack](https://storage.googleapis.com/coderabbit_public_assets/review-stack-in-coderabbit-ui.svg)](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 ( - -
- -
-

{field.label}

-
-
- -
- - {/* 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 ( + +
+ +
+

{field.label}

+
+
+ +
+ + {/* 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. [![Review Change Stack](https://storage.googleapis.com/coderabbit_public_assets/review-stack-in-coderabbit-ui.svg)](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('')} /> - - - + + {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. [![Review Change Stack](https://storage.googleapis.com/coderabbit_public_assets/review-stack-in-coderabbit-ui.svg)](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. [![Review Change Stack](https://storage.googleapis.com/coderabbit_public_assets/review-stack-in-coderabbit-ui.svg)](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 image ### 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 [![Review Change Stack](https://storage.googleapis.com/coderabbit_public_assets/review-stack-in-coderabbit-ui.svg)](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 image ## 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. [![Review Change Stack](https://storage.googleapis.com/coderabbit_public_assets/review-stack-in-coderabbit-ui.svg)](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 + } >