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' 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 { InlineLink } from '@/components/ui/InlineLink' 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, exposedSchemas } = 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({ isSchemaExposed: exposedSchemas.has(table.schema), apiAccessData: apiAccessMap?.[table.name], isRLSEnabled: table.rls_enabled, policiesCount: policies.length, }), [exposedSchemas, apiAccessMap, table.schema, 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), [status]) return ( {!isLoadingRolesAccess && !isRolesAccessError && status === 'schema-not-exposed' && (

No data will be selectable via Briven APIs as this schema is not exposed. You may configure this in your project’s{' '} API settings .

)} {!isLoadingRolesAccess && !isRolesAccessError && admonitionMessage !== null && (

{admonitionMessage}

)} {(isPoliciesLoading || isLoadingRolesAccess) && ( )} {isPoliciesError && ( )} {showPolicies && ( {policies.length === 0 ? (

No policies created yet

) : ( Name Command Applied to Actions {policies.map((policy) => ( ))}
)}
)}
) } export const PolicyTableRow = memo(PolicyTableRowComponent) PolicyTableRow.displayName = 'PolicyTableRow'