mirror of
https://github.com/prowler-cloud/prowler.git
synced 2026-10-26 13:24:20 +00:00
145 lines
4.3 KiB
TypeScript
145 lines
4.3 KiB
TypeScript
"use client";
|
|
|
|
import { usePathname, useRouter, useSearchParams } from "next/navigation";
|
|
import { type ReactNode, useState } from "react";
|
|
|
|
import { MutedFindingsConfigButton } from "@/components/providers/muted-findings-config-button";
|
|
import {
|
|
Button,
|
|
Tabs,
|
|
TabsContent,
|
|
TabsList,
|
|
TabsTrigger,
|
|
} from "@/components/shadcn";
|
|
import {
|
|
LAUNCH_SCAN_SEARCH_PARAM,
|
|
LAUNCH_SCAN_SEARCH_VALUE,
|
|
} from "@/lib/scans-navigation";
|
|
import { useScansStore } from "@/store";
|
|
import { SCAN_JOBS_TAB, SCAN_TAB_LABELS, type ScanJobsTab } from "@/types";
|
|
import type { ProviderProps } from "@/types/providers";
|
|
|
|
import { CliImportBanner } from "./cli-import-banner";
|
|
import { LaunchScanModal } from "./launch-scan-modal";
|
|
import { ScansFilterBar } from "./scans-filter-bar";
|
|
import { useScansFilters } from "./use-scans-filters";
|
|
|
|
interface ScansPageShellProps {
|
|
providers: ProviderProps[];
|
|
hasManageScansPermission: boolean;
|
|
activeScanCount?: number;
|
|
children: ReactNode;
|
|
}
|
|
|
|
export function ScansPageShell({
|
|
providers,
|
|
hasManageScansPermission,
|
|
activeScanCount = 0,
|
|
children,
|
|
}: ScansPageShellProps) {
|
|
const router = useRouter();
|
|
const pathname = usePathname();
|
|
const searchParams = useSearchParams();
|
|
const [urlLaunchOpen, setUrlLaunchOpen] = useState(
|
|
() =>
|
|
searchParams.get(LAUNCH_SCAN_SEARCH_PARAM) === LAUNCH_SCAN_SEARCH_VALUE,
|
|
);
|
|
const isLaunchScanModalOpen = useScansStore(
|
|
(state) => state.isLaunchScanModalOpen,
|
|
);
|
|
const setLaunchScanModalOpen = useScansStore(
|
|
(state) => state.setLaunchScanModalOpen,
|
|
);
|
|
const filters = useScansFilters();
|
|
const hasConnectedProviders = providers.some(
|
|
(provider) => provider.attributes.connection.connected === true,
|
|
);
|
|
const isCloudEnvironment = process.env.NEXT_PUBLIC_IS_CLOUD_ENV === "true";
|
|
const launchDisabled = !hasManageScansPermission || !hasConnectedProviders;
|
|
const launchOpen = isLaunchScanModalOpen || urlLaunchOpen;
|
|
|
|
const getTabLabel = (tab: ScanJobsTab) => {
|
|
const label = SCAN_TAB_LABELS[tab];
|
|
if (tab !== SCAN_JOBS_TAB.ACTIVE) return label;
|
|
|
|
return `${label} (${activeScanCount})`;
|
|
};
|
|
|
|
const handleLaunchOpenChange = (open: boolean) => {
|
|
setLaunchScanModalOpen(open);
|
|
if (open) return;
|
|
setUrlLaunchOpen(false);
|
|
if (!searchParams.has(LAUNCH_SCAN_SEARCH_PARAM)) return;
|
|
const params = new URLSearchParams(searchParams.toString());
|
|
params.delete(LAUNCH_SCAN_SEARCH_PARAM);
|
|
const query = params.toString();
|
|
router.replace(query ? `${pathname}?${query}` : pathname, {
|
|
scroll: false,
|
|
});
|
|
};
|
|
|
|
return (
|
|
<div className="flex flex-col gap-[18px]">
|
|
<div
|
|
role="group"
|
|
aria-label="Scan filters and actions"
|
|
className="flex flex-wrap items-center gap-3"
|
|
>
|
|
<ScansFilterBar
|
|
providers={providers}
|
|
activeTab={filters.activeTab}
|
|
scheduleType={filters.scheduleType}
|
|
scanStatus={filters.scanStatus}
|
|
showStatusFilter={filters.showStatusFilter}
|
|
onScheduleTypeChange={filters.setScheduleType}
|
|
onScanStatusChange={filters.setScanStatus}
|
|
/>
|
|
|
|
<Button
|
|
type="button"
|
|
size="lg"
|
|
onClick={() => handleLaunchOpenChange(true)}
|
|
disabled={launchDisabled}
|
|
className="w-full md:w-auto"
|
|
>
|
|
Launch Scan
|
|
</Button>
|
|
</div>
|
|
|
|
{isCloudEnvironment && <CliImportBanner />}
|
|
|
|
<Tabs
|
|
value={filters.activeTab}
|
|
onValueChange={filters.setTab}
|
|
className="flex flex-col gap-[18px]"
|
|
>
|
|
<div
|
|
role="group"
|
|
aria-label="Scan tabs"
|
|
className="flex flex-col gap-3 sm:flex-row sm:items-center sm:justify-between"
|
|
>
|
|
<TabsList className="overflow-x-auto">
|
|
{Object.values(SCAN_JOBS_TAB).map((tab) => (
|
|
<TabsTrigger key={tab} value={tab}>
|
|
{getTabLabel(tab as ScanJobsTab)}
|
|
</TabsTrigger>
|
|
))}
|
|
</TabsList>
|
|
<div className="shrink-0">
|
|
<MutedFindingsConfigButton />
|
|
</div>
|
|
</div>
|
|
<TabsContent value={filters.activeTab} className="mt-0">
|
|
{children}
|
|
</TabsContent>
|
|
</Tabs>
|
|
|
|
<LaunchScanModal
|
|
open={launchOpen}
|
|
onOpenChange={handleLaunchOpenChange}
|
|
providers={providers}
|
|
/>
|
|
</div>
|
|
);
|
|
}
|