Compare commits

...

3 Commits

Author SHA1 Message Date
sumit_chaturvedi
fc1337a4e6 Merge branch 'master' into PRWLR-7732-add-mutelist-menu-item 2025-08-05 09:03:14 +05:30
sumit_chaturvedi
71b5f3714c docs: changelog update 2025-08-04 19:58:00 +05:30
sumit_chaturvedi
ae697d838c feat(ui): add mutelist menu item under configuration to link to cloud providers 2025-08-04 19:44:19 +05:30
5 changed files with 44 additions and 24 deletions

View File

@@ -10,6 +10,7 @@ All notable changes to the **Prowler UI** are documented in this file.
- Amazon AWS S3 integration [(#8391)](https://github.com/prowler-cloud/prowler/pull/8391)
- Github provider support [(#8405)](https://github.com/prowler-cloud/prowler/pull/8405)
- XML validation for SAML metadata in the UI [(#8429)](https://github.com/prowler-cloud/prowler/pull/8429)
- Mutelist menu item under Configuration [(#8440)](https://github.com/prowler-cloud/prowler/pull/8440)
### 🔄 Changed

View File

@@ -1,4 +1,5 @@
import { Spacer } from "@nextui-org/react";
import { redirect } from "next/navigation";
import { Suspense } from "react";
import { getProviders } from "@/actions/providers";
@@ -23,19 +24,27 @@ export default async function Providers({
}) {
const searchParamsKey = JSON.stringify(searchParams || {});
const providersData = await getProviders({});
const hasProviders = providersData?.data && providersData.data.length > 0;
// If modal=mutelist is present but no providers, redirect
if (searchParams.modal === "mutelist" && !hasProviders) {
redirect("/providers");
}
return (
<ContentLayout title="Cloud Providers" icon="fluent:cloud-sync-24-regular">
<FilterControls search customFilters={filterProviders || []} />
<Spacer y={8} />
<div className="flex items-center gap-4 md:justify-end">
<ManageGroupsButton />
<MutedFindingsConfigButton isDisabled={!hasProviders} />
<AddProviderButton />
</div>
<Suspense
key={searchParamsKey}
fallback={
<>
<div className="flex items-center gap-4 md:justify-end">
<ManageGroupsButton />
<MutedFindingsConfigButton isDisabled={true} />
<AddProviderButton />
</div>
<Spacer y={8} />
<div className="grid grid-cols-12 gap-4">
<div className="col-span-12">
@@ -76,8 +85,6 @@ const ProvidersContent = async ({
pageSize,
});
const hasProviders = providersData?.data && providersData.data.length > 0;
const providerGroupDict =
providersData?.included
?.filter((item: any) => item.type === "provider-groups")
@@ -98,11 +105,6 @@ const ProvidersContent = async ({
return (
<>
<div className="flex items-center gap-4 md:justify-end">
<ManageGroupsButton />
<MutedFindingsConfigButton isDisabled={!hasProviders} />
<AddProviderButton />
</div>
<Spacer y={8} />
<div className="grid grid-cols-12 gap-4">

View File

@@ -1,7 +1,7 @@
"use client";
import { Textarea } from "@nextui-org/react";
import { Dispatch, SetStateAction, useEffect, useState } from "react";
import { useEffect, useState } from "react";
import { useFormState } from "react-dom";
import {
@@ -23,11 +23,11 @@ import {
} from "@/types/processors";
interface MutedFindingsConfigFormProps {
setIsOpen: Dispatch<SetStateAction<boolean>>;
onCancel: () => void;
}
export const MutedFindingsConfigForm = ({
setIsOpen,
onCancel,
}: MutedFindingsConfigFormProps) => {
const [config, setConfig] = useState<ProcessorData | null>(null);
const [configText, setConfigText] = useState("");
@@ -64,7 +64,7 @@ export const MutedFindingsConfigForm = ({
title: "Configuration saved successfully",
description: state.success,
});
setIsOpen(false);
onCancel();
} else if (state?.errors?.general) {
toast({
variant: "destructive",
@@ -75,7 +75,7 @@ export const MutedFindingsConfigForm = ({
// Reset typing state when there are new server errors
setHasUserStartedTyping(false);
}
}, [state, toast, setIsOpen]);
}, [state, toast, onCancel]);
const handleConfigChange = (value: string) => {
setConfigText(value);
@@ -100,7 +100,7 @@ export const MutedFindingsConfigForm = ({
title: "Configuration deleted successfully",
description: result.success,
});
setIsOpen(false);
onCancel();
} else if (result?.errors?.general) {
toast({
variant: "destructive",
@@ -232,7 +232,8 @@ export const MutedFindingsConfigForm = ({
<div className="flex flex-col space-y-4">
<FormButtons
setIsOpen={setIsOpen}
setIsOpen={() => {}}
onCancel={onCancel}
submitText={config ? "Update" : "Save"}
isDisabled={!yamlValidation.isValid || !configText.trim()}
/>

View File

@@ -1,7 +1,7 @@
"use client";
import { SettingsIcon } from "lucide-react";
import { useState } from "react";
import { useSearchParams } from "next/navigation";
import { CustomAlertModal, CustomButton } from "@/components/ui/custom";
@@ -14,23 +14,33 @@ interface MutedFindingsConfigButtonProps {
export const MutedFindingsConfigButton = ({
isDisabled = false,
}: MutedFindingsConfigButtonProps) => {
const [isOpen, setIsOpen] = useState(false);
const searchParams = useSearchParams();
const isOpen = searchParams.get("modal") === "mutelist";
const handleOpenModal = () => {
if (!isDisabled) {
setIsOpen(true);
const params = new URLSearchParams(window.location.search);
params.set("modal", "mutelist");
window.history.pushState({}, "", `?${params.toString()}`);
}
};
const handleModalClose = () => {
const params = new URLSearchParams(window.location.search);
params.delete("modal");
window.history.pushState({}, "", `?${params.toString()}`);
};
return (
<>
<CustomAlertModal
isOpen={isOpen}
onOpenChange={setIsOpen}
onOpenChange={handleModalClose}
title="Configure Mutelist"
size="3xl"
>
<MutedFindingsConfigForm setIsOpen={setIsOpen} />
<MutedFindingsConfigForm onCancel={handleModalClose} />
</CustomAlertModal>
<CustomButton

View File

@@ -30,6 +30,7 @@ import {
KubernetesIcon,
LighthouseIcon,
M365Icon,
MutedIcon,
SupportIcon,
} from "@/components/icons/Icons";
import { GroupProps } from "@/types";
@@ -151,6 +152,11 @@ export const getMenuList = (pathname: string): GroupProps[] => {
{ href: "/integrations", label: "Integrations", icon: Puzzle },
{ href: "/roles", label: "Roles", icon: UserCog },
{ href: "/lighthouse/config", label: "Lighthouse AI", icon: Cog },
{
href: "/providers?modal=mutelist",
label: "Mutelist",
icon: MutedIcon,
},
],
defaultOpen: true,
},