Files
Danny White 476d4a5851 refactor(ui): drop redundant Button variant="default" props (#50161)
## What kind of change does this PR introduce?

Mechanical cleanup on top of the Button default-variant change (#50160).

## What is the current behavior?

Many callsites still pass `variant="default"` even though that is now
the component default.

## What is the new behavior?

Removes redundant static `variant="default"` from legacy `Button` and
`ButtonTooltip` callsites. Keeps explicit defaults where they document
the API:

- `button-default.tsx` and `button-sizes.tsx` demos
- `DocsButton`, which pins neutral styling at the wrapper boundary

## To test

Studio:

- [Auth → Rate
Limits](https://studio-staging-2s957kwc4-supabase.vercel.app/dashboard/project/_/auth/rate-limits):
dirty the form so Cancel appears; Cancel stays neutral, Save stays green
- [Project Settings → API
Keys](https://studio-staging-2s957kwc4-supabase.vercel.app/dashboard/project/_/settings/api-keys):
`DocsButton` in the header actions stays neutral

Design system:

- [Design system →
Button](https://design-system-git-dnywh-dc924ac1-supabase.vercel.app/design-system/docs/components/button):
`button-default` / `button-sizes` still show explicit default styling;
Primary (green) is restricted to the Primary section (and `asChild`)

WWW:

- [www → Brand
assets](https://zone-www-dot-com-git-dnywh-dc924ac1-supabase.vercel.app/brand-assets):
Download logo kit / Download button kit stay neutral
2026-09-11 17:05:26 +10:00

228 lines
7.3 KiB
TypeScript
Raw Permalink Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
import { useParams } from 'common'
import { isEmpty } from 'lodash'
import Link from 'next/link'
import { useCallback, useState } from 'react'
import { toast } from 'sonner'
import { Button, Card, CardContent } from 'ui'
import { Admonition } from 'ui-patterns/Admonition'
import ConfirmationModal from 'ui-patterns/Dialogs/ConfirmationModal'
import { usePoliciesData } from './PoliciesDataContext'
import {
PolicyTableRow,
PolicyTableRowProps,
} from '@/components/interfaces/Database/Policies/PolicyTableRow'
import type { Policy } from '@/components/interfaces/Database/Policies/PolicyTableRow/PolicyTableRow.utils'
import { ProtectedSchemaWarning } from '@/components/interfaces/Database/ProtectedSchemaWarning'
import { RLSToggleDialog } from '@/components/interfaces/Database/RLSToggleDialog'
import { InlineLink } from '@/components/ui/InlineLink'
import { NoSearchResults } from '@/components/ui/NoSearchResults'
import { useDatabasePolicyDeleteMutation } from '@/data/database-policies/database-policy-delete-mutation'
import { useTableUpdateMutation } from '@/data/tables/table-update-mutation'
import { useSelectedProjectQuery } from '@/hooks/misc/useSelectedProject'
interface PoliciesProps {
search?: string
schema: string
tables: PolicyTableRowProps['table'][]
hasTables: boolean
isLocked: boolean
visibleTableIds: Set<number>
onSelectCreatePolicy: (table: string) => void
onSelectEditPolicy: (policy: Policy) => void
onResetSearch?: () => void
}
export const Policies = ({
search,
schema,
tables,
hasTables,
isLocked,
visibleTableIds,
onSelectCreatePolicy,
onSelectEditPolicy: onSelectEditPolicyAI,
onResetSearch,
}: PoliciesProps) => {
const { ref } = useParams()
const { data: project } = useSelectedProjectQuery()
const { exposedSchemas } = usePoliciesData()
const isSchemaExposedAPI = exposedSchemas.has(schema)
const [selectedTableToToggleRLS, setSelectedTableToToggleRLS] = useState<{
id: number
schema: string
name: string
rls_enabled: boolean
}>()
const [selectedPolicyToDelete, setSelectedPolicyToDelete] = useState<any>({})
const { mutateAsync: updateTable, isPending: isUpdatingTable } = useTableUpdateMutation({
onError: (error) => {
toast.error(`Failed to toggle RLS: ${error.message}`)
},
})
const { mutate: deleteDatabasePolicy, isPending: isDeletingPolicy } =
useDatabasePolicyDeleteMutation({
onSuccess: () => {
toast.success('Successfully deleted policy!')
},
onSettled: () => {
closeConfirmModal()
},
})
const closeConfirmModal = useCallback(() => {
setSelectedPolicyToDelete({})
setSelectedTableToToggleRLS(undefined)
}, [])
const onSelectToggleRLS = useCallback(
(table: { id: number; schema: string; name: string; rls_enabled: boolean }) => {
setSelectedTableToToggleRLS(table)
},
[]
)
const onSelectEditPolicy = useCallback(
(policy: Policy) => {
onSelectEditPolicyAI(policy)
},
[onSelectEditPolicyAI]
)
const onSelectDeletePolicy = useCallback((policy: Policy) => {
setSelectedPolicyToDelete(policy)
}, [])
// Methods that involve some API
const onToggleRLS = async () => {
if (!selectedTableToToggleRLS) return console.error('Table is required')
const payload = {
id: selectedTableToToggleRLS.id,
rls_enabled: !selectedTableToToggleRLS.rls_enabled,
}
return updateTable({
projectRef: project?.ref!,
connectionString: project?.connectionString,
id: selectedTableToToggleRLS.id,
name: selectedTableToToggleRLS.name,
schema: selectedTableToToggleRLS.schema,
payload: payload,
})
}
const onDeletePolicy = async () => {
if (!project) return console.error('Project is required')
deleteDatabasePolicy({
projectRef: project.ref,
connectionString: project.connectionString,
originalPolicy: selectedPolicyToDelete,
})
}
const handleCreatePolicy = useCallback(
(tableData: PolicyTableRowProps['table']) => {
onSelectCreatePolicy(tableData.name)
},
[onSelectCreatePolicy]
)
if (!hasTables) {
return (
<Card className="w-full bg-transparent">
<CardContent className="flex flex-col items-center justify-center p-8">
<h2 className="heading-default">No tables to create policies for</h2>
<p className="text-sm text-foreground-light text-center mb-4">
RLS Policies control per-user access to table rows. Create a table in this schema first
before creating a policy.
</p>
<Button asChild>
<Link href={`/project/${ref}/editor`}>Create a table</Link>
</Button>
</CardContent>
</Card>
)
}
return (
<>
<div className="flex flex-col gap-y-4 pb-4">
{isLocked && <ProtectedSchemaWarning schema={schema} entity="policies" />}
{!isSchemaExposedAPI && (
<Admonition
type="warning"
title="No data from any table in this schema will be selectable via Supabase APIs"
>
This schema is not exposed via the Supabase APIs. You may configure this in your
project’s{' '}
<InlineLink href={`/project/${ref}/integrations/data_api/settings`}>
Data API settings
</InlineLink>
.
</Admonition>
)}
{tables.length > 0 ? (
<>
{tables.map((table) => {
const isVisible = visibleTableIds.has(table.id)
return (
<section
key={table.id}
hidden={!isVisible}
aria-hidden={!isVisible}
data-testid={`policy-table-${table.name}`}
>
<PolicyTableRow
table={table}
isLocked={schema === 'realtime' ? true : isLocked}
onSelectToggleRLS={onSelectToggleRLS}
onSelectCreatePolicy={handleCreatePolicy}
onSelectEditPolicy={onSelectEditPolicy}
onSelectDeletePolicy={onSelectDeletePolicy}
/>
</section>
)
})}
{!!search && visibleTableIds.size === 0 && (
<NoSearchResults searchString={search ?? ''} onResetFilter={onResetSearch} />
)}
</>
) : hasTables ? (
<NoSearchResults searchString={search ?? ''} onResetFilter={onResetSearch} />
) : null}
</div>
<ConfirmationModal
visible={!isEmpty(selectedPolicyToDelete)}
variant="destructive"
title="Delete policy"
description={`Are you sure you want to delete the policy “${selectedPolicyToDelete.name}”? This action cannot be undone.`}
confirmLabel="Delete"
confirmLabelLoading="Deleting"
loading={isDeletingPolicy}
onCancel={closeConfirmModal}
onConfirm={onDeletePolicy}
/>
<RLSToggleDialog
open={selectedTableToToggleRLS !== undefined}
tableName={selectedTableToToggleRLS?.name}
isEnabled={selectedTableToToggleRLS?.rls_enabled ?? false}
isSubmitting={isUpdatingTable}
onOpenChange={(open) => {
if (!open) closeConfirmModal()
}}
onConfirm={onToggleRLS}
/>
</>
)
}