Add CTA to unrestricted badge in table editor (#37730)

* Add CTA to unrestricted badge in table editor

* Update apps/studio/components/interfaces/TableGridEditor/GridHeaderActions.tsx

Co-authored-by: Alaister Young <alaister@users.noreply.github.com>

---------

Co-authored-by: Alaister Young <alaister@users.noreply.github.com>
This commit is contained in:
Joshen LimandAlaister Young authored and GitHub committed 2025-08-12 10:44:48 +07:00
1 parent 76e8df5546
commit 7ed5edd320
2 files changed
+45 -13

No files matched your search

@@ -26,6 +26,7 @@ import { useIsFeatureEnabled } from 'hooks/misc/useIsFeatureEnabled'
import { useSelectedOrganizationQuery } from 'hooks/misc/useSelectedOrganization'
import { useSelectedProjectQuery } from 'hooks/misc/useSelectedProject'
import { useIsProtectedSchema } from 'hooks/useProtectedSchemas'
import { parseAsBoolean, useQueryState } from 'nuqs'
import { useTableEditorTableStateSnapshot } from 'state/table-editor-table'
import {
Button,
@@ -51,6 +52,11 @@ const GridHeaderActions = ({ table }: GridHeaderActionsProps) => {
const { data: project } = useSelectedProjectQuery()
const { data: org } = useSelectedOrganizationQuery()
const [showWarning, setShowWarning] = useQueryState(
'showWarning',
parseAsBoolean.withDefault(false)
)
// need project lints to get security status for views
const { data: lints = [] } = useProjectLintsQuery({ projectRef: project?.ref })
@@ -261,7 +267,7 @@ const GridHeaderActions = ({ table }: GridHeaderActionsProps) => {
)}
</>
) : (
<Popover_Shadcn_ modal={false}>
<Popover_Shadcn_ modal={false} open={showWarning} onOpenChange={setShowWarning}>
<PopoverTrigger_Shadcn_ asChild>
<Button type="warning" icon={<Lock strokeWidth={1.5} />}>
RLS disabled
@@ -301,7 +307,7 @@ const GridHeaderActions = ({ table }: GridHeaderActionsProps) => {
)
) : null}
{isView && viewHasLints && (
<Popover_Shadcn_ modal={false}>
<Popover_Shadcn_ modal={false} open={showWarning} onOpenChange={setShowWarning}>
<PopoverTrigger_Shadcn_ asChild>
<Button type="warning" icon={<Unlock strokeWidth={1.5} />}>
Security Definer view
@@ -351,7 +357,7 @@ const GridHeaderActions = ({ table }: GridHeaderActionsProps) => {
</Popover_Shadcn_>
)}
{isMaterializedView && materializedViewHasLints && (
<Popover_Shadcn_ modal={false}>
<Popover_Shadcn_ modal={false} open={showWarning} onOpenChange={setShowWarning}>
<PopoverTrigger_Shadcn_ asChild>
<Button type="warning" icon={<Unlock strokeWidth={1.5} />}>
Security Definer view
@@ -393,7 +399,7 @@ const GridHeaderActions = ({ table }: GridHeaderActionsProps) => {
</Popover_Shadcn_>
)}
{isForeignTable && table.schema === 'public' && (
<Popover_Shadcn_ modal={false}>
<Popover_Shadcn_ modal={false} open={showWarning} onOpenChange={setShowWarning}>
<PopoverTrigger_Shadcn_ asChild>
<Button type="warning" icon={<Unlock strokeWidth={1.5} />}>
Unprotected Data API access
@@ -4,7 +4,7 @@ import Link from 'next/link'
import Papa from 'papaparse'
import { toast } from 'sonner'
import { IS_PLATFORM } from 'common'
import { IS_PLATFORM, useParams } from 'common'
import {
MAX_EXPORT_ROW_COUNT,
MAX_EXPORT_ROW_COUNT_MESSAGE,
@@ -16,6 +16,7 @@ import {
} from 'components/interfaces/TableGridEditor/TableEntity.utils'
import { EntityTypeIcon } from 'components/ui/EntityTypeIcon'
import type { ItemRenderer } from 'components/ui/InfiniteList'
import { InlineLink } from 'components/ui/InlineLink'
import { getTableDefinition } from 'data/database/table-definition-query'
import { ENTITY_TYPE } from 'data/entity-types/entity-type-constants'
import { Entity } from 'data/entity-types/entity-types-infinite-query'
@@ -453,28 +454,53 @@ const EntityTooltipTrigger = ({
materializedViewHasLints: boolean
foreignTableHasLints: boolean
}) => {
let tooltipContent = ''
const { ref } = useParams()
let tooltipContent = null
const accessWarning = 'Data is publicly accessible via API'
const learnMoreCTA = (
<InlineLink
href={`/project/${ref}/editor/${entity.id}?schema=${entity.schema}&showWarning=true`}
>
Learn more
</InlineLink>
)
switch (entity.type) {
case ENTITY_TYPE.TABLE:
if (tableHasLints) {
tooltipContent = `${accessWarning} as RLS is disabled`
tooltipContent = (
<>
{accessWarning} as RLS is disabled. {learnMoreCTA}.
</>
)
}
break
case ENTITY_TYPE.VIEW:
if (viewHasLints) {
tooltipContent = `${accessWarning} as this is a Security definer view`
tooltipContent = (
<>
{accessWarning} as this is a Security definer view. {learnMoreCTA}.
</>
)
}
break
case ENTITY_TYPE.MATERIALIZED_VIEW:
if (materializedViewHasLints) {
tooltipContent = `${accessWarning} Security definer view`
tooltipContent = (
<>
{accessWarning} as this is a Security definer view {learnMoreCTA}.
</>
)
}
break
case ENTITY_TYPE.FOREIGN_TABLE:
if (foreignTableHasLints) {
tooltipContent = `${accessWarning} as RLS is not enforced on foreign tables`
tooltipContent = (
<>
{accessWarning} as RLS is not enforced on foreign tables. {learnMoreCTA}.
</>
)
}
break
default:
@@ -483,12 +509,12 @@ const EntityTooltipTrigger = ({
if (tooltipContent) {
return (
<Tooltip disableHoverableContent={true}>
<Tooltip>
<TooltipTrigger className="min-w-4">
<Badge variant="destructive">Unrestricted</Badge>
</TooltipTrigger>
<TooltipContent side="bottom" className="max-w-44 text-center">
<span>{tooltipContent}</span>
<TooltipContent side="right" className="max-w-52 text-center">
{tooltipContent}
</TooltipContent>
</Tooltip>
)