Shift refresh button to header in table editor and make realtime + API docs button smaller (#38463)

* Shift refresh button to header in table editor and make realtime button + api docs button smaller

* Fix ts
This commit is contained in:
Joshen Lim authored and GitHub committed 2025-09-08 14:15:39 +08:00
1 parent b9c8b3087c
commit f066c02c69
12 files changed
+73 -68

No files matched your search

+4 -4
View File
@@ -13,9 +13,9 @@ import { useTableEditorStateSnapshot } from 'state/table-editor'
import { useTableEditorTableStateSnapshot } from 'state/table-editor-table'
import { Shortcuts } from './components/common/Shortcuts'
import Footer from './components/footer/Footer'
import { Footer } from './components/footer/Footer'
import { Grid } from './components/grid/Grid'
import Header, { HeaderProps } from './components/header/Header'
import { Header, HeaderProps } from './components/header/Header'
import { RowContextMenu } from './components/menu'
import { GridProps } from './types'
@@ -84,7 +84,7 @@ export const SupabaseGrid = ({
return (
<DndProvider backend={HTML5Backend} context={window}>
<div className="sb-grid h-full flex flex-col">
<Header customHeader={customHeader} />
<Header customHeader={customHeader} isRefetching={isRefetching} />
{children || (
<>
@@ -99,7 +99,7 @@ export const SupabaseGrid = ({
filters={filters}
onApplyFilters={onApplyFilters}
/>
<Footer isRefetching={isRefetching} />
<Footer />
<Shortcuts gridRef={gridRef} rows={rows} />
</>
)}
@@ -5,14 +5,9 @@ import { useTableEditorQuery } from 'data/table-editor/table-editor-query'
import { isTableLike, isViewLike } from 'data/table-editor/table-editor-types'
import { useSelectedProjectQuery } from 'hooks/misc/useSelectedProject'
import { useUrlState } from 'hooks/ui/useUrlState'
import RefreshButton from '../header/RefreshButton'
import { Pagination } from './pagination'
export interface FooterProps {
isRefetching?: boolean
}
const Footer = ({ isRefetching }: FooterProps) => {
export const Footer = () => {
const { id: _id } = useParams()
const id = _id ? Number(_id) : undefined
const { data: project } = useSelectedProjectQuery()
@@ -41,10 +36,6 @@ const Footer = ({ isRefetching }: FooterProps) => {
{selectedView === 'data' && <Pagination />}
<div className="ml-auto flex items-center gap-x-2">
{entity && selectedView === 'data' && (
<RefreshButton tableId={entity.id} isRefetching={isRefetching} />
)}
{(isViewSelected || isTableSelected) && (
<TwoOptionToggle
width={75}
@@ -58,5 +49,3 @@ const Footer = ({ isRefetching }: FooterProps) => {
</GridFooter>
)
}
export default Footer
@@ -8,7 +8,7 @@ import { toast } from 'sonner'
import { useParams } from 'common'
import { useTableFilter } from 'components/grid/hooks/useTableFilter'
import { useTableSort } from 'components/grid/hooks/useTableSort'
import GridHeaderActions from 'components/interfaces/TableGridEditor/GridHeaderActions'
import { GridHeaderActions } from 'components/interfaces/TableGridEditor/GridHeaderActions'
import { formatTableRowsToSQL } from 'components/interfaces/TableGridEditor/TableEntity.utils'
import { ButtonTooltip } from 'components/ui/ButtonTooltip'
import { useTableRowsCountQuery } from 'data/table-rows/table-rows-count-query'
@@ -56,9 +56,10 @@ export const MAX_EXPORT_ROW_COUNT_MESSAGE = (
export type HeaderProps = {
customHeader: ReactNode
isRefetching: boolean
}
const Header = ({ customHeader }: HeaderProps) => {
export const Header = ({ customHeader, isRefetching }: HeaderProps) => {
const snap = useTableEditorTableStateSnapshot()
return (
@@ -71,14 +72,12 @@ const Header = ({ customHeader }: HeaderProps) => {
) : (
<DefaultHeader />
)}
<GridHeaderActions table={snap.originalTable} />
<GridHeaderActions table={snap.originalTable} isRefetching={isRefetching} />
</div>
</div>
)
}
export default Header
const DefaultHeader = () => {
const { ref: projectRef } = useParams()
const { data: org } = useSelectedOrganizationQuery()
@@ -2,15 +2,15 @@ import { useQueryClient } from '@tanstack/react-query'
import { RefreshCw } from 'lucide-react'
import { useParams } from 'common'
import { ButtonTooltip } from 'components/ui/ButtonTooltip'
import { tableRowKeys } from 'data/table-rows/keys'
import { Button } from 'ui'
export type RefreshButtonProps = {
tableId?: number
isRefetching?: boolean
}
const RefreshButton = ({ tableId, isRefetching }: RefreshButtonProps) => {
export const RefreshButton = ({ tableId, isRefetching }: RefreshButtonProps) => {
const { ref } = useParams()
const queryClient = useQueryClient()
const queryKey = tableRowKeys.tableRowsAndCount(ref, tableId)
@@ -20,14 +20,18 @@ const RefreshButton = ({ tableId, isRefetching }: RefreshButtonProps) => {
}
return (
<Button
type="text"
<ButtonTooltip
type="outline"
loading={isRefetching}
icon={<RefreshCw className="text-foreground-muted" strokeWidth={1.5} />}
icon={<RefreshCw />}
onClick={() => onClick()}
>
Refresh
</Button>
className="w-7 h-7 p-0"
tooltip={{
content: {
side: 'bottom',
text: 'Refresh table data',
},
}}
/>
)
}
export default RefreshButton
@@ -8,7 +8,7 @@ import { toast } from 'sonner'
import { LOCAL_STORAGE_KEYS, useParams } from 'common'
import { useIsAPIDocsSidePanelEnabled } from 'components/interfaces/App/FeaturePreview/FeaturePreviewContext'
import AlertError from 'components/ui/AlertError'
import APIDocsButton from 'components/ui/APIDocsButton'
import { APIDocsButton } from 'components/ui/APIDocsButton'
import { ButtonTooltip } from 'components/ui/ButtonTooltip'
import { FilterPopover } from 'components/ui/FilterPopover'
import { FormHeader } from 'components/ui/Forms/FormHeader'
@@ -17,7 +17,7 @@ import {
import { useCallback, useEffect, useRef, useState } from 'react'
import { useIsAPIDocsSidePanelEnabled } from 'components/interfaces/App/FeaturePreview/FeaturePreviewContext'
import APIDocsButton from 'components/ui/APIDocsButton'
import { APIDocsButton } from 'components/ui/APIDocsButton'
import { ButtonTooltip } from 'components/ui/ButtonTooltip'
import { useAsyncCheckProjectPermissions } from 'hooks/misc/useCheckPermissions'
import { useStorageExplorerStateSnapshot } from 'state/storage-explorer'
@@ -5,8 +5,9 @@ import { useState } from 'react'
import { toast } from 'sonner'
import { useParams } from 'common'
import { RefreshButton } from 'components/grid/components/header/RefreshButton'
import { getEntityLintDetails } from 'components/interfaces/TableGridEditor/TableEntity.utils'
import APIDocsButton from 'components/ui/APIDocsButton'
import { APIDocsButton } from 'components/ui/APIDocsButton'
import { ButtonTooltip } from 'components/ui/ButtonTooltip'
import { useDatabasePoliciesQuery } from 'data/database-policies/database-policies-query'
import { useDatabasePublicationsQuery } from 'data/database-publications/database-publications-query'
@@ -45,9 +46,10 @@ import ViewEntityAutofixSecurityModal from './ViewEntityAutofixSecurityModal'
export interface GridHeaderActionsProps {
table: Entity
isRefetching: boolean
}
const GridHeaderActions = ({ table }: GridHeaderActionsProps) => {
export const GridHeaderActions = ({ table, isRefetching }: GridHeaderActionsProps) => {
const { ref } = useParams()
const { data: project } = useSelectedProjectQuery()
const { data: org } = useSelectedOrganizationQuery()
@@ -277,13 +279,13 @@ const GridHeaderActions = ({ table }: GridHeaderActionsProps) => {
<PopoverContent_Shadcn_
// using `portal` for a safari fix. issue with rendering outside of body element
portal
className="min-w-[395px] text-sm"
className="w-80 text-sm"
align="end"
>
<h3 className="flex items-center gap-2">
<h4 className="flex items-center gap-2">
<Lock size={16} /> Row Level Security (RLS)
</h3>
<div className="grid gap-2 mt-4 text-foreground-light text-sm">
</h4>
<div className="grid gap-2 mt-4 text-foreground-light text-xs">
<p>
You can restrict and control who can read, write and update data in this table
using Row Level Security.
@@ -293,14 +295,13 @@ const GridHeaderActions = ({ table }: GridHeaderActionsProps) => {
table.
</p>
{!isSchemaLocked && (
<div className="mt-2">
<Button
type="default"
onClick={() => setRlsConfirmModalOpen(!rlsConfirmModalOpen)}
>
Enable RLS for this table
</Button>
</div>
<Button
type="default"
className="mt-2 w-min"
onClick={() => setRlsConfirmModalOpen(!rlsConfirmModalOpen)}
>
Enable RLS for this table
</Button>
)}
</div>
</PopoverContent_Shadcn_>
@@ -443,8 +444,9 @@ const GridHeaderActions = ({ table }: GridHeaderActionsProps) => {
<RoleImpersonationPopover serviceRoleLabel="postgres" />
{isTable && realtimeEnabled && (
<Button
<ButtonTooltip
type="default"
size="tiny"
icon={
<MousePointer2
strokeWidth={1.5}
@@ -452,11 +454,23 @@ const GridHeaderActions = ({ table }: GridHeaderActionsProps) => {
/>
}
onClick={() => setShowEnableRealtime(true)}
className={cn(isRealtimeEnabled && 'w-7 h-7 p-0 text-brand hover:text-brand-hover')}
tooltip={{
content: {
side: 'bottom',
text: isRealtimeEnabled
? 'Click to disable realtime for this table'
: 'Click to enable realtime for this table',
},
}}
>
Realtime {isRealtimeEnabled ? 'on' : 'off'}
</Button>
{!isRealtimeEnabled && 'Enable Realtime'}
</ButtonTooltip>
)}
{doesHaveAutoGeneratedAPIDocs && <APIDocsButton section={['entities', table.name]} />}
<RefreshButton tableId={table.id} isRefetching={isRefetching} />
</div>
)}
<ConfirmationModal
@@ -506,5 +520,3 @@ const GridHeaderActions = ({ table }: GridHeaderActionsProps) => {
</div>
)
}
export default GridHeaderActions
@@ -4,7 +4,7 @@ import { DndProvider } from 'react-dnd'
import { HTML5Backend } from 'react-dnd-html5-backend'
import { useParams } from 'common'
import RefreshButton from 'components/grid/components/header/RefreshButton'
import { RefreshButton } from 'components/grid/components/header/RefreshButton'
import { FilterPopoverPrimitive } from 'components/grid/components/header/filter/FilterPopoverPrimitive'
import { SortPopoverPrimitive } from 'components/grid/components/header/sort/SortPopoverPrimitive'
import type { Filter, Sort } from 'components/grid/types'
@@ -4,7 +4,7 @@ import Link from 'next/link'
import { useMemo, useRef } from 'react'
import { useParams } from 'common'
import Footer from 'components/grid/components/footer/Footer'
import { Footer } from 'components/grid/components/footer/Footer'
import { GenericSkeletonLoader } from 'components/ui/ShimmeringLoader'
import { useTableDefinitionQuery } from 'data/database/table-definition-query'
import { useViewDefinitionQuery } from 'data/database/view-definition-query'
@@ -24,7 +24,7 @@ export interface TableDefinitionProps {
entity?: Entity
}
const TableDefinition = ({ entity }: TableDefinitionProps) => {
export const TableDefinition = ({ entity }: TableDefinitionProps) => {
const { ref } = useParams()
const editorRef = useRef(null)
const monacoRef = useRef(null)
@@ -132,5 +132,3 @@ const TableDefinition = ({ entity }: TableDefinitionProps) => {
</>
)
}
export default TableDefinition
@@ -22,7 +22,7 @@ import { Button } from 'ui'
import { Admonition, GenericSkeletonLoader } from 'ui-patterns'
import DeleteConfirmationDialogs from './DeleteConfirmationDialogs'
import SidePanelEditor from './SidePanelEditor/SidePanelEditor'
import TableDefinition from './TableDefinition'
import { TableDefinition } from './TableDefinition'
export interface TableGridEditorProps {
isLoadingSelectedTable?: boolean
@@ -9,7 +9,7 @@ import { useParams } from 'common'
import { useIsAPIDocsSidePanelEnabled } from 'components/interfaces/App/FeaturePreview/FeaturePreviewContext'
import { EdgeFunctionTesterSheet } from 'components/interfaces/Functions/EdgeFunctionDetails/EdgeFunctionTesterSheet'
import { PageLayout } from 'components/layouts/PageLayout/PageLayout'
import APIDocsButton from 'components/ui/APIDocsButton'
import { APIDocsButton } from 'components/ui/APIDocsButton'
import { DocsButton } from 'components/ui/DocsButton'
import NoPermission from 'components/ui/NoPermission'
import { useEdgeFunctionBodyQuery } from 'data/edge-functions/edge-function-body-query'
+13 -10
View File
@@ -1,27 +1,30 @@
import { Code } from 'lucide-react'
import { BookOpenText } from 'lucide-react'
import { useAppStateSnapshot } from 'state/app-state'
import { Button } from 'ui'
import { ButtonTooltip } from './ButtonTooltip'
interface APIDocsButtonProps {
section?: string[]
}
const APIDocsButton = ({ section }: APIDocsButtonProps) => {
export const APIDocsButton = ({ section }: APIDocsButtonProps) => {
const snap = useAppStateSnapshot()
return (
<Button
<ButtonTooltip
size="tiny"
type="default"
onClick={() => {
if (section) snap.setActiveDocsSection(section)
snap.setShowProjectApiDocs(true)
}}
icon={<Code strokeWidth={1.5} className="text-foreground-muted" />}
>
API Docs
</Button>
icon={<BookOpenText />}
className="h-7 w-7"
tooltip={{
content: {
side: 'bottom',
text: 'API Docs',
},
}}
/>
)
}
export default APIDocsButton