mirror of
https://github.com/supabase/supabase.git
synced 2026-09-06 18:11:51 +08:00
Follow-up to #48344: collapses the two resolution paths for the Admonition module into one. `src/admonition.tsx` was a back-compat shim re-exporting `src/Admonition/`. Two ways to resolve one module is exactly what produced the macOS self-import bug fixed in #48344, and the local typecheck errors that #48374 worked around. This removes the shim and standardizes on the PascalCase subpath, matching every other export in the package. **Changed:** - Codemodded all 246 `ui-patterns/admonition` imports to `ui-patterns/Admonition` (240 `.tsx`, 5 `.mdx`, 1 `.ts` across studio, docs, www, design-system, and lite-studio) - Pointed the 5 internal `'../admonition'` imports back at the `'../Admonition'` directory **Removed:** - `packages/ui-patterns/src/admonition.tsx`, and its `./admonition` entry in the exports map (regenerated with `pnpm gen:exports`) ## To test - `grep -r "ui-patterns/admonition" --include='*.ts*'` → no hits - `pnpm test:case-hazards` → passes - `pnpm typecheck` → all 15 tasks green - `pnpm --filter studio run lint:ratchet` → passes - `pnpm --filter ui-patterns vitest run src/Admonition` → 11 tests pass <!-- This is an auto-generated comment: release notes by coderabbit.ai --> ## Summary by CodeRabbit * **Bug Fixes** * Standardized Admonition component imports across the application and documentation. * Improved compatibility with case-sensitive environments by using the canonical component path. * Removed the legacy Admonition import entry point. <!-- end of auto-generated comment: release notes by coderabbit.ai --> --------- Co-authored-by: Alaister Young <10985857+alaister@users.noreply.github.com>
171 lines
5.7 KiB
TypeScript
171 lines
5.7 KiB
TypeScript
import { useParams } from 'common'
|
|
import { noop } from 'lodash'
|
|
import { memo, useMemo } from 'react'
|
|
import {
|
|
Card,
|
|
CardContent,
|
|
CardHeader,
|
|
cn,
|
|
Table,
|
|
TableBody,
|
|
TableHead,
|
|
TableHeader,
|
|
TableRow,
|
|
} from 'ui'
|
|
import { Admonition } from 'ui-patterns/Admonition'
|
|
import { ShimmeringLoader } from 'ui-patterns/ShimmeringLoader'
|
|
|
|
import { usePoliciesData } from '../PoliciesDataContext'
|
|
import { PolicyRow } from './PolicyRow'
|
|
import type { PolicyTable } from './PolicyTableRow.types'
|
|
import type { Policy } from './PolicyTableRow.utils'
|
|
import { getTableAdmonitionMessage, getTableDataApiStatus } from './PolicyTableRow.utils'
|
|
import { PolicyTableRowHeader } from './PolicyTableRowHeader'
|
|
import { AlertError } from '@/components/ui/AlertError'
|
|
import { useTableApiAccessQuery } from '@/data/privileges/table-api-access-query'
|
|
import { useSelectedProjectQuery } from '@/hooks/misc/useSelectedProject'
|
|
|
|
export interface PolicyTableRowProps {
|
|
table: PolicyTable
|
|
isLocked: boolean
|
|
onSelectToggleRLS: (table: PolicyTable) => void
|
|
onSelectCreatePolicy: (table: PolicyTable) => void
|
|
onSelectEditPolicy: (policy: Policy) => void
|
|
onSelectDeletePolicy: (policy: Policy) => void
|
|
}
|
|
|
|
const PolicyTableRowComponent = ({
|
|
table,
|
|
isLocked,
|
|
onSelectToggleRLS = noop,
|
|
onSelectCreatePolicy = noop,
|
|
onSelectEditPolicy = noop,
|
|
onSelectDeletePolicy = noop,
|
|
}: PolicyTableRowProps) => {
|
|
const { ref } = useParams()
|
|
const { data: project } = useSelectedProjectQuery()
|
|
const { getPoliciesForTable, isPoliciesLoading, isPoliciesError, policiesError } =
|
|
usePoliciesData()
|
|
|
|
const policies = useMemo(
|
|
() => getPoliciesForTable(table.schema, table.name),
|
|
[getPoliciesForTable, table.schema, table.name]
|
|
)
|
|
|
|
// [Joshen] Classification is more granular than "RLS on/off" alone — it also considers
|
|
// schema exposure and whether anon/authenticated/service_role actually have grants.
|
|
// Ideally we'd rely on the security lints, but they only look at the public schema and
|
|
// ignore roles. Once the lints cover both, we can switch to them as the source of truth.
|
|
const tableNames = useMemo(() => [table.name], [table.name])
|
|
const {
|
|
data: apiAccessMap,
|
|
isPending: isLoadingRolesAccess,
|
|
isError: isRolesAccessError,
|
|
} = useTableApiAccessQuery({
|
|
projectRef: project?.ref,
|
|
connectionString: project?.connectionString,
|
|
schemaName: table.schema,
|
|
tableNames,
|
|
})
|
|
|
|
const status = useMemo(
|
|
() =>
|
|
getTableDataApiStatus({
|
|
apiAccessData: apiAccessMap?.[table.name],
|
|
isRLSEnabled: table.rls_enabled,
|
|
policiesCount: policies.length,
|
|
}),
|
|
[apiAccessMap, table.name, table.rls_enabled, policies.length]
|
|
)
|
|
|
|
const hasApiAccess =
|
|
status === 'publicly-readable' || status === 'locked-by-rls' || status === 'secured'
|
|
const isPubliclyReadable = status === 'publicly-readable'
|
|
|
|
const isRealtimeSchema = table.schema === 'realtime'
|
|
const isRealtimeMessagesTable = isRealtimeSchema && table.name === 'messages'
|
|
const isTableLocked = isRealtimeSchema ? !isRealtimeMessagesTable : isLocked
|
|
|
|
const showPolicies = !isPoliciesLoading && !isPoliciesError && !isLoadingRolesAccess
|
|
|
|
const admonitionMessage = useMemo(() => getTableAdmonitionMessage({ status, ref }), [status, ref])
|
|
|
|
return (
|
|
<Card className={cn(isPubliclyReadable && 'border-warning-500')}>
|
|
<CardHeader
|
|
className={cn('py-3 px-4', status !== 'secured' && status !== 'unknown' && 'border-b-0')}
|
|
>
|
|
<PolicyTableRowHeader
|
|
table={table}
|
|
isLocked={isLocked}
|
|
hasApiAccess={hasApiAccess}
|
|
isLoadingApiAccess={isLoadingRolesAccess}
|
|
onSelectToggleRLS={onSelectToggleRLS}
|
|
onSelectCreatePolicy={onSelectCreatePolicy}
|
|
/>
|
|
</CardHeader>
|
|
|
|
{!isLoadingRolesAccess && !isRolesAccessError && admonitionMessage !== null && (
|
|
<Admonition
|
|
showIcon={false}
|
|
type={isPubliclyReadable ? 'warning' : 'default'}
|
|
className="border-0 border-y rounded-none min-h-12 flex items-center"
|
|
>
|
|
{admonitionMessage}
|
|
</Admonition>
|
|
)}
|
|
|
|
{(isPoliciesLoading || isLoadingRolesAccess) && (
|
|
<CardContent>
|
|
<ShimmeringLoader />
|
|
</CardContent>
|
|
)}
|
|
|
|
{isPoliciesError && (
|
|
<CardContent>
|
|
<AlertError
|
|
className="border-0 rounded-none"
|
|
error={policiesError}
|
|
subject="Failed to retrieve policies"
|
|
/>
|
|
</CardContent>
|
|
)}
|
|
|
|
{showPolicies && (
|
|
<CardContent className="p-0">
|
|
{policies.length === 0 ? (
|
|
<p className="text-foreground-lighter text-sm p-4">No policies created yet</p>
|
|
) : (
|
|
<Table className="table-fixed">
|
|
<TableHeader>
|
|
<TableRow>
|
|
<TableHead className="w-[40%]">Name</TableHead>
|
|
<TableHead className="w-[20%]">Command</TableHead>
|
|
<TableHead className="w-[30%]">Applied to</TableHead>
|
|
<TableHead className="text-right">
|
|
<span className="sr-only">Actions</span>
|
|
</TableHead>
|
|
</TableRow>
|
|
</TableHeader>
|
|
<TableBody>
|
|
{policies.map((policy) => (
|
|
<PolicyRow
|
|
key={policy.id}
|
|
policy={policy}
|
|
isLocked={isTableLocked}
|
|
onSelectEditPolicy={onSelectEditPolicy}
|
|
onSelectDeletePolicy={onSelectDeletePolicy}
|
|
/>
|
|
))}
|
|
</TableBody>
|
|
</Table>
|
|
)}
|
|
</CardContent>
|
|
)}
|
|
</Card>
|
|
)
|
|
}
|
|
|
|
export const PolicyTableRow = memo(PolicyTableRowComponent)
|
|
PolicyTableRow.displayName = 'PolicyTableRow'
|