From ef6e7b7e52ecaefaccac9efee63be4d1e51403a1 Mon Sep 17 00:00:00 2001 From: Francesco Sansalvadore Date: Fri, 27 Mar 2026 11:39:16 +0100 Subject: [PATCH] add pages to v2 --- .../[projectRef]/obs/advisors/page.tsx | 10 ++ .../obs/advisors/performance/page.tsx | 13 ++ .../obs/advisors/security/page.tsx | 7 ++ .../project/[projectRef]/obs/alerts/page.tsx | 4 +- .../[projectRef]/obs/logs/api/page.tsx | 23 +++- .../[projectRef]/obs/logs/auth/page.tsx | 12 +- .../[projectRef]/obs/logs/cron/page.tsx | 21 ++++ .../obs/logs/dedicated-pooler/page.tsx | 22 ++++ .../obs/logs/edge-functions/page.tsx | 21 ++++ .../v2/project/[projectRef]/obs/logs/page.tsx | 6 +- .../[projectRef]/obs/logs/pooler/page.tsx | 22 ++++ .../[projectRef]/obs/logs/postgres/page.tsx | 23 +++- .../[projectRef]/obs/logs/postgrest/page.tsx | 31 +++++ .../[projectRef]/obs/logs/realtime/page.tsx | 21 ++++ .../[projectRef]/obs/logs/storage/page.tsx | 21 ++++ .../{connections => api-overview}/page.tsx | 0 .../v2/project/[projectRef]/observe/page.tsx | 5 + .../[projectRef]/settings/api-keys/page.tsx | 4 +- .../settings/preferences/page.tsx | 5 + .../Advisors/AdvisorLintsPageContent.tsx | 114 ++++++++++++++++++ .../interfaces/Linter/LintPageTabs.tsx | 27 ++++- .../interfaces/Linter/LinterDataGrid.tsx | 41 +++++-- apps/studio/components/v2/ActivityBar.tsx | 2 +- apps/studio/components/v2/BrowserPanel.tsx | 39 +++--- apps/studio/components/v2/TopBar.tsx | 6 +- .../v2/views/V2AuthSettingsView.tsx | 23 ++-- .../project/[ref]/advisors/performance.tsx | 93 +------------- .../pages/project/[ref]/advisors/security.tsx | 99 +-------------- 28 files changed, 472 insertions(+), 243 deletions(-) create mode 100644 apps/studio/app/v2/project/[projectRef]/obs/advisors/page.tsx create mode 100644 apps/studio/app/v2/project/[projectRef]/obs/advisors/performance/page.tsx create mode 100644 apps/studio/app/v2/project/[projectRef]/obs/advisors/security/page.tsx create mode 100644 apps/studio/app/v2/project/[projectRef]/obs/logs/cron/page.tsx create mode 100644 apps/studio/app/v2/project/[projectRef]/obs/logs/dedicated-pooler/page.tsx create mode 100644 apps/studio/app/v2/project/[projectRef]/obs/logs/edge-functions/page.tsx create mode 100644 apps/studio/app/v2/project/[projectRef]/obs/logs/pooler/page.tsx create mode 100644 apps/studio/app/v2/project/[projectRef]/obs/logs/postgrest/page.tsx create mode 100644 apps/studio/app/v2/project/[projectRef]/obs/logs/realtime/page.tsx create mode 100644 apps/studio/app/v2/project/[projectRef]/obs/logs/storage/page.tsx rename apps/studio/app/v2/project/[projectRef]/obs/metrics/{connections => api-overview}/page.tsx (100%) create mode 100644 apps/studio/app/v2/project/[projectRef]/observe/page.tsx create mode 100644 apps/studio/app/v2/project/[projectRef]/settings/preferences/page.tsx create mode 100644 apps/studio/components/interfaces/Advisors/AdvisorLintsPageContent.tsx diff --git a/apps/studio/app/v2/project/[projectRef]/obs/advisors/page.tsx b/apps/studio/app/v2/project/[projectRef]/obs/advisors/page.tsx new file mode 100644 index 00000000000..d346508b08c --- /dev/null +++ b/apps/studio/app/v2/project/[projectRef]/obs/advisors/page.tsx @@ -0,0 +1,10 @@ +import { redirect } from 'next/navigation' + +export default async function ObsAdvisorsSecurityPage({ + params, +}: { + params: Promise<{ projectRef: string }> +}) { + const { projectRef } = await params + redirect(`/v2/project/${projectRef}/advisors/security`) +} diff --git a/apps/studio/app/v2/project/[projectRef]/obs/advisors/performance/page.tsx b/apps/studio/app/v2/project/[projectRef]/obs/advisors/performance/page.tsx new file mode 100644 index 00000000000..c57d5fc0a61 --- /dev/null +++ b/apps/studio/app/v2/project/[projectRef]/obs/advisors/performance/page.tsx @@ -0,0 +1,13 @@ +'use client' + +import { AdvisorLintsPageContent } from '@/components/interfaces/Advisors/AdvisorLintsPageContent' + +export default function ObsAdvisorsPerformancePage() { + return ( + + ) +} diff --git a/apps/studio/app/v2/project/[projectRef]/obs/advisors/security/page.tsx b/apps/studio/app/v2/project/[projectRef]/obs/advisors/security/page.tsx new file mode 100644 index 00000000000..3f98f178d4e --- /dev/null +++ b/apps/studio/app/v2/project/[projectRef]/obs/advisors/security/page.tsx @@ -0,0 +1,7 @@ +'use client' + +import { AdvisorLintsPageContent } from '@/components/interfaces/Advisors/AdvisorLintsPageContent' + +export default function ObsAdvisorsSecurityPage() { + return +} diff --git a/apps/studio/app/v2/project/[projectRef]/obs/alerts/page.tsx b/apps/studio/app/v2/project/[projectRef]/obs/alerts/page.tsx index 38bf2643be8..66b0f4b4e03 100644 --- a/apps/studio/app/v2/project/[projectRef]/obs/alerts/page.tsx +++ b/apps/studio/app/v2/project/[projectRef]/obs/alerts/page.tsx @@ -1,5 +1,5 @@ -import { V2PlaceholderView } from '@/components/v2/views/V2PlaceholderView' +import { redirect } from 'next/navigation' export default function ObsAlertsPage() { - return + redirect('./advisors/security') } diff --git a/apps/studio/app/v2/project/[projectRef]/obs/logs/api/page.tsx b/apps/studio/app/v2/project/[projectRef]/obs/logs/api/page.tsx index c6407030269..c707d888ee2 100644 --- a/apps/studio/app/v2/project/[projectRef]/obs/logs/api/page.tsx +++ b/apps/studio/app/v2/project/[projectRef]/obs/logs/api/page.tsx @@ -1,5 +1,24 @@ -import { V2PlaceholderView } from '@/components/v2/views/V2PlaceholderView' +'use client' + +import { LogsTableName } from '@/components/interfaces/Settings/Logs/Logs.constants' +import { LogsPreviewer } from '@/components/interfaces/Settings/Logs/LogsPreviewer' +import { useParams, useSearchParams } from 'next/navigation' export default function ObsLogsApiPage() { - return + const params = useParams() + const searchParams = useSearchParams() + const projectRef = params?.projectRef as string | undefined + const identifier = searchParams?.get('db') ?? undefined + + if (!projectRef) return null + + return ( + + ) } diff --git a/apps/studio/app/v2/project/[projectRef]/obs/logs/auth/page.tsx b/apps/studio/app/v2/project/[projectRef]/obs/logs/auth/page.tsx index 6228bfc536f..e00a8873c3f 100644 --- a/apps/studio/app/v2/project/[projectRef]/obs/logs/auth/page.tsx +++ b/apps/studio/app/v2/project/[projectRef]/obs/logs/auth/page.tsx @@ -1,5 +1,13 @@ -import { V2PlaceholderView } from '@/components/v2/views/V2PlaceholderView' +'use client' + +import { LogsPreviewer } from '@/components/interfaces/Settings/Logs/LogsPreviewer' +import { useParams } from 'next/navigation' export default function ObsLogsAuthPage() { - return + const params = useParams() + const projectRef = params?.projectRef as string | undefined + + if (!projectRef) return null + + return } diff --git a/apps/studio/app/v2/project/[projectRef]/obs/logs/cron/page.tsx b/apps/studio/app/v2/project/[projectRef]/obs/logs/cron/page.tsx new file mode 100644 index 00000000000..4817485a6da --- /dev/null +++ b/apps/studio/app/v2/project/[projectRef]/obs/logs/cron/page.tsx @@ -0,0 +1,21 @@ +'use client' + +import { LogsTableName } from '@/components/interfaces/Settings/Logs/Logs.constants' +import { LogsPreviewer } from '@/components/interfaces/Settings/Logs/LogsPreviewer' +import { useParams } from 'next/navigation' + +export default function ObsLogsCronPage() { + const params = useParams() + const projectRef = params?.projectRef as string | undefined + + if (!projectRef) return null + + return ( + + ) +} diff --git a/apps/studio/app/v2/project/[projectRef]/obs/logs/dedicated-pooler/page.tsx b/apps/studio/app/v2/project/[projectRef]/obs/logs/dedicated-pooler/page.tsx new file mode 100644 index 00000000000..8dea42f4017 --- /dev/null +++ b/apps/studio/app/v2/project/[projectRef]/obs/logs/dedicated-pooler/page.tsx @@ -0,0 +1,22 @@ +'use client' + +import { IS_PLATFORM } from 'common' +import { LogsTableName } from '@/components/interfaces/Settings/Logs/Logs.constants' +import { LogsPreviewer } from '@/components/interfaces/Settings/Logs/LogsPreviewer' +import { useParams } from 'next/navigation' + +export default function ObsLogsDedicatedPoolerPage() { + const params = useParams() + const projectRef = params?.projectRef as string | undefined + + if (!IS_PLATFORM || !projectRef) return null + + return ( + + ) +} diff --git a/apps/studio/app/v2/project/[projectRef]/obs/logs/edge-functions/page.tsx b/apps/studio/app/v2/project/[projectRef]/obs/logs/edge-functions/page.tsx new file mode 100644 index 00000000000..b30854dbf42 --- /dev/null +++ b/apps/studio/app/v2/project/[projectRef]/obs/logs/edge-functions/page.tsx @@ -0,0 +1,21 @@ +'use client' + +import { LogsTableName } from '@/components/interfaces/Settings/Logs/Logs.constants' +import { LogsPreviewer } from '@/components/interfaces/Settings/Logs/LogsPreviewer' +import { useParams } from 'next/navigation' + +export default function ObsLogsEdgeFunctionsPage() { + const params = useParams() + const projectRef = params?.projectRef as string | undefined + + if (!projectRef) return null + + return ( + + ) +} diff --git a/apps/studio/app/v2/project/[projectRef]/obs/logs/page.tsx b/apps/studio/app/v2/project/[projectRef]/obs/logs/page.tsx index fc548badbb0..eb40c84f25e 100644 --- a/apps/studio/app/v2/project/[projectRef]/obs/logs/page.tsx +++ b/apps/studio/app/v2/project/[projectRef]/obs/logs/page.tsx @@ -1,5 +1,5 @@ -import { V2PlaceholderView } from '@/components/v2/views/V2PlaceholderView' +import { redirect } from 'next/navigation' -export default function ObsLogsPage() { - return +export default function ObsLogsIndexPage() { + redirect('./logs/api') } diff --git a/apps/studio/app/v2/project/[projectRef]/obs/logs/pooler/page.tsx b/apps/studio/app/v2/project/[projectRef]/obs/logs/pooler/page.tsx new file mode 100644 index 00000000000..db3a7724768 --- /dev/null +++ b/apps/studio/app/v2/project/[projectRef]/obs/logs/pooler/page.tsx @@ -0,0 +1,22 @@ +'use client' + +import { IS_PLATFORM } from 'common' +import { LogsTableName } from '@/components/interfaces/Settings/Logs/Logs.constants' +import { LogsPreviewer } from '@/components/interfaces/Settings/Logs/LogsPreviewer' +import { useParams } from 'next/navigation' + +export default function ObsLogsPoolerPage() { + const params = useParams() + const projectRef = params?.projectRef as string | undefined + + if (!IS_PLATFORM || !projectRef) return null + + return ( + + ) +} diff --git a/apps/studio/app/v2/project/[projectRef]/obs/logs/postgres/page.tsx b/apps/studio/app/v2/project/[projectRef]/obs/logs/postgres/page.tsx index 45c70583532..a7a90bc6e04 100644 --- a/apps/studio/app/v2/project/[projectRef]/obs/logs/postgres/page.tsx +++ b/apps/studio/app/v2/project/[projectRef]/obs/logs/postgres/page.tsx @@ -1,5 +1,24 @@ -import { V2PlaceholderView } from '@/components/v2/views/V2PlaceholderView' +'use client' + +import { LogsTableName } from '@/components/interfaces/Settings/Logs/Logs.constants' +import { LogsPreviewer } from '@/components/interfaces/Settings/Logs/LogsPreviewer' +import { useParams, useSearchParams } from 'next/navigation' export default function ObsLogsPostgresPage() { - return + const params = useParams() + const searchParams = useSearchParams() + const projectRef = params?.projectRef as string | undefined + const identifier = searchParams?.get('db') ?? undefined + + if (!projectRef) return null + + return ( + + ) } diff --git a/apps/studio/app/v2/project/[projectRef]/obs/logs/postgrest/page.tsx b/apps/studio/app/v2/project/[projectRef]/obs/logs/postgrest/page.tsx new file mode 100644 index 00000000000..22d2cc498ac --- /dev/null +++ b/apps/studio/app/v2/project/[projectRef]/obs/logs/postgrest/page.tsx @@ -0,0 +1,31 @@ +'use client' + +import { LogsTableName } from '@/components/interfaces/Settings/Logs/Logs.constants' +import { LogsPreviewer } from '@/components/interfaces/Settings/Logs/LogsPreviewer' +import { LogsTableEmptyState } from '@/components/interfaces/Settings/Logs/LogsTableEmptyState' +import { useParams, useSearchParams } from 'next/navigation' + +export default function ObsLogsPostgrestPage() { + const params = useParams() + const searchParams = useSearchParams() + const projectRef = params?.projectRef as string | undefined + const identifier = searchParams?.get('db') ?? undefined + + if (!projectRef) return null + + return ( + + } + filterOverride={identifier ? { identifier } : undefined} + /> + ) +} diff --git a/apps/studio/app/v2/project/[projectRef]/obs/logs/realtime/page.tsx b/apps/studio/app/v2/project/[projectRef]/obs/logs/realtime/page.tsx new file mode 100644 index 00000000000..04f64069941 --- /dev/null +++ b/apps/studio/app/v2/project/[projectRef]/obs/logs/realtime/page.tsx @@ -0,0 +1,21 @@ +'use client' + +import { LogsTableName } from '@/components/interfaces/Settings/Logs/Logs.constants' +import { LogsPreviewer } from '@/components/interfaces/Settings/Logs/LogsPreviewer' +import { useParams } from 'next/navigation' + +export default function ObsLogsRealtimePage() { + const params = useParams() + const projectRef = params?.projectRef as string | undefined + + if (!projectRef) return null + + return ( + + ) +} diff --git a/apps/studio/app/v2/project/[projectRef]/obs/logs/storage/page.tsx b/apps/studio/app/v2/project/[projectRef]/obs/logs/storage/page.tsx new file mode 100644 index 00000000000..b2c7fa9ec81 --- /dev/null +++ b/apps/studio/app/v2/project/[projectRef]/obs/logs/storage/page.tsx @@ -0,0 +1,21 @@ +'use client' + +import { LogsTableName } from '@/components/interfaces/Settings/Logs/Logs.constants' +import { LogsPreviewer } from '@/components/interfaces/Settings/Logs/LogsPreviewer' +import { useParams } from 'next/navigation' + +export default function ObsLogsStoragePage() { + const params = useParams() + const projectRef = params?.projectRef as string | undefined + + if (!projectRef) return null + + return ( + + ) +} diff --git a/apps/studio/app/v2/project/[projectRef]/obs/metrics/connections/page.tsx b/apps/studio/app/v2/project/[projectRef]/obs/metrics/api-overview/page.tsx similarity index 100% rename from apps/studio/app/v2/project/[projectRef]/obs/metrics/connections/page.tsx rename to apps/studio/app/v2/project/[projectRef]/obs/metrics/api-overview/page.tsx diff --git a/apps/studio/app/v2/project/[projectRef]/observe/page.tsx b/apps/studio/app/v2/project/[projectRef]/observe/page.tsx new file mode 100644 index 00000000000..b871e4d010e --- /dev/null +++ b/apps/studio/app/v2/project/[projectRef]/observe/page.tsx @@ -0,0 +1,5 @@ +import { redirect } from 'next/navigation' + +export default function ObsLogsIndexPage() { + redirect('./obs/advisors/security') +} diff --git a/apps/studio/app/v2/project/[projectRef]/settings/api-keys/page.tsx b/apps/studio/app/v2/project/[projectRef]/settings/api-keys/page.tsx index 8c62569a565..32978a4fe73 100644 --- a/apps/studio/app/v2/project/[projectRef]/settings/api-keys/page.tsx +++ b/apps/studio/app/v2/project/[projectRef]/settings/api-keys/page.tsx @@ -1,5 +1,5 @@ import { V2PlaceholderView } from '@/components/v2/views/V2PlaceholderView' -export default function SettingsApiKeysPage() { - return +export default function SettingsPreferencesPage() { + return } diff --git a/apps/studio/app/v2/project/[projectRef]/settings/preferences/page.tsx b/apps/studio/app/v2/project/[projectRef]/settings/preferences/page.tsx new file mode 100644 index 00000000000..8c62569a565 --- /dev/null +++ b/apps/studio/app/v2/project/[projectRef]/settings/preferences/page.tsx @@ -0,0 +1,5 @@ +import { V2PlaceholderView } from '@/components/v2/views/V2PlaceholderView' + +export default function SettingsApiKeysPage() { + return +} diff --git a/apps/studio/components/interfaces/Advisors/AdvisorLintsPageContent.tsx b/apps/studio/components/interfaces/Advisors/AdvisorLintsPageContent.tsx new file mode 100644 index 00000000000..7a87dcdb2d4 --- /dev/null +++ b/apps/studio/components/interfaces/Advisors/AdvisorLintsPageContent.tsx @@ -0,0 +1,114 @@ +'use client' + +import { LINTER_LEVELS } from 'components/interfaces/Linter/Linter.constants' +import { lintInfoMap } from 'components/interfaces/Linter/Linter.utils' +import LinterDataGrid from 'components/interfaces/Linter/LinterDataGrid' +import LinterFilters from 'components/interfaces/Linter/LinterFilters' +import { LinterPageFooter } from 'components/interfaces/Linter/LinterPageFooter' +import LintPageTabs from 'components/interfaces/Linter/LintPageTabs' +import { FormHeader } from 'components/ui/Forms/FormHeader' +import { useProjectLintsQuery, type Lint } from 'data/lint/lint-query' +import { useSelectedProjectQuery } from 'hooks/misc/useSelectedProject' +import { DOCS_URL } from 'lib/constants' +import { useMemo, useState } from 'react' +import { useRouter as useCompatRouter } from 'next/compat/router' +import { useSearchParams } from 'next/navigation' +import { LoadingLine } from 'ui' + +type AdvisorCategory = 'SECURITY' | 'PERFORMANCE' + +interface AdvisorLintsPageContentProps { + category: AdvisorCategory + title: string + hideDbInspectCTA?: boolean + headerClassName?: string +} + +export function AdvisorLintsPageContent({ + category, + title, + hideDbInspectCTA, + headerClassName, +}: AdvisorLintsPageContentProps) { + const compatRouter = useCompatRouter() + const searchParams = useSearchParams() + const preset = (compatRouter?.query?.preset as string | undefined) ?? searchParams?.get('preset') ?? undefined + const id = (compatRouter?.query?.id as string | undefined) ?? searchParams?.get('id') ?? undefined + const { data: project } = useSelectedProjectQuery() + + const [filters, setFilters] = useState<{ level: LINTER_LEVELS; filters: string[] }[]>([ + { level: LINTER_LEVELS.ERROR, filters: [] }, + { level: LINTER_LEVELS.WARN, filters: [] }, + { level: LINTER_LEVELS.INFO, filters: [] }, + ]) + const [currentTab, setCurrentTab] = useState( + (preset as LINTER_LEVELS) ?? LINTER_LEVELS.ERROR + ) + const { + data, + isPending: isLoading, + isRefetching, + refetch, + } = useProjectLintsQuery({ + projectRef: project?.ref, + }) + + const activeLints = useMemo(() => { + return [...(data ?? [])].filter((x) => x.categories.includes(category)) + }, [data, category]) + + const currentTabFilters = (filters.find((filter) => filter.level === currentTab)?.filters || + []) as string[] + const filteredLints = activeLints + .filter((x) => x.level === currentTab) + .filter((x) => (currentTabFilters.length > 0 ? currentTabFilters.includes(x.name) : x)) + const filterOptions = lintInfoMap + .filter((item) => activeLints.some((lint) => lint.name === item.name && lint.level === currentTab)) + .map((type) => ({ + name: type.title, + value: type.name, + })) + + const selectedLint: Lint | null = useMemo(() => { + return activeLints.find((lint) => lint.cache_key === id) ?? null + }, [id, activeLints]) + + return ( +
+ + + + + + +
+ ) +} diff --git a/apps/studio/components/interfaces/Linter/LintPageTabs.tsx b/apps/studio/components/interfaces/Linter/LintPageTabs.tsx index 7a3b27d39ef..c78ee02f754 100644 --- a/apps/studio/components/interfaces/Linter/LintPageTabs.tsx +++ b/apps/studio/components/interfaces/Linter/LintPageTabs.tsx @@ -13,8 +13,9 @@ import { } from 'ui' import { LINTER_LEVELS, LINT_TABS } from 'components/interfaces/Linter/Linter.constants' -import { Lint } from 'data/lint/lint-query' -import { useRouter } from 'next/router' +import type { Lint } from 'data/lint/lint-query' +import { useRouter as useCompatRouter } from 'next/compat/router' +import { usePathname, useRouter as useAppRouter, useSearchParams } from 'next/navigation' import { ShimmeringLoader } from 'ui-patterns/ShimmeringLoader' interface LintPageTabsProps { @@ -24,7 +25,10 @@ interface LintPageTabsProps { activeLints: Lint[] } const LintPageTabs = ({ currentTab, setCurrentTab, isLoading, activeLints }: LintPageTabsProps) => { - const router = useRouter() + const compatRouter = useCompatRouter() + const appRouter = useAppRouter() + const pathname = usePathname() ?? '' + const searchParams = useSearchParams() const warnLintsCount = activeLints.filter((x) => x.level === 'WARN').length const errorLintsCount = activeLints.filter((x) => x.level === 'ERROR').length @@ -66,8 +70,21 @@ const LintPageTabs = ({ currentTab, setCurrentTab, isLoading, activeLints }: Lin defaultValue={currentTab} onValueChange={(value) => { setCurrentTab(value as LINTER_LEVELS) - const { sort, search, ...rest } = router.query - router.push({ ...router, query: { ...rest, preset: value, id: null } }) + if (compatRouter) { + const { sort: _sort, search: _search, ...rest } = compatRouter.query + void compatRouter.push({ + pathname: compatRouter.pathname ?? '/', + query: { ...rest, preset: value, id: null }, + }) + } else { + const next = new URLSearchParams(searchParams?.toString() ?? '') + next.delete('sort') + next.delete('search') + next.delete('id') + next.set('preset', value) + const qs = next.toString() + void appRouter.push(qs ? `${pathname}?${qs}` : pathname) + } }} > diff --git a/apps/studio/components/interfaces/Linter/LinterDataGrid.tsx b/apps/studio/components/interfaces/Linter/LinterDataGrid.tsx index a69ca95d9aa..f54ac17b347 100644 --- a/apps/studio/components/interfaces/Linter/LinterDataGrid.tsx +++ b/apps/studio/components/interfaces/Linter/LinterDataGrid.tsx @@ -1,17 +1,18 @@ import { useParams } from 'common' -import { LINTER_LEVELS } from 'components/interfaces/Linter/Linter.constants' +import type { LINTER_LEVELS } from 'components/interfaces/Linter/Linter.constants' import { LintCategoryBadge, LintEntity, lintInfoMap, NoIssuesFound, } from 'components/interfaces/Linter/Linter.utils' -import { Lint } from 'data/lint/lint-query' +import type { Lint } from 'data/lint/lint-query' import { useTrack } from 'lib/telemetry/track' import { X } from 'lucide-react' -import { useRouter } from 'next/router' +import { useRouter as useCompatRouter } from 'next/compat/router' +import { usePathname, useRouter as useAppRouter, useSearchParams } from 'next/navigation' import { useRef } from 'react' -import DataGrid, { Column, DataGridHandle, Row } from 'react-data-grid' +import DataGrid, { type Column, type DataGridHandle, Row } from 'react-data-grid' import ReactMarkdown from 'react-markdown' import { Button, cn, ResizableHandle, ResizablePanel, ResizablePanelGroup } from 'ui' import { GenericSkeletonLoader } from 'ui-patterns/ShimmeringLoader' @@ -34,7 +35,10 @@ const LinterDataGrid = ({ }: LinterDataGridProps) => { const gridRef = useRef(null) const { ref } = useParams() - const router = useRouter() + const compatRouter = useCompatRouter() + const appRouter = useAppRouter() + const pathname = usePathname() ?? '' + const searchParams = useSearchParams() const track = useTrack() const lintCols = [ @@ -111,8 +115,15 @@ const LinterDataGrid = ({ }) function handleSidepanelClose() { - const { id, ...otherParams } = router.query - router.push({ query: otherParams }) + if (compatRouter) { + const { id: _id, ...otherParams } = compatRouter.query + void compatRouter.push({ pathname: compatRouter.pathname ?? '/', query: otherParams }) + } else { + const next = new URLSearchParams(searchParams?.toString() ?? '') + next.delete('id') + const qs = next.toString() + void appRouter.push(qs ? `${pathname}?${qs}` : pathname) + } } return ( @@ -148,8 +159,18 @@ const LinterDataGrid = ({ onClick={() => { if (typeof idx === 'number' && idx >= 0) { gridRef.current?.scrollToCell({ idx: 0, rowIdx: idx }) - const { id, ...rest } = router.query - router.push({ ...router, query: { ...rest, id: props.row.cache_key } }) + if (compatRouter) { + const { id: _id, ...rest } = compatRouter.query + void compatRouter.push({ + pathname: compatRouter.pathname ?? '/', + query: { ...rest, id: props.row.cache_key }, + }) + } else { + const next = new URLSearchParams(searchParams?.toString() ?? '') + next.set('id', props.row.cache_key) + const qs = next.toString() + void appRouter.push(qs ? `${pathname}?${qs}` : pathname) + } track('advisor_detail_opened', { origin: 'advisors_page', @@ -192,7 +213,7 @@ const LinterDataGrid = ({ - - {renderedItems} - + {renderedItems} ) })} diff --git a/apps/studio/components/v2/TopBar.tsx b/apps/studio/components/v2/TopBar.tsx index 43481cd3255..ef14d8ca9af 100644 --- a/apps/studio/components/v2/TopBar.tsx +++ b/apps/studio/components/v2/TopBar.tsx @@ -1,5 +1,6 @@ 'use client' +import { FeedbackDropdown } from 'components/layouts/Navigation/LayoutHeader/FeedbackDropdown/FeedbackDropdown' import { cn } from 'ui' import { CommandMenuTriggerInput } from 'ui-patterns' @@ -12,7 +13,7 @@ export function TopBar() { 'h-11 md:h-12 flex items-center justify-between pl-1 pr-1.5 border-b border-border bg-dash-sidebar shrink-0' )} > -
+
@@ -21,6 +22,9 @@ export function TopBar() { className="text-foreground-lighter border border-border rounded px-2 py-1 text-xs" />
+
+ +
) } diff --git a/apps/studio/components/v2/views/V2AuthSettingsView.tsx b/apps/studio/components/v2/views/V2AuthSettingsView.tsx index c12d2bb26af..bdec93664dc 100644 --- a/apps/studio/components/v2/views/V2AuthSettingsView.tsx +++ b/apps/studio/components/v2/views/V2AuthSettingsView.tsx @@ -1,27 +1,26 @@ 'use client' -import { useMemo } from 'react' import { usePathname, useRouter, useSearchParams } from 'next/navigation' +import { useMemo } from 'react' +import type { NextPageWithLayout } from 'types' import { Tabs_Shadcn_, TabsContent_Shadcn_, TabsList_Shadcn_, TabsTrigger_Shadcn_ } from 'ui' import { useV2Params } from '@/app/v2/V2ParamsContext' import { BannerStackProvider } from '@/components/ui/BannerStack/BannerStackProvider' import { StudioDataWorkspace } from '@/components/v2/data/StudioDataWorkspace' - -import UrlConfigurationPage from '@/pages/project/[ref]/auth/url-configuration' -import ProtectionPage from '@/pages/project/[ref]/auth/protection' +import AuditLogsPage from '@/pages/project/[ref]/auth/audit-logs' +import HooksPage from '@/pages/project/[ref]/auth/hooks' import MfaPage from '@/pages/project/[ref]/auth/mfa' -import SessionsPage from '@/pages/project/[ref]/auth/sessions' +import OAuthServerPage from '@/pages/project/[ref]/auth/oauth-server' +import PerformancePage from '@/pages/project/[ref]/auth/performance' +import AuthPoliciesPage from '@/pages/project/[ref]/auth/policies' +import ProtectionPage from '@/pages/project/[ref]/auth/protection' import RateLimitsPage from '@/pages/project/[ref]/auth/rate-limits' +import SessionsPage from '@/pages/project/[ref]/auth/sessions' import SmtpPage from '@/pages/project/[ref]/auth/smtp' import TemplatesPage from '@/pages/project/[ref]/auth/templates' -import AuthPoliciesPage from '@/pages/project/[ref]/auth/policies' -import HooksPage from '@/pages/project/[ref]/auth/hooks' import ThirdPartyPage from '@/pages/project/[ref]/auth/third-party' -import OAuthServerPage from '@/pages/project/[ref]/auth/oauth-server' -import AuditLogsPage from '@/pages/project/[ref]/auth/audit-logs' -import PerformancePage from '@/pages/project/[ref]/auth/performance' -import type { NextPageWithLayout } from 'types' +import UrlConfigurationPage from '@/pages/project/[ref]/auth/url-configuration' const TABS: Array<{ key: string; label: string; content: NextPageWithLayout }> = [ { key: 'url', label: 'URL', content: UrlConfigurationPage }, @@ -64,7 +63,7 @@ export function V2AuthSettingsView() {
-
+
{TABS.map((tab) => ( { - const { preset, id } = useParams() - const { data: project } = useSelectedProjectQuery() - - // need to maintain a list of filters for each tab - const [filters, setFilters] = useState<{ level: LINTER_LEVELS; filters: string[] }[]>([ - { level: LINTER_LEVELS.ERROR, filters: [] }, - { level: LINTER_LEVELS.WARN, filters: [] }, - { level: LINTER_LEVELS.INFO, filters: [] }, - ]) - const [currentTab, setCurrentTab] = useState( - (preset as LINTER_LEVELS) ?? LINTER_LEVELS.ERROR - ) - const { - data, - isPending: isLoading, - isRefetching, - refetch, - } = useProjectLintsQuery({ - projectRef: project?.ref, - }) - - const activeLints = useMemo(() => { - return [...(data ?? [])]?.filter((x) => x.categories.includes('PERFORMANCE')) - }, [data]) - const currentTabFilters = (filters.find((filter) => filter.level === currentTab)?.filters || - []) as string[] - const filteredLints = activeLints - .filter((x) => x.level === currentTab) - .filter((x) => (currentTabFilters.length > 0 ? currentTabFilters.includes(x.name) : x)) - const filterOptions = lintInfoMap - // only show filters for lint types which are present in the results and not ignored - .filter((item) => - activeLints.some((lint) => lint.name === item.name && lint.level === currentTab) - ) - .map((type) => ({ - name: type.title, - value: type.name, - })) - - const selectedLint: Lint | null = useMemo(() => { - return activeLints.find((lint) => lint.cache_key === id) ?? null - }, [id, activeLints]) - return ( -
- - - - - - -
+ ) } diff --git a/apps/studio/pages/project/[ref]/advisors/security.tsx b/apps/studio/pages/project/[ref]/advisors/security.tsx index f58aa695d3d..597efc7466c 100644 --- a/apps/studio/pages/project/[ref]/advisors/security.tsx +++ b/apps/studio/pages/project/[ref]/advisors/security.tsx @@ -1,105 +1,10 @@ -import { useParams } from 'common' -import { LINTER_LEVELS } from 'components/interfaces/Linter/Linter.constants' -import { lintInfoMap } from 'components/interfaces/Linter/Linter.utils' -import LinterDataGrid from 'components/interfaces/Linter/LinterDataGrid' -import LinterFilters from 'components/interfaces/Linter/LinterFilters' -import { LinterPageFooter } from 'components/interfaces/Linter/LinterPageFooter' -import LintPageTabs from 'components/interfaces/Linter/LintPageTabs' +import { AdvisorLintsPageContent } from 'components/interfaces/Advisors/AdvisorLintsPageContent' import AdvisorsLayout from 'components/layouts/AdvisorsLayout/AdvisorsLayout' import DefaultLayout from 'components/layouts/DefaultLayout' -import { FormHeader } from 'components/ui/Forms/FormHeader' -import { Lint, useProjectLintsQuery } from 'data/lint/lint-query' -import { useSelectedProjectQuery } from 'hooks/misc/useSelectedProject' -import { DOCS_URL } from 'lib/constants' -import { useMemo, useState } from 'react' import type { NextPageWithLayout } from 'types' -import { LoadingLine } from 'ui' const ProjectLints: NextPageWithLayout = () => { - const { preset, id } = useParams() - const { data: project } = useSelectedProjectQuery() - - // need to maintain a list of filters for each tab - const [filters, setFilters] = useState<{ level: LINTER_LEVELS; filters: string[] }[]>([ - { level: LINTER_LEVELS.ERROR, filters: [] }, - { level: LINTER_LEVELS.WARN, filters: [] }, - { level: LINTER_LEVELS.INFO, filters: [] }, - ]) - const [currentTab, setCurrentTab] = useState( - (preset as LINTER_LEVELS) ?? LINTER_LEVELS.ERROR - ) - const { - data, - isPending: isLoading, - isRefetching, - refetch, - } = useProjectLintsQuery({ - projectRef: project?.ref, - }) - - const activeLints = (data ?? []).filter((lint) => lint.categories.includes('SECURITY')) - // hide vulnerable_postgres_version lint temporarily - // https://linear.app/supabase/project/pg-minor-version-upgrade-for-security-vulnerabilities-0124b2c2dcf5 - // https://github.com/supabase/supabase/pull/38280/files - //.filter((lint) => lint.name !== 'vulnerable_postgres_version') - - const currentTabFilters = (filters.find((filter) => filter.level === currentTab)?.filters || - []) as string[] - const filteredLints = activeLints - .filter((x) => x.level === currentTab) - .filter((x) => (currentTabFilters.length > 0 ? currentTabFilters.includes(x.name) : x)) - const filterOptions = lintInfoMap - // only show filters for lint types which are present in the results and not ignored - .filter((item) => - activeLints.some((lint) => lint.name === item.name && lint.level === currentTab) - ) - .map((type) => ({ - name: type.title, - value: type.name, - })) - - const selectedLint: Lint | null = useMemo(() => { - return activeLints.find((lint) => lint.cache_key === id) ?? null - }, [id, activeLints]) - - return ( -
- - - - - - -
- ) + return } ProjectLints.getLayout = (page) => (