Files
Saxon FletcherandJoshen Lim 3b756e4d9f Chore/project secure (#45108)
<img width="2652" height="830" alt="image"
src="https://github.com/user-attachments/assets/3c3921e7-c255-4e59-a9c3-c5f97da87788"
/>

Adds a full screen alert behind a feature flag `projectNeedsSecuring`
that prompts for fixing RLS issues.

Adjusts a few other small styles to add more prominence to critical
advisor issues.

To test:

- Enable the flag
- Make sure you have a table with RLS disabled
- Open project home and note the fade in of full page review
- Click "copy prompt" or "fix" and note the prompt
- Click skip to home and refresh the page, note it doesn't appear
anymore


<!-- This is an auto-generated comment: release notes by coderabbit.ai
-->
## Summary by CodeRabbit

* **New Features**
* Project-level security gate on project home with AI assistant prompts,
table details, per-project dismissible notice, and a new telemetry event
for CTA interactions.

* **Improvements**
* Stronger visual treatment for critical advisor items and advisor CTA
when critical issues exist.
* Assistant dropdown supports a copy-prompt callback; added
local-storage key and utilities/types to support project security
workflows.

* **Tests**
  * Added tests covering gate behavior, navigation, and dismissal logic.
<!-- end of auto-generated comment: release notes by coderabbit.ai -->

---------

Co-authored-by: Joshen Lim <joshenlimek@gmail.com>
2026-04-29 04:08:09 +00:00

79 lines
2.9 KiB
TypeScript

import { Lightbulb } from 'lucide-react'
import { useMemo } from 'react'
import { cn } from 'ui'
import { SIDEBAR_KEYS } from '@/components/layouts/ProjectLayout/LayoutSidebar/LayoutSidebarProvider'
import { useAdvisorSignals } from '@/components/ui/AdvisorPanel/useAdvisorSignals'
import { ButtonTooltip } from '@/components/ui/ButtonTooltip'
import { useProjectLintsQuery } from '@/data/lint/lint-query'
import { useNotificationsV2Query } from '@/data/notifications/notifications-v2-query'
import { useSidebarManagerSnapshot } from '@/state/sidebar-manager-state'
export const AdvisorButton = ({ projectRef }: { projectRef?: string }) => {
const { toggleSidebar, activeSidebar } = useSidebarManagerSnapshot()
const { data: lints } = useProjectLintsQuery({ projectRef })
const { data: signalItems } = useAdvisorSignals({ projectRef })
const { data: notificationsData } = useNotificationsV2Query({
filters: {},
limit: 20,
})
const notifications = useMemo(() => {
return notificationsData?.pages.flatMap((page) => page) ?? []
}, [notificationsData?.pages])
const hasUnreadNotifications = notifications.some((x) => x?.status === 'new')
const hasCriticalNotifications = notifications.some((x) => x?.priority === 'Critical')
const hasSignals = signalItems.length > 0
const hasCriticalSignals = signalItems.some((item) => item.severity === 'critical')
const hasCriticalIssues =
hasCriticalNotifications ||
hasCriticalSignals ||
(Array.isArray(lints) && lints.some((lint) => lint.level === 'ERROR'))
const hasWarningIssues = hasSignals && !hasCriticalIssues
const isOpen = activeSidebar?.id === SIDEBAR_KEYS.ADVISOR_PANEL
const handleClick = () => {
toggleSidebar(SIDEBAR_KEYS.ADVISOR_PANEL)
}
return (
<div className="relative">
<ButtonTooltip
type="outline"
size="tiny"
id="advisor-center-trigger"
className={cn(
'rounded-full w-[32px] h-[32px] flex items-center justify-center p-0 group',
hasCriticalIssues && 'bg-destructive-200 border-destructive-500',
isOpen && 'bg-foreground text-background'
)}
onClick={handleClick}
tooltip={{
content: {
text: 'Advisor Center',
},
}}
>
<Lightbulb
size={16}
strokeWidth={1.5}
className={cn(
'text-foreground-light group-hover:text-foreground',
isOpen && 'text-background group-hover:text-background'
)}
/>
</ButtonTooltip>
{hasCriticalIssues ? (
<span className="absolute top-1.5 right-1.5 w-1.5 h-1.5 rounded-full bg-destructive" />
) : hasWarningIssues ? (
<span className="absolute top-1.5 right-1.5 w-1.5 h-1.5 rounded-full bg-warning" />
) : hasUnreadNotifications ? (
<span className="absolute top-1.5 right-1.5 w-1.5 h-1.5 rounded-full bg-brand" />
) : null}
</div>
)
}