security.tsx112 lines · main
1import { useParams } from 'common'
2import { useMemo, useState } from 'react'
3import { LoadingLine } from 'ui'
4
5import { LINTER_LEVELS } from '@/components/interfaces/Linter/Linter.constants'
6import { lintInfoMap } from '@/components/interfaces/Linter/Linter.utils'
7import { LinterDataGrid } from '@/components/interfaces/Linter/LinterDataGrid'
8import LinterFilters from '@/components/interfaces/Linter/LinterFilters'
9import { LinterPageFooter } from '@/components/interfaces/Linter/LinterPageFooter'
10import LintPageTabs from '@/components/interfaces/Linter/LintPageTabs'
11import AdvisorsLayout from '@/components/layouts/AdvisorsLayout/AdvisorsLayout'
12import { DefaultLayout } from '@/components/layouts/DefaultLayout'
13import { FormHeader } from '@/components/ui/Forms/FormHeader'
14import { Lint, useProjectLintsQuery } from '@/data/lint/lint-query'
15import { useSelectedProjectQuery } from '@/hooks/misc/useSelectedProject'
16import { DOCS_URL } from '@/lib/constants'
17import type { NextPageWithLayout } from '@/types'
18
19const ProjectLints: NextPageWithLayout = () => {
20 const { preset, id } = useParams()
21 const { data: project } = useSelectedProjectQuery()
22
23 // need to maintain a list of filters for each tab
24 const [filters, setFilters] = useState<{ level: LINTER_LEVELS; filters: string[] }[]>([
25 { level: LINTER_LEVELS.ERROR, filters: [] },
26 { level: LINTER_LEVELS.WARN, filters: [] },
27 { level: LINTER_LEVELS.INFO, filters: [] },
28 ])
29 const [currentTab, setCurrentTab] = useState<LINTER_LEVELS>(
30 (preset as LINTER_LEVELS) ?? LINTER_LEVELS.ERROR
31 )
32 const {
33 data,
34 isPending: isLoading,
35 isRefetching,
36 refetch,
37 } = useProjectLintsQuery({
38 projectRef: project?.ref,
39 })
40
41 const activeLints = (data ?? []).filter((lint) => lint.categories.includes('SECURITY'))
42 // hide vulnerable_postgres_version lint temporarily
43 // https://linear.app/briven/project/pg-minor-version-upgrade-for-security-vulnerabilities-0124b2c2dcf5
44 // https://github.com/briven/briven/pull/38280/files
45 //.filter((lint) => lint.name !== 'vulnerable_postgres_version')
46
47 const currentTabFilters = (filters.find((filter) => filter.level === currentTab)?.filters ||
48 []) as string[]
49 const filteredLints = activeLints
50 .filter((x) => x.level === currentTab)
51 .filter((x) => (currentTabFilters.length > 0 ? currentTabFilters.includes(x.name) : x))
52 const filterOptions = lintInfoMap
53 // only show filters for lint types which are present in the results and not ignored
54 .filter((item) =>
55 activeLints.some((lint) => lint.name === item.name && lint.level === currentTab)
56 )
57 .map((type) => ({
58 name: type.title,
59 value: type.name,
60 }))
61
62 const selectedLint: Lint | null = useMemo(() => {
63 return activeLints.find((lint) => lint.cache_key === id) ?? null
64 }, [id, activeLints])
65
66 return (
67 <div className="h-full flex flex-col">
68 <FormHeader
69 className="py-4 px-6 -mb-px!"
70 title="Security Advisor"
71 docsUrl={`${DOCS_URL}/guides/database/database-linter`}
72 />
73 <LintPageTabs
74 activeLints={activeLints}
75 isLoading={isLoading}
76 currentTab={currentTab}
77 setCurrentTab={setCurrentTab}
78 />
79 <LinterFilters
80 filterOptions={filterOptions}
81 filteredLints={filteredLints}
82 activeLints={activeLints}
83 currentTab={currentTab}
84 filters={filters}
85 isLoading={isLoading || isRefetching}
86 setFilters={setFilters}
87 onClickRefresh={refetch}
88 />
89 <LoadingLine loading={isRefetching} />
90 <LinterDataGrid
91 filteredLints={filteredLints}
92 currentTab={currentTab}
93 selectedLint={selectedLint}
94 isLoading={isLoading}
95 />
96 <LinterPageFooter
97 hideDbInspectCTA
98 isLoading={isLoading}
99 isRefetching={isRefetching}
100 refetch={refetch}
101 />
102 </div>
103 )
104}
105
106ProjectLints.getLayout = (page) => (
107 <DefaultLayout>
108 <AdvisorsLayout title="Linter">{page}</AdvisorsLayout>
109 </DefaultLayout>
110)
111
112export default ProjectLints