mirror of
https://github.com/prowler-cloud/prowler.git
synced 2026-07-23 12:31:54 +00:00
feat(ui): add search bar inside Connect a Cloud Provider
This commit is contained in:
@@ -1,7 +1,9 @@
|
||||
"use client";
|
||||
|
||||
import { Input } from "@heroui/input";
|
||||
import { RadioGroup } from "@heroui/radio";
|
||||
import { FC } from "react";
|
||||
import { SearchIcon, XCircle } from "lucide-react";
|
||||
import { FC, useState } from "react";
|
||||
import { Control, Controller } from "react-hook-form";
|
||||
import { z } from "zod";
|
||||
|
||||
@@ -22,6 +24,59 @@ import {
|
||||
import { CustomRadio } from "../ui/custom";
|
||||
import { FormMessage } from "../ui/form";
|
||||
|
||||
const PROVIDERS = [
|
||||
{
|
||||
value: "aws",
|
||||
label: "Amazon Web Services",
|
||||
badge: AWSProviderBadge,
|
||||
},
|
||||
{
|
||||
value: "gcp",
|
||||
label: "Google Cloud Platform",
|
||||
badge: GCPProviderBadge,
|
||||
},
|
||||
{
|
||||
value: "azure",
|
||||
label: "Microsoft Azure",
|
||||
badge: AzureProviderBadge,
|
||||
},
|
||||
{
|
||||
value: "m365",
|
||||
label: "Microsoft 365",
|
||||
badge: M365ProviderBadge,
|
||||
},
|
||||
{
|
||||
value: "mongodbatlas",
|
||||
label: "MongoDB Atlas",
|
||||
badge: MongoDBAtlasProviderBadge,
|
||||
},
|
||||
{
|
||||
value: "kubernetes",
|
||||
label: "Kubernetes",
|
||||
badge: KS8ProviderBadge,
|
||||
},
|
||||
{
|
||||
value: "github",
|
||||
label: "GitHub",
|
||||
badge: GitHubProviderBadge,
|
||||
},
|
||||
{
|
||||
value: "iac",
|
||||
label: "Infrastructure as Code",
|
||||
badge: IacProviderBadge,
|
||||
},
|
||||
{
|
||||
value: "oraclecloud",
|
||||
label: "Oracle Cloud Infrastructure",
|
||||
badge: OracleCloudProviderBadge,
|
||||
},
|
||||
{
|
||||
value: "alibabacloud",
|
||||
label: "Alibaba Cloud",
|
||||
badge: AlibabaCloudProviderBadge,
|
||||
},
|
||||
] as const;
|
||||
|
||||
interface RadioGroupProviderProps {
|
||||
control: Control<z.infer<typeof addProviderFormSchema>>;
|
||||
isInvalid: boolean;
|
||||
@@ -33,12 +88,55 @@ export const RadioGroupProvider: FC<RadioGroupProviderProps> = ({
|
||||
isInvalid,
|
||||
errorMessage,
|
||||
}) => {
|
||||
const [searchTerm, setSearchTerm] = useState("");
|
||||
|
||||
const lowerSearch = searchTerm.trim().toLowerCase();
|
||||
const filteredProviders = lowerSearch
|
||||
? PROVIDERS.filter(
|
||||
(provider) =>
|
||||
provider.label.toLowerCase().includes(lowerSearch) ||
|
||||
provider.value.toLowerCase().includes(lowerSearch),
|
||||
)
|
||||
: PROVIDERS;
|
||||
|
||||
return (
|
||||
<Controller
|
||||
name="providerType"
|
||||
control={control}
|
||||
render={({ field }) => (
|
||||
<>
|
||||
<div className="flex flex-col gap-4">
|
||||
<Input
|
||||
aria-label="Search providers"
|
||||
placeholder="Search providers..."
|
||||
value={searchTerm}
|
||||
onChange={(e) => setSearchTerm(e.target.value)}
|
||||
startContent={
|
||||
<SearchIcon
|
||||
className="text-bg-button-secondary shrink-0"
|
||||
width={16}
|
||||
/>
|
||||
}
|
||||
endContent={
|
||||
searchTerm && (
|
||||
<button
|
||||
type="button"
|
||||
aria-label="Clear search"
|
||||
onClick={() => setSearchTerm("")}
|
||||
className="text-bg-button-secondary shrink-0 focus:outline-none"
|
||||
>
|
||||
<XCircle className="h-4 w-4" />
|
||||
</button>
|
||||
)
|
||||
}
|
||||
classNames={{
|
||||
base: "w-full",
|
||||
input:
|
||||
"text-bg-button-secondary placeholder:text-bg-button-secondary text-sm",
|
||||
inputWrapper:
|
||||
"!border-border-input-primary !bg-bg-input-primary dark:!bg-input/30 dark:hover:!bg-input/50 hover:!bg-bg-neutral-secondary !border !rounded-lg !shadow-xs !transition-[color,box-shadow] focus-within:!border-border-input-primary-press focus-within:!ring-1 focus-within:!ring-border-input-primary-press focus-within:!ring-offset-1 !h-10 !px-4 !py-3 !outline-none",
|
||||
}}
|
||||
/>
|
||||
|
||||
<RadioGroup
|
||||
className="flex flex-wrap"
|
||||
isInvalid={isInvalid}
|
||||
@@ -46,77 +144,36 @@ export const RadioGroupProvider: FC<RadioGroupProviderProps> = ({
|
||||
value={field.value || ""}
|
||||
>
|
||||
<div className="flex flex-col gap-4">
|
||||
<CustomRadio description="Amazon Web Services" value="aws">
|
||||
<div className="flex items-center">
|
||||
<AWSProviderBadge size={26} />
|
||||
<span className="ml-2">Amazon Web Services</span>
|
||||
</div>
|
||||
</CustomRadio>
|
||||
<CustomRadio description="Google Cloud Platform" value="gcp">
|
||||
<div className="flex items-center">
|
||||
<GCPProviderBadge size={26} />
|
||||
<span className="ml-2">Google Cloud Platform</span>
|
||||
</div>
|
||||
</CustomRadio>
|
||||
<CustomRadio description="Microsoft Azure" value="azure">
|
||||
<div className="flex items-center">
|
||||
<AzureProviderBadge size={26} />
|
||||
<span className="ml-2">Microsoft Azure</span>
|
||||
</div>
|
||||
</CustomRadio>
|
||||
<CustomRadio description="Microsoft 365" value="m365">
|
||||
<div className="flex items-center">
|
||||
<M365ProviderBadge size={26} />
|
||||
<span className="ml-2">Microsoft 365</span>
|
||||
</div>
|
||||
</CustomRadio>
|
||||
<CustomRadio description="MongoDB Atlas" value="mongodbatlas">
|
||||
<div className="flex items-center">
|
||||
<MongoDBAtlasProviderBadge size={26} />
|
||||
<span className="ml-2">MongoDB Atlas</span>
|
||||
</div>
|
||||
</CustomRadio>
|
||||
<CustomRadio description="Kubernetes" value="kubernetes">
|
||||
<div className="flex items-center">
|
||||
<KS8ProviderBadge size={26} />
|
||||
<span className="ml-2">Kubernetes</span>
|
||||
</div>
|
||||
</CustomRadio>
|
||||
<CustomRadio description="GitHub" value="github">
|
||||
<div className="flex items-center">
|
||||
<GitHubProviderBadge size={26} />
|
||||
<span className="ml-2">GitHub</span>
|
||||
</div>
|
||||
</CustomRadio>
|
||||
<CustomRadio description="Infrastructure as Code" value="iac">
|
||||
<div className="flex items-center">
|
||||
<IacProviderBadge size={26} />
|
||||
<span className="ml-2">Infrastructure as Code</span>
|
||||
</div>
|
||||
</CustomRadio>
|
||||
<CustomRadio
|
||||
description="Oracle Cloud Infrastructure"
|
||||
value="oraclecloud"
|
||||
>
|
||||
<div className="flex items-center">
|
||||
<OracleCloudProviderBadge size={26} />
|
||||
<span className="ml-2">Oracle Cloud Infrastructure</span>
|
||||
</div>
|
||||
</CustomRadio>
|
||||
<CustomRadio description="Alibaba Cloud" value="alibabacloud">
|
||||
<div className="flex items-center">
|
||||
<AlibabaCloudProviderBadge size={26} />
|
||||
<span className="ml-2">Alibaba Cloud</span>
|
||||
</div>
|
||||
</CustomRadio>
|
||||
{filteredProviders.length > 0 ? (
|
||||
filteredProviders.map((provider) => {
|
||||
const BadgeComponent = provider.badge;
|
||||
return (
|
||||
<CustomRadio
|
||||
key={provider.value}
|
||||
description={provider.label}
|
||||
value={provider.value}
|
||||
>
|
||||
<div className="flex items-center">
|
||||
<BadgeComponent size={26} />
|
||||
<span className="ml-2">{provider.label}</span>
|
||||
</div>
|
||||
</CustomRadio>
|
||||
);
|
||||
})
|
||||
) : (
|
||||
<p className="text-default-500 py-4 text-sm">
|
||||
No providers found matching "{searchTerm}"
|
||||
</p>
|
||||
)}
|
||||
</div>
|
||||
</RadioGroup>
|
||||
|
||||
{errorMessage && (
|
||||
<FormMessage className="text-text-error">
|
||||
{errorMessage}
|
||||
</FormMessage>
|
||||
)}
|
||||
</>
|
||||
</div>
|
||||
)}
|
||||
/>
|
||||
);
|
||||
|
||||
Reference in New Issue
Block a user