security.tsx112 lines · main
| 1 | import { useParams } from 'common' |
| 2 | import { useMemo, useState } from 'react' |
| 3 | import { LoadingLine } from 'ui' |
| 4 | |
| 5 | import { LINTER_LEVELS } from '@/components/interfaces/Linter/Linter.constants' |
| 6 | import { lintInfoMap } from '@/components/interfaces/Linter/Linter.utils' |
| 7 | import { LinterDataGrid } from '@/components/interfaces/Linter/LinterDataGrid' |
| 8 | import LinterFilters from '@/components/interfaces/Linter/LinterFilters' |
| 9 | import { LinterPageFooter } from '@/components/interfaces/Linter/LinterPageFooter' |
| 10 | import LintPageTabs from '@/components/interfaces/Linter/LintPageTabs' |
| 11 | import AdvisorsLayout from '@/components/layouts/AdvisorsLayout/AdvisorsLayout' |
| 12 | import { DefaultLayout } from '@/components/layouts/DefaultLayout' |
| 13 | import { FormHeader } from '@/components/ui/Forms/FormHeader' |
| 14 | import { Lint, useProjectLintsQuery } from '@/data/lint/lint-query' |
| 15 | import { useSelectedProjectQuery } from '@/hooks/misc/useSelectedProject' |
| 16 | import { DOCS_URL } from '@/lib/constants' |
| 17 | import type { NextPageWithLayout } from '@/types' |
| 18 | |
| 19 | const 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 | |
| 106 | ProjectLints.getLayout = (page) => ( |
| 107 | <DefaultLayout> |
| 108 | <AdvisorsLayout title="Linter">{page}</AdvisorsLayout> |
| 109 | </DefaultLayout> |
| 110 | ) |
| 111 | |
| 112 | export default ProjectLints |