11import { CheckCircle2 , Loader2 } from 'lucide-react'
22import { useState } from 'react'
3- import { Button , PopoverContent_Shadcn_ , PopoverTrigger_Shadcn_ , Popover_Shadcn_ , cn } from 'ui'
3+ import {
4+ Button ,
5+ PopoverContent_Shadcn_ ,
6+ PopoverTrigger_Shadcn_ ,
7+ Popover_Shadcn_ ,
8+ PopoverSeparator_Shadcn_ ,
9+ cn ,
10+ } from 'ui'
411import { useProjectLintsQuery } from 'data/lint/lint-query'
512import { useSelectedProject } from 'hooks/misc/useSelectedProject'
613import Link from 'next/link'
7- import { WarningIcon } from 'ui/src/components/StatusIcon'
14+
15+ import { LINTER_LEVELS , LINT_TABS } from '../Linter/Linter.constants'
816
917export const SecurityStatus = ( ) => {
1018 const project = useSelectedProject ( )
@@ -14,8 +22,9 @@ export const SecurityStatus = () => {
1422 const securityLints = ( data ?? [ ] ) . filter ( ( lint ) => lint . categories . includes ( 'SECURITY' ) )
1523 const errorLints = securityLints . filter ( ( lint ) => lint . level === 'ERROR' )
1624 const warnLints = securityLints . filter ( ( lint ) => lint . level === 'WARN' )
17- const noIssuesFound = errorLints . length === 0 && warnLints . length === 0
18- const totalIssues = securityLints . length
25+ const infoLints = securityLints . filter ( ( lint ) => lint . level === 'INFO' )
26+
27+ const noIssuesFound = errorLints . length === 0 && warnLints . length === 0 && infoLints . length === 0
1928
2029 return (
2130 < Popover_Shadcn_ modal = { false } open = { open } onOpenChange = { setOpen } >
@@ -43,46 +52,69 @@ export const SecurityStatus = () => {
4352 </ Button >
4453 </ PopoverTrigger_Shadcn_ >
4554 < PopoverContent_Shadcn_
46- className = { `py-1.5 px-0 ${ noIssuesFound ? 'w-64 ' : 'w-84' } ` }
55+ className = { `py-1.5 px-0 ${ noIssuesFound ? 'w-72 ' : 'w-84' } ` }
4756 side = "bottom"
4857 align = "center"
4958 >
50- < div className = "px-4 py-2 text-sm flex gap-3" >
59+ < div className = "py-2 text-sm flex gap-3" >
5160 { noIssuesFound ? (
52- < CheckCircle2 className = "text-brand shrink-0" size = { 18 } strokeWidth = { 1.5 } />
53- ) : (
54- < WarningIcon className = "shrink-0" />
55- ) }
56- < div className = "flex flex-col gap-y-3 -mt-1" >
57- { noIssuesFound ? (
58- < div className = "flex flex-col gap-y-1" >
59- < p className = "text-xs" > No security issues found</ p >
61+ < div className = "flex gap-3 px-4" >
62+ < CheckCircle2 className = "text-brand shrink-0" size = { 18 } strokeWidth = { 1.5 } />
63+ < div className = "grid gap-1" >
64+ < p className = "" > No security issues found</ p >
6065 < p className = "text-xs text-foreground-light" >
6166 Keep monitoring Security Advisor for updates as your project grows.
6267 </ p >
68+ < Button asChild type = "default" className = "w-min mt-2" >
69+ < Link href = { `/project/${ project ?. ref } /database/security-advisor` } >
70+ Security Advisor
71+ </ Link >
72+ </ Button >
6373 </ div >
64- ) : (
65- < div className = "flex flex-col gap-y-1" >
66- < p className = "text-xs" >
67- { totalIssues } security issue{ totalIssues > 1 ? 's' : '' } require
68- { totalIssues > 1 ? '' : 's' } { ' ' }
69- { errorLints . length > 0 ? 'urgent attention' : 'attention' }
70- </ p >
71- < p className = "text-xs text-foreground-light" >
72- Check the Security Advisor to address them
73- </ p >
74- </ div >
75- ) }
76- < Button asChild type = "default" className = "w-min" >
77- < Link
78- href = { `/project/${ project ?. ref } /database/security-advisor${ errorLints . length === 0 ? '?preset=WARN' : '' } ` }
79- >
80- Head to Security Advisor
81- </ Link >
82- </ Button >
83- </ div >
74+ </ div >
75+ ) : (
76+ < div className = "grid gap-y-3.5" >
77+ { [
78+ { lints : errorLints , level : LINTER_LEVELS . ERROR } ,
79+ { lints : warnLints , level : LINTER_LEVELS . WARN } ,
80+ { lints : infoLints , level : LINTER_LEVELS . INFO } ,
81+ ] . map (
82+ ( { lints, level } ) =>
83+ lints . length > 0 && (
84+ < >
85+ < div key = { level } className = "flex gap-3 pb-0 px-4" >
86+ < StatusDot level = { level } />
87+ < div >
88+ { lints . length } { level . toLowerCase ( ) } issue{ lints . length > 1 ? 's' : '' }
89+ < p className = "text-xs text-foreground-lighter" >
90+ { LINT_TABS . find ( ( tab ) => tab . id === level ) ?. descriptionShort }
91+ </ p >
92+ </ div >
93+ </ div >
94+ < PopoverSeparator_Shadcn_ className = "" />
95+ </ >
96+ )
97+ ) }
98+ < Button asChild type = "default" className = "w-min ml-4" >
99+ < Link
100+ href = { `/project/${ project ?. ref } /database/security-advisor${ errorLints . length === 0 ? '?preset=WARN' : '' } ` }
101+ >
102+ Security Advisor
103+ </ Link >
104+ </ Button >
105+ </ div >
106+ ) }
84107 </ div >
85108 </ PopoverContent_Shadcn_ >
86109 </ Popover_Shadcn_ >
87110 )
88111}
112+
113+ const StatusDot = ( { level } : { level : LINTER_LEVELS } ) => {
114+ const variants = {
115+ [ LINTER_LEVELS . ERROR ] : 'bg-destructive-600' ,
116+ [ LINTER_LEVELS . WARN ] : 'bg-warning-600' ,
117+ [ LINTER_LEVELS . INFO ] : 'bg-foreground-lighter dark:bg-foreground-light' ,
118+ }
119+ return < div className = { cn ( 'w-2 h-2 rounded-full mt-1.5' , variants [ level ] ) } />
120+ }
0 commit comments