fix types

This commit is contained in:
Francesco Sansalvadore committed 2026-03-23 15:54:02 +01:00
1 parent c1e9dadb98
commit 72c2bef2ed
14 files changed
+230 -206

No files matched your search

@@ -7,12 +7,10 @@ import { useParams } from 'common'
import { SupabaseGrid } from 'components/grid/SupabaseGrid'
import { useSyncTableEditorStateFromLocalStorageWithUrl } from 'components/grid/SupabaseGrid.utils'
import {
Entity,
isForeignTable,
isMaterializedView,
isTableLike,
isView,
TableLike,
} from 'data/table-editor/table-editor-types'
import { useAsyncCheckPermissions } from 'hooks/misc/useCheckPermissions'
import { useDashboardHistory } from 'hooks/misc/useDashboardHistory'
@@ -23,6 +21,8 @@ import { TableEditorTableStateContextProvider } from 'state/table-editor-table'
import { createTabId, useTabsStateSnapshot } from 'state/tabs'
import { Button } from 'ui'
import { Admonition, GenericSkeletonLoader } from 'ui-patterns'
import type { Entity, TableLike } from 'data/table-editor/table-editor-types'
import DeleteConfirmationDialogs from './DeleteConfirmationDialogs'
import { SidePanelEditor } from './SidePanelEditor/SidePanelEditor'
import { TableDefinition } from './TableDefinition'
@@ -67,14 +67,23 @@ export const TableGridEditor = ({
(table: { id: number }) => {
if (variant === 'v2') {
const base = projectRef ? `/v2/project/${projectRef}` : ''
router.push(
`${base}/data/tables/${table.id}/data${
!!selectedSchema ? `?schema=${selectedSchema}` : ''
}`
)
if (router) {
router.push(
`${base}/data/tables/${table.id}/data${
!!selectedSchema ? `?schema=${selectedSchema}` : ''
}`
)
} else if (typeof window !== 'undefined') {
window.location.assign(
`${base}/data/tables/${table.id}/data${
!!selectedSchema ? `?schema=${selectedSchema}` : ''
}`
)
}
return
}
if (!router) return
router.push(
`/project/${projectRef}/editor/${table.id}${
!!selectedSchema ? `?schema=${selectedSchema}` : ''
@@ -84,6 +93,19 @@ export const TableGridEditor = ({
[projectRef, router, selectedSchema, variant]
)
const closeLegacyTab = useCallback(
(id: string) => {
if (!router) return
tabs.handleTabClose({
id,
router,
editor: 'table',
onClearDashboardHistory: () => setLastVisitedTable(undefined),
})
},
[router, setLastVisitedTable, tabs]
)
const onTableDeleted = useCallback(async () => {
if (!selectedTable) return
@@ -96,17 +118,16 @@ export const TableGridEditor = ({
setLastVisitedTable(undefined)
const base = projectRef ? `/v2/project/${projectRef}` : ''
router.push(`${base}/data/tables`)
if (router) {
router.push(`${base}/data/tables`)
} else if (typeof window !== 'undefined') {
window.location.assign(`${base}/data/tables`)
}
return
}
tabs.handleTabClose({
id: tabId,
router,
editor: 'table',
onClearDashboardHistory: () => setLastVisitedTable(undefined),
})
}, [projectRef, router, selectedTable, tabs, setLastVisitedTable, variant])
closeLegacyTab(tabId)
}, [closeLegacyTab, projectRef, router, selectedTable, tabs, setLastVisitedTable, variant])
const { isSchemaLocked } = useIsProtectedSchema({ schema: selectedTable?.schema ?? '' })
@@ -141,7 +162,7 @@ export const TableGridEditor = ({
return (
// When any click happens in a table tab, the tab becomes permanent
<div className="h-full" onClick={() => tabs.makeActiveTabPermanent()}>
<div className="h-full" onPointerDownCapture={() => tabs.makeActiveTabPermanent()}>
{!selectedTable ? (
<div className="flex items-center justify-center h-full">
<div className="w-[400px]">
@@ -159,7 +180,11 @@ export const TableGridEditor = ({
tabs.removeTab(tabId)
setLastVisitedTable(undefined)
const base = projectRef ? `/v2/project/${projectRef}` : ''
router.push(`${base}/data/tables`)
if (router) {
router.push(`${base}/data/tables`)
} else if (typeof window !== 'undefined') {
window.location.assign(`${base}/data/tables`)
}
}}
>
Close tab
@@ -188,18 +213,7 @@ export const TableGridEditor = ({
</Button>
)
) : !!tabId ? (
<Button
type="default"
className="mt-2"
onClick={() => {
tabs.handleTabClose({
id: tabId,
router,
editor: 'table',
onClearDashboardHistory: () => setLastVisitedTable(undefined),
})
}}
>
<Button type="default" className="mt-2" onClick={() => closeLegacyTab(tabId)}>
Close tab
</Button>
) : openTabs.length > 0 ? (
@@ -261,9 +275,7 @@ export const TableGridEditor = ({
<SidePanelEditor
editable={editable}
selectedTable={
isTableSelected || isForeignTableSelected ? (selectedTable as TableLike) : undefined
}
selectedTable={isTableSelected || isForeignTableSelected ? (selectedTable as TableLike) : undefined}
onTableCreated={onTableCreated}
/>
</div>
@@ -26,8 +26,7 @@ interface ModelSelectorProps {
export const ModelSelector = ({ selectedModel, onSelectModel }: ModelSelectorProps) => {
const router = useRouter()
const { data: organization } = useSelectedOrganizationQuery()
const { hasAccess: hasAccessToAdvanceModel, isLoading: isLoadingEntitlements } =
useCheckEntitlements('assistant.advance_model')
const { hasAccess: hasAccessToAdvanceModel } = useCheckEntitlements('assistant.advance_model')
const [open, setOpen] = useState(false)
@@ -38,7 +37,8 @@ export const ModelSelector = ({ selectedModel, onSelectModel }: ModelSelectorPro
const handleSelectModel = (model: 'gpt-5' | 'gpt-5-mini') => {
if (model === 'gpt-5' && !hasAccessToAdvanceModel) {
setOpen(false)
void router.push(upgradeHref)
if (router) void router.push(upgradeHref)
else if (typeof window !== 'undefined') window.location.assign(upgradeHref)
return
}
@@ -83,7 +83,7 @@ export const ModelSelector = ({ selectedModel, onSelectModel }: ModelSelectorPro
<Tooltip>
<TooltipTrigger asChild>
<div>
<Badge role="button" variant="warning">
<Badge variant="warning">
Upgrade
</Badge>
</div>
-2
View File
@@ -17,7 +17,6 @@ import {
} from 'lucide-react'
import { useRouter } from 'next/navigation'
import { useState } from 'react'
import { cn } from 'ui'
import { Input } from 'ui/src/components/shadcn/ui/input'
import { TypeBadge } from './TypeBadge'
@@ -72,7 +71,6 @@ const COUNT_KEY_MAP: Record<string, keyof ReturnType<typeof useV2DataCounts>> =
types: 'types',
roles: 'roles',
extensions: 'extensions',
indexes: 'indexes',
publications: 'publications',
users: 'users',
buckets: 'buckets',
+68 -83
View File
@@ -2,9 +2,7 @@
import { ArrowDown, ArrowUp } from 'lucide-react'
import { useCallback, useMemo, useState, type ReactNode } from 'react'
import DataGrid, { Row, type Column } from 'react-data-grid'
import { cn } from 'ui'
import { GenericSkeletonLoader } from 'ui-patterns/ShimmeringLoader'
export type DataListColumnDef<TRow> = {
key: string
@@ -93,50 +91,6 @@ export function DataListGrid<TRow>({
[columnDefs, sortKey]
)
const columns: Column<TRow>[] = useMemo(
() =>
columnDefs.map((col) => ({
key: col.key,
name: col.name,
resizable: true,
minWidth: col.minWidth ?? 120,
sortable: false,
headerCellClass: 'sb-grid-column-header sb-grid-column-header--cursor',
renderHeaderCell: () => {
const active = sortKey === col.key
const canSort = Boolean(col.sortValue)
return (
<button
type="button"
className={cn(
'sb-grid-column-header flex h-full w-full items-center px-2 text-left',
canSort && 'hover:bg-surface-200/80 dark:hover:bg-surface-200/20'
)}
disabled={!canSort}
onClick={() => canSort && onHeaderClick(col.key)}
>
<div className="sb-grid-column-header__inner min-w-0 flex-1">
<span className="sb-grid-column-header__inner__name">{col.name}</span>
</div>
{canSort && active ? (
sortDir === 'asc' ? (
<ArrowUp className="h-3.5 w-3.5 shrink-0 text-foreground-light" />
) : (
<ArrowDown className="h-3.5 w-3.5 shrink-0 text-foreground-light" />
)
) : null}
</button>
)
},
renderCell: (props) => (
<div className="flex h-full w-full items-center px-2 text-xs">
{col.renderCell(props.row)}
</div>
),
})),
[columnDefs, sortKey, sortDir, onHeaderClick]
)
return (
<div className={cn('sb-grid flex h-full min-h-0 flex-col', className)}>
{(toolbar != null || toolbarTrailing != null) && (
@@ -151,43 +105,74 @@ export function DataListGrid<TRow>({
<div className="flex h-9 shrink-0 items-center border-b border-border px-2">{tabs}</div>
) : null}
<div className="relative min-h-0 flex-1">
<DataGrid
className="h-full flex-1"
style={{ height: '100%' }}
rowHeight={36}
headerRowHeight={34}
columns={columns}
rows={sortedRows}
rowKeyGetter={(row) => rowKeyGetter(row)}
rowClass={() =>
cn(
'[&>.rdg-cell]:flex [&>.rdg-cell]:items-center',
'[&>.rdg-cell]:border-box [&>.rdg-cell]:outline-none [&>.rdg-cell]:shadow-none',
(onRowClick || onRowDoubleClick) && 'cursor-pointer'
)
}
renderers={{
renderRow(_, props) {
return (
<Row
key={rowKeyGetter(props.row)}
{...props}
onClick={() => onRowClick?.(props.row)}
onDoubleClick={() => onRowDoubleClick?.(props.row)}
/>
)
},
noRowsFallback: isLoading ? (
<div className="absolute top-10 w-full px-4">
<GenericSkeletonLoader />
</div>
) : (
<div className="flex h-full items-center justify-center p-8 text-center text-sm text-foreground-lighter">
{emptyMessage ?? 'No rows'}
</div>
),
}}
/>
{isLoading ? (
<div className="absolute top-10 w-full px-4">Loading...</div>
) : sortedRows.length === 0 ? (
<div className="flex h-full items-center justify-center p-8 text-center text-sm text-foreground-lighter">
{emptyMessage ?? 'No rows'}
</div>
) : (
<div className="h-full overflow-auto">
<table className="w-full border-collapse text-xs">
<thead className="sticky top-0 z-10 bg-background">
<tr className="border-b border-border">
{columnDefs.map((col) => {
const active = sortKey === col.key
const canSort = Boolean(col.sortValue)
return (
<th
key={col.key}
className="h-[34px] px-2 text-left font-medium text-foreground-light"
style={{ minWidth: col.minWidth ?? 120 }}
>
<button
type="button"
className={cn(
'flex h-full w-full items-center gap-1 text-left',
canSort && 'hover:text-foreground'
)}
disabled={!canSort}
onClick={() => canSort && onHeaderClick(col.key)}
>
<span className="min-w-0 flex-1 truncate">{col.name}</span>
{canSort && active ? (
sortDir === 'asc' ? (
<ArrowUp className="h-3.5 w-3.5 shrink-0" />
) : (
<ArrowDown className="h-3.5 w-3.5 shrink-0" />
)
) : null}
</button>
</th>
)
})}
</tr>
</thead>
<tbody>
{sortedRows.map((row) => {
const key = rowKeyGetter(row)
return (
<tr
key={key}
className={cn(
'h-9 border-b border-border',
(onRowClick || onRowDoubleClick) && 'cursor-pointer hover:bg-surface-200/30'
)}
onClick={() => onRowClick?.(row)}
onDoubleClick={() => onRowDoubleClick?.(row)}
>
{columnDefs.map((col) => (
<td key={col.key} className="px-2 align-middle">
<div className="min-w-0 truncate">{col.renderCell(row)}</div>
</td>
))}
</tr>
)
})}
</tbody>
</table>
</div>
)}
</div>
</div>
)
+14 -6
View File
@@ -24,6 +24,7 @@ import { Badge, Button, cn, copyToClipboard } from 'ui'
import { useV2Params } from '@/app/v2/V2ParamsContext'
import { useV2DashboardStore } from '@/stores/v2-dashboard'
import type { InfraMonitoringAttribute } from 'data/analytics/infra-monitoring-query'
function maskConnectionString(conn: string | null | undefined) {
if (!conn) return ''
@@ -69,7 +70,7 @@ export function HomeView() {
const startDate = now.subtract(1, 'day').toISOString()
const endDate = now.toISOString()
const attributes = useMemo(
const attributes = useMemo<InfraMonitoringAttribute[]>(
() => [
'avg_cpu_usage',
'ram_usage',
@@ -83,7 +84,7 @@ export function HomeView() {
[]
)
const { data: infraData, isLoading: infraLoading } = useInfraMonitoringAttributesQuery(
const { data: infraData } = useInfraMonitoringAttributesQuery(
{
projectRef,
attributes,
@@ -103,7 +104,7 @@ export function HomeView() {
const connections = parseConnectionsData(infraData, maxConnectionsData)
const { recentItems } = useV2DashboardStore((s) => ({ recentItems: s.recentItems }))
const addDetailTab = useV2DashboardStore((s) => s.addDetailTab)
const openDataTab = useV2DashboardStore((s) => s.openDataTab)
const { openSidebar } = useSidebarManagerSnapshot()
const { setSelectedItem } = useAdvisorStateSnapshot()
@@ -114,9 +115,16 @@ export function HomeView() {
openSidebar(SIDEBAR_KEYS.ADVISOR_PANEL)
}
const handleOpenRecent = (item: { id: string; label: string; path: string }) => {
const handleOpenRecent = (item: (typeof recentItems)[number]) => {
if (!projectRef) return
addDetailTab({ id: item.id, label: item.label, path: item.path })
openDataTab({
id: item.id,
label: item.label,
type: 'detail',
category: item.category,
domain: item.domain,
path: item.path,
})
router.push(item.path)
}
@@ -257,7 +265,7 @@ export function HomeView() {
className="text-left border border-border rounded-md p-3 hover:bg-sidebar-accent/50"
>
<div className="text-sm truncate">{item.label}</div>
<div className="text-xs text-foreground-lighter truncate">{item.type}</div>
<div className="text-xs text-foreground-lighter truncate">{item.category}</div>
</button>
))}
</div>
@@ -4,7 +4,7 @@ import { ConnectButton } from 'components/interfaces/ConnectButton/ConnectButton
import { LocalDropdown } from 'components/interfaces/LocalDropdown'
import { SidebarContent } from 'components/interfaces/Sidebar'
import { UserDropdown } from 'components/interfaces/UserDropdown'
import FloatingMobileToolbar from 'components/layouts/Navigation/FloatingMobileToolbar/FloatingMobileToolbar'
import { FloatingMobileToolbar } from 'components/layouts/Navigation/FloatingMobileToolbar/FloatingMobileToolbar'
import { useOrganizationsQuery } from 'data/organizations/organizations-query'
import { useSelectedOrganizationQuery } from 'hooks/misc/useSelectedOrganization'
import { IS_PLATFORM } from 'lib/constants'
@@ -14,7 +14,7 @@ import { useState } from 'react'
import { Button, cn } from 'ui'
import { CommandMenuTrigger, MobileSheetNav } from 'ui-patterns'
import { HomeIcon } from '../LayoutHeader/HomeIcon'
import { HomeIcon } from 'components/layouts/Navigation/LayoutHeader/HomeIcon'
import { useMobileSheet } from './MobileSheetContext'
import { OrgSelector } from './OrgSelector'
import { ProjectBranchSelector } from './ProjectBranchSelector'
@@ -1,7 +1,7 @@
import type { PropsWithChildren, ReactNode } from 'react'
import { createContext, useCallback, useContext, useRef, useState } from 'react'
import type { TYPEOF_SIDEBAR_KEYS } from '../../ProjectLayout/LayoutSidebar/LayoutSidebarProvider'
import type { TYPEOF_SIDEBAR_KEYS } from 'components/layouts/ProjectLayout/LayoutSidebar/LayoutSidebarProvider'
/**
* Sheet content: null = closed; sidebar id = one of SIDEBAR_KEYS; ReactNode = custom content (menu, search, etc.).
@@ -1,17 +1,12 @@
import { noop } from 'lodash'
import Link from 'next/link'
import {
AnchorHTMLAttributes,
cloneElement,
ComponentPropsWithoutRef,
forwardRef,
isValidElement,
} from 'react'
import { cloneElement, forwardRef, isValidElement } from 'react'
import { cn, Tooltip, TooltipContent, TooltipTrigger } from 'ui'
import type { Route } from 'components/ui/ui.types'
import { useLocalStorageQuery } from 'hooks/misc/useLocalStorage'
import { LOCAL_STORAGE_KEYS } from 'common'
import type { AnchorHTMLAttributes } from 'react'
interface NavigationIconButtonProps extends AnchorHTMLAttributes<HTMLAnchorElement> {
route: Route
@@ -46,48 +41,64 @@ const NavigationIconLink = forwardRef<HTMLAnchorElement, NavigationIconButtonPro
`${isActive && '!bg-selection shadow-sm'}`,
]
const LinkComponent = forwardRef<HTMLAnchorElement, ComponentPropsWithoutRef<typeof Link>>(
function LinkComponent(props, ref) {
if (route.linkElement && isValidElement(route.linkElement)) {
return cloneElement<any>(route.linkElement, { ...props, ref })
const sharedProps = {
role: 'button' as const,
'aria-current': isActive,
ref,
href: route.link || '#',
...props,
onClick: (e: React.MouseEvent<HTMLAnchorElement>) => {
if (!route.link) {
e.preventDefault()
}
return <Link ref={ref} {...props} />
}
)
onClick(e)
},
className: cn(classes, props.className),
}
const linkContent = (
<LinkComponent
role="button"
aria-current={isActive}
ref={ref}
href={route.link || '#'} // Provide a fallback href
{...props}
onClick={(e) => {
if (!route.link) {
e.preventDefault() // Prevent navigation if there's no link
}
onClick(e)
}}
className={cn(classes, props.className)}
>
<span id="icon-link" className={cn(...iconClasses)} {...props}>
{route.icon}
</span>
<span
className={cn(
'min-w-[128px] text-sm text-foreground-light',
'group-hover/item:text-foreground',
'group-aria-current/item:text-foreground',
'absolute left-10 md:left-7 md:group-data-[state=expanded]:left-12',
'opacity-100 md:opacity-0 md:group-data-[state=expanded]:opacity-100',
`${isActive && 'text-foreground hover:text-foreground'}`,
'transition-all'
)}
>
{route.label}
</span>
</LinkComponent>
<>
{route.linkElement && isValidElement(route.linkElement) ? (
cloneElement(route.linkElement, sharedProps, [
<span key="icon" id="icon-link" className={cn(...iconClasses)} {...props}>
{route.icon}
</span>,
<span
key="label"
className={cn(
'min-w-[128px] text-sm text-foreground-light',
'group-hover/item:text-foreground',
'group-aria-current/item:text-foreground',
'absolute left-10 md:left-7 md:group-data-[state=expanded]:left-12',
'opacity-100 md:opacity-0 md:group-data-[state=expanded]:opacity-100',
`${isActive && 'text-foreground hover:text-foreground'}`,
'transition-all'
)}
>
{route.label}
</span>,
])
) : (
<Link {...sharedProps}>
<span id="icon-link" className={cn(...iconClasses)} {...props}>
{route.icon}
</span>
<span
className={cn(
'min-w-[128px] text-sm text-foreground-light',
'group-hover/item:text-foreground',
'group-aria-current/item:text-foreground',
'absolute left-10 md:left-7 md:group-data-[state=expanded]:left-12',
'opacity-100 md:opacity-0 md:group-data-[state=expanded]:opacity-100',
`${isActive && 'text-foreground hover:text-foreground'}`,
'transition-all'
)}
>
{route.label}
</span>
</Link>
)}
</>
)
if (!allowNavPanelToExpand) {
@@ -1,10 +1,17 @@
import type { OrganizationsData } from 'data/organizations/organizations-query'
import { ChevronsUpDown, GitBranch } from 'lucide-react'
import * as React from 'react'
import { cn, SidebarMenuButton as SidebarMenuButtonComponent } from 'ui'
import {
cn,
SidebarMenuButton as SidebarMenuButtonComponent,
Tooltip,
TooltipContent,
TooltipTrigger,
} from 'ui'
export interface ProjectBranchSelectorTriggerProps {
displayProjectName: string
selectedOrgInitial: string
selectedOrg: OrganizationsData
isBranch: boolean
isProductionBranch: boolean
branchDisplayName: string
@@ -22,7 +29,7 @@ export const ProjectBranchSelectorTrigger = React.forwardRef<
(
{
displayProjectName,
selectedOrgInitial,
selectedOrg,
isBranch,
isProductionBranch: _isProductionBranch,
branchDisplayName,
@@ -31,6 +38,8 @@ export const ProjectBranchSelectorTrigger = React.forwardRef<
},
ref
) => {
const selectedOrgInitial = selectedOrg?.name?.trim().charAt(0).toUpperCase() ?? 'O'
return (
<SidebarMenuButtonComponent
ref={ref}
@@ -38,9 +47,14 @@ export const ProjectBranchSelectorTrigger = React.forwardRef<
className="group px-1 py-0.5 gap-1.5 w-full max-w-[250px] flex h-auto text-left data-[state=open]:bg-sidebar-accent data-[state=open]:text-sidebar-accent-foreground touch-manipulation"
{...buttonProps}
>
<div className="relative flex h-7 aspect-square shrink-0 items-center bg-background-muted group-hover:border-stronger justify-center rounded border border-strong text-xs">
{selectedOrgInitial}
</div>
<Tooltip>
<TooltipTrigger asChild>
<div className="relative flex h-7 aspect-square shrink-0 items-center bg-background-muted group-hover:border-stronger justify-center rounded border border-strong text-xs">
{selectedOrgInitial}
</div>
</TooltipTrigger>
<TooltipContent>{selectedOrg.name}</TooltipContent>
</Tooltip>
<div className="text-left flex-grow min-w-0">
<div className="w-full truncate text-foreground leading-tight">{displayProjectName}</div>
<div
@@ -6,7 +6,7 @@ import { CommandWrapper, MobileSheetNav } from 'ui-patterns'
import {
SIDEBAR_KEYS,
type TYPEOF_SIDEBAR_KEYS,
} from '../../ProjectLayout/LayoutSidebar/LayoutSidebarProvider'
} from 'components/layouts/ProjectLayout/LayoutSidebar/LayoutSidebarProvider'
import type { MobileSheetContentType } from './MobileSheetContext'
import { useMobileSheet } from './MobileSheetContext'
@@ -29,7 +29,7 @@ function getSheetChildren(
</CommandWrapper>
)
}
if (isSidebarId(content) && activeSidebar?.id === content) {
if (isSidebarId(content) && activeSidebar && activeSidebar.id === content) {
return activeSidebar.component?.() ?? null
}
if (!isSidebarId(content)) return content
+5 -6
View File
@@ -1,8 +1,7 @@
'use client'
import { usePathname } from 'next/navigation'
import { X } from 'lucide-react'
import { Button, cn } from 'ui'
import { Button } from 'ui'
import { useV2DashboardStore } from '@/stores/v2-dashboard'
@@ -24,13 +23,13 @@ export function RightPanel() {
<div className="flex items-center justify-between px-3 py-2 border-b border-border shrink-0">
<span className="text-sm font-medium text-foreground">{title}</span>
<Button
variant="ghost"
size="icon"
type="text"
size="tiny"
className="h-7 w-7"
onClick={closeRightPanel}
aria-label="Close panel"
icon={<X className="h-4 w-4" />}
>
<X className="h-4 w-4" />
<span className="sr-only">Close panel</span>
</Button>
</div>
<div className="flex-1 min-h-0 overflow-auto">
+5 -5
View File
@@ -6,7 +6,7 @@ import { usePathname } from 'next/navigation'
import { cn } from 'ui'
import { useV2Params } from '@/app/v2/V2ParamsContext'
import { useV2DashboardStore } from '@/stores/v2-dashboard'
import { useV2DashboardStore, type DataTab } from '@/stores/v2-dashboard'
const CATEGORY_LABELS: Record<string, string> = {
tables: 'Tables',
@@ -27,7 +27,8 @@ const CATEGORY_LABELS: Record<string, string> = {
export function TabBar() {
const pathname = usePathname()
const { projectRef } = useV2Params()
const { detailTabs, removeDetailTab } = useV2DashboardStore()
const { dataTabs, closeDataTab } = useV2DashboardStore()
const detailTabs = dataTabs.filter((t) => t.type === 'detail')
const base = projectRef ? `/v2/project/${projectRef}` : ''
const pathParts =
@@ -35,7 +36,6 @@ export function TabBar() {
?.replace(/^\/v2\/[^/]+\/[^/]+/, '')
.split('/')
.filter(Boolean) ?? []
const activity = pathParts[0]
const category = pathParts[1]
const categoryLabel = category ? (CATEGORY_LABELS[category] ?? category) : 'Data'
const categoryListHref = category ? `${base}/data/${category}` : `${base}/data/tables`
@@ -64,7 +64,7 @@ export function TabBar() {
>
<Plus className="h-4 w-4" />
</button>
{detailTabs.map((tab) => {
{detailTabs.map((tab: DataTab) => {
const isActive = activeTabPath === tab.path
return (
<div
@@ -83,7 +83,7 @@ export function TabBar() {
type="button"
onClick={(e) => {
e.preventDefault()
removeDetailTab(tab.id)
closeDataTab(tab.id)
}}
className="opacity-0 group-hover:opacity-100 p-0.5 hover:bg-background rounded text-foreground-light hover:text-foreground"
aria-label="Close tab"
@@ -51,7 +51,7 @@ export function V2OrgProjectSelector() {
return (
<Popover_Shadcn_ open={open} onOpenChange={setOpen}>
<PopoverTrigger_Shadcn_ asChild>
<Button variant="ghost" size="tiny" className="gap-1 text-foreground font-medium h-7 px-2">
<Button type="text" size="tiny" className="gap-1 text-foreground font-medium h-7 px-2">
<span className="text-foreground-lighter text-xs truncate max-w-[120px]">
{selectedOrg?.name ?? orgSlug ?? 'Org'}
</span>
@@ -1,25 +1,23 @@
'use client'
import { useBranchesQuery } from 'data/branches/branches-query'
import { useOrganizationsQuery } from 'data/organizations/organizations-query'
import { useProjectDetailQuery } from 'data/projects/project-detail-query'
import { IS_PLATFORM } from 'lib/constants'
import { useMemo, useState } from 'react'
import {
Popover_Shadcn_,
PopoverContent_Shadcn_,
PopoverTrigger_Shadcn_,
Popover_Shadcn_,
SidebarMenu,
SidebarMenuButton,
SidebarMenuItem,
} from 'ui'
import { IS_PLATFORM } from 'lib/constants'
import { ShimmeringLoader } from 'ui-patterns/ShimmeringLoader'
import { useV2Params } from '@/app/v2/V2ParamsContext'
import { ProjectBranchSelectorPopover } from '@/components/v2/Navigation/ProjectBranchSelectorPopover'
import { ProjectBranchSelectorTrigger } from '@/components/v2/Navigation/ProjectBranchSelectorTrigger'
import { useBranchesQuery } from 'data/branches/branches-query'
import { useOrganizationsQuery } from 'data/organizations/organizations-query'
import { useProjectDetailQuery } from 'data/projects/project-detail-query'
import { ShimmeringLoader } from 'ui-patterns/ShimmeringLoader'
export function V2ProjectBranchSelector() {
const { orgSlug, projectRef } = useV2Params()
@@ -53,7 +51,6 @@ export function V2ProjectBranchSelector() {
const selectedBranch = branches?.find((b) => b.project_ref === projectRef)
const branchDisplayName = selectedBranch?.name ?? 'main'
const isProductionBranch = selectedBranch?.is_default ?? true
const selectedOrgInitial = selectedOrg?.name?.trim().charAt(0).toUpperCase() ?? 'O'
const isTriggerLoading = Boolean(projectRef) && (isProjectPending || !displayProject)
@@ -81,7 +78,7 @@ export function V2ProjectBranchSelector() {
) : (
<ProjectBranchSelectorTrigger
displayProjectName={displayProject?.name ?? projectRef ?? 'Project'}
selectedOrgInitial={selectedOrgInitial}
selectedOrg={selectedOrg}
isBranch={!isProductionBranch}
isProductionBranch={isProductionBranch}
branchDisplayName={branchDisplayName}