import { ArrowRight, Check, ExternalLink, Lightbulb, X } from 'lucide-react'
import Link from 'next/link'
import { useRouter } from 'next/router'
import { useMemo } from 'react'
import {
Button,
Button_Shadcn_,
Card,
Table,
TableBody,
TableCell,
TableHead,
TableHeader,
TableRow,
} from 'ui'
import { PageContainer } from 'ui-patterns/PageContainer'
import {
PageHeader,
PageHeaderAside,
PageHeaderDescription,
PageHeaderIcon,
PageHeaderMeta,
PageHeaderSummary,
PageHeaderTitle,
} from 'ui-patterns/PageHeader'
import {
PageSection,
PageSectionAside,
PageSectionContent,
PageSectionMeta,
PageSectionSummary,
PageSectionTitle,
} from 'ui-patterns/PageSection'
import { GenericSkeletonLoader } from 'ui-patterns/ShimmeringLoader'
import type {
ProjectSecurityActionDetails,
ProjectSecurityActionType,
ProjectSecurityTable,
} from './ProjectNeedsSecuring.types'
import {
buildSecurityPromptMarkdown,
formatRlsDescription,
getTableKey,
getTablePoliciesHref,
} from './ProjectNeedsSecuring.utils'
import { SIDEBAR_KEYS } from '@/components/layouts/ProjectLayout/LayoutSidebar/LayoutSidebarProvider'
import { AiAssistantDropdown } from '@/components/ui/AiAssistantDropdown'
import AlertError from '@/components/ui/AlertError'
import { createNavigationHandler } from '@/lib/navigation'
import { useAiAssistantStateSnapshot } from '@/state/ai-assistant-state'
import { useSidebarManagerSnapshot } from '@/state/sidebar-manager-state'
const StatusCell = ({ enabled, label }: { enabled: boolean; label: string }) => (
{enabled ? (
) : (
)}
{label}
)
export const ProjectNeedsSecuringView = ({
projectRef,
issueCount,
tables,
isLoading,
error,
onDismiss,
onTrackAction,
}: {
projectRef: string
issueCount: number
tables: ProjectSecurityTable[]
isLoading: boolean
error?: { message: string } | null
onDismiss: () => void
onTrackAction: (type: ProjectSecurityActionType, details?: ProjectSecurityActionDetails) => void
}) => {
const router = useRouter()
const aiSnap = useAiAssistantStateSnapshot()
const { openSidebar } = useSidebarManagerSnapshot()
const promptMarkdown = useMemo(
() => buildSecurityPromptMarkdown(issueCount, tables),
[issueCount, tables]
)
const handleOpenAssistant = () => {
onTrackAction('ask_assistant')
openSidebar(SIDEBAR_KEYS.AI_ASSISTANT)
aiSnap.newChat({
name: 'Review project security',
initialInput: promptMarkdown,
})
}
return (
Your project needs securing
{formatRlsDescription(issueCount)}
}>
{
onTrackAction('skip_to_home')
onDismiss()
}}
>
Skip to home
Review and fix
promptMarkdown}
onOpenAssistant={handleOpenAssistant}
onCopyPrompt={() => onTrackAction('copy_prompt')}
copyLabel="Copy Markdown"
disabled={isLoading}
/>
{isLoading ? (
) : error ? (
) : (
Name
Schema
Accessible via Data API
RLS
{tables.map((table) => {
const policiesHref = getTablePoliciesHref(
projectRef,
table.schema,
table.name
)
const handleNavigation = createNavigationHandler(policiesHref, router)
const trackViewPolicies = () =>
onTrackAction('view_policies', {
schema: table.schema,
tableName: table.name,
})
return (
{
trackViewPolicies()
handleNavigation(event)
}}
onAuxClick={(event) => {
if (event.button === 1) trackViewPolicies()
handleNavigation(event)
}}
onKeyDown={(event) => {
if (event.key === 'Enter' || event.key === ' ') trackViewPolicies()
handleNavigation(event)
}}
tabIndex={0}
>
{table.name}
{table.schema}
)
})}
)}
)
}