chore(ui): Merge UI repository
No files matched your search
@@ -0,0 +1,82 @@
|
||||
"use client";
|
||||
|
||||
import { SwitchProps, useSwitch } from "@nextui-org/react";
|
||||
import { useIsSSR } from "@react-aria/ssr";
|
||||
import { VisuallyHidden } from "@react-aria/visually-hidden";
|
||||
import clsx from "clsx";
|
||||
import { useTheme } from "next-themes";
|
||||
import { FC } from "react";
|
||||
import React from "react";
|
||||
|
||||
import { MoonFilledIcon, SunFilledIcon } from "./icons";
|
||||
|
||||
export interface ThemeSwitchProps {
|
||||
className?: string;
|
||||
classNames?: SwitchProps["classNames"];
|
||||
}
|
||||
|
||||
export const ThemeSwitch: FC<ThemeSwitchProps> = ({
|
||||
className,
|
||||
classNames,
|
||||
}) => {
|
||||
const { theme, setTheme } = useTheme();
|
||||
const isSSR = useIsSSR();
|
||||
|
||||
const onChange = () => {
|
||||
theme === "light" ? setTheme("dark") : setTheme("light");
|
||||
};
|
||||
|
||||
const {
|
||||
Component,
|
||||
slots,
|
||||
isSelected,
|
||||
getBaseProps,
|
||||
getInputProps,
|
||||
getWrapperProps,
|
||||
} = useSwitch({
|
||||
isSelected: theme === "light" || isSSR,
|
||||
"aria-label": `Switch to ${theme === "light" || isSSR ? "dark" : "light"} mode`,
|
||||
onChange,
|
||||
});
|
||||
|
||||
return (
|
||||
<Component
|
||||
{...getBaseProps({
|
||||
className: clsx(
|
||||
"px-px transition-opacity hover:opacity-80 cursor-pointer",
|
||||
className,
|
||||
classNames?.base,
|
||||
),
|
||||
})}
|
||||
>
|
||||
<VisuallyHidden>
|
||||
<input {...getInputProps()} />
|
||||
</VisuallyHidden>
|
||||
<div
|
||||
{...getWrapperProps()}
|
||||
className={slots.wrapper({
|
||||
class: clsx(
|
||||
[
|
||||
"h-auto w-auto",
|
||||
"bg-transparent",
|
||||
"rounded-lg",
|
||||
"flex items-center justify-center",
|
||||
"group-data-[selected=true]:bg-transparent",
|
||||
"!text-default-500",
|
||||
"pt-px",
|
||||
"px-0",
|
||||
"mx-0",
|
||||
],
|
||||
classNames?.wrapper,
|
||||
),
|
||||
})}
|
||||
>
|
||||
{!isSelected || isSSR ? (
|
||||
<SunFilledIcon size={22} />
|
||||
) : (
|
||||
<MoonFilledIcon size={22} />
|
||||
)}
|
||||
</div>
|
||||
</Component>
|
||||
);
|
||||
};
|
||||
@@ -0,0 +1,318 @@
|
||||
"use client";
|
||||
|
||||
import { zodResolver } from "@hookform/resolvers/zod";
|
||||
import { Icon } from "@iconify/react";
|
||||
import { Button, Checkbox, Divider, Link } from "@nextui-org/react";
|
||||
import { useRouter } from "next/navigation";
|
||||
import { useForm } from "react-hook-form";
|
||||
import { z } from "zod";
|
||||
|
||||
import { authenticate, createNewUser } from "@/actions/auth";
|
||||
import { NotificationIcon, ProwlerExtended } from "@/components/icons";
|
||||
import { ThemeSwitch } from "@/components/ThemeSwitch";
|
||||
import { useToast } from "@/components/ui";
|
||||
import { CustomButton, CustomInput } from "@/components/ui/custom";
|
||||
import {
|
||||
Form,
|
||||
FormControl,
|
||||
FormField,
|
||||
FormMessage,
|
||||
} from "@/components/ui/form";
|
||||
import { ApiError, authFormSchema } from "@/types";
|
||||
|
||||
export const AuthForm = ({
|
||||
type,
|
||||
invitationToken,
|
||||
}: {
|
||||
type: string;
|
||||
invitationToken?: string | null;
|
||||
}) => {
|
||||
const formSchema = authFormSchema(type);
|
||||
const router = useRouter();
|
||||
|
||||
const form = useForm<z.infer<typeof formSchema>>({
|
||||
resolver: zodResolver(formSchema),
|
||||
defaultValues: {
|
||||
email: "",
|
||||
password: "",
|
||||
...(type === "sign-up" && {
|
||||
name: "",
|
||||
company: "",
|
||||
termsAndConditions: false,
|
||||
confirmPassword: "",
|
||||
...(invitationToken && { invitationToken }),
|
||||
}),
|
||||
},
|
||||
});
|
||||
|
||||
const isLoading = form.formState.isSubmitting;
|
||||
const { toast } = useToast();
|
||||
|
||||
const onSubmit = async (data: z.infer<typeof formSchema>) => {
|
||||
if (type === "sign-in") {
|
||||
const result = await authenticate(null, {
|
||||
email: data.email.toLowerCase(),
|
||||
password: data.password,
|
||||
});
|
||||
|
||||
if (result?.message === "Success") {
|
||||
router.push("/");
|
||||
} else if (result?.errors && "credentials" in result.errors) {
|
||||
form.setError("email", {
|
||||
type: "server",
|
||||
message: result.errors.credentials ?? "Incorrect email or password",
|
||||
});
|
||||
} else {
|
||||
toast({
|
||||
variant: "destructive",
|
||||
title: "Oops! Something went wrong",
|
||||
description: "An unexpected error occurred. Please try again.",
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
if (type === "sign-up") {
|
||||
const newUser = await createNewUser(data);
|
||||
|
||||
if (!newUser.errors) {
|
||||
toast({
|
||||
title: "Success!",
|
||||
description: "The user was registered successfully.",
|
||||
});
|
||||
form.reset();
|
||||
router.push("/sign-in");
|
||||
} else {
|
||||
newUser.errors.forEach((error: ApiError) => {
|
||||
const errorMessage = error.detail;
|
||||
switch (error.source.pointer) {
|
||||
case "/data/attributes/name":
|
||||
form.setError("name", { type: "server", message: errorMessage });
|
||||
break;
|
||||
case "/data/attributes/email":
|
||||
form.setError("email", { type: "server", message: errorMessage });
|
||||
break;
|
||||
case "/data/attributes/company_name":
|
||||
form.setError("company", {
|
||||
type: "server",
|
||||
message: errorMessage,
|
||||
});
|
||||
break;
|
||||
case "/data/attributes/password":
|
||||
form.setError("password", {
|
||||
type: "server",
|
||||
message: errorMessage,
|
||||
});
|
||||
break;
|
||||
case "/data":
|
||||
form.setError("invitationToken", {
|
||||
type: "server",
|
||||
message: errorMessage,
|
||||
});
|
||||
break;
|
||||
default:
|
||||
toast({
|
||||
variant: "destructive",
|
||||
title: "Oops! Something went wrong",
|
||||
description: errorMessage,
|
||||
});
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
return (
|
||||
<div className="relative flex h-screen w-screen">
|
||||
{/* Auth Form */}
|
||||
<div className="relative flex w-full items-center justify-center lg:w-full">
|
||||
{/* Background Pattern */}
|
||||
<div className="absolute h-full w-full bg-[radial-gradient(#6af400_1px,transparent_1px)] [background-size:16px_16px] [mask-image:radial-gradient(ellipse_50%_50%_at_50%_50%,#000_10%,transparent_80%)]"></div>
|
||||
|
||||
<div className="relative z-10 flex w-full max-w-sm flex-col gap-4 rounded-large border-1 border-divider bg-white/90 px-8 py-10 shadow-small dark:bg-background/85 md:max-w-md">
|
||||
{/* Prowler Logo */}
|
||||
<div className="absolute -top-[100px] left-1/2 z-10 flex h-fit w-fit -translate-x-1/2">
|
||||
<ProwlerExtended width={300} />
|
||||
</div>
|
||||
<div className="flex items-center justify-between">
|
||||
<p className="pb-2 text-xl font-medium">
|
||||
{type === "sign-in" ? "Sign In" : "Sign Up"}
|
||||
</p>
|
||||
<ThemeSwitch aria-label="Toggle theme" />
|
||||
</div>
|
||||
|
||||
<Form {...form}>
|
||||
<form
|
||||
className="flex flex-col gap-3"
|
||||
onSubmit={form.handleSubmit(onSubmit)}
|
||||
>
|
||||
{type === "sign-up" && (
|
||||
<>
|
||||
<CustomInput
|
||||
control={form.control}
|
||||
name="name"
|
||||
type="text"
|
||||
label="Name"
|
||||
placeholder="Enter your name"
|
||||
isInvalid={!!form.formState.errors.name}
|
||||
/>
|
||||
<CustomInput
|
||||
control={form.control}
|
||||
name="company"
|
||||
type="text"
|
||||
label="Company Name"
|
||||
placeholder="Enter your company name"
|
||||
isRequired={false}
|
||||
isInvalid={!!form.formState.errors.company}
|
||||
/>
|
||||
</>
|
||||
)}
|
||||
<CustomInput
|
||||
control={form.control}
|
||||
name="email"
|
||||
type="email"
|
||||
label="Email"
|
||||
placeholder="Enter your email"
|
||||
isInvalid={!!form.formState.errors.email}
|
||||
/>
|
||||
|
||||
<CustomInput
|
||||
control={form.control}
|
||||
name="password"
|
||||
password
|
||||
isInvalid={!!form.formState.errors.password}
|
||||
/>
|
||||
|
||||
{type === "sign-in" && (
|
||||
<div className="flex items-center justify-between px-1 py-2">
|
||||
<Checkbox name="remember" size="sm">
|
||||
Remember me
|
||||
</Checkbox>
|
||||
<Link className="text-default-500" href="#">
|
||||
Forgot password?
|
||||
</Link>
|
||||
</div>
|
||||
)}
|
||||
{type === "sign-up" && (
|
||||
<>
|
||||
<CustomInput
|
||||
control={form.control}
|
||||
name="confirmPassword"
|
||||
confirmPassword
|
||||
/>
|
||||
{invitationToken && (
|
||||
<CustomInput
|
||||
control={form.control}
|
||||
name="invitationToken"
|
||||
type="text"
|
||||
label="Invitation Token"
|
||||
placeholder={invitationToken}
|
||||
defaultValue={invitationToken}
|
||||
isRequired={false}
|
||||
isInvalid={!!form.formState.errors.invitationToken}
|
||||
/>
|
||||
)}
|
||||
<FormField
|
||||
control={form.control}
|
||||
name="termsAndConditions"
|
||||
render={({ field }) => (
|
||||
<>
|
||||
<FormControl>
|
||||
<Checkbox
|
||||
isRequired
|
||||
className="py-4"
|
||||
size="sm"
|
||||
checked={field.value}
|
||||
onChange={(e) => field.onChange(e.target.checked)}
|
||||
>
|
||||
I agree with the
|
||||
<Link href="#" size="sm">
|
||||
Terms
|
||||
</Link>
|
||||
and
|
||||
<Link href="#" size="sm">
|
||||
Privacy Policy
|
||||
</Link>
|
||||
</Checkbox>
|
||||
</FormControl>
|
||||
<FormMessage className="text-system-error dark:text-system-error" />
|
||||
</>
|
||||
)}
|
||||
/>
|
||||
</>
|
||||
)}
|
||||
|
||||
{form.formState.errors?.email && (
|
||||
<div className="flex flex-row items-center gap-2 text-system-error">
|
||||
<NotificationIcon size={16} />
|
||||
<p className="text-s">No user found</p>
|
||||
</div>
|
||||
)}
|
||||
|
||||
<CustomButton
|
||||
type="submit"
|
||||
ariaLabel={type === "sign-in" ? "Log In" : "Sign Up"}
|
||||
ariaDisabled={isLoading}
|
||||
className="w-full"
|
||||
variant="solid"
|
||||
color="action"
|
||||
size="md"
|
||||
radius="md"
|
||||
isLoading={isLoading}
|
||||
isDisabled={isLoading}
|
||||
>
|
||||
{isLoading ? (
|
||||
<span>Loading</span>
|
||||
) : (
|
||||
<span>{type === "sign-in" ? "Log In" : "Sign Up"}</span>
|
||||
)}
|
||||
</CustomButton>
|
||||
</form>
|
||||
</Form>
|
||||
|
||||
{type === "sign-in" && (
|
||||
<>
|
||||
<div className="flex items-center gap-4 py-2">
|
||||
<Divider className="flex-1" />
|
||||
<p className="shrink-0 text-tiny text-default-500">OR</p>
|
||||
<Divider className="flex-1" />
|
||||
</div>
|
||||
<div className="flex flex-col gap-2">
|
||||
<Button
|
||||
startContent={
|
||||
<Icon icon="flat-color-icons:google" width={24} />
|
||||
}
|
||||
variant="bordered"
|
||||
>
|
||||
Continue with Google
|
||||
</Button>
|
||||
<Button
|
||||
startContent={
|
||||
<Icon
|
||||
className="text-default-500"
|
||||
icon="fe:github"
|
||||
width={24}
|
||||
/>
|
||||
}
|
||||
variant="bordered"
|
||||
>
|
||||
Continue with Github
|
||||
</Button>
|
||||
</div>
|
||||
</>
|
||||
)}
|
||||
{type === "sign-in" ? (
|
||||
<p className="text-center text-small">
|
||||
Need to create an account?
|
||||
<Link href="/sign-up">Sign Up</Link>
|
||||
</p>
|
||||
) : (
|
||||
<p className="text-center text-small">
|
||||
Already have an account?
|
||||
<Link href="/sign-in">Log In</Link>
|
||||
</p>
|
||||
)}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
};
|
||||
@@ -0,0 +1 @@
|
||||
export * from "./auth-form";
|
||||
@@ -0,0 +1,76 @@
|
||||
"use client";
|
||||
|
||||
import { Bar, BarChart, LabelList, XAxis, YAxis } from "recharts";
|
||||
|
||||
import {
|
||||
ChartConfig,
|
||||
ChartContainer,
|
||||
ChartTooltip,
|
||||
ChartTooltipContent,
|
||||
} from "@/components/ui/chart/Chart";
|
||||
|
||||
const chartData = [
|
||||
{ severity: "critical", findings: 32, fill: "var(--color-critical)" },
|
||||
{ severity: "high", findings: 78, fill: "var(--color-high)" },
|
||||
{ severity: "medium", findings: 117, fill: "var(--color-medium)" },
|
||||
{ severity: "low", findings: 39, fill: "var(--color-low)" },
|
||||
];
|
||||
|
||||
const chartConfig = {
|
||||
findings: {
|
||||
label: "Findings",
|
||||
},
|
||||
critical: {
|
||||
label: "Critical",
|
||||
color: "hsl(var(--chart-critical))",
|
||||
},
|
||||
high: {
|
||||
label: "High",
|
||||
color: "hsl(var(--chart-fail))",
|
||||
},
|
||||
medium: {
|
||||
label: "Medium",
|
||||
color: "hsl(var(--chart-medium))",
|
||||
},
|
||||
low: {
|
||||
label: "Low",
|
||||
color: "hsl(var(--chart-low))",
|
||||
},
|
||||
} satisfies ChartConfig;
|
||||
|
||||
export const SeverityChart = () => {
|
||||
return (
|
||||
<div className="my-auto">
|
||||
<ChartContainer config={chartConfig}>
|
||||
<BarChart accessibilityLayer data={chartData} layout="vertical">
|
||||
<YAxis
|
||||
dataKey="severity"
|
||||
type="category"
|
||||
tickLine={false}
|
||||
tickMargin={10}
|
||||
axisLine={false}
|
||||
tickFormatter={(value) =>
|
||||
chartConfig[value as keyof typeof chartConfig]?.label
|
||||
}
|
||||
/>
|
||||
<XAxis dataKey="findings" type="number" hide>
|
||||
<LabelList position="insideTop" offset={12} fontSize={12} />
|
||||
</XAxis>
|
||||
<ChartTooltip
|
||||
cursor={false}
|
||||
content={<ChartTooltipContent indicator="line" />}
|
||||
/>
|
||||
|
||||
<Bar dataKey="findings" layout="vertical" radius={12}>
|
||||
<LabelList
|
||||
position="insideRight"
|
||||
offset={10}
|
||||
className="fill-foreground font-bold"
|
||||
fontSize={12}
|
||||
/>
|
||||
</Bar>
|
||||
</BarChart>
|
||||
</ChartContainer>
|
||||
</div>
|
||||
);
|
||||
};
|
||||
@@ -0,0 +1,148 @@
|
||||
"use client";
|
||||
|
||||
import { Chip, Divider, Spacer } from "@nextui-org/react";
|
||||
import { TrendingUp } from "lucide-react";
|
||||
import * as React from "react";
|
||||
import { Label, Pie, PieChart } from "recharts";
|
||||
|
||||
import { NotificationIcon, SuccessIcon } from "../icons";
|
||||
import {
|
||||
ChartConfig,
|
||||
ChartContainer,
|
||||
ChartTooltip,
|
||||
ChartTooltipContent,
|
||||
} from "../ui";
|
||||
|
||||
const calculatePercent = (
|
||||
chartData: { findings: string; number: number; fill: string }[],
|
||||
) => {
|
||||
const total = chartData.reduce((sum, item) => sum + item.number, 0);
|
||||
|
||||
return chartData.map((item) => ({
|
||||
...item,
|
||||
percent: Math.round((item.number / total) * 100) + "%",
|
||||
}));
|
||||
};
|
||||
|
||||
const chartData = [
|
||||
{
|
||||
findings: "Success",
|
||||
number: 436,
|
||||
fill: "var(--color-success)",
|
||||
},
|
||||
{ findings: "Fail", number: 293, fill: "var(--color-fail)" },
|
||||
];
|
||||
|
||||
const updatedChartData = calculatePercent(chartData);
|
||||
|
||||
const chartConfig = {
|
||||
number: {
|
||||
label: "Findings",
|
||||
},
|
||||
success: {
|
||||
label: "Success",
|
||||
color: "hsl(var(--chart-success))",
|
||||
},
|
||||
fail: {
|
||||
label: "Fail",
|
||||
color: "hsl(var(--chart-fail))",
|
||||
},
|
||||
} satisfies ChartConfig;
|
||||
|
||||
export function StatusChart() {
|
||||
const totalVisitors = React.useMemo(() => {
|
||||
return chartData.reduce((acc, curr) => acc + curr.number, 0);
|
||||
}, []);
|
||||
|
||||
return (
|
||||
<div className="my-auto flex items-center justify-center self-center">
|
||||
<ChartContainer
|
||||
config={chartConfig}
|
||||
className="mx-auto aspect-square min-w-[200px] md:min-h-[250px]"
|
||||
>
|
||||
<PieChart>
|
||||
<ChartTooltip cursor={false} content={<ChartTooltipContent />} />
|
||||
<Pie
|
||||
data={chartData}
|
||||
dataKey="number"
|
||||
nameKey="findings"
|
||||
innerRadius={60}
|
||||
strokeWidth={50}
|
||||
>
|
||||
<Label
|
||||
content={({ viewBox }) => {
|
||||
if (viewBox && "cx" in viewBox && "cy" in viewBox) {
|
||||
return (
|
||||
<text
|
||||
x={viewBox.cx}
|
||||
y={viewBox.cy}
|
||||
radius={70}
|
||||
textAnchor="middle"
|
||||
dominantBaseline="middle"
|
||||
>
|
||||
<tspan
|
||||
x={viewBox.cx}
|
||||
y={viewBox.cy}
|
||||
className="fill-foreground text-3xl font-bold"
|
||||
>
|
||||
{totalVisitors.toLocaleString()}
|
||||
</tspan>
|
||||
<tspan
|
||||
x={viewBox.cx}
|
||||
y={(viewBox.cy || 0) + 24}
|
||||
className="fill-foreground"
|
||||
>
|
||||
Findings
|
||||
</tspan>
|
||||
</text>
|
||||
);
|
||||
}
|
||||
}}
|
||||
/>
|
||||
</Pie>
|
||||
</PieChart>
|
||||
</ChartContainer>
|
||||
<div className="mx-6 flex flex-col justify-center gap-2 text-small">
|
||||
<div className="flex space-x-4">
|
||||
<Chip
|
||||
className="h-5"
|
||||
variant="flat"
|
||||
startContent={<SuccessIcon size={18} />}
|
||||
color="success"
|
||||
radius="lg"
|
||||
size="md"
|
||||
>
|
||||
{chartData[0].number}
|
||||
</Chip>
|
||||
<Divider orientation="vertical" />
|
||||
<span>{updatedChartData[0].percent}</span>
|
||||
<Divider orientation="vertical" />
|
||||
</div>
|
||||
<div className="flex items-center font-light leading-none">
|
||||
No change from last scan
|
||||
</div>
|
||||
<Spacer y={4} />
|
||||
<div className="text-muted-foreground flex flex-col gap-2 leading-none">
|
||||
<div className="flex space-x-4">
|
||||
<Chip
|
||||
className="h-5"
|
||||
variant="flat"
|
||||
startContent={<NotificationIcon size={18} />}
|
||||
color="danger"
|
||||
radius="lg"
|
||||
size="md"
|
||||
>
|
||||
{chartData[1].number}
|
||||
</Chip>
|
||||
<Divider orientation="vertical" />
|
||||
<span>{updatedChartData[1].percent}</span>
|
||||
<Divider orientation="vertical" />
|
||||
</div>
|
||||
<div className="flex items-center gap-1 font-medium leading-none">
|
||||
+2 findings from last scan <TrendingUp className="h-4 w-4" />
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
@@ -0,0 +1,2 @@
|
||||
export * from "./SeverityChart";
|
||||
export * from "./StatusChart";
|
||||
@@ -0,0 +1,83 @@
|
||||
import { Card, CardBody, Progress } from "@nextui-org/react";
|
||||
import Image from "next/image";
|
||||
import React from "react";
|
||||
|
||||
import { getComplianceIcon } from "../icons";
|
||||
|
||||
interface ComplianceCardProps {
|
||||
title: string;
|
||||
passingRequirements: number;
|
||||
totalRequirements: number;
|
||||
prevPassingRequirements: number;
|
||||
prevTotalRequirements: number;
|
||||
}
|
||||
|
||||
export const ComplianceCard: React.FC<ComplianceCardProps> = ({
|
||||
title,
|
||||
passingRequirements,
|
||||
totalRequirements,
|
||||
}) => {
|
||||
const ratingPercentage = Math.floor(
|
||||
(passingRequirements / totalRequirements) * 100,
|
||||
);
|
||||
|
||||
// const prevRatingPercentage = Math.floor(
|
||||
// (prevPassingRequirements / prevTotalRequirements) * 100,
|
||||
// );
|
||||
|
||||
// const getScanChange = () => {
|
||||
// const scanDifference = ratingPercentage - prevRatingPercentage;
|
||||
// if (scanDifference < 0 && scanDifference <= -1) {
|
||||
// return `${scanDifference}% from last scan`;
|
||||
// }
|
||||
// if (scanDifference > 0 && scanDifference >= 1) {
|
||||
// return `+${scanDifference}% from last scan`;
|
||||
// }
|
||||
// return "No changes from last scan";
|
||||
// };
|
||||
|
||||
const getRatingColor = (ratingPercentage: number) => {
|
||||
if (ratingPercentage <= 10) {
|
||||
return "danger";
|
||||
}
|
||||
if (ratingPercentage <= 40) {
|
||||
return "warning";
|
||||
}
|
||||
return "success";
|
||||
};
|
||||
|
||||
return (
|
||||
<Card fullWidth isPressable isHoverable shadow="sm">
|
||||
<CardBody className="flex flex-row items-center justify-between space-x-4 dark:bg-prowler-blue-800">
|
||||
<div className="flex w-full items-center space-x-4">
|
||||
<Image
|
||||
src={getComplianceIcon(title)}
|
||||
alt={`${title} logo`}
|
||||
className="h-10 w-10 min-w-10 rounded-md border-1 border-gray-300 bg-white object-contain p-1"
|
||||
/>
|
||||
<div className="flex w-full flex-col">
|
||||
<h4 className="text-md font-bold leading-5 3xl:text-lg">{title}</h4>
|
||||
<Progress
|
||||
label="Your Rating:"
|
||||
size="sm"
|
||||
aria-label="Your Rating"
|
||||
value={ratingPercentage}
|
||||
showValueLabel={true}
|
||||
className="mt-2 font-semibold"
|
||||
color={getRatingColor(ratingPercentage)}
|
||||
/>
|
||||
<div className="mt-2 flex justify-between">
|
||||
<small>
|
||||
<span className="mr-1 font-semibold">
|
||||
{passingRequirements} / {totalRequirements}
|
||||
</span>
|
||||
Passing Requirements
|
||||
</small>
|
||||
{/* <small>{getScanChange()}</small> */}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</CardBody>
|
||||
</Card>
|
||||
);
|
||||
};
|
||||
@@ -0,0 +1,18 @@
|
||||
import { Card, Skeleton } from "@nextui-org/react";
|
||||
import React from "react";
|
||||
|
||||
export const ComplianceSkeletonGrid = () => {
|
||||
return (
|
||||
<Card className="h-fit w-full p-4">
|
||||
<div className="grid grid-cols-1 gap-4 sm:grid-cols-2 lg:grid-cols-3 xl:grid-cols-3 3xl:grid-cols-4">
|
||||
{[...Array(28)].map((_, index) => (
|
||||
<div key={index} className="flex flex-col space-y-4">
|
||||
<Skeleton className="h-28 rounded-lg">
|
||||
<div className="h-full bg-default-300"></div>
|
||||
</Skeleton>
|
||||
</div>
|
||||
))}
|
||||
</div>
|
||||
</Card>
|
||||
);
|
||||
};
|
||||
@@ -0,0 +1,90 @@
|
||||
"use client";
|
||||
|
||||
import { useRouter, useSearchParams } from "next/navigation";
|
||||
import { useCallback, useEffect, useState } from "react";
|
||||
|
||||
import { SelectScanComplianceData } from "@/components/compliance/data-compliance";
|
||||
import { CrossIcon } from "@/components/icons";
|
||||
import { CustomButton, CustomDropdownFilter } from "@/components/ui/custom";
|
||||
|
||||
interface DataComplianceProps {
|
||||
scans: { id: string; name: string; state: string; progress: number }[];
|
||||
regions: string[];
|
||||
}
|
||||
|
||||
export const DataCompliance = ({ scans, regions }: DataComplianceProps) => {
|
||||
const router = useRouter();
|
||||
const searchParams = useSearchParams();
|
||||
const [showClearButton, setShowClearButton] = useState(false);
|
||||
const scanIdParam = searchParams.get("scanId");
|
||||
const selectedScanId = scanIdParam || scans[0]?.id;
|
||||
|
||||
useEffect(() => {
|
||||
const hasFilters = Array.from(searchParams.keys()).some(
|
||||
(key) => key.startsWith("filter[") || key === "sort",
|
||||
);
|
||||
setShowClearButton(hasFilters);
|
||||
}, [searchParams]);
|
||||
const handleScanChange = (selectedKey: string) => {
|
||||
const params = new URLSearchParams(searchParams);
|
||||
params.set("scanId", selectedKey);
|
||||
router.push(`?${params.toString()}`);
|
||||
};
|
||||
|
||||
const pushDropdownFilter = useCallback(
|
||||
(key: string, values: string[]) => {
|
||||
const params = new URLSearchParams(searchParams);
|
||||
const filterKey = `filter[${key}]`;
|
||||
|
||||
if (values.length === 0) {
|
||||
params.delete(filterKey);
|
||||
} else {
|
||||
params.set(filterKey, values.join(","));
|
||||
}
|
||||
|
||||
router.push(`?${params.toString()}`);
|
||||
},
|
||||
[router, searchParams],
|
||||
);
|
||||
const clearAllFilters = useCallback(() => {
|
||||
const params = new URLSearchParams(searchParams.toString());
|
||||
Array.from(params.keys()).forEach((key) => {
|
||||
if (key.startsWith("filter[") || key === "sort") {
|
||||
params.delete(key);
|
||||
}
|
||||
});
|
||||
router.push(`?${params.toString()}`, { scroll: false });
|
||||
}, [router, searchParams]);
|
||||
return (
|
||||
<div className="flex flex-col gap-4">
|
||||
<div className="grid grid-cols-1 items-center gap-x-4 gap-y-4 md:grid-cols-2 xl:grid-cols-4">
|
||||
<SelectScanComplianceData
|
||||
scans={scans}
|
||||
selectedScanId={selectedScanId}
|
||||
onSelectionChange={handleScanChange}
|
||||
/>
|
||||
<CustomDropdownFilter
|
||||
filter={{
|
||||
key: "region__in",
|
||||
values: regions,
|
||||
labelCheckboxGroup: "Regions",
|
||||
}}
|
||||
onFilterChange={pushDropdownFilter}
|
||||
/>
|
||||
{showClearButton && (
|
||||
<CustomButton
|
||||
ariaLabel="Reset"
|
||||
className="w-full md:w-fit"
|
||||
onPress={clearAllFilters}
|
||||
variant="dashed"
|
||||
size="sm"
|
||||
endContent={<CrossIcon size={24} />}
|
||||
radius="sm"
|
||||
>
|
||||
Reset
|
||||
</CustomButton>
|
||||
)}
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
};
|
||||
@@ -0,0 +1,2 @@
|
||||
export * from "./data-compliance";
|
||||
export * from "./select-scan-compliance-data";
|
||||
@@ -0,0 +1,50 @@
|
||||
import { Select, SelectItem } from "@nextui-org/react";
|
||||
|
||||
interface SelectScanComplianceDataProps {
|
||||
scans: { id: string; name: string; state: string; progress: number }[];
|
||||
selectedScanId: string;
|
||||
onSelectionChange: (selectedKey: string) => void;
|
||||
}
|
||||
|
||||
export const SelectScanComplianceData = ({
|
||||
scans,
|
||||
selectedScanId,
|
||||
onSelectionChange,
|
||||
}: SelectScanComplianceDataProps) => {
|
||||
return (
|
||||
<Select
|
||||
aria-label="Select a Scan"
|
||||
placeholder="Select a scan"
|
||||
labelPlacement="outside"
|
||||
size="md"
|
||||
selectedKeys={new Set([selectedScanId])}
|
||||
onSelectionChange={(keys) =>
|
||||
onSelectionChange(Array.from(keys)[0] as string)
|
||||
}
|
||||
renderValue={() => {
|
||||
const selectedItem = scans.find((item) => item.id === selectedScanId);
|
||||
return selectedItem ? (
|
||||
<div className="flex flex-col">
|
||||
<span className="font-bold">{selectedItem.name}</span>
|
||||
<span className="text-sm text-gray-500">
|
||||
State: {selectedItem.state}, Progress: {selectedItem.progress}%
|
||||
</span>
|
||||
</div>
|
||||
) : (
|
||||
"Select a scan"
|
||||
);
|
||||
}}
|
||||
>
|
||||
{scans.map((scan) => (
|
||||
<SelectItem key={scan.id} textValue={scan.name}>
|
||||
<div className="flex flex-col">
|
||||
<span className="font-bold">{scan.name}</span>
|
||||
<span className="text-sm text-gray-500">
|
||||
State: {scan.state}, Progress: {scan.progress}%
|
||||
</span>
|
||||
</div>
|
||||
</SelectItem>
|
||||
))}
|
||||
</Select>
|
||||
);
|
||||
};
|
||||
@@ -0,0 +1,2 @@
|
||||
export * from "./compliance-card";
|
||||
export * from "./compliance-skeleton-grid";
|
||||
@@ -0,0 +1,32 @@
|
||||
"use client";
|
||||
import { Select, SelectItem } from "@nextui-org/react";
|
||||
|
||||
const accounts = [
|
||||
{ key: "audit-test-1", label: "740350143844" },
|
||||
{ key: "audit-test-2", label: "890837126756" },
|
||||
{ key: "audit-test-3", label: "563829104923" },
|
||||
{ key: "audit-test-4", label: "678943217543" },
|
||||
{ key: "audit-test-5", label: "932187465320" },
|
||||
{ key: "audit-test-6", label: "492837106587" },
|
||||
{ key: "audit-test-7", label: "812736459201" },
|
||||
{ key: "audit-test-8", label: "374829106524" },
|
||||
{ key: "audit-test-9", label: "926481053298" },
|
||||
{ key: "audit-test-10", label: "748192364579" },
|
||||
{ key: "audit-test-11", label: "501374829106" },
|
||||
];
|
||||
export const CustomAccountSelection = () => {
|
||||
return (
|
||||
<Select
|
||||
label="Account"
|
||||
aria-label="Select an Account"
|
||||
placeholder="Select an account"
|
||||
selectionMode="multiple"
|
||||
className="w-full"
|
||||
size="sm"
|
||||
>
|
||||
{accounts.map((acc) => (
|
||||
<SelectItem key={acc.key}>{acc.label}</SelectItem>
|
||||
))}
|
||||
</Select>
|
||||
);
|
||||
};
|
||||
@@ -0,0 +1,15 @@
|
||||
import { Checkbox } from "@nextui-org/react";
|
||||
import React from "react";
|
||||
|
||||
export const CustomCheckboxMutedFindings = () => {
|
||||
return (
|
||||
<Checkbox
|
||||
className="xl:-mt-8"
|
||||
size="md"
|
||||
color="danger"
|
||||
aria-label="Include Muted Findings"
|
||||
>
|
||||
Include Muted Findings
|
||||
</Checkbox>
|
||||
);
|
||||
};
|
||||
@@ -0,0 +1,97 @@
|
||||
"use client";
|
||||
|
||||
import {
|
||||
getLocalTimeZone,
|
||||
startOfMonth,
|
||||
startOfWeek,
|
||||
today,
|
||||
} from "@internationalized/date";
|
||||
import { Button, ButtonGroup, DatePicker } from "@nextui-org/react";
|
||||
import { useLocale } from "@react-aria/i18n";
|
||||
import { useRouter, useSearchParams } from "next/navigation";
|
||||
import React, { useCallback, useEffect, useRef } from "react";
|
||||
|
||||
export const CustomDatePicker = () => {
|
||||
const router = useRouter();
|
||||
const searchParams = useSearchParams();
|
||||
const defaultDate = today(getLocalTimeZone());
|
||||
|
||||
const [value, setValue] = React.useState(defaultDate);
|
||||
|
||||
const { locale } = useLocale();
|
||||
|
||||
const now = today(getLocalTimeZone());
|
||||
const nextWeek = startOfWeek(now.add({ weeks: 1 }), locale);
|
||||
const nextMonth = startOfMonth(now.add({ months: 1 }));
|
||||
|
||||
const applyDateFilter = useCallback(
|
||||
(date: any) => {
|
||||
const params = new URLSearchParams(searchParams.toString());
|
||||
if (date) {
|
||||
params.set("filter[updated_at]", date.toString());
|
||||
} else {
|
||||
params.delete("filter[updated_at]");
|
||||
}
|
||||
router.push(`?${params.toString()}`, { scroll: false });
|
||||
},
|
||||
[router, searchParams],
|
||||
);
|
||||
|
||||
const initialRender = useRef(true);
|
||||
|
||||
useEffect(() => {
|
||||
if (initialRender.current) {
|
||||
initialRender.current = false;
|
||||
return;
|
||||
}
|
||||
const params = new URLSearchParams(searchParams.toString());
|
||||
if (params.size === 0) {
|
||||
// If all params are cleared, reset to default date
|
||||
setValue(defaultDate);
|
||||
}
|
||||
}, [searchParams]);
|
||||
|
||||
const handleDateChange = (newValue: any) => {
|
||||
setValue(newValue);
|
||||
applyDateFilter(newValue);
|
||||
};
|
||||
|
||||
return (
|
||||
<div className="flex w-full flex-col md:gap-2">
|
||||
<DatePicker
|
||||
aria-label="Select a Date"
|
||||
CalendarTopContent={
|
||||
<ButtonGroup
|
||||
fullWidth
|
||||
className="bg-content1 px-3 pb-2 pt-3 dark:bg-prowler-blue-400 [&>button]:border-default-200/60 [&>button]:text-default-500"
|
||||
radius="full"
|
||||
size="sm"
|
||||
variant="bordered"
|
||||
>
|
||||
<Button onPress={() => handleDateChange(now)}>Today</Button>
|
||||
<Button onPress={() => handleDateChange(nextWeek)}>
|
||||
Next week
|
||||
</Button>
|
||||
<Button onPress={() => handleDateChange(nextMonth)}>
|
||||
Next month
|
||||
</Button>
|
||||
</ButtonGroup>
|
||||
}
|
||||
calendarProps={{
|
||||
focusedValue: value,
|
||||
onFocusChange: setValue,
|
||||
nextButtonProps: {
|
||||
variant: "bordered",
|
||||
},
|
||||
prevButtonProps: {
|
||||
variant: "bordered",
|
||||
},
|
||||
}}
|
||||
value={value}
|
||||
onChange={handleDateChange}
|
||||
size="sm"
|
||||
variant="flat"
|
||||
/>
|
||||
</div>
|
||||
);
|
||||
};
|
||||
@@ -0,0 +1,44 @@
|
||||
import React from "react";
|
||||
|
||||
import {
|
||||
AWSProviderBadge,
|
||||
AzureProviderBadge,
|
||||
GCPProviderBadge,
|
||||
KS8ProviderBadge,
|
||||
} from "../icons/providers-badge";
|
||||
|
||||
export const CustomProviderInputAWS = () => {
|
||||
return (
|
||||
<div className="flex items-center gap-x-2">
|
||||
<AWSProviderBadge width={25} height={25} />
|
||||
<p className="text-sm">Amazon Web Services</p>
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
export const CustomProviderInputAzure = () => {
|
||||
return (
|
||||
<div className="flex items-center gap-x-2">
|
||||
<AzureProviderBadge width={25} height={25} />
|
||||
<p className="text-sm">Azure</p>
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
export const CustomProviderInputGCP = () => {
|
||||
return (
|
||||
<div className="flex items-center gap-x-2">
|
||||
<GCPProviderBadge width={25} height={25} />
|
||||
<p className="text-sm">Google Cloud Platform</p>
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
export const CustomProviderInputKubernetes = () => {
|
||||
return (
|
||||
<div className="flex items-center gap-x-2">
|
||||
<KS8ProviderBadge width={25} height={25} />
|
||||
<p className="text-sm">Kubernetes</p>
|
||||
</div>
|
||||
);
|
||||
};
|
||||
@@ -0,0 +1,51 @@
|
||||
"use client";
|
||||
import { Select, SelectItem } from "@nextui-org/react";
|
||||
|
||||
const regions = [
|
||||
{ key: "af-south-1", label: "AF South 1" },
|
||||
{ key: "ap-east-1", label: "AP East 1" },
|
||||
{ key: "ap-northeast-1", label: "AP Northeast 1" },
|
||||
{ key: "ap-northeast-2", label: "AP Northeast 2" },
|
||||
{ key: "ap-northeast-3", label: "AP Northeast 3" },
|
||||
{ key: "ap-south-1", label: "AP South 1" },
|
||||
{ key: "ap-south-2", label: "AP South 2" },
|
||||
{ key: "ap-southeast-1", label: "AP Southeast 1" },
|
||||
{ key: "ap-southeast-2", label: "AP Southeast 2" },
|
||||
{ key: "ap-southeast-3", label: "AP Southeast 3" },
|
||||
{ key: "ap-southeast-4", label: "AP Southeast 4" },
|
||||
{ key: "ca-central-1", label: "CA Central 1" },
|
||||
{ key: "ca-west-1", label: "CA West 1" },
|
||||
{ key: "eu-central-1", label: "EU Central 1" },
|
||||
{ key: "eu-central-2", label: "EU Central 2" },
|
||||
{ key: "eu-north-1", label: "EU North 1" },
|
||||
{ key: "eu-south-1", label: "EU South 1" },
|
||||
{ key: "eu-south-2", label: "EU South 2" },
|
||||
{ key: "eu-west-1", label: "EU West 1" },
|
||||
{ key: "eu-west-2", label: "EU West 2" },
|
||||
{ key: "eu-west-3", label: "EU West 3" },
|
||||
{ key: "il-central-1", label: "IL Central 1" },
|
||||
{ key: "me-central-1", label: "ME Central 1" },
|
||||
{ key: "me-south-1", label: "ME South 1" },
|
||||
{ key: "sa-east-1", label: "SA East 1" },
|
||||
{ key: "us-east-1", label: "US East 1" },
|
||||
{ key: "us-east-2", label: "US East 2" },
|
||||
{ key: "us-west-1", label: "US West 1" },
|
||||
{ key: "us-west-2", label: "US West 2" },
|
||||
];
|
||||
|
||||
export const CustomRegionSelection = () => {
|
||||
return (
|
||||
<Select
|
||||
label="Region"
|
||||
aria-label="Select a Region"
|
||||
placeholder="Select a region"
|
||||
selectionMode="multiple"
|
||||
className="w-full"
|
||||
size="sm"
|
||||
>
|
||||
{regions.map((acc) => (
|
||||
<SelectItem key={acc.key}>{acc.label}</SelectItem>
|
||||
))}
|
||||
</Select>
|
||||
);
|
||||
};
|
||||
@@ -0,0 +1,62 @@
|
||||
import { Input } from "@nextui-org/react";
|
||||
import debounce from "lodash.debounce";
|
||||
import { SearchIcon, XCircle } from "lucide-react";
|
||||
import { useRouter, useSearchParams } from "next/navigation";
|
||||
import React, { useCallback, useEffect, useState } from "react";
|
||||
|
||||
export const CustomSearchInput: React.FC = () => {
|
||||
const router = useRouter();
|
||||
const searchParams = useSearchParams();
|
||||
|
||||
const [searchQuery, setSearchQuery] = useState("");
|
||||
|
||||
const applySearch = useCallback(
|
||||
(query: string) => {
|
||||
const params = new URLSearchParams(searchParams.toString());
|
||||
if (query) {
|
||||
params.set("filter[search]", query);
|
||||
} else {
|
||||
params.delete("filter[search]");
|
||||
}
|
||||
router.push(`?${params.toString()}`, { scroll: false });
|
||||
},
|
||||
[router, searchParams],
|
||||
);
|
||||
|
||||
const debouncedChangeHandler = useCallback(debounce(applySearch, 300), []);
|
||||
|
||||
const clearIconSearch = () => {
|
||||
setSearchQuery("");
|
||||
applySearch("");
|
||||
};
|
||||
|
||||
useEffect(() => {
|
||||
const searchFromUrl = searchParams.get("filter[search]") || "";
|
||||
setSearchQuery(searchFromUrl);
|
||||
}, [searchParams]);
|
||||
|
||||
return (
|
||||
<Input
|
||||
variant="flat"
|
||||
aria-label="Search"
|
||||
placeholder="Search..."
|
||||
labelPlacement="outside"
|
||||
value={searchQuery}
|
||||
startContent={<SearchIcon className="text-default-400" width={16} />}
|
||||
onChange={(e) => {
|
||||
const value = e.target.value;
|
||||
setSearchQuery(value);
|
||||
debouncedChangeHandler(value);
|
||||
}}
|
||||
endContent={
|
||||
searchQuery && (
|
||||
<button onClick={clearIconSearch} className="focus:outline-none">
|
||||
<XCircle className="h-4 w-4 text-default-400" />
|
||||
</button>
|
||||
)
|
||||
}
|
||||
radius="sm"
|
||||
size="sm"
|
||||
/>
|
||||
);
|
||||
};
|
||||
@@ -0,0 +1,91 @@
|
||||
"use client";
|
||||
|
||||
import { Select, SelectItem } from "@nextui-org/react";
|
||||
import { useRouter, useSearchParams } from "next/navigation";
|
||||
import React, { useCallback, useMemo } from "react";
|
||||
|
||||
import {
|
||||
CustomProviderInputAWS,
|
||||
CustomProviderInputAzure,
|
||||
CustomProviderInputGCP,
|
||||
CustomProviderInputKubernetes,
|
||||
} from "./custom-provider-inputs";
|
||||
|
||||
const dataInputsProvider = [
|
||||
{
|
||||
key: "aws",
|
||||
label: "Amazon Web Services",
|
||||
value: <CustomProviderInputAWS />,
|
||||
},
|
||||
{
|
||||
key: "gcp",
|
||||
label: "Google Cloud Platform",
|
||||
value: <CustomProviderInputGCP />,
|
||||
},
|
||||
{
|
||||
key: "azure",
|
||||
label: "Microsoft Azure",
|
||||
value: <CustomProviderInputAzure />,
|
||||
},
|
||||
{
|
||||
key: "kubernetes",
|
||||
label: "Kubernetes",
|
||||
value: <CustomProviderInputKubernetes />,
|
||||
},
|
||||
];
|
||||
|
||||
export const CustomSelectProvider: React.FC = () => {
|
||||
const router = useRouter();
|
||||
const searchParams = useSearchParams();
|
||||
|
||||
const applyProviderFilter = useCallback(
|
||||
(value: string) => {
|
||||
const params = new URLSearchParams(searchParams.toString());
|
||||
if (value) {
|
||||
params.set("filter[provider_type]", value);
|
||||
} else {
|
||||
params.delete("filter[provider_type]");
|
||||
}
|
||||
router.push(`?${params.toString()}`, { scroll: false });
|
||||
},
|
||||
[router, searchParams],
|
||||
);
|
||||
|
||||
const currentProvider = searchParams.get("filter[provider_type]") || "";
|
||||
|
||||
const selectedKeys = useMemo(() => {
|
||||
return dataInputsProvider.some(
|
||||
(provider) => provider.key === currentProvider,
|
||||
)
|
||||
? [currentProvider]
|
||||
: [];
|
||||
}, [currentProvider]);
|
||||
|
||||
return (
|
||||
<Select
|
||||
items={dataInputsProvider}
|
||||
aria-label="Select a Provider"
|
||||
placeholder="Select a provider"
|
||||
labelPlacement="outside"
|
||||
size="sm"
|
||||
onChange={(e) => {
|
||||
const value = e.target.value;
|
||||
applyProviderFilter(value);
|
||||
}}
|
||||
selectedKeys={selectedKeys}
|
||||
renderValue={(items) => {
|
||||
return items.map((item) => (
|
||||
<div key={item.key} className="flex items-center gap-2">
|
||||
{item.data?.value}
|
||||
</div>
|
||||
));
|
||||
}}
|
||||
>
|
||||
{(item) => (
|
||||
<SelectItem key={item.key} textValue={item.key} aria-label={item.label}>
|
||||
<div className="flex items-center gap-2">{item.value}</div>
|
||||
</SelectItem>
|
||||
)}
|
||||
</Select>
|
||||
);
|
||||
};
|
||||
@@ -0,0 +1,74 @@
|
||||
export const filterProviders = [
|
||||
{
|
||||
key: "connected",
|
||||
labelCheckboxGroup: "Connection",
|
||||
values: ["false", "true"],
|
||||
},
|
||||
// Add more filter categories as needed
|
||||
];
|
||||
|
||||
export const filterScans = [
|
||||
{
|
||||
key: "provider_type__in",
|
||||
labelCheckboxGroup: "Provider",
|
||||
values: ["aws", "azure", "gcp", "kubernetes"],
|
||||
},
|
||||
{
|
||||
key: "state",
|
||||
labelCheckboxGroup: "State",
|
||||
values: [
|
||||
"available",
|
||||
"scheduled",
|
||||
"executing",
|
||||
"completed",
|
||||
"failed",
|
||||
"cancelled",
|
||||
],
|
||||
},
|
||||
{
|
||||
key: "trigger",
|
||||
labelCheckboxGroup: "Schedule",
|
||||
values: ["scheduled", "manual"],
|
||||
},
|
||||
// Add more filter categories as needed
|
||||
];
|
||||
|
||||
export const filterFindings = [
|
||||
{
|
||||
key: "severity__in",
|
||||
labelCheckboxGroup: "Severity",
|
||||
values: ["critical", "high", "medium", "low", "informational"],
|
||||
},
|
||||
{
|
||||
key: "status__in",
|
||||
labelCheckboxGroup: "Status",
|
||||
values: ["PASS", "FAIL", "MANUAL", "MUTED"],
|
||||
},
|
||||
{
|
||||
key: "delta__in",
|
||||
labelCheckboxGroup: "Delta",
|
||||
values: ["new", "changed"],
|
||||
},
|
||||
{
|
||||
key: "provider_type__in",
|
||||
labelCheckboxGroup: "Provider",
|
||||
values: ["aws", "azure", "gcp", "kubernetes"],
|
||||
},
|
||||
// Add more filter categories as needed
|
||||
];
|
||||
|
||||
export const filterUsers = [
|
||||
{
|
||||
key: "is_active",
|
||||
labelCheckboxGroup: "Status",
|
||||
values: ["true", "false"],
|
||||
},
|
||||
];
|
||||
|
||||
export const filterInvitations = [
|
||||
{
|
||||
key: "state",
|
||||
labelCheckboxGroup: "State",
|
||||
values: ["pending", "accepted", "expired", "revoked"],
|
||||
},
|
||||
];
|
||||
@@ -0,0 +1,75 @@
|
||||
"use client";
|
||||
|
||||
import { useRouter, useSearchParams } from "next/navigation";
|
||||
import React, { useCallback, useEffect, useState } from "react";
|
||||
|
||||
import { FilterControlsProps } from "@/types";
|
||||
|
||||
import { CrossIcon } from "../icons";
|
||||
import { CustomButton } from "../ui/custom";
|
||||
import { DataTableFilterCustom } from "../ui/table";
|
||||
import { CustomAccountSelection } from "./custom-account-selection";
|
||||
import { CustomCheckboxMutedFindings } from "./custom-checkbox-muted-findings";
|
||||
import { CustomDatePicker } from "./custom-date-picker";
|
||||
import { CustomRegionSelection } from "./custom-region-selection";
|
||||
import { CustomSearchInput } from "./custom-search-input";
|
||||
import { CustomSelectProvider } from "./custom-select-provider";
|
||||
|
||||
export const FilterControls: React.FC<FilterControlsProps> = ({
|
||||
search = false,
|
||||
providers = false,
|
||||
date = false,
|
||||
regions = false,
|
||||
accounts = false,
|
||||
mutedFindings = false,
|
||||
customFilters,
|
||||
}) => {
|
||||
const router = useRouter();
|
||||
const searchParams = useSearchParams();
|
||||
const [showClearButton, setShowClearButton] = useState(false);
|
||||
|
||||
useEffect(() => {
|
||||
const hasFilters = Array.from(searchParams.keys()).some(
|
||||
(key) => key.startsWith("filter[") || key === "sort",
|
||||
);
|
||||
setShowClearButton(hasFilters);
|
||||
}, [searchParams]);
|
||||
|
||||
const clearAllFilters = useCallback(() => {
|
||||
const params = new URLSearchParams(searchParams.toString());
|
||||
Array.from(params.keys()).forEach((key) => {
|
||||
if (key.startsWith("filter[") || key === "sort") {
|
||||
params.delete(key);
|
||||
}
|
||||
});
|
||||
router.push(`?${params.toString()}`, { scroll: false });
|
||||
}, [router, searchParams]);
|
||||
|
||||
return (
|
||||
<div className="flex flex-col gap-4">
|
||||
<div className="grid grid-cols-1 items-center gap-x-4 gap-y-4 md:grid-cols-2 xl:grid-cols-4">
|
||||
{search && <CustomSearchInput />}
|
||||
{providers && <CustomSelectProvider />}
|
||||
{date && <CustomDatePicker />}
|
||||
{regions && <CustomRegionSelection />}
|
||||
{accounts && <CustomAccountSelection />}
|
||||
{mutedFindings && <CustomCheckboxMutedFindings />}
|
||||
|
||||
{showClearButton && (
|
||||
<CustomButton
|
||||
ariaLabel="Reset"
|
||||
className="w-full md:w-fit"
|
||||
onPress={clearAllFilters}
|
||||
variant="dashed"
|
||||
size="sm"
|
||||
endContent={<CrossIcon size={24} />}
|
||||
radius="sm"
|
||||
>
|
||||
Reset
|
||||
</CustomButton>
|
||||
)}
|
||||
</div>
|
||||
{customFilters && <DataTableFilterCustom filters={customFilters} />}
|
||||
</div>
|
||||
);
|
||||
};
|
||||
@@ -0,0 +1,8 @@
|
||||
export * from "./custom-account-selection";
|
||||
export * from "./custom-checkbox-muted-findings";
|
||||
export * from "./custom-date-picker";
|
||||
export * from "./custom-provider-inputs";
|
||||
export * from "./custom-region-selection";
|
||||
export * from "./custom-select-provider";
|
||||
export * from "./data-filters";
|
||||
export * from "./filter-controls";
|
||||
@@ -0,0 +1,177 @@
|
||||
"use client";
|
||||
|
||||
import { ColumnDef } from "@tanstack/react-table";
|
||||
import { useSearchParams } from "next/navigation";
|
||||
|
||||
import { DataTableRowDetails } from "@/components/findings/table";
|
||||
import { InfoIcon } from "@/components/icons";
|
||||
import { TriggerSheet } from "@/components/ui/sheet";
|
||||
import {
|
||||
DataTableColumnHeader,
|
||||
SeverityBadge,
|
||||
StatusFindingBadge,
|
||||
} from "@/components/ui/table";
|
||||
import { FindingProps } from "@/types";
|
||||
|
||||
import { DataTableRowActions } from "./data-table-row-actions";
|
||||
|
||||
const getFindingsData = (row: { original: FindingProps }) => {
|
||||
return row.original;
|
||||
};
|
||||
|
||||
const getFindingsMetadata = (row: { original: FindingProps }) => {
|
||||
return row.original.attributes.check_metadata;
|
||||
};
|
||||
|
||||
const getResourceData = (
|
||||
row: { original: FindingProps },
|
||||
field: keyof FindingProps["relationships"]["resource"]["attributes"],
|
||||
) => {
|
||||
return (
|
||||
row.original.relationships?.resource?.attributes?.[field] ||
|
||||
`No ${field} found in resource`
|
||||
);
|
||||
};
|
||||
|
||||
const getProviderData = (
|
||||
row: { original: FindingProps },
|
||||
field: keyof FindingProps["relationships"]["provider"]["attributes"],
|
||||
) => {
|
||||
return (
|
||||
row.original.relationships?.provider?.attributes?.[field] ||
|
||||
`No ${field} found in provider`
|
||||
);
|
||||
};
|
||||
|
||||
const getScanData = (
|
||||
row: { original: FindingProps },
|
||||
field: keyof FindingProps["relationships"]["scan"]["attributes"],
|
||||
) => {
|
||||
return (
|
||||
row.original.relationships?.scan?.attributes?.[field] ||
|
||||
`No ${field} found in scan`
|
||||
);
|
||||
};
|
||||
|
||||
export const ColumnFindings: ColumnDef<FindingProps>[] = [
|
||||
{
|
||||
accessorKey: "check",
|
||||
header: ({ column }) => (
|
||||
<DataTableColumnHeader column={column} title={"Check"} param="check_id" />
|
||||
),
|
||||
cell: ({ row }) => {
|
||||
const { checktitle } = getFindingsMetadata(row);
|
||||
return <p className="max-w-96 truncate text-small">{checktitle}</p>;
|
||||
},
|
||||
},
|
||||
{
|
||||
accessorKey: "severity",
|
||||
header: ({ column }) => (
|
||||
<DataTableColumnHeader
|
||||
column={column}
|
||||
title={"Severity"}
|
||||
param="severity"
|
||||
/>
|
||||
),
|
||||
cell: ({ row }) => {
|
||||
const {
|
||||
attributes: { severity },
|
||||
} = getFindingsData(row);
|
||||
return <SeverityBadge severity={severity} />;
|
||||
},
|
||||
},
|
||||
{
|
||||
accessorKey: "status",
|
||||
header: ({ column }) => (
|
||||
<DataTableColumnHeader column={column} title={"Status"} param="status" />
|
||||
),
|
||||
cell: ({ row }) => {
|
||||
const {
|
||||
attributes: { status },
|
||||
} = getFindingsData(row);
|
||||
|
||||
return <StatusFindingBadge size="sm" status={status} />;
|
||||
},
|
||||
},
|
||||
{
|
||||
accessorKey: "scanName",
|
||||
header: "Scan Name",
|
||||
cell: ({ row }) => {
|
||||
const name = getScanData(row, "name");
|
||||
|
||||
return (
|
||||
<p className="text-small">
|
||||
{typeof name === "string" || typeof name === "number"
|
||||
? name
|
||||
: "Invalid data"}
|
||||
</p>
|
||||
);
|
||||
},
|
||||
},
|
||||
{
|
||||
accessorKey: "region",
|
||||
header: "Region",
|
||||
cell: ({ row }) => {
|
||||
const region = getResourceData(row, "region");
|
||||
|
||||
return (
|
||||
<>
|
||||
<div>{typeof region === "string" ? region : "Invalid region"}</div>
|
||||
</>
|
||||
);
|
||||
},
|
||||
},
|
||||
{
|
||||
accessorKey: "service",
|
||||
header: "Service",
|
||||
cell: ({ row }) => {
|
||||
const { servicename } = getFindingsMetadata(row);
|
||||
return <p className="max-w-96 truncate text-small">{servicename}</p>;
|
||||
},
|
||||
},
|
||||
{
|
||||
accessorKey: "account",
|
||||
header: "Account",
|
||||
cell: ({ row }) => {
|
||||
const account = getProviderData(row, "uid");
|
||||
|
||||
return (
|
||||
<>
|
||||
<p className="max-w-96 truncate text-small">
|
||||
{typeof account === "string" ? account : "Invalid account"}
|
||||
</p>
|
||||
</>
|
||||
);
|
||||
},
|
||||
},
|
||||
{
|
||||
id: "moreInfo",
|
||||
header: "Details",
|
||||
cell: ({ row }) => {
|
||||
const searchParams = useSearchParams();
|
||||
const findingId = searchParams.get("id");
|
||||
const isOpen = findingId === row.original.id;
|
||||
return (
|
||||
<div className="flex justify-center">
|
||||
<TriggerSheet
|
||||
triggerComponent={<InfoIcon className="text-primary" size={16} />}
|
||||
title="Finding Details"
|
||||
description="View the finding details"
|
||||
defaultOpen={isOpen}
|
||||
>
|
||||
<DataTableRowDetails
|
||||
entityId={row.original.id}
|
||||
findingDetails={row.original}
|
||||
/>
|
||||
</TriggerSheet>
|
||||
</div>
|
||||
);
|
||||
},
|
||||
},
|
||||
{
|
||||
id: "actions",
|
||||
cell: ({ row }) => {
|
||||
return <DataTableRowActions row={row} />;
|
||||
},
|
||||
},
|
||||
];
|
||||
@@ -0,0 +1,99 @@
|
||||
"use client";
|
||||
|
||||
import {
|
||||
Button,
|
||||
Dropdown,
|
||||
DropdownItem,
|
||||
DropdownMenu,
|
||||
DropdownSection,
|
||||
DropdownTrigger,
|
||||
} from "@nextui-org/react";
|
||||
import {
|
||||
// AddNoteBulkIcon,
|
||||
EditDocumentBulkIcon,
|
||||
} from "@nextui-org/shared-icons";
|
||||
import { Row } from "@tanstack/react-table";
|
||||
|
||||
// import { useState } from "react";
|
||||
import { VerticalDotsIcon } from "@/components/icons";
|
||||
// import { CustomAlertModal } from "@/components/ui/custom";
|
||||
|
||||
// import { EditForm } from "../forms";
|
||||
// import { DeleteForm } from "../forms/delete-form";
|
||||
|
||||
interface DataTableRowActionsProps<FindingProps> {
|
||||
row: Row<FindingProps>;
|
||||
}
|
||||
const iconClasses =
|
||||
"text-2xl text-default-500 pointer-events-none flex-shrink-0";
|
||||
|
||||
export function DataTableRowActions<FindingProps>({
|
||||
row,
|
||||
}: DataTableRowActionsProps<FindingProps>) {
|
||||
const findingId = (row.original as { id: string }).id;
|
||||
return (
|
||||
<>
|
||||
{/* <CustomAlertModal
|
||||
isOpen={isEditOpen}
|
||||
onOpenChange={setIsEditOpen}
|
||||
title="Edit Provider"
|
||||
description={"Edit the provider details"}
|
||||
>
|
||||
<EditForm
|
||||
providerId={providerId}
|
||||
providerAlias={providerAlias}
|
||||
setIsOpen={setIsEditOpen}
|
||||
/>
|
||||
</CustomAlertModal>
|
||||
<CustomAlertModal
|
||||
isOpen={isDeleteOpen}
|
||||
onOpenChange={setIsDeleteOpen}
|
||||
title="Are you absolutely sure?"
|
||||
description="This action cannot be undone. This will permanently delete your provider account and remove your data from the server."
|
||||
>
|
||||
<DeleteForm providerId={providerId} setIsOpen={setIsDeleteOpen} />
|
||||
</CustomAlertModal> */}
|
||||
|
||||
<div className="relative flex items-center justify-end gap-2">
|
||||
<Dropdown
|
||||
className="shadow-xl dark:bg-prowler-blue-800"
|
||||
placement="bottom"
|
||||
>
|
||||
<DropdownTrigger>
|
||||
<Button isIconOnly radius="full" size="sm" variant="light">
|
||||
<VerticalDotsIcon className="text-default-400" />
|
||||
</Button>
|
||||
</DropdownTrigger>
|
||||
<DropdownMenu
|
||||
closeOnSelect
|
||||
aria-label="Actions"
|
||||
color="default"
|
||||
variant="flat"
|
||||
>
|
||||
<DropdownSection title="Actions">
|
||||
<DropdownItem
|
||||
key="jira"
|
||||
description="Allows you to send the finding to Jira"
|
||||
textValue="Send to Jira"
|
||||
startContent={<EditDocumentBulkIcon className={iconClasses} />}
|
||||
// onClick={() => setIsEditOpen(true)}
|
||||
>
|
||||
<span className="hidden text-sm">{findingId}</span>
|
||||
Send to Jira
|
||||
</DropdownItem>
|
||||
<DropdownItem
|
||||
key="slack"
|
||||
description="Allows you to send the finding to Slack"
|
||||
textValue="Send to Slack"
|
||||
startContent={<EditDocumentBulkIcon className={iconClasses} />}
|
||||
// onClick={() => setIsEditOpen(true)}
|
||||
>
|
||||
Send to Slack
|
||||
</DropdownItem>
|
||||
</DropdownSection>
|
||||
</DropdownMenu>
|
||||
</Dropdown>
|
||||
</div>
|
||||
</>
|
||||
);
|
||||
}
|
||||
@@ -0,0 +1,40 @@
|
||||
"use client";
|
||||
|
||||
// import { usePathname, useRouter, useSearchParams } from "next/navigation";
|
||||
// import { useEffect } from "react";
|
||||
|
||||
import { FindingProps } from "@/types/components";
|
||||
|
||||
import { FindingDetail } from "./finding-detail";
|
||||
|
||||
export const DataTableRowDetails = ({
|
||||
// entityId,
|
||||
findingDetails,
|
||||
}: {
|
||||
entityId: string;
|
||||
findingDetails: FindingProps;
|
||||
}) => {
|
||||
// const router = useRouter();
|
||||
// const pathname = usePathname();
|
||||
// const searchParams = useSearchParams();
|
||||
|
||||
// useEffect(() => {
|
||||
// if (entityId) {
|
||||
// const params = new URLSearchParams(searchParams.toString());
|
||||
// params.set("id", entityId);
|
||||
// router.push(`${pathname}?${params.toString()}`, { scroll: false });
|
||||
// }
|
||||
|
||||
// return () => {
|
||||
// if (entityId) {
|
||||
// const cleanupParams = new URLSearchParams(searchParams.toString());
|
||||
// cleanupParams.delete("id");
|
||||
// router.push(`${pathname}?${cleanupParams.toString()}`, {
|
||||
// scroll: false,
|
||||
// });
|
||||
// }
|
||||
// };
|
||||
// }, [entityId, pathname, router, searchParams]);
|
||||
|
||||
return <FindingDetail findingDetails={findingDetails} />;
|
||||
};
|
||||
@@ -0,0 +1,219 @@
|
||||
"use client";
|
||||
|
||||
import { Snippet } from "@nextui-org/react";
|
||||
import Link from "next/link";
|
||||
|
||||
import { SnippetId } from "@/components/ui/entities";
|
||||
import { DateWithTime } from "@/components/ui/entities/date-with-time";
|
||||
import { SeverityBadge } from "@/components/ui/table/severity-badge";
|
||||
import { FindingProps } from "@/types";
|
||||
|
||||
export const FindingDetail = ({
|
||||
findingDetails,
|
||||
}: {
|
||||
findingDetails: FindingProps;
|
||||
}) => {
|
||||
const finding = findingDetails;
|
||||
const attributes = finding.attributes;
|
||||
const resource = finding.relationships.resource.attributes;
|
||||
|
||||
const remediation = attributes.check_metadata.remediation;
|
||||
|
||||
return (
|
||||
<div className="flex flex-col gap-6 rounded-lg">
|
||||
{/* Header */}
|
||||
<div className="flex items-center justify-between">
|
||||
<div>
|
||||
<h2 className="line-clamp-2 text-xl font-bold leading-tight text-gray-800 dark:text-prowler-theme-pale/90">
|
||||
{attributes.check_metadata.checktitle}
|
||||
</h2>
|
||||
<p className="text-sm text-gray-500 dark:text-prowler-theme-pale/70">
|
||||
{resource.service}
|
||||
</p>
|
||||
</div>
|
||||
<div
|
||||
className={`rounded-lg px-3 py-1 text-sm font-semibold ${
|
||||
attributes.status === "PASS"
|
||||
? "bg-green-100 text-green-600"
|
||||
: attributes.status === "MANUAL"
|
||||
? "bg-gray-100 text-gray-600"
|
||||
: "bg-red-100 text-red-600"
|
||||
}`}
|
||||
>
|
||||
{attributes.status}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{/* Check Metadata */}
|
||||
<div className="flex flex-col gap-4 rounded-lg p-4 shadow dark:bg-prowler-blue-400">
|
||||
<div className="flex items-center justify-between">
|
||||
<h3 className="text-lg font-bold text-gray-800 dark:text-prowler-theme-pale/90">
|
||||
Check Metadata
|
||||
</h3>
|
||||
<SeverityBadge severity={attributes.severity} />
|
||||
</div>
|
||||
{attributes.status === "FAIL" && (
|
||||
<Snippet
|
||||
className="max-w-full py-4"
|
||||
color="danger"
|
||||
hideCopyButton
|
||||
hideSymbol
|
||||
>
|
||||
<p className="text-sm font-semibold dark:text-prowler-theme-pale">
|
||||
Risk
|
||||
</p>
|
||||
<p className="whitespace-pre-line text-gray-800 dark:text-prowler-theme-pale/90">
|
||||
{attributes.check_metadata.risk}
|
||||
</p>
|
||||
</Snippet>
|
||||
)}
|
||||
|
||||
<div className="flex flex-col gap-2">
|
||||
<p className="text-sm font-semibold dark:text-prowler-theme-pale">
|
||||
Description
|
||||
</p>
|
||||
<p className="text-gray-800 dark:text-prowler-theme-pale/90">
|
||||
{attributes.check_metadata.description}
|
||||
</p>
|
||||
</div>
|
||||
|
||||
<div className="flex flex-col gap-2">
|
||||
<h3 className="text-sm font-semibold dark:text-prowler-theme-pale">
|
||||
Remediation
|
||||
</h3>
|
||||
<div className="text-gray-800 dark:text-prowler-theme-pale/90">
|
||||
{remediation.recommendation && (
|
||||
<>
|
||||
<p className="text-sm font-semibold">Recommendation:</p>
|
||||
<p>{remediation.recommendation.text}</p>
|
||||
<Link
|
||||
target="_blank"
|
||||
href={remediation.recommendation.url}
|
||||
className="mt-2 inline-block text-sm text-blue-500 underline"
|
||||
>
|
||||
Learn more
|
||||
</Link>
|
||||
</>
|
||||
)}
|
||||
{remediation.code &&
|
||||
Object.values(remediation.code).some(Boolean) && (
|
||||
<div className="flex flex-col gap-2">
|
||||
<p className="mt-4 text-sm font-semibold">
|
||||
Check these links:
|
||||
</p>
|
||||
<div className="flex flex-col gap-2">
|
||||
{remediation.code.cli && (
|
||||
<div>
|
||||
<p className="text-sm font-semibold">CLI Command:</p>
|
||||
<Snippet hideSymbol size="sm" className="max-w-full">
|
||||
<p className="whitespace-pre-line">
|
||||
{remediation.code.cli}
|
||||
</p>
|
||||
</Snippet>
|
||||
</div>
|
||||
)}
|
||||
<div className="flex flex-row gap-4">
|
||||
{Object.entries(remediation.code)
|
||||
.filter(([key]) => key !== "cli")
|
||||
.map(([key, value]) =>
|
||||
value ? (
|
||||
<Link
|
||||
key={key}
|
||||
href={value}
|
||||
target="_blank"
|
||||
className="text-sm font-medium text-blue-500"
|
||||
>
|
||||
{key === "other"
|
||||
? "External doc"
|
||||
: key.charAt(0).toUpperCase() +
|
||||
key.slice(1).toLowerCase()}
|
||||
</Link>
|
||||
) : null,
|
||||
)}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{/* Resources Section */}
|
||||
<div className="flex flex-col gap-4 rounded-lg p-4 shadow dark:bg-prowler-blue-400">
|
||||
<h3 className="text-lg font-bold text-gray-800 dark:text-prowler-theme-pale/90">
|
||||
Resource Details
|
||||
</h3>
|
||||
<div className="grid grid-cols-2 gap-6">
|
||||
<div className="col-span-2">
|
||||
<p className="text-sm font-semibold dark:text-prowler-theme-pale">
|
||||
Resource ID
|
||||
</p>
|
||||
<Snippet size="sm" hideSymbol className="max-w-full">
|
||||
<p className="whitespace-pre-line">{resource.uid}</p>
|
||||
</Snippet>
|
||||
</div>
|
||||
<div>
|
||||
<p className="text-sm font-semibold dark:text-prowler-theme-pale">
|
||||
Resource Name
|
||||
</p>
|
||||
<p className="text-gray-800 dark:text-prowler-theme-pale/90">
|
||||
{resource.name}
|
||||
</p>
|
||||
</div>
|
||||
<div>
|
||||
<p className="text-sm font-semibold dark:text-prowler-theme-pale">
|
||||
Region
|
||||
</p>
|
||||
<p className="text-gray-800 dark:text-prowler-theme-pale/90">
|
||||
{resource.region}
|
||||
</p>
|
||||
</div>
|
||||
<div>
|
||||
<p className="text-sm font-semibold dark:text-prowler-theme-pale">
|
||||
Resource Type
|
||||
</p>
|
||||
<p className="text-gray-800 dark:text-prowler-theme-pale/90">
|
||||
{resource.type}
|
||||
</p>
|
||||
</div>
|
||||
<div>
|
||||
<p className="text-sm font-semibold dark:text-prowler-theme-pale">
|
||||
Severity
|
||||
</p>
|
||||
<SeverityBadge severity={attributes.severity} />
|
||||
</div>
|
||||
{resource.tags &&
|
||||
Object.entries(resource.tags).map(([key, value]) => (
|
||||
<div key={key}>
|
||||
<p className="text-sm font-semibold dark:text-prowler-theme-pale">
|
||||
Tag: {key}
|
||||
</p>
|
||||
<SnippetId
|
||||
entityId={value}
|
||||
hideSymbol
|
||||
size="sm"
|
||||
className="max-w-full"
|
||||
>
|
||||
<p className="whitespace-pre-line">{value}</p>
|
||||
</SnippetId>
|
||||
</div>
|
||||
))}
|
||||
<div className="col-span-2 grid grid-cols-2 gap-6">
|
||||
<div>
|
||||
<p className="text-sm font-semibold dark:text-prowler-theme-pale">
|
||||
Inserted At
|
||||
</p>
|
||||
<DateWithTime inline dateTime={resource.inserted_at} />
|
||||
</div>
|
||||
<div>
|
||||
<p className="text-sm font-semibold dark:text-prowler-theme-pale">
|
||||
Updated At
|
||||
</p>
|
||||
<DateWithTime inline dateTime={resource.updated_at} />
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
};
|
||||
@@ -0,0 +1,5 @@
|
||||
export * from "./column-findings";
|
||||
export * from "./data-table-row-actions";
|
||||
export * from "./data-table-row-details";
|
||||
export * from "./finding-detail";
|
||||
export * from "./skeleton-table-findings";
|
||||
@@ -0,0 +1,65 @@
|
||||
import { Card, Skeleton } from "@nextui-org/react";
|
||||
import React from "react";
|
||||
|
||||
export const SkeletonTableFindings = () => {
|
||||
return (
|
||||
<Card className="h-full w-full space-y-5 p-4" radius="sm">
|
||||
{/* Table headers */}
|
||||
<div className="hidden justify-between md:flex">
|
||||
<Skeleton className="w-1/12 rounded-lg">
|
||||
<div className="h-8 bg-default-200"></div>
|
||||
</Skeleton>
|
||||
<Skeleton className="w-2/12 rounded-lg">
|
||||
<div className="h-8 bg-default-200"></div>
|
||||
</Skeleton>
|
||||
<Skeleton className="w-2/12 rounded-lg">
|
||||
<div className="h-8 bg-default-200"></div>
|
||||
</Skeleton>
|
||||
<Skeleton className="w-2/12 rounded-lg">
|
||||
<div className="h-8 bg-default-200"></div>
|
||||
</Skeleton>
|
||||
<Skeleton className="w-2/12 rounded-lg">
|
||||
<div className="h-8 bg-default-200"></div>
|
||||
</Skeleton>
|
||||
<Skeleton className="w-1/12 rounded-lg">
|
||||
<div className="h-8 bg-default-200"></div>
|
||||
</Skeleton>
|
||||
<Skeleton className="w-1/12 rounded-lg">
|
||||
<div className="h-8 bg-default-200"></div>
|
||||
</Skeleton>
|
||||
</div>
|
||||
|
||||
{/* Table body */}
|
||||
<div className="space-y-3">
|
||||
{[...Array(3)].map((_, index) => (
|
||||
<div
|
||||
key={index}
|
||||
className="flex flex-col items-center justify-between space-x-0 md:flex-row md:space-x-4"
|
||||
>
|
||||
<Skeleton className="mb-2 w-full rounded-lg md:mb-0 md:w-1/12">
|
||||
<div className="h-12 bg-default-300"></div>
|
||||
</Skeleton>
|
||||
<Skeleton className="mb-2 w-full rounded-lg md:mb-0 md:w-2/12">
|
||||
<div className="h-12 bg-default-300"></div>
|
||||
</Skeleton>
|
||||
<Skeleton className="mb-2 hidden rounded-lg sm:flex md:mb-0 md:w-2/12">
|
||||
<div className="h-12 bg-default-300"></div>
|
||||
</Skeleton>
|
||||
<Skeleton className="mb-2 hidden rounded-lg sm:flex md:mb-0 md:w-2/12">
|
||||
<div className="h-12 bg-default-300"></div>
|
||||
</Skeleton>
|
||||
<Skeleton className="mb-2 hidden rounded-lg sm:flex md:mb-0 md:w-2/12">
|
||||
<div className="h-12 bg-default-300"></div>
|
||||
</Skeleton>
|
||||
<Skeleton className="mb-2 hidden rounded-lg sm:flex md:mb-0 md:w-1/12">
|
||||
<div className="h-12 bg-default-300"></div>
|
||||
</Skeleton>
|
||||
<Skeleton className="mb-2 hidden rounded-lg sm:flex md:mb-0 md:w-1/12">
|
||||
<div className="h-12 bg-default-300"></div>
|
||||
</Skeleton>
|
||||
</div>
|
||||
))}
|
||||
</div>
|
||||
</Card>
|
||||
);
|
||||
};
|
||||
@@ -0,0 +1,810 @@
|
||||
import * as React from "react";
|
||||
|
||||
import { IconSvgProps } from "@/types";
|
||||
|
||||
export const TwitterIcon: React.FC<IconSvgProps> = ({
|
||||
size = 24,
|
||||
width,
|
||||
height,
|
||||
...props
|
||||
}) => {
|
||||
return (
|
||||
<svg
|
||||
height={size || height}
|
||||
viewBox="0 0 24 24"
|
||||
width={size || width}
|
||||
{...props}
|
||||
>
|
||||
<path
|
||||
d="M19.633 7.997c.013.175.013.349.013.523 0 5.325-4.053 11.461-11.46 11.461-2.282 0-4.402-.661-6.186-1.809.324.037.636.05.973.05a8.07 8.07 0 0 0 5.001-1.721 4.036 4.036 0 0 1-3.767-2.793c.249.037.499.062.761.062.361 0 .724-.05 1.061-.137a4.027 4.027 0 0 1-3.23-3.953v-.05c.537.299 1.16.486 1.82.511a4.022 4.022 0 0 1-1.796-3.354c0-.748.199-1.434.548-2.032a11.457 11.457 0 0 0 8.306 4.215c-.062-.3-.1-.611-.1-.923a4.026 4.026 0 0 1 4.028-4.028c1.16 0 2.207.486 2.943 1.272a7.957 7.957 0 0 0 2.556-.973 4.02 4.02 0 0 1-1.771 2.22 8.073 8.073 0 0 0 2.319-.624 8.645 8.645 0 0 1-2.019 2.083z"
|
||||
fill="currentColor"
|
||||
/>
|
||||
</svg>
|
||||
);
|
||||
};
|
||||
|
||||
export const GithubIcon: React.FC<IconSvgProps> = ({
|
||||
size = 24,
|
||||
width,
|
||||
height,
|
||||
...props
|
||||
}) => {
|
||||
return (
|
||||
<svg
|
||||
height={size || height}
|
||||
viewBox="0 0 24 24"
|
||||
width={size || width}
|
||||
{...props}
|
||||
>
|
||||
<path
|
||||
clipRule="evenodd"
|
||||
d="M12.026 2c-5.509 0-9.974 4.465-9.974 9.974 0 4.406 2.857 8.145 6.821 9.465.499.09.679-.217.679-.481 0-.237-.008-.865-.011-1.696-2.775.602-3.361-1.338-3.361-1.338-.452-1.152-1.107-1.459-1.107-1.459-.905-.619.069-.605.069-.605 1.002.07 1.527 1.028 1.527 1.028.89 1.524 2.336 1.084 2.902.829.091-.645.351-1.085.635-1.334-2.214-.251-4.542-1.107-4.542-4.93 0-1.087.389-1.979 1.024-2.675-.101-.253-.446-1.268.099-2.64 0 0 .837-.269 2.742 1.021a9.582 9.582 0 0 1 2.496-.336 9.554 9.554 0 0 1 2.496.336c1.906-1.291 2.742-1.021 2.742-1.021.545 1.372.203 2.387.099 2.64.64.696 1.024 1.587 1.024 2.675 0 3.833-2.33 4.675-4.552 4.922.355.308.675.916.675 1.846 0 1.334-.012 2.41-.012 2.737 0 .267.178.577.687.479C19.146 20.115 22 16.379 22 11.974 22 6.465 17.535 2 12.026 2z"
|
||||
fill="currentColor"
|
||||
fillRule="evenodd"
|
||||
/>
|
||||
</svg>
|
||||
);
|
||||
};
|
||||
|
||||
export const MoonFilledIcon: React.FC<IconSvgProps> = ({
|
||||
size = 24,
|
||||
width,
|
||||
height,
|
||||
...props
|
||||
}) => (
|
||||
<svg
|
||||
aria-hidden="true"
|
||||
focusable="false"
|
||||
height={size || height}
|
||||
role="presentation"
|
||||
viewBox="0 0 24 24"
|
||||
width={size || width}
|
||||
{...props}
|
||||
>
|
||||
<path
|
||||
d="M21.53 15.93c-.16-.27-.61-.69-1.73-.49a8.46 8.46 0 01-1.88.13 8.409 8.409 0 01-5.91-2.82 8.068 8.068 0 01-1.44-8.66c.44-1.01.13-1.54-.09-1.76s-.77-.55-1.83-.11a10.318 10.318 0 00-6.32 10.21 10.475 10.475 0 007.04 8.99 10 10 0 002.89.55c.16.01.32.02.48.02a10.5 10.5 0 008.47-4.27c.67-.93.49-1.519.32-1.79z"
|
||||
fill="currentColor"
|
||||
/>
|
||||
</svg>
|
||||
);
|
||||
|
||||
export const SunFilledIcon: React.FC<IconSvgProps> = ({
|
||||
size = 24,
|
||||
width,
|
||||
height,
|
||||
...props
|
||||
}) => (
|
||||
<svg
|
||||
aria-hidden="true"
|
||||
focusable="false"
|
||||
height={size || height}
|
||||
role="presentation"
|
||||
viewBox="0 0 24 24"
|
||||
width={size || width}
|
||||
{...props}
|
||||
>
|
||||
<g fill="currentColor">
|
||||
<path d="M19 12a7 7 0 11-7-7 7 7 0 017 7z" />
|
||||
<path d="M12 22.96a.969.969 0 01-1-.96v-.08a1 1 0 012 0 1.038 1.038 0 01-1 1.04zm7.14-2.82a1.024 1.024 0 01-.71-.29l-.13-.13a1 1 0 011.41-1.41l.13.13a1 1 0 010 1.41.984.984 0 01-.7.29zm-14.28 0a1.024 1.024 0 01-.71-.29 1 1 0 010-1.41l.13-.13a1 1 0 011.41 1.41l-.13.13a1 1 0 01-.7.29zM22 13h-.08a1 1 0 010-2 1.038 1.038 0 011.04 1 .969.969 0 01-.96 1zM2.08 13H2a1 1 0 010-2 1.038 1.038 0 011.04 1 .969.969 0 01-.96 1zm16.93-7.01a1.024 1.024 0 01-.71-.29 1 1 0 010-1.41l.13-.13a1 1 0 011.41 1.41l-.13.13a.984.984 0 01-.7.29zm-14.02 0a1.024 1.024 0 01-.71-.29l-.13-.14a1 1 0 011.41-1.41l.13.13a1 1 0 010 1.41.97.97 0 01-.7.3zM12 3.04a.969.969 0 01-1-.96V2a1 1 0 012 0 1.038 1.038 0 01-1 1.04z" />
|
||||
</g>
|
||||
</svg>
|
||||
);
|
||||
|
||||
export const SearchIcon: React.FC<IconSvgProps> = ({
|
||||
size = 24,
|
||||
width,
|
||||
height,
|
||||
...props
|
||||
}) => (
|
||||
<svg
|
||||
aria-hidden="true"
|
||||
fill="none"
|
||||
focusable="false"
|
||||
height={size || height}
|
||||
role="presentation"
|
||||
viewBox="0 0 24 24"
|
||||
width={size || width}
|
||||
{...props}
|
||||
>
|
||||
<path
|
||||
d="M11.5 21C16.7467 21 21 16.7467 21 11.5C21 6.25329 16.7467 2 11.5 2C6.25329 2 2 6.25329 2 11.5C2 16.7467 6.25329 21 11.5 21Z"
|
||||
stroke="currentColor"
|
||||
strokeLinecap="round"
|
||||
strokeLinejoin="round"
|
||||
strokeWidth="2"
|
||||
/>
|
||||
<path
|
||||
d="M22 22L20 20"
|
||||
stroke="currentColor"
|
||||
strokeLinecap="round"
|
||||
strokeLinejoin="round"
|
||||
strokeWidth="2"
|
||||
/>
|
||||
</svg>
|
||||
);
|
||||
|
||||
export const ChevronDownIcon: React.FC<IconSvgProps> = ({
|
||||
size = 24,
|
||||
width,
|
||||
height,
|
||||
strokeWidth = 1.5,
|
||||
...props
|
||||
}) => (
|
||||
<svg
|
||||
aria-hidden="true"
|
||||
fill="none"
|
||||
focusable="false"
|
||||
height={size || height}
|
||||
role="presentation"
|
||||
viewBox="0 0 24 24"
|
||||
width={size || width}
|
||||
{...props}
|
||||
>
|
||||
<path
|
||||
d="M19.92 8.95l-6.52 6.52c-.77.77-2.03.77-2.8 0L4.08 8.95"
|
||||
stroke="currentColor"
|
||||
strokeLinecap="round"
|
||||
strokeLinejoin="round"
|
||||
strokeMiterlimit={10}
|
||||
strokeWidth={strokeWidth}
|
||||
/>
|
||||
</svg>
|
||||
);
|
||||
|
||||
export const PlusIcon: React.FC<IconSvgProps> = ({
|
||||
size = 24,
|
||||
width,
|
||||
height,
|
||||
...props
|
||||
}) => (
|
||||
<svg
|
||||
aria-hidden="true"
|
||||
fill="none"
|
||||
focusable="false"
|
||||
height={size || height}
|
||||
role="presentation"
|
||||
viewBox="0 0 24 24"
|
||||
width={size || width}
|
||||
{...props}
|
||||
>
|
||||
<g
|
||||
fill="none"
|
||||
stroke="currentColor"
|
||||
strokeLinecap="round"
|
||||
strokeLinejoin="round"
|
||||
strokeWidth={1.5}
|
||||
>
|
||||
<path d="M6 12h12" />
|
||||
<path d="M12 18V6" />
|
||||
</g>
|
||||
</svg>
|
||||
);
|
||||
|
||||
export const VerticalDotsIcon: React.FC<IconSvgProps> = ({
|
||||
size = 24,
|
||||
width,
|
||||
height,
|
||||
...props
|
||||
}) => (
|
||||
<svg
|
||||
aria-hidden="true"
|
||||
fill="none"
|
||||
focusable="false"
|
||||
height={size || height}
|
||||
role="presentation"
|
||||
viewBox="0 0 24 24"
|
||||
width={size || width}
|
||||
{...props}
|
||||
>
|
||||
<g fill="currentColor">
|
||||
<path d="M12 10c-1.1 0-2 .9-2 2s.9 2 2 2 2-.9 2-2-.9-2-2-2zM12 4c-1.1 0-2 .9-2 2s.9 2 2 2 2-.9 2-2-.9-2-2-2zM12 16c-1.1 0-2 .9-2 2s.9 2 2 2 2-.9 2-2-.9-2-2-2z" />
|
||||
</g>
|
||||
</svg>
|
||||
);
|
||||
|
||||
export const DeleteIcon: React.FC<IconSvgProps> = ({
|
||||
size,
|
||||
height,
|
||||
width,
|
||||
...props
|
||||
}) => {
|
||||
return (
|
||||
<svg
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
fill="none"
|
||||
height={size || height || 48}
|
||||
viewBox="0 0 24 24"
|
||||
width={size || width || 48}
|
||||
aria-hidden="true"
|
||||
{...props}
|
||||
>
|
||||
<g fill="none">
|
||||
<path d="m12.593 23.258-.011.002-.071.035-.02.004-.014-.004-.071-.035q-.016-.005-.024.005l-.004.01-.017.428.005.02.01.013.104.074.015.004.012-.004.104-.074.012-.016.004-.017-.017-.427q-.004-.016-.017-.018m.265-.113-.013.002-.185.093-.01.01-.003.011.018.43.005.012.008.007.201.093q.019.005.029-.008l.004-.014-.034-.614q-.005-.018-.02-.022m-.715.002a.02.02 0 0 0-.027.006l-.006.014-.034.614q.001.018.017.024l.015-.002.201-.093.01-.008.004-.011.017-.43-.003-.012-.01-.01z" />
|
||||
<path
|
||||
fill="currentColor"
|
||||
d="M14.28 2a2 2 0 0 1 1.897 1.368L16.72 5H20a1 1 0 1 1 0 2l-.003.071-.867 12.143A3 3 0 0 1 16.138 22H7.862a3 3 0 0 1-2.992-2.786L4.003 7.07 4 7a1 1 0 0 1 0-2h3.28l.543-1.632A2 2 0 0 1 9.721 2zm3.717 5H6.003l.862 12.071a1 1 0 0 0 .997.929h8.276a1 1 0 0 0 .997-.929zM10 10a1 1 0 0 1 .993.883L11 11v5a1 1 0 0 1-1.993.117L9 16v-5a1 1 0 0 1 1-1m4 0a1 1 0 0 1 1 1v5a1 1 0 1 1-2 0v-5a1 1 0 0 1 1-1m.28-6H9.72l-.333 1h5.226z"
|
||||
/>
|
||||
</g>
|
||||
</svg>
|
||||
);
|
||||
};
|
||||
|
||||
export const CheckIcon: React.FC<IconSvgProps> = ({
|
||||
size = 24,
|
||||
width,
|
||||
height,
|
||||
...props
|
||||
}) => (
|
||||
<svg
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
width={size || width}
|
||||
height={size || height}
|
||||
viewBox="0 0 2048 2048"
|
||||
{...props}
|
||||
>
|
||||
<path
|
||||
fill="currentColor"
|
||||
d="M2048 1024q0 142-36 272t-103 245t-160 207t-208 160t-245 103t-272 37q-142 0-272-36t-245-103t-207-160t-160-208t-103-245t-37-272q0-141 36-272t103-245t160-207t208-160T752 37t272-37q141 0 272 36t245 103t207 160t160 208t103 245t37 272m-1024 896q123 0 237-32t214-90t182-141t140-181t91-214t32-238q0-123-32-237t-90-214t-141-182t-181-140t-214-91t-238-32q-124 0-238 32t-213 90t-182 141t-140 181t-91 214t-32 238q0 124 32 238t90 213t141 182t181 140t214 91t238 32m0-512q55 0 107-15t98-45t81-69t61-91l116 56q-32 67-80 121t-109 92t-130 58t-144 21q-110 0-210-45t-174-128v173H512v-384h384v128H738q54 60 129 94t157 34m384-723V512h128v384h-384V768h158q-54-60-129-94t-157-34q-55 0-107 15t-98 45t-81 69t-61 91l-116-56q32-67 80-121t109-92t130-58t144-21q110 0 210 45t174 128"
|
||||
/>
|
||||
</svg>
|
||||
);
|
||||
|
||||
export const CrossIcon: React.FC<IconSvgProps> = ({
|
||||
size = 24,
|
||||
width,
|
||||
height,
|
||||
...props
|
||||
}) => (
|
||||
<svg
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
width={size || width}
|
||||
height={size || height}
|
||||
viewBox="0 0 24 24"
|
||||
{...props}
|
||||
>
|
||||
<path
|
||||
fill="currentColor"
|
||||
d="M16.066 8.995a.75.75 0 1 0-1.06-1.061L12 10.939L8.995 7.934a.75.75 0 1 0-1.06 1.06L10.938 12l-3.005 3.005a.75.75 0 0 0 1.06 1.06L12 13.06l3.005 3.006a.75.75 0 0 0 1.06-1.06L13.062 12z"
|
||||
/>
|
||||
</svg>
|
||||
);
|
||||
|
||||
export const PassIcon: React.FC<IconSvgProps> = ({
|
||||
size = 24,
|
||||
width,
|
||||
height,
|
||||
...props
|
||||
}) => (
|
||||
<svg
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
width={size || width}
|
||||
height={size || height}
|
||||
viewBox="0 0 16 16"
|
||||
{...props}
|
||||
>
|
||||
<g fill="currentColor">
|
||||
<path d="M6.27 10.87h.71l4.56-4.56l-.71-.71l-4.2 4.21l-1.92-1.92L4 8.6z" />
|
||||
<path
|
||||
fillRule="evenodd"
|
||||
d="M8.6 1c1.6.1 3.1.9 4.2 2c1.3 1.4 2 3.1 2 5.1c0 1.6-.6 3.1-1.6 4.4c-1 1.2-2.4 2.1-4 2.4s-3.2.1-4.6-.7s-2.5-2-3.1-3.5S.8 7.5 1.3 6c.5-1.6 1.4-2.9 2.8-3.8C5.4 1.3 7 .9 8.6 1m.5 12.9c1.3-.3 2.5-1 3.4-2.1c.8-1.1 1.3-2.4 1.2-3.8c0-1.6-.6-3.2-1.7-4.3c-1-1-2.2-1.6-3.6-1.7c-1.3-.1-2.7.2-3.8 1S2.7 4.9 2.3 6.3c-.4 1.3-.4 2.7.2 4q.9 1.95 2.7 3c1.2.7 2.6.9 3.9.6"
|
||||
clipRule="evenodd"
|
||||
/>
|
||||
</g>
|
||||
</svg>
|
||||
);
|
||||
|
||||
export const RocketIcon: React.FC<IconSvgProps> = ({
|
||||
size = 24,
|
||||
width,
|
||||
height,
|
||||
...props
|
||||
}) => {
|
||||
return (
|
||||
<svg
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
width={size || width}
|
||||
height={size || height}
|
||||
viewBox="0 0 24 24"
|
||||
{...props}
|
||||
>
|
||||
<path
|
||||
fill="currentColor"
|
||||
d="m5.65 10.025l1.95.825q.35-.7.725-1.35t.825-1.3l-1.4-.275zM9.2 12.1l2.85 2.825q1.05-.4 2.25-1.225t2.25-1.875q1.75-1.75 2.738-3.887T20.15 4q-1.8-.125-3.95.863T12.3 7.6q-1.05 1.05-1.875 2.25T9.2 12.1m4.45-1.625q-.575-.575-.575-1.412t.575-1.413t1.425-.575t1.425.575t.575 1.413t-.575 1.412t-1.425.575t-1.425-.575m.475 8.025l2.1-2.1l-.275-1.4q-.65.45-1.3.812t-1.35.713zM21.95 2.175q.475 3.025-.587 5.888T17.7 13.525L18.2 16q.1.5-.05.975t-.5.825l-4.2 4.2l-2.1-4.925L7.075 12.8L2.15 10.7l4.175-4.2q.35-.35.838-.5t.987-.05l2.475.5q2.6-2.6 5.45-3.675t5.875-.6m-18.025 13.8q.875-.875 2.138-.887t2.137.862t.863 2.138t-.888 2.137q-.625.625-2.087 1.075t-4.038.8q.35-2.575.8-4.038t1.075-2.087m1.425 1.4q-.25.25-.5.913t-.35 1.337q.675-.1 1.338-.337t.912-.488q.3-.3.325-.725T6.8 17.35t-.725-.288t-.725.313"
|
||||
/>
|
||||
</svg>
|
||||
);
|
||||
};
|
||||
|
||||
export const AlertIcon: React.FC<IconSvgProps> = ({
|
||||
size = 24,
|
||||
width,
|
||||
height,
|
||||
...props
|
||||
}) => (
|
||||
<svg
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
aria-hidden="true"
|
||||
fill="none"
|
||||
focusable="false"
|
||||
height={size || height}
|
||||
role="presentation"
|
||||
viewBox="0 0 24 24"
|
||||
width={size || width}
|
||||
{...props}
|
||||
>
|
||||
<g fill="none">
|
||||
<path d="M24 0v24H0V0zM12.593 23.258l-.011.002l-.071.035l-.02.004l-.014-.004l-.071-.035q-.016-.005-.024.005l-.004.01l-.017.428l.005.02l.01.013l.104.074l.015.004l.012-.004l.104-.074l.012-.016l.004-.017l-.017-.427q-.004-.016-.017-.018m.265-.113l-.013.002l-.185.093l-.01.01l-.003.011l.018.43l.005.012l.008.007l.201.093q.019.005.029-.008l.004-.014l-.034-.614q-.005-.019-.02-.022m-.715.002a.02.02 0 0 0-.027.006l-.006.014l-.034.614q.001.018.017.024l.015-.002l.201-.093l.01-.008l.004-.011l.017-.43l-.003-.012l-.01-.01z" />
|
||||
<path
|
||||
fill="currentColor"
|
||||
d="m13.299 3.148l8.634 14.954a1.5 1.5 0 0 1-1.299 2.25H3.366a1.5 1.5 0 0 1-1.299-2.25l8.634-14.954c.577-1 2.02-1 2.598 0M12 4.898L4.232 18.352h15.536zM12 15a1 1 0 1 1 0 2a1 1 0 0 1 0-2m0-7a1 1 0 0 1 1 1v4a1 1 0 1 1-2 0V9a1 1 0 0 1 1-1"
|
||||
/>
|
||||
</g>
|
||||
</svg>
|
||||
);
|
||||
|
||||
export const NotificationIcon: React.FC<IconSvgProps> = ({
|
||||
size = 24,
|
||||
width,
|
||||
height,
|
||||
...props
|
||||
}) => (
|
||||
<svg
|
||||
fill="none"
|
||||
height={size || height || 24}
|
||||
viewBox="0 0 24 24"
|
||||
width={size || width || 24}
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
{...props}
|
||||
>
|
||||
<path
|
||||
clipRule="evenodd"
|
||||
d="M18.707 8.796c0 1.256.332 1.997 1.063 2.85.553.628.73 1.435.73 2.31 0 .874-.287 1.704-.863 2.378a4.537 4.537 0 01-2.9 1.413c-1.571.134-3.143.247-4.736.247-1.595 0-3.166-.068-4.737-.247a4.532 4.532 0 01-2.9-1.413 3.616 3.616 0 01-.864-2.378c0-.875.178-1.682.73-2.31.754-.854 1.064-1.594 1.064-2.85V8.37c0-1.682.42-2.781 1.283-3.858C7.861 2.942 9.919 2 11.956 2h.09c2.08 0 4.204.987 5.466 2.625.82 1.054 1.195 2.108 1.195 3.745v.426zM9.074 20.061c0-.504.462-.734.89-.833.5-.106 3.545-.106 4.045 0 .428.099.89.33.89.833-.025.48-.306.904-.695 1.174a3.635 3.635 0 01-1.713.731 3.795 3.795 0 01-1.008 0 3.618 3.618 0 01-1.714-.732c-.39-.269-.67-.694-.695-1.173z"
|
||||
fill="currentColor"
|
||||
fillRule="evenodd"
|
||||
/>
|
||||
</svg>
|
||||
);
|
||||
|
||||
export const IdIcon: React.FC<IconSvgProps> = ({
|
||||
size = 24,
|
||||
width,
|
||||
height,
|
||||
...props
|
||||
}) => (
|
||||
<svg
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
fill="currentColor"
|
||||
height={size || height || 24}
|
||||
viewBox="0 0 24 24"
|
||||
width={size || width || 24}
|
||||
{...props}
|
||||
>
|
||||
<path d="M18 4v16H6V8.8L10.8 4zm0-2h-8L4 8v12c0 1.1.9 2 2 2h12c1.1 0 2-.9 2-2V4c0-1.1-.9-2-2-2M9.5 19h-2v-2h2zm7 0h-2v-2h2zm-7-4h-2v-4h2zm3.5 4h-2v-4h2zm0-6h-2v-2h2zm3.5 2h-2v-4h2z" />
|
||||
</svg>
|
||||
);
|
||||
|
||||
export const DoneIcon: React.FC<IconSvgProps> = ({
|
||||
size,
|
||||
height,
|
||||
width,
|
||||
...props
|
||||
}) => {
|
||||
return (
|
||||
<svg
|
||||
width={size || width || 24}
|
||||
height={size || height || 24}
|
||||
viewBox="0 0 24 24"
|
||||
fill="currentColor"
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
{...props}
|
||||
>
|
||||
<path d="m2.394 13.742 4.743 3.62 7.616-8.704-1.506-1.316-6.384 7.296-3.257-2.486zm19.359-5.084-1.506-1.316-6.369 7.279-.753-.602-1.25 1.562 2.247 1.798z" />
|
||||
</svg>
|
||||
);
|
||||
};
|
||||
|
||||
export const CopyIcon: React.FC<IconSvgProps> = ({
|
||||
size,
|
||||
height,
|
||||
width,
|
||||
...props
|
||||
}) => {
|
||||
return (
|
||||
<svg
|
||||
fill="none"
|
||||
height={size || height || 20}
|
||||
shapeRendering="geometricPrecision"
|
||||
stroke="currentColor"
|
||||
strokeLinecap="round"
|
||||
strokeLinejoin="round"
|
||||
strokeWidth="1.5"
|
||||
viewBox="0 0 24 24"
|
||||
width={size || width || 20}
|
||||
{...props}
|
||||
>
|
||||
<path d="M6 17C4.89543 17 4 16.1046 4 15V5C4 3.89543 4.89543 3 6 3H13C13.7403 3 14.3866 3.4022 14.7324 4M11 21H18C19.1046 21 20 20.1046 20 19V9C20 7.89543 19.1046 7 18 7H11C9.89543 7 9 7.89543 9 9V19C9 20.1046 9.89543 21 11 21Z" />
|
||||
</svg>
|
||||
);
|
||||
};
|
||||
|
||||
export const FlowIcon: React.FC<IconSvgProps> = ({
|
||||
size,
|
||||
height,
|
||||
width,
|
||||
...props
|
||||
}) => {
|
||||
return (
|
||||
<svg
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
fill="none"
|
||||
height={size || height || 20}
|
||||
viewBox="0 0 20 20"
|
||||
width={size || width || 20}
|
||||
{...props}
|
||||
>
|
||||
<path
|
||||
fill="currentColor"
|
||||
d="M16.4 4a2.4 2.4 0 1 0-4.8 0c0 .961.568 1.784 1.384 2.167c-.082 1.584-1.27 2.122-3.335 2.896c-.87.327-1.829.689-2.649 1.234V6.176A2.396 2.396 0 0 0 6 1.6a2.397 2.397 0 0 0-1 4.576v7.649A2.39 2.39 0 0 0 3.6 16a2.4 2.4 0 1 0 4.8 0c0-.961-.568-1.784-1.384-2.167c.082-1.583 1.271-2.122 3.335-2.896c2.03-.762 4.541-1.711 4.64-4.756A2.4 2.4 0 0 0 16.4 4M6 2.615a1.384 1.384 0 1 1 0 2.768a1.384 1.384 0 0 1 0-2.768m0 14.77a1.385 1.385 0 1 1 0-2.77a1.385 1.385 0 0 1 0 2.77m8-12a1.385 1.385 0 1 1 0-2.77a1.385 1.385 0 0 1 0 2.77"
|
||||
/>
|
||||
</svg>
|
||||
);
|
||||
};
|
||||
|
||||
export const ConnectionIcon: React.FC<IconSvgProps> = ({
|
||||
size,
|
||||
height,
|
||||
width,
|
||||
...props
|
||||
}) => {
|
||||
return (
|
||||
<svg
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
fill="none"
|
||||
height={size || height || 20}
|
||||
viewBox="0 0 20 20"
|
||||
width={size || width || 20}
|
||||
{...props}
|
||||
>
|
||||
<path
|
||||
fill="currentColor"
|
||||
d="M18 14.824V12.5A3.5 3.5 0 0 0 14.5 9h-2A1.5 1.5 0 0 1 11 7.5V5.176A2.4 2.4 0 0 0 12.4 3a2.4 2.4 0 1 0-4.8 0c0 .967.576 1.796 1.4 2.176V7.5A1.5 1.5 0 0 1 7.5 9h-2A3.5 3.5 0 0 0 2 12.5v2.324A2.396 2.396 0 0 0 3 19.4a2.397 2.397 0 0 0 1-4.576V12.5A1.5 1.5 0 0 1 5.5 11h2c.539 0 1.044-.132 1.5-.35v4.174a2.396 2.396 0 0 0 1 4.576a2.397 2.397 0 0 0 1-4.576V10.65c.456.218.961.35 1.5.35h2a1.5 1.5 0 0 1 1.5 1.5v2.324A2.4 2.4 0 0 0 14.6 17a2.4 2.4 0 1 0 4.8 0c0-.967-.575-1.796-1.4-2.176M10 1.615a1.384 1.384 0 1 1 0 2.768a1.384 1.384 0 0 1 0-2.768m-7 16.77a1.385 1.385 0 1 1 0-2.77a1.385 1.385 0 0 1 0 2.77m7 0a1.385 1.385 0 1 1 0-2.77a1.385 1.385 0 0 1 0 2.77m7 0a1.385 1.385 0 1 1 0-2.77a1.385 1.385 0 0 1 0 2.77"
|
||||
/>
|
||||
</svg>
|
||||
);
|
||||
};
|
||||
|
||||
export const ConnectionTrue: React.FC<IconSvgProps> = ({
|
||||
size = 24,
|
||||
width,
|
||||
height,
|
||||
...props
|
||||
}) => (
|
||||
<svg
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
fill="none"
|
||||
stroke="currentColor"
|
||||
strokeLinecap="round"
|
||||
strokeLinejoin="round"
|
||||
strokeWidth="1.5"
|
||||
height={size || height || 24}
|
||||
viewBox="0 0 24 24"
|
||||
width={size || width || 24}
|
||||
{...props}
|
||||
>
|
||||
<path
|
||||
d="M12 20h.012M8.25 17c2-2 5.5-2 7.5 0m2.75-3c-3.768-3.333-9-3.333-13 0M2 11c3.158-2.667 6.579-4 10-4m3 .5s1 0 2 2c0 0 2.477-3.9 5-5.5"
|
||||
color="currentColor"
|
||||
/>
|
||||
</svg>
|
||||
);
|
||||
|
||||
export const ConnectionFalse: React.FC<IconSvgProps> = ({
|
||||
size = 24,
|
||||
width,
|
||||
height,
|
||||
...props
|
||||
}) => (
|
||||
<svg
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
fill="none"
|
||||
stroke="currentColor"
|
||||
strokeLinecap="round"
|
||||
strokeLinejoin="round"
|
||||
strokeWidth="1.5"
|
||||
height={size || height || 24}
|
||||
viewBox="0 0 24 24"
|
||||
width={size || width || 24}
|
||||
{...props}
|
||||
>
|
||||
<path
|
||||
d="M12 18h.012M8.25 15c2-2 5.5-2 7.5 0m2.75-3a11 11 0 0 0-.231-.199M5.5 12c2.564-2.136 5.634-2.904 8.5-2.301M2 9c3.466-2.927 7.248-4.247 11-3.962M22 5l-6 6m6 0-6-6"
|
||||
color="currentColor"
|
||||
/>
|
||||
</svg>
|
||||
);
|
||||
|
||||
export const ConnectionPending: React.FC<IconSvgProps> = ({
|
||||
size = 24,
|
||||
width,
|
||||
height,
|
||||
...props
|
||||
}) => (
|
||||
<svg
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
fill="none"
|
||||
stroke="currentColor"
|
||||
strokeWidth="1.05"
|
||||
height={size || height || 24}
|
||||
viewBox="0 0 24 24"
|
||||
width={size || width || 24}
|
||||
{...props}
|
||||
>
|
||||
<g fill="none" stroke="currentColor" strokeWidth="1.05">
|
||||
<circle cx="12" cy="18" r="2" />
|
||||
<path strokeOpacity=".2" d="M7.757 13.757a6 6 0 0 1 8.486 0" />
|
||||
<path
|
||||
strokeOpacity=".2"
|
||||
d="M4.929 10.93c3.905-3.905 10.237-3.905 14.142 0"
|
||||
opacity=".8"
|
||||
/>
|
||||
<path
|
||||
strokeOpacity=".2"
|
||||
d="M2.101 8.1c5.467-5.468 14.331-5.468 19.798 0"
|
||||
opacity=".8"
|
||||
/>
|
||||
</g>
|
||||
</svg>
|
||||
);
|
||||
|
||||
export const SuccessIcon: React.FC<IconSvgProps> = ({
|
||||
size = 24,
|
||||
width,
|
||||
height,
|
||||
...props
|
||||
}) => (
|
||||
<svg
|
||||
width={size || width || 24}
|
||||
height={size || height || 24}
|
||||
viewBox="0 0 24 24"
|
||||
fill="none"
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
{...props}
|
||||
>
|
||||
<path
|
||||
d="M12 2C6.49 2 2 6.49 2 12C2 17.51 6.49 22 12 22C17.51 22 22 17.51 22 12C22 6.49 17.51 2 12 2ZM16.78 9.7L11.11 15.37C10.97 15.51 10.78 15.59 10.58 15.59C10.38 15.59 10.19 15.51 10.05 15.37L7.22 12.54C6.93 12.25 6.93 11.77 7.22 11.48C7.51 11.19 7.99 11.19 8.28 11.48L10.58 13.78L15.72 8.64C16.01 8.35 16.49 8.35 16.78 8.64C17.07 8.93 17.07 9.4 16.78 9.7Z"
|
||||
fill="currentColor"
|
||||
/>
|
||||
</svg>
|
||||
);
|
||||
|
||||
export const ArrowUpIcon: React.FC<IconSvgProps> = ({
|
||||
size,
|
||||
height,
|
||||
width,
|
||||
...props
|
||||
}) => {
|
||||
return (
|
||||
<svg
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
fill="none"
|
||||
height={size || height || "1em"}
|
||||
viewBox="0 0 12 12"
|
||||
width={size || width || "1em"}
|
||||
aria-hidden="true"
|
||||
focusable="false"
|
||||
role="presentation"
|
||||
{...props}
|
||||
>
|
||||
<path
|
||||
d="M3 7.5L6 4.5L9 7.5"
|
||||
stroke="currentColor"
|
||||
strokeLinecap="round"
|
||||
strokeLinejoin="round"
|
||||
strokeWidth="1.5"
|
||||
/>
|
||||
</svg>
|
||||
);
|
||||
};
|
||||
|
||||
export const ArrowDownIcon: React.FC<IconSvgProps> = ({
|
||||
size,
|
||||
height,
|
||||
width,
|
||||
...props
|
||||
}) => {
|
||||
return (
|
||||
<svg
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
fill="none"
|
||||
height={size || height || "1em"}
|
||||
viewBox="0 0 12 12"
|
||||
width={size || width || "1em"}
|
||||
aria-hidden="true"
|
||||
focusable="false"
|
||||
role="presentation"
|
||||
{...props}
|
||||
>
|
||||
<path
|
||||
d="M3 4.5L6 7.5L9 4.5"
|
||||
stroke="currentColor"
|
||||
strokeLinecap="round"
|
||||
strokeLinejoin="round"
|
||||
strokeWidth="1.5"
|
||||
/>
|
||||
</svg>
|
||||
);
|
||||
};
|
||||
|
||||
export const ChevronsLeftRightIcon: React.FC<IconSvgProps> = ({
|
||||
size,
|
||||
height,
|
||||
width,
|
||||
...props
|
||||
}) => {
|
||||
return (
|
||||
<svg
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
fill="none"
|
||||
height={size || height || 24}
|
||||
viewBox="0 0 24 24"
|
||||
width={size || width || 24}
|
||||
stroke="currentColor"
|
||||
strokeWidth="2"
|
||||
strokeLinecap="round"
|
||||
strokeLinejoin="round"
|
||||
className="lucide lucide-chevrons-left-right ml-2 h-4 w-4 rotate-90"
|
||||
{...props}
|
||||
>
|
||||
<path d="m9 7-5 5 5 5M15 7l5 5-5 5" />
|
||||
</svg>
|
||||
);
|
||||
};
|
||||
|
||||
export const PlusCircleIcon: React.FC<IconSvgProps> = ({
|
||||
size,
|
||||
height,
|
||||
width,
|
||||
...props
|
||||
}) => {
|
||||
return (
|
||||
<svg
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
fill="none"
|
||||
height={size || height || 15}
|
||||
viewBox="0 0 15 15"
|
||||
width={size || width || 15}
|
||||
className="mr-2 size-4"
|
||||
{...props}
|
||||
>
|
||||
<path
|
||||
d="M7.5.877a6.623 6.623 0 1 0 0 13.246A6.623 6.623 0 0 0 7.5.877ZM1.827 7.5a5.673 5.673 0 1 1 11.346 0 5.673 5.673 0 0 1-11.346 0ZM7.5 4a.5.5 0 0 1 .5.5V7h2.5a.5.5 0 1 1 0 1H8v2.5a.5.5 0 0 1-1 0V8H4.5a.5.5 0 0 1 0-1H7V4.5a.5.5 0 0 1 .5-.5Z"
|
||||
fill="currentColor"
|
||||
fillRule="evenodd"
|
||||
clipRule="evenodd"
|
||||
/>
|
||||
</svg>
|
||||
);
|
||||
};
|
||||
|
||||
export const CustomFilterIcon: React.FC<IconSvgProps> = ({
|
||||
size,
|
||||
height,
|
||||
width,
|
||||
...props
|
||||
}) => {
|
||||
return (
|
||||
<svg
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
aria-hidden="true"
|
||||
height={size || height || 16}
|
||||
width={size || width || 16}
|
||||
viewBox="0 0 24 24"
|
||||
{...props}
|
||||
>
|
||||
<g fill="none" stroke="currentColor" strokeWidth="1.5">
|
||||
<path d="M9.5 14a3 3 0 1 1 0 6 3 3 0 0 1 0-6Zm5-10a3 3 0 1 0 0 6 3 3 0 0 0 0-6Z" />
|
||||
<path strokeLinecap="round" d="M15 16.959h7m-13-10H2m0 10h2m18-10h-2" />
|
||||
</g>
|
||||
</svg>
|
||||
);
|
||||
};
|
||||
|
||||
export const SaveIcon: React.FC<IconSvgProps> = ({
|
||||
size,
|
||||
height,
|
||||
width,
|
||||
...props
|
||||
}) => {
|
||||
return (
|
||||
<svg
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
fill="none"
|
||||
height={size || height || 48}
|
||||
viewBox="0 0 24 24"
|
||||
width={size || width || 48}
|
||||
aria-hidden="true"
|
||||
{...props}
|
||||
>
|
||||
<path
|
||||
d="m20.71 9.29l-6-6a1 1 0 0 0-.32-.21A1.1 1.1 0 0 0 14 3H6a3 3 0 0 0-3 3v12a3 3 0 0 0 3 3h12a3 3 0 0 0 3-3v-8a1 1 0 0 0-.29-.71M9 5h4v2H9Zm6 14H9v-3a1 1 0 0 1 1-1h4a1 1 0 0 1 1 1Zm4-1a1 1 0 0 1-1 1h-1v-3a3 3 0 0 0-3-3h-4a3 3 0 0 0-3 3v3H6a1 1 0 0 1-1-1V6a1 1 0 0 1 1-1h1v3a1 1 0 0 0 1 1h6a1 1 0 0 0 1-1V6.41l4 4Z"
|
||||
fill="currentColor"
|
||||
/>
|
||||
</svg>
|
||||
);
|
||||
};
|
||||
|
||||
export const AddIcon: React.FC<IconSvgProps> = ({
|
||||
size,
|
||||
height,
|
||||
width,
|
||||
...props
|
||||
}) => {
|
||||
return (
|
||||
<svg
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
fill="none"
|
||||
height={size || height || 20}
|
||||
viewBox="0 0 24 24"
|
||||
width={size || width || 20}
|
||||
aria-hidden="true"
|
||||
{...props}
|
||||
>
|
||||
<path
|
||||
fill="currentColor"
|
||||
fillRule="evenodd"
|
||||
d="M12 22c5.523 0 10-4.477 10-10S17.523 2 12 2 2 6.477 2 12s4.477 10 10 10m.75-13a.75.75 0 0 0-1.5 0v2.25H9a.75.75 0 0 0 0 1.5h2.25V15a.75.75 0 0 0 1.5 0v-2.25H15a.75.75 0 0 0 0-1.5h-2.25z"
|
||||
clipRule="evenodd"
|
||||
/>
|
||||
</svg>
|
||||
);
|
||||
};
|
||||
|
||||
export const ScheduleIcon: React.FC<IconSvgProps> = ({
|
||||
size,
|
||||
height,
|
||||
width,
|
||||
...props
|
||||
}) => {
|
||||
return (
|
||||
<svg
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
width={size || width || 24}
|
||||
height={size || height || 24}
|
||||
fill="none"
|
||||
stroke="currentColor"
|
||||
strokeWidth="2"
|
||||
strokeLinecap="round"
|
||||
strokeLinejoin="round"
|
||||
aria-hidden="true"
|
||||
{...props}
|
||||
>
|
||||
<path d="M21 7.5V6a2 2 0 0 0-2-2H5a2 2 0 0 0-2 2v14a2 2 0 0 0 2 2h3.5" />
|
||||
<path d="M16 2v4M8 2v4M3 10h5" />
|
||||
<path d="M17.5 17.5L16 16.3V14" />
|
||||
<circle cx="16" cy="16" r="6" />
|
||||
</svg>
|
||||
);
|
||||
};
|
||||
|
||||
export const InfoIcon: React.FC<IconSvgProps> = ({
|
||||
size = 24,
|
||||
width,
|
||||
height,
|
||||
...props
|
||||
}) => (
|
||||
<svg
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
width={size || width}
|
||||
height={size || height}
|
||||
viewBox="0 0 24 24"
|
||||
fill="none"
|
||||
stroke="currentColor"
|
||||
strokeLinecap="round"
|
||||
strokeLinejoin="round"
|
||||
strokeWidth="2"
|
||||
{...props}
|
||||
>
|
||||
<circle cx="12" cy="12" r="10" />
|
||||
<path d="M12 16v-4M12 8h.01" />
|
||||
</svg>
|
||||
);
|
||||
@@ -0,0 +1,63 @@
|
||||
import AWSLogo from "./aws.svg";
|
||||
import CISLogo from "./cis.svg";
|
||||
import CISALogo from "./cisa.svg";
|
||||
import ENSLogo from "./ens.png";
|
||||
import FedRAMPLogo from "./fedramp.svg";
|
||||
import FFIECLogo from "./ffiec.svg";
|
||||
import GDPRLogo from "./gdpr.svg";
|
||||
import GxPLogo from "./gxp-aws.svg";
|
||||
import HIPAALogo from "./hipaa.svg";
|
||||
import ISOLogo from "./iso-27001.svg";
|
||||
import MITRELogo from "./mitre-attack.svg";
|
||||
import NISTLogo from "./nist.svg";
|
||||
import PCILogo from "./pci-dss.svg";
|
||||
import RBILogo from "./rbi.svg";
|
||||
import SOC2Logo from "./soc2.svg";
|
||||
|
||||
export const getComplianceIcon = (complianceTitle: string) => {
|
||||
if (complianceTitle.toLowerCase().includes("aws")) {
|
||||
return AWSLogo;
|
||||
}
|
||||
if (complianceTitle.toLowerCase().includes("cisa")) {
|
||||
return CISALogo;
|
||||
}
|
||||
if (complianceTitle.toLowerCase().includes("cis")) {
|
||||
return CISLogo;
|
||||
}
|
||||
if (complianceTitle.toLowerCase().includes("ens")) {
|
||||
return ENSLogo;
|
||||
}
|
||||
if (complianceTitle.toLowerCase().includes("ffiec")) {
|
||||
return FFIECLogo;
|
||||
}
|
||||
if (complianceTitle.toLowerCase().includes("fedramp")) {
|
||||
return FedRAMPLogo;
|
||||
}
|
||||
if (complianceTitle.toLowerCase().includes("gdpr")) {
|
||||
return GDPRLogo;
|
||||
}
|
||||
if (complianceTitle.toLowerCase().includes("gxp")) {
|
||||
return GxPLogo;
|
||||
}
|
||||
if (complianceTitle.toLowerCase().includes("hipaa")) {
|
||||
return HIPAALogo;
|
||||
}
|
||||
if (complianceTitle.toLowerCase().includes("iso")) {
|
||||
return ISOLogo;
|
||||
}
|
||||
if (complianceTitle.toLowerCase().includes("mitre")) {
|
||||
return MITRELogo;
|
||||
}
|
||||
if (complianceTitle.toLowerCase().includes("nist")) {
|
||||
return NISTLogo;
|
||||
}
|
||||
if (complianceTitle.toLowerCase().includes("pci")) {
|
||||
return PCILogo;
|
||||
}
|
||||
if (complianceTitle.toLowerCase().includes("rbi")) {
|
||||
return RBILogo;
|
||||
}
|
||||
if (complianceTitle.toLowerCase().includes("soc2")) {
|
||||
return SOC2Logo;
|
||||
}
|
||||
};
|
||||
@@ -0,0 +1,38 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<!-- Generator: Adobe Illustrator 19.0.1, SVG Export Plug-In . SVG Version: 6.00 Build 0) -->
|
||||
<svg version="1.1" id="Layer_1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px"
|
||||
viewBox="0 0 304 182" style="enable-background:new 0 0 304 182;" xml:space="preserve">
|
||||
<style type="text/css">
|
||||
.st0{fill:#252F3E;}
|
||||
.st1{fill-rule:evenodd;clip-rule:evenodd;fill:#FF9900;}
|
||||
</style>
|
||||
<g>
|
||||
<path class="st0" d="M86.4,66.4c0,3.7,0.4,6.7,1.1,8.9c0.8,2.2,1.8,4.6,3.2,7.2c0.5,0.8,0.7,1.6,0.7,2.3c0,1-0.6,2-1.9,3l-6.3,4.2
|
||||
c-0.9,0.6-1.8,0.9-2.6,0.9c-1,0-2-0.5-3-1.4C76.2,90,75,88.4,74,86.8c-1-1.7-2-3.6-3.1-5.9c-7.8,9.2-17.6,13.8-29.4,13.8
|
||||
c-8.4,0-15.1-2.4-20-7.2c-4.9-4.8-7.4-11.2-7.4-19.2c0-8.5,3-15.4,9.1-20.6c6.1-5.2,14.2-7.8,24.5-7.8c3.4,0,6.9,0.3,10.6,0.8
|
||||
c3.7,0.5,7.5,1.3,11.5,2.2v-7.3c0-7.6-1.6-12.9-4.7-16c-3.2-3.1-8.6-4.6-16.3-4.6c-3.5,0-7.1,0.4-10.8,1.3c-3.7,0.9-7.3,2-10.8,3.4
|
||||
c-1.6,0.7-2.8,1.1-3.5,1.3c-0.7,0.2-1.2,0.3-1.6,0.3c-1.4,0-2.1-1-2.1-3.1v-4.9c0-1.6,0.2-2.8,0.7-3.5c0.5-0.7,1.4-1.4,2.8-2.1
|
||||
c3.5-1.8,7.7-3.3,12.6-4.5c4.9-1.3,10.1-1.9,15.6-1.9c11.9,0,20.6,2.7,26.2,8.1c5.5,5.4,8.3,13.6,8.3,24.6V66.4z M45.8,81.6
|
||||
c3.3,0,6.7-0.6,10.3-1.8c3.6-1.2,6.8-3.4,9.5-6.4c1.6-1.9,2.8-4,3.4-6.4c0.6-2.4,1-5.3,1-8.7v-4.2c-2.9-0.7-6-1.3-9.2-1.7
|
||||
c-3.2-0.4-6.3-0.6-9.4-0.6c-6.7,0-11.6,1.3-14.9,4c-3.3,2.7-4.9,6.5-4.9,11.5c0,4.7,1.2,8.2,3.7,10.6
|
||||
C37.7,80.4,41.2,81.6,45.8,81.6z M126.1,92.4c-1.8,0-3-0.3-3.8-1c-0.8-0.6-1.5-2-2.1-3.9L96.7,10.2c-0.6-2-0.9-3.3-0.9-4
|
||||
c0-1.6,0.8-2.5,2.4-2.5h9.8c1.9,0,3.2,0.3,3.9,1c0.8,0.6,1.4,2,2,3.9l16.8,66.2l15.6-66.2c0.5-2,1.1-3.3,1.9-3.9c0.8-0.6,2.2-1,4-1
|
||||
h8c1.9,0,3.2,0.3,4,1c0.8,0.6,1.5,2,1.9,3.9l15.8,67l17.3-67c0.6-2,1.3-3.3,2-3.9c0.8-0.6,2.1-1,3.9-1h9.3c1.6,0,2.5,0.8,2.5,2.5
|
||||
c0,0.5-0.1,1-0.2,1.6c-0.1,0.6-0.3,1.4-0.7,2.5l-24.1,77.3c-0.6,2-1.3,3.3-2.1,3.9c-0.8,0.6-2.1,1-3.8,1h-8.6c-1.9,0-3.2-0.3-4-1
|
||||
c-0.8-0.7-1.5-2-1.9-4L156,23l-15.4,64.4c-0.5,2-1.1,3.3-1.9,4c-0.8,0.7-2.2,1-4,1H126.1z M254.6,95.1c-5.2,0-10.4-0.6-15.4-1.8
|
||||
c-5-1.2-8.9-2.5-11.5-4c-1.6-0.9-2.7-1.9-3.1-2.8c-0.4-0.9-0.6-1.9-0.6-2.8v-5.1c0-2.1,0.8-3.1,2.3-3.1c0.6,0,1.2,0.1,1.8,0.3
|
||||
c0.6,0.2,1.5,0.6,2.5,1c3.4,1.5,7.1,2.7,11,3.5c4,0.8,7.9,1.2,11.9,1.2c6.3,0,11.2-1.1,14.6-3.3c3.4-2.2,5.2-5.4,5.2-9.5
|
||||
c0-2.8-0.9-5.1-2.7-7c-1.8-1.9-5.2-3.6-10.1-5.2L246,52c-7.3-2.3-12.7-5.7-16-10.2c-3.3-4.4-5-9.3-5-14.5c0-4.2,0.9-7.9,2.7-11.1
|
||||
c1.8-3.2,4.2-6,7.2-8.2c3-2.3,6.4-4,10.4-5.2c4-1.2,8.2-1.7,12.6-1.7c2.2,0,4.5,0.1,6.7,0.4c2.3,0.3,4.4,0.7,6.5,1.1
|
||||
c2,0.5,3.9,1,5.7,1.6c1.8,0.6,3.2,1.2,4.2,1.8c1.4,0.8,2.4,1.6,3,2.5c0.6,0.8,0.9,1.9,0.9,3.3v4.7c0,2.1-0.8,3.2-2.3,3.2
|
||||
c-0.8,0-2.1-0.4-3.8-1.2c-5.7-2.6-12.1-3.9-19.2-3.9c-5.7,0-10.2,0.9-13.3,2.8c-3.1,1.9-4.7,4.8-4.7,8.9c0,2.8,1,5.2,3,7.1
|
||||
c2,1.9,5.7,3.8,11,5.5l14.2,4.5c7.2,2.3,12.4,5.5,15.5,9.6c3.1,4.1,4.6,8.8,4.6,14c0,4.3-0.9,8.2-2.6,11.6
|
||||
c-1.8,3.4-4.2,6.4-7.3,8.8c-3.1,2.5-6.8,4.3-11.1,5.6C264.4,94.4,259.7,95.1,254.6,95.1z"/>
|
||||
<g>
|
||||
<path class="st1" d="M273.5,143.7c-32.9,24.3-80.7,37.2-121.8,37.2c-57.6,0-109.5-21.3-148.7-56.7c-3.1-2.8-0.3-6.6,3.4-4.4
|
||||
c42.4,24.6,94.7,39.5,148.8,39.5c36.5,0,76.6-7.6,113.5-23.2C274.2,133.6,278.9,139.7,273.5,143.7z"/>
|
||||
<path class="st1" d="M287.2,128.1c-4.2-5.4-27.8-2.6-38.5-1.3c-3.2,0.4-3.7-2.4-0.8-4.5c18.8-13.2,49.7-9.4,53.3-5
|
||||
c3.6,4.5-1,35.4-18.6,50.2c-2.7,2.3-5.3,1.1-4.1-1.9C282.5,155.7,291.4,133.4,287.2,128.1z"/>
|
||||
</g>
|
||||
</g>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 3.4 KiB |
@@ -0,0 +1,9 @@
|
||||
<svg width="40" height="45" viewBox="0 0 40 45" fill="none" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink">
|
||||
<rect width="40" height="44.8" fill="url(#pattern0)"/>
|
||||
<defs>
|
||||
<pattern id="pattern0" patternContentUnits="objectBoundingBox" width="1" height="1">
|
||||
<use xlink:href="#image0_407_5880" transform="matrix(0.00282945 0 0 0.0025 0.00666748 0)"/>
|
||||
</pattern>
|
||||
<image id="image0_407_5880" width="400" height="400" xlink:href="data:image/png;base64,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 truncated
|
||||
</defs>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 128 KiB |
@@ -0,0 +1,2 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<svg width="465.74" height="466.54" version="1.1" viewBox="0 0 465.73919 466.54269" xml:space="preserve" xmlns="http://www.w3.org/2000/svg"><defs><clipPath id="a"><path d="m72 660.3h59.6v59.701h-59.6z"/></clipPath></defs><g transform="matrix(1.3333 0 0 -1.3333 97.411 1153.7)"><g transform="matrix(6 0 0 6 -507.97 -3451.8)"><g clip-path="url(#a)"><g transform="matrix(.010781 0 0 -.0108 72 720)"><g transform="translate(5445,2745)"><path d="m0 0c0 1491-1209 2700-2700 2700s-2700-1209-2700-2700 1209-2700 2700-2700 2700 1209 2700 2700" fill="#fff"/></g></g><g transform="matrix(.010781 0 0 -.0108 72 720)"><g transform="translate(2745,110)"><path d="m0 0c-1453 0-2635 1182-2635 2635s1182 2635 2635 2635 2635-1182 2635-2635-1182-2635-2635-2635m0 5114c-1367 0-2479-1112-2479-2479s1112-2479 2479-2479 2479 1112 2479 2479-1112 2479-2479 2479" fill="#005288"/></g></g><g transform="matrix(.010781 0 0 -.0108 72 720)"><g transform="translate(2893,3725)"><path d="m0 0c84-16 173-27 261-30v21c-215 10-375 69-481 126-15-15-29-31-43-46 74-27 165-52 263-71m-206 131c36 37 73 73 113 107v-71c0-38 26-69 58-69 33 0 59 31 59 69v163c18 14 36 26 55 39v-253c0-38 26-69 58-69s59 31 59 69v324c21 13 43 24 65 35v-466c-208 10-363 68-467 122m147-401 39 19 21-12-53-31zm22-82 42-33-27-21zm22-79 39 31 39-30-39-149zm84 180v-25l-21 13zm-63 12 63 31v-16l-45-26zm65-167-27 21 41 33zm-47 129 68-39-67-54-68 54zm66-11 6 3 8 4-3-13zm-44-2033-59 33-32 45c-18-8-66-29-110-45-45-17-106-36-106-36 114 1 141 1 146 1h1c5 1 34 1 160 2m1601 1341c0 991-804 1794-1795 1794-207 0-407-35-592-99 0 0 346-277 493-426-102-96-194-204-274-322-63-93-117-191-162-292l-860 859 29-350c-267-313-428-720-428-1164 0-991 803-1794 1794-1794s1795 803 1795 1794m-2694-1457 400 215-231 237 170-7-140 233h9c105 0 203 34 283 92 184-29 447-64 695-79-1-2-2-3-3-5-3-7-7-14-11-22-5-11-11-22-17-33-7-15-15-30-22-45-9-17-18-35-27-52-9-20-19-40-29-60 0 0 43-59 126-84 77-24 162-1 212 66 16 21 28 45 28 70 0 0 132-198 100-311-32-114-284-102-284-102h-84l-76-80c-20-21-48-34-77-34h-1022zm-330 1679 203-215v-214l-183 193zm621-287c97-35 162-128 162-231v-9c-33-5-59-27-70-57h-157c-6 15-15 28-26 38-15 12-35 20-56 20-37 0-69-24-82-58h-43l-87 93v300l-270 286-23 270 272-287c-6-12-9-25-9-39 0-48 39-87 87-87s87 39 87 87-39 87-87 87c-13 0-24-3-35-8l-323 342-23 270 303-320c-6-12-9-25-9-39 0-48 39-87 87-87s87 39 87 87-39 87-87 87c-12 0-24-3-35-8l-354 377-27 312 698-697v-722zm-302 685c15 0 27-12 27-27s-12-28-27-28c-16 0-28 13-28 28s12 27 28 27m0-332c15 0 27-12 27-27 0-16-12-28-27-28-16 0-28 12-28 28 0 15 12 27 28 27m155-652c15 0 28-12 28-27 0-16-13-28-28-28s-27 12-27 28c0 15 12 27 27 27m320 0c15 0 28-12 28-27 0-16-13-28-28-28s-27 12-27 28c0 15 12 27 27 27m19 816v-421c93-79 152-196 152-327 0-133-60-252-156-330-22-18-46-34-72-48-59-31-127-49-199-49-152 0-285 79-361 198v1c-6 9-133 228-133 228l-16 187 296-312h68c12-33 44-57 82-57 21 0 40 7 55 20 12 10 21 22 27 37h157c12-33 44-57 81-57 48 0 87 39 87 87 0 30-16 57-40 73 1 7 2 15 2 22 0 121-73 231-182 279v622zm2039-574v-467s-489-126-1095-126h-38c-272 2-605 44-839 78 87 88 141 208 141 341 0 134-55 261-152 352v15h1889c-27 251-107 490-232 702v-51h-154v-78h-86v-91h-52v-55c0-8-2-15-7-22-8-12-21-19-35-19s-27 7-35 19c-4 7-6 14-6 22v55h-52v90h-63v-295h-398v428l-120-59c-33-111-66-220-97-330 9-6 15-16 15-28 0-20-16-35-35-35s-35 15-35 35c0 12 6 22 15 28-30 103-60 206-91 309l-2-1-27-13v103h-46l-21-352-1-18h-141l-1 18-21 352h-109c-46-76-86-156-119-238l-63 63c188 438 541 789 981 975 665-281 1132-940 1132-1707" fill="#005288"/></g></g><g transform="matrix(.010781 0 0 -.0108 72 720)"><g transform="translate(593,2862)"><path d="m0 0-2-68c37-1 67 9 92 27 24 19 38 45 40 79 4 41-9 74-38 98s-70 38-123 42c-54 5-98-3-130-22s-50-49-53-91c-6-70 34-111 120-124l10 66c-49 6-73 24-70 53 1 15 10 27 26 34 17 8 49 10 95 7 41-4 69-10 83-20 15-9 22-22 21-39-3-27-26-41-71-42" fill="#005288"/></g></g><g transform="matrix(.010781 0 0 -.0108 72 720)"><g transform="translate(374,2785)"><path d="m0 0 3-81 124-43-121-55 3-72 190 100 142 5-3 73-142-5z" fill="#005288"/></g></g><g transform="matrix(.010781 0 0 -.0108 72 720)"><g transform="translate(388,2487)"><path d="m0 0 18-113c4-27 9-47 16-60 6-12 17-22 33-29 15-7 34-9 55-6 37 6 58 26 64 59 19-36 49-50 90-44 21 3 39 11 52 24 13 12 21 26 24 42 2 16 2 38-3 65l-17 113zm145-49 4-24c3-23 1-39-6-46-8-7-17-12-28-14-10-1-19 0-28 5s-15 17-18 37l-4 29zm141 22 5-36c6-34-6-53-35-57-16-3-28 0-36 7s-13 20-16 36l-5 36z" fill="#005288"/></g></g><g transform="matrix(.010781 0 0 -.0108 72 720)"><g transform="translate(444,2178)"><path d="m0 0 56-196 55 15-36 125 75 22 28-97 55 15-27 98 79 22 36-125 57 17-56 196z" fill="#005288"/></g></g><g transform="matrix(.010781 0 0 -.0108 72 720)"><g transform="translate(523,1919)"><path d="m0 0 41-97c8-19 15-33 21-42 6-10 15-18 27-25s25-11 41-11 32 3 48 10c39 17 60 43 63 78l159 1-31 73-140-10-14 34 122 52-29 67zm78-47 87 37 13-30c11-27 2-46-28-59-10-4-19-6-28-4-8 1-14 4-19 8-4 4-9 11-13 21z" fill="#005288"/></g></g><g transform="matrix(.010781 0 0 -.0108Line truncated
|
||||
|
After Width: | Height: | Size: 20 KiB |
|
After Width: | Height: | Size: 95 KiB |
@@ -0,0 +1,9 @@
|
||||
<svg width="41" height="45" viewBox="0 0 41 45" fill="none" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink">
|
||||
<rect x="0.666626" width="40" height="44.8" fill="url(#pattern0)"/>
|
||||
<defs>
|
||||
<pattern id="pattern0" patternContentUnits="objectBoundingBox" width="1" height="1">
|
||||
<use xlink:href="#image0_407_6053" transform="matrix(0.00396921 0 0 0.00354393 0.0880347 0.104852)"/>
|
||||
</pattern>
|
||||
<image id="image0_407_6053" width="204" height="223" xlink:href="data:image/png;base64,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 truncated
|
||||
</defs>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 47 KiB |
@@ -0,0 +1,9 @@
|
||||
<svg width="40" height="45" viewBox="0 0 40 45" fill="none" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink">
|
||||
<rect width="40" height="44.8" fill="url(#pattern0)"/>
|
||||
<defs>
|
||||
<pattern id="pattern0" patternContentUnits="objectBoundingBox" width="1" height="1">
|
||||
<use xlink:href="#image0_407_6036" transform="matrix(0.00583333 0 0 0.00520833 -0.0950001 0)"/>
|
||||
</pattern>
|
||||
<image id="image0_407_6036" width="204" height="192" xlink:href="data:image/png;base64,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 truncated
|
||||
</defs>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 24 KiB |
@@ -0,0 +1,9 @@
|
||||
<svg width="41" height="45" viewBox="0 0 41 45" fill="none" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink">
|
||||
<rect x="0.333374" width="40" height="44.8" fill="url(#pattern0)"/>
|
||||
<defs>
|
||||
<pattern id="pattern0" patternContentUnits="objectBoundingBox" width="1" height="1">
|
||||
<use xlink:href="#image0_407_5914" transform="matrix(0.000711563 0 0 0.000635324 -0.0600001 0)"/>
|
||||
</pattern>
|
||||
<image id="image0_407_5914" width="1574" height="1574" xlink:href="data:image/png;base64,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 truncated
|
||||
</defs>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 164 KiB |
@@ -0,0 +1,455 @@
|
||||
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
|
||||
<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">
|
||||
<svg xmlns="http://www.w3.org/2000/svg" version="1.1" viewBox="0.00 0.00 100.00 100.00">
|
||||
<g stroke-width="2.00" fill="none" stroke-linecap="butt">
|
||||
<path stroke="#848584" vector-effect="non-scaling-stroke" d="
|
||||
M 48.23 60.97
|
||||
L 43.12 67.44
|
||||
Q 42.76 67.89 42.23 67.66
|
||||
C 36.78 65.22 31.94 71.81 36.22 76.09
|
||||
Q 38.02 77.89 40.38 77.56
|
||||
C 43.18 77.18 45.96 74.47 45.02 71.42
|
||||
Q 44.65 70.21 44.02 69.09
|
||||
Q 43.75 68.62 44.08 68.20
|
||||
L 49.24 61.63
|
||||
Q 49.56 61.22 50.06 61.39
|
||||
Q 61.24 65.17 65.37 53.86
|
||||
Q 65.55 53.39 66.05 53.37
|
||||
L 76.75 53.00
|
||||
Q 77.69 52.96 77.90 53.88
|
||||
C 79.90 62.49 90.68 65.73 96.38 58.39
|
||||
C 101.86 51.31 96.65 39.99 86.93 41.28
|
||||
Q 78.93 42.35 77.60 51.24
|
||||
Q 77.53 51.70 77.05 51.72
|
||||
L 66.20 52.15
|
||||
Q 65.56 52.17 65.46 51.54
|
||||
C 64.95 48.35 64.30 46.30 62.01 43.93
|
||||
Q 61.60 43.50 61.97 43.03
|
||||
L 67.61 35.97
|
||||
Q 68.00 35.49 68.56 35.76
|
||||
C 75.35 39.06 79.78 29.09 73.12 26.29
|
||||
C 68.17 24.21 64.34 29.50 66.80 34.16
|
||||
Q 67.05 34.64 66.71 35.07
|
||||
L 61.01 42.25
|
||||
Q 60.65 42.71 60.11 42.47
|
||||
Q 51.98 38.79 46.37 45.44
|
||||
Q 46.00 45.87 45.52 45.57
|
||||
L 34.41 38.51
|
||||
Q 33.89 38.18 34.05 37.59
|
||||
C 34.32 36.55 34.82 35.64 34.96 34.55
|
||||
C 36.06 25.73 26.63 19.00 18.95 24.03
|
||||
C 13.82 27.39 12.49 33.80 16.12 39.22
|
||||
Q 16.46 39.73 16.03 40.16
|
||||
L 9.27 46.81
|
||||
A 0.72 0.72 0.0 0 1 8.50 46.97
|
||||
C -0.18 43.45 -2.23 55.00 4.29 56.50
|
||||
C 9.15 57.63 12.10 52.98 9.95 48.66
|
||||
Q 9.69 48.12 10.11 47.71
|
||||
L 16.76 41.14
|
||||
Q 17.16 40.74 17.63 41.07
|
||||
Q 25.88 46.89 32.97 39.48
|
||||
Q 33.23 39.21 33.55 39.41
|
||||
L 44.90 46.63
|
||||
Q 45.31 46.89 45.26 47.37
|
||||
Q 45.24 47.67 45.08 47.94
|
||||
Q 44.82 48.39 44.71 48.90
|
||||
Q 43.26 55.44 48.15 59.96
|
||||
Q 48.66 60.43 48.23 60.97"
|
||||
/>
|
||||
<path stroke="#848584" vector-effect="non-scaling-stroke" d="
|
||||
M 34.25 32.97
|
||||
A 9.72 9.72 0.0 0 0 24.53 23.25
|
||||
A 9.72 9.72 0.0 0 0 14.81 32.97
|
||||
A 9.72 9.72 0.0 0 0 24.53 42.69
|
||||
A 9.72 9.72 0.0 0 0 34.25 32.97"
|
||||
/>
|
||||
<path stroke="#825212" vector-effect="non-scaling-stroke" d="
|
||||
M 75.76 31.11
|
||||
A 4.63 4.63 0.0 0 0 71.13 26.48
|
||||
A 4.63 4.63 0.0 0 0 66.50 31.11
|
||||
A 4.63 4.63 0.0 0 0 71.13 35.74
|
||||
A 4.63 4.63 0.0 0 0 75.76 31.11"
|
||||
/>
|
||||
<path stroke="#848584" vector-effect="non-scaling-stroke" d="
|
||||
M 64.59 51.77
|
||||
A 9.72 9.72 0.0 0 0 54.87 42.05
|
||||
A 9.72 9.72 0.0 0 0 45.15 51.77
|
||||
A 9.72 9.72 0.0 0 0 54.87 61.49
|
||||
A 9.72 9.72 0.0 0 0 64.59 51.77"
|
||||
/>
|
||||
<path stroke="#848584" vector-effect="non-scaling-stroke" d="
|
||||
M 97.88 51.77
|
||||
A 9.71 9.71 0.0 0 0 88.17 42.06
|
||||
A 9.71 9.71 0.0 0 0 78.46 51.77
|
||||
A 9.71 9.71 0.0 0 0 88.17 61.48
|
||||
A 9.71 9.71 0.0 0 0 97.88 51.77"
|
||||
/>
|
||||
<path stroke="#825212" vector-effect="non-scaling-stroke" d="
|
||||
M 10.13 51.48
|
||||
A 4.54 4.54 0.0 0 0 5.59 46.94
|
||||
A 4.54 4.54 0.0 0 0 1.05 51.48
|
||||
A 4.54 4.54 0.0 0 0 5.59 56.02
|
||||
A 4.54 4.54 0.0 0 0 10.13 51.48"
|
||||
/>
|
||||
<path stroke="#825212" vector-effect="non-scaling-stroke" d="
|
||||
M 44.56 72.32
|
||||
A 4.65 4.65 0.0 0 0 39.91 67.67
|
||||
A 4.65 4.65 0.0 0 0 35.26 72.32
|
||||
A 4.65 4.65 0.0 0 0 39.91 76.97
|
||||
A 4.65 4.65 0.0 0 0 44.56 72.32"
|
||||
/>
|
||||
<path stroke="#848584" vector-effect="non-scaling-stroke" d="
|
||||
M 25.04 30.94
|
||||
Q 25.24 31.16 25.52 31.12
|
||||
Q 27.86 30.86 25.89 29.54
|
||||
Q 24.29 28.46 22.93 29.73
|
||||
C 21.78 30.79 22.00 33.06 22.12 34.53
|
||||
C 22.41 38.14 27.59 37.43 26.98 33.28
|
||||
Q 26.89 32.71 26.33 32.57
|
||||
Q 25.69 32.42 25.01 32.63
|
||||
Q 23.86 32.99 24.83 33.70
|
||||
Q 26.06 34.60 24.84 35.30
|
||||
A 0.71 0.70 65.0 0 1 23.83 34.93
|
||||
Q 23.12 33.02 23.74 31.22
|
||||
Q 24.15 29.99 25.04 30.94"
|
||||
/>
|
||||
<path stroke="#848584" vector-effect="non-scaling-stroke" d="
|
||||
M 54.33 49.42
|
||||
Q 54.00 48.76 53.41 48.45
|
||||
Q 52.77 48.13 52.80 48.84
|
||||
Q 52.83 49.81 53.56 50.51
|
||||
Q 54.56 51.46 53.73 52.56
|
||||
Q 53.08 53.43 52.75 54.46
|
||||
Q 52.58 54.98 53.13 55.02
|
||||
L 53.45 55.04
|
||||
A 0.49 0.48 -80.1 0 0 53.94 54.69
|
||||
Q 54.15 53.92 54.75 53.63
|
||||
Q 55.16 53.44 55.32 53.86
|
||||
Q 55.76 55.04 56.85 54.98
|
||||
Q 57.42 54.94 57.12 54.44
|
||||
L 55.71 52.11
|
||||
Q 55.28 51.40 55.88 50.82
|
||||
Q 56.63 50.12 57.00 49.11
|
||||
A 0.44 0.43 18.4 0 0 56.71 48.54
|
||||
L 56.40 48.45
|
||||
A 0.55 0.55 0.0 0 0 55.75 48.74
|
||||
Q 55.52 49.20 55.17 49.55
|
||||
Q 54.66 50.06 54.33 49.42"
|
||||
/>
|
||||
<path stroke="#848584" vector-effect="non-scaling-stroke" d="
|
||||
M 87.99 52.73
|
||||
C 92.09 52.99 91.31 46.51 86.30 47.93
|
||||
Q 85.74 48.08 85.74 48.67
|
||||
L 85.73 54.86
|
||||
Q 85.73 55.74 86.61 55.65
|
||||
L 86.93 55.62
|
||||
A 0.51 0.50 85.5 0 0 87.39 55.07
|
||||
L 87.27 53.45
|
||||
Q 87.21 52.68 87.99 52.73"
|
||||
/>
|
||||
<path stroke="#848584" vector-effect="non-scaling-stroke" d="
|
||||
M 87.98 51.33
|
||||
L 88.46 51.24
|
||||
Q 89.03 51.13 89.07 50.55
|
||||
Q 89.12 49.66 88.34 49.29
|
||||
Q 87.97 49.11 87.66 49.38
|
||||
Q 87.04 49.92 87.23 50.84
|
||||
Q 87.36 51.46 87.98 51.33"
|
||||
/>
|
||||
</g>
|
||||
<path fill="#fefefe" d="
|
||||
M 0.00 0.00
|
||||
L 100.00 0.00
|
||||
L 100.00 100.00
|
||||
L 0.00 100.00
|
||||
L 0.00 0.00
|
||||
Z
|
||||
M 48.23 60.97
|
||||
L 43.12 67.44
|
||||
Q 42.76 67.89 42.23 67.66
|
||||
C 36.78 65.22 31.94 71.81 36.22 76.09
|
||||
Q 38.02 77.89 40.38 77.56
|
||||
C 43.18 77.18 45.96 74.47 45.02 71.42
|
||||
Q 44.65 70.21 44.02 69.09
|
||||
Q 43.75 68.62 44.08 68.20
|
||||
L 49.24 61.63
|
||||
Q 49.56 61.22 50.06 61.39
|
||||
Q 61.24 65.17 65.37 53.86
|
||||
Q 65.55 53.39 66.05 53.37
|
||||
L 76.75 53.00
|
||||
Q 77.69 52.96 77.90 53.88
|
||||
C 79.90 62.49 90.68 65.73 96.38 58.39
|
||||
C 101.86 51.31 96.65 39.99 86.93 41.28
|
||||
Q 78.93 42.35 77.60 51.24
|
||||
Q 77.53 51.70 77.05 51.72
|
||||
L 66.20 52.15
|
||||
Q 65.56 52.17 65.46 51.54
|
||||
C 64.95 48.35 64.30 46.30 62.01 43.93
|
||||
Q 61.60 43.50 61.97 43.03
|
||||
L 67.61 35.97
|
||||
Q 68.00 35.49 68.56 35.76
|
||||
C 75.35 39.06 79.78 29.09 73.12 26.29
|
||||
C 68.17 24.21 64.34 29.50 66.80 34.16
|
||||
Q 67.05 34.64 66.71 35.07
|
||||
L 61.01 42.25
|
||||
Q 60.65 42.71 60.11 42.47
|
||||
Q 51.98 38.79 46.37 45.44
|
||||
Q 46.00 45.87 45.52 45.57
|
||||
L 34.41 38.51
|
||||
Q 33.89 38.18 34.05 37.59
|
||||
C 34.32 36.55 34.82 35.64 34.96 34.55
|
||||
C 36.06 25.73 26.63 19.00 18.95 24.03
|
||||
C 13.82 27.39 12.49 33.80 16.12 39.22
|
||||
Q 16.46 39.73 16.03 40.16
|
||||
L 9.27 46.81
|
||||
A 0.72 0.72 0.0 0 1 8.50 46.97
|
||||
C -0.18 43.45 -2.23 55.00 4.29 56.50
|
||||
C 9.15 57.63 12.10 52.98 9.95 48.66
|
||||
Q 9.69 48.12 10.11 47.71
|
||||
L 16.76 41.14
|
||||
Q 17.16 40.74 17.63 41.07
|
||||
Q 25.88 46.89 32.97 39.48
|
||||
Q 33.23 39.21 33.55 39.41
|
||||
L 44.90 46.63
|
||||
Q 45.31 46.89 45.26 47.37
|
||||
Q 45.24 47.67 45.08 47.94
|
||||
Q 44.82 48.39 44.71 48.90
|
||||
Q 43.26 55.44 48.15 59.96
|
||||
Q 48.66 60.43 48.23 60.97
|
||||
Z"
|
||||
/>
|
||||
<path fill="#0a0b0a" d="
|
||||
M 48.15 59.96
|
||||
Q 43.26 55.44 44.71 48.90
|
||||
Q 44.82 48.39 45.08 47.94
|
||||
Q 45.24 47.67 45.26 47.37
|
||||
Q 45.31 46.89 44.90 46.63
|
||||
L 33.55 39.41
|
||||
Q 33.23 39.21 32.97 39.48
|
||||
Q 25.88 46.89 17.63 41.07
|
||||
Q 17.16 40.74 16.76 41.14
|
||||
L 10.11 47.71
|
||||
Q 9.69 48.12 9.95 48.66
|
||||
C 12.10 52.98 9.15 57.63 4.29 56.50
|
||||
C -2.23 55.00 -0.18 43.45 8.50 46.97
|
||||
A 0.72 0.72 0.0 0 0 9.27 46.81
|
||||
L 16.03 40.16
|
||||
Q 16.46 39.73 16.12 39.22
|
||||
C 12.49 33.80 13.82 27.39 18.95 24.03
|
||||
C 26.63 19.00 36.06 25.73 34.96 34.55
|
||||
C 34.82 35.64 34.32 36.55 34.05 37.59
|
||||
Q 33.89 38.18 34.41 38.51
|
||||
L 45.52 45.57
|
||||
Q 46.00 45.87 46.37 45.44
|
||||
Q 51.98 38.79 60.11 42.47
|
||||
Q 60.65 42.71 61.01 42.25
|
||||
L 66.71 35.07
|
||||
Q 67.05 34.64 66.80 34.16
|
||||
C 64.34 29.50 68.17 24.21 73.12 26.29
|
||||
C 79.78 29.09 75.35 39.06 68.56 35.76
|
||||
Q 68.00 35.49 67.61 35.97
|
||||
L 61.97 43.03
|
||||
Q 61.60 43.50 62.01 43.93
|
||||
C 64.30 46.30 64.95 48.35 65.46 51.54
|
||||
Q 65.56 52.17 66.20 52.15
|
||||
L 77.05 51.72
|
||||
Q 77.53 51.70 77.60 51.24
|
||||
Q 78.93 42.35 86.93 41.28
|
||||
C 96.65 39.99 101.86 51.31 96.38 58.39
|
||||
C 90.68 65.73 79.90 62.49 77.90 53.88
|
||||
Q 77.69 52.96 76.75 53.00
|
||||
L 66.05 53.37
|
||||
Q 65.55 53.39 65.37 53.86
|
||||
Q 61.24 65.17 50.06 61.39
|
||||
Q 49.56 61.22 49.24 61.63
|
||||
L 44.08 68.20
|
||||
Q 43.75 68.62 44.02 69.09
|
||||
Q 44.65 70.21 45.02 71.42
|
||||
C 45.96 74.47 43.18 77.18 40.38 77.56
|
||||
Q 38.02 77.89 36.22 76.09
|
||||
C 31.94 71.81 36.78 65.22 42.23 67.66
|
||||
Q 42.76 67.89 43.12 67.44
|
||||
L 48.23 60.97
|
||||
Q 48.66 60.43 48.15 59.96
|
||||
Z
|
||||
M 34.25 32.97
|
||||
A 9.72 9.72 0.0 0 0 24.53 23.25
|
||||
A 9.72 9.72 0.0 0 0 14.81 32.97
|
||||
A 9.72 9.72 0.0 0 0 24.53 42.69
|
||||
A 9.72 9.72 0.0 0 0 34.25 32.97
|
||||
Z
|
||||
M 75.76 31.11
|
||||
A 4.63 4.63 0.0 0 0 71.13 26.48
|
||||
A 4.63 4.63 0.0 0 0 66.50 31.11
|
||||
A 4.63 4.63 0.0 0 0 71.13 35.74
|
||||
A 4.63 4.63 0.0 0 0 75.76 31.11
|
||||
Z
|
||||
M 64.59 51.77
|
||||
A 9.72 9.72 0.0 0 0 54.87 42.05
|
||||
A 9.72 9.72 0.0 0 0 45.15 51.77
|
||||
A 9.72 9.72 0.0 0 0 54.87 61.49
|
||||
A 9.72 9.72 0.0 0 0 64.59 51.77
|
||||
Z
|
||||
M 97.88 51.77
|
||||
A 9.71 9.71 0.0 0 0 88.17 42.06
|
||||
A 9.71 9.71 0.0 0 0 78.46 51.77
|
||||
A 9.71 9.71 0.0 0 0 88.17 61.48
|
||||
A 9.71 9.71 0.0 0 0 97.88 51.77
|
||||
Z
|
||||
M 10.13 51.48
|
||||
A 4.54 4.54 0.0 0 0 5.59 46.94
|
||||
A 4.54 4.54 0.0 0 0 1.05 51.48
|
||||
A 4.54 4.54 0.0 0 0 5.59 56.02
|
||||
A 4.54 4.54 0.0 0 0 10.13 51.48
|
||||
Z
|
||||
M 44.56 72.32
|
||||
A 4.65 4.65 0.0 0 0 39.91 67.67
|
||||
A 4.65 4.65 0.0 0 0 35.26 72.32
|
||||
A 4.65 4.65 0.0 0 0 39.91 76.97
|
||||
A 4.65 4.65 0.0 0 0 44.56 72.32
|
||||
Z"
|
||||
/>
|
||||
<path fill="#fefefe" d="
|
||||
M 34.25 32.97
|
||||
A 9.72 9.72 0.0 0 1 24.53 42.69
|
||||
A 9.72 9.72 0.0 0 1 14.81 32.97
|
||||
A 9.72 9.72 0.0 0 1 24.53 23.25
|
||||
A 9.72 9.72 0.0 0 1 34.25 32.97
|
||||
Z
|
||||
M 25.04 30.94
|
||||
Q 25.24 31.16 25.52 31.12
|
||||
Q 27.86 30.86 25.89 29.54
|
||||
Q 24.29 28.46 22.93 29.73
|
||||
C 21.78 30.79 22.00 33.06 22.12 34.53
|
||||
C 22.41 38.14 27.59 37.43 26.98 33.28
|
||||
Q 26.89 32.71 26.33 32.57
|
||||
Q 25.69 32.42 25.01 32.63
|
||||
Q 23.86 32.99 24.83 33.70
|
||||
Q 26.06 34.60 24.84 35.30
|
||||
A 0.71 0.70 65.0 0 1 23.83 34.93
|
||||
Q 23.12 33.02 23.74 31.22
|
||||
Q 24.15 29.99 25.04 30.94
|
||||
Z"
|
||||
/>
|
||||
<circle fill="#f9981a" cx="71.13" cy="31.11" r="4.63"/>
|
||||
<path fill="#0a0b0a" d="
|
||||
M 23.74 31.22
|
||||
Q 23.12 33.02 23.83 34.93
|
||||
A 0.71 0.70 65.0 0 0 24.84 35.30
|
||||
Q 26.06 34.60 24.83 33.70
|
||||
Q 23.86 32.99 25.01 32.63
|
||||
Q 25.69 32.42 26.33 32.57
|
||||
Q 26.89 32.71 26.98 33.28
|
||||
C 27.59 37.43 22.41 38.14 22.12 34.53
|
||||
C 22.00 33.06 21.78 30.79 22.93 29.73
|
||||
Q 24.29 28.46 25.89 29.54
|
||||
Q 27.86 30.86 25.52 31.12
|
||||
Q 25.24 31.16 25.04 30.94
|
||||
Q 24.15 29.99 23.74 31.22
|
||||
Z"
|
||||
/>
|
||||
<path fill="#fefefe" d="
|
||||
M 64.59 51.77
|
||||
A 9.72 9.72 0.0 0 1 54.87 61.49
|
||||
A 9.72 9.72 0.0 0 1 45.15 51.77
|
||||
A 9.72 9.72 0.0 0 1 54.87 42.05
|
||||
A 9.72 9.72 0.0 0 1 64.59 51.77
|
||||
Z
|
||||
M 54.33 49.42
|
||||
Q 54.00 48.76 53.41 48.45
|
||||
Q 52.77 48.13 52.80 48.84
|
||||
Q 52.83 49.81 53.56 50.51
|
||||
Q 54.56 51.46 53.73 52.56
|
||||
Q 53.08 53.43 52.75 54.46
|
||||
Q 52.58 54.98 53.13 55.02
|
||||
L 53.45 55.04
|
||||
A 0.49 0.48 -80.1 0 0 53.94 54.69
|
||||
Q 54.15 53.92 54.75 53.63
|
||||
Q 55.16 53.44 55.32 53.86
|
||||
Q 55.76 55.04 56.85 54.98
|
||||
Q 57.42 54.94 57.12 54.44
|
||||
L 55.71 52.11
|
||||
Q 55.28 51.40 55.88 50.82
|
||||
Q 56.63 50.12 57.00 49.11
|
||||
A 0.44 0.43 18.4 0 0 56.71 48.54
|
||||
L 56.40 48.45
|
||||
A 0.55 0.55 0.0 0 0 55.75 48.74
|
||||
Q 55.52 49.20 55.17 49.55
|
||||
Q 54.66 50.06 54.33 49.42
|
||||
Z"
|
||||
/>
|
||||
<path fill="#fefefe" d="
|
||||
M 97.88 51.77
|
||||
A 9.71 9.71 0.0 0 1 88.17 61.48
|
||||
A 9.71 9.71 0.0 0 1 78.46 51.77
|
||||
A 9.71 9.71 0.0 0 1 88.17 42.06
|
||||
A 9.71 9.71 0.0 0 1 97.88 51.77
|
||||
Z
|
||||
M 87.99 52.73
|
||||
C 92.09 52.99 91.31 46.51 86.30 47.93
|
||||
Q 85.74 48.08 85.74 48.67
|
||||
L 85.73 54.86
|
||||
Q 85.73 55.74 86.61 55.65
|
||||
L 86.93 55.62
|
||||
A 0.51 0.50 85.5 0 0 87.39 55.07
|
||||
L 87.27 53.45
|
||||
Q 87.21 52.68 87.99 52.73
|
||||
Z"
|
||||
/>
|
||||
<circle fill="#f9981a" cx="5.59" cy="51.48" r="4.54"/>
|
||||
<path fill="#0a0b0a" d="
|
||||
M 87.27 53.45
|
||||
L 87.39 55.07
|
||||
A 0.51 0.50 85.5 0 1 86.93 55.62
|
||||
L 86.61 55.65
|
||||
Q 85.73 55.74 85.73 54.86
|
||||
L 85.74 48.67
|
||||
Q 85.74 48.08 86.30 47.93
|
||||
C 91.31 46.51 92.09 52.99 87.99 52.73
|
||||
Q 87.21 52.68 87.27 53.45
|
||||
Z
|
||||
M 87.98 51.33
|
||||
L 88.46 51.24
|
||||
Q 89.03 51.13 89.07 50.55
|
||||
Q 89.12 49.66 88.34 49.29
|
||||
Q 87.97 49.11 87.66 49.38
|
||||
Q 87.04 49.92 87.23 50.84
|
||||
Q 87.36 51.46 87.98 51.33
|
||||
Z"
|
||||
/>
|
||||
<path fill="#0a0b0a" d="
|
||||
M 55.17 49.55
|
||||
Q 55.52 49.20 55.75 48.74
|
||||
A 0.55 0.55 0.0 0 1 56.40 48.45
|
||||
L 56.71 48.54
|
||||
A 0.44 0.43 18.4 0 1 57.00 49.11
|
||||
Q 56.63 50.12 55.88 50.82
|
||||
Q 55.28 51.40 55.71 52.11
|
||||
L 57.12 54.44
|
||||
Q 57.42 54.94 56.85 54.98
|
||||
Q 55.76 55.04 55.32 53.86
|
||||
Q 55.16 53.44 54.75 53.63
|
||||
Q 54.15 53.92 53.94 54.69
|
||||
A 0.49 0.48 -80.1 0 1 53.45 55.04
|
||||
L 53.13 55.02
|
||||
Q 52.58 54.98 52.75 54.46
|
||||
Q 53.08 53.43 53.73 52.56
|
||||
Q 54.56 51.46 53.56 50.51
|
||||
Q 52.83 49.81 52.80 48.84
|
||||
Q 52.77 48.13 53.41 48.45
|
||||
Q 54.00 48.76 54.33 49.42
|
||||
Q 54.66 50.06 55.17 49.55
|
||||
Z"
|
||||
/>
|
||||
<path fill="#fefefe" d="
|
||||
M 87.98 51.33
|
||||
Q 87.36 51.46 87.23 50.84
|
||||
Q 87.04 49.92 87.66 49.38
|
||||
Q 87.97 49.11 88.34 49.29
|
||||
Q 89.12 49.66 89.07 50.55
|
||||
Q 89.03 51.13 88.46 51.24
|
||||
L 87.98 51.33
|
||||
Z"
|
||||
/>
|
||||
<circle fill="#f9981a" cx="39.91" cy="72.32" r="4.65"/>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 12 KiB |
@@ -0,0 +1,9 @@
|
||||
<svg width="40" height="45" viewBox="0 0 40 45" fill="none" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink">
|
||||
<rect width="40" height="44.8" fill="url(#pattern0)"/>
|
||||
<defs>
|
||||
<pattern id="pattern0" patternContentUnits="objectBoundingBox" width="1" height="1">
|
||||
<use xlink:href="#image0_407_5984" transform="matrix(0.00165375 0 0 0.00147656 0.0132889 0.0570321)"/>
|
||||
</pattern>
|
||||
<image id="image0_407_5984" width="600" height="600" xlink:href="data:image/png;base64,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 truncated
|
||||
</defs>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 48 KiB |
@@ -0,0 +1,9 @@
|
||||
<svg width="41" height="45" viewBox="0 0 41 45" fill="none" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink">
|
||||
<rect x="0.666626" width="40" height="44.8" fill="url(#pattern0)"/>
|
||||
<defs>
|
||||
<pattern id="pattern0" patternContentUnits="objectBoundingBox" width="1" height="1">
|
||||
<use xlink:href="#image0_407_5949" transform="matrix(0.00233051 0 0 0.00208081 -0.237112 0.0838373)"/>
|
||||
</pattern>
|
||||
<image id="image0_407_5949" width="650" height="400" xlink:href="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAooAAAGQCAIAAACms9a7AAAMPmlDQ1BJQ0MgUHJvZmlsZQAASImVVwdYU8kWnluSkEBoAQSkhN4EkRpASggt9N5shCRAKDEGgoodXVRw7SICNnRVRMFKsyN2FsXeFwsqyrpYsCtvUkDXfeV7831z57//nPnPmXNn7r0DgNpxjkiUi6oDkCcsEMcG+9OTU1LppKcABxggAy1gzuHmi5jR0eEAlqH27+XddYBI2yv2Uq1/9v/XosHj53MBQKIhTuflc/MgPgAAXs0ViQsAIEp5s6kFIimGFWiJYYAQL5LiTDmuluJ0Od4js4mPZUHcDoCSCocjzgRA9RLk6YXcTKih2g+xo5AnEAKgRofYJy9vMg/iNIitoY0IYqk+I/0Hncy/aaYPa3I4mcNYPhdZUQoQ5ItyOdP/z3T875KXKxnyYQmrSpY4JFY6Z5i3mzmTw6RYBeI+YXpkFMSaEH8Q8GT2EKOULElIgtweNeDms2DOgA7EjjxOQBjEBhAHCXMjwxV8eoYgiA0xXCHoNEEBOx5iXYgX8fMD4xQ2m8STYxW+0MYMMYup4M9yxDK/Ul/3JTkJTIX+6yw+W6GPqRZlxSdBTIHYvFCQGAmxKsQO+TlxYQqbsUVZrMghG7EkVhq/OcSxfGGwv1wfK8wQB8Uq7Evz8ofmi23KErAjFXhfQVZ8iDw/WDuXI4sfzgW7xBcyE4Z0+PnJ4UNz4fEDAuVzx57xhQlxCp0PogL/WPlYnCLKjVbY46b83GApbwqxS35hnGIsnlgAF6RcH88QFUTHy+PEi7I5odHyePDlIBywQACgAwms6WAyyAaCzr6mPngn7wkCHCAGmYAP7BXM0IgkWY8QXuNAEfgTIj7IHx7nL+vlg0LIfx1m5Vd7kCHrLZSNyAFPIM4DYSAX3ktko4TD3hLBY8gI/uGdAysXxpsLq7T/3/ND7HeGCZlwBSMZ8khXG7IkBhIDiCHEIKINro/74F54OLz6weqEM3CPoXl8tyc8IXQRHhKuEboJtyYJisU/RRkBuqF+kCIX6T/mAreEmq64P+4N1aEyroPrA3vcBfph4r7QsytkWYq4pVmh/6T9txn88DQUdmRHMkoeQfYjW/88UtVW1XVYRZrrH/MjjzV9ON+s4Z6f/bN+yD4PtmE/W2KLsP3YGewEdg47jDUBOnYMa8Y6sCNSPLy6HstW15C3WFk8OVBH8A9/Q09Wmsl8xzrHXscv8r4C/jTpOxqwJoumiwWZWQV0Jvwi8OlsIddhFN3J0ckZAOn3Rf76ehMj+24gOh3fufl/AOB9bHBw8NB3LvQYAHvd4fZv+c5ZM+CnQxmAsy1cibhQzuHSCwG+JdTgTtMDRsAMWMP5OAE34AX8QCAIBVEgHqSAiTD6LLjOxWAqmAnmgRJQBpaDNaASbARbwA6wG+wDTeAwOAFOgwvgErgG7sDV0wNegH7wDnxGEISEUBEaoocYIxaIHeKEMBAfJBAJR2KRFCQNyUSEiASZicxHypCVSCWyGalF9iItyAnkHNKF3EIeIL3Ia+QTiqEqqBZqiFqio1EGykTD0Hh0ApqJTkGL0AXoUrQCrUF3oY3oCfQCeg3tRl+gAxjAlDEdzASzxxgYC4vCUrEMTIzNxkqxcqwGq8da4XO+gnVjfdhHnIjTcDpuD1dwCJ6Ac/Ep+Gx8CV6J78Ab8Xb8Cv4A78e/EagEA4IdwZPAJiQTMglTCSWEcsI2wkHCKbiXegjviESiDtGK6A73YgoxmziDuIS4nthAPE7sIj4iDpBIJD2SHcmbFEXikApIJaR1pF2kY6TLpB7SByVlJWMlJ6UgpVQloVKxUrnSTqWjSpeVnip9JquTLcie5CgyjzydvIy8ldxKvkjuIX+maFCsKN6UeEo2ZR6lglJPOUW5S3mjrKxsquyhHKMsUJ6rXKG8R/ms8gPljyqaKrYqLJXxKhKVpSrbVY6r3FJ5Q6VSLal+1FRqAXUptZZ6knqf+kGVpuqgylblqc5RrVJtVL2s+lKNrGahxlSbqFakVq62X+2iWp86Wd1SnaXOUZ+tXqXeon5DfUCDpjFGI0ojT2OJxk6NcxrPNEmalpqBmjzNBZpbNE9qPqJhNDMai8alzadtpZ2i9WgRtay02FrZWmVau7U6tfq1NbVdtBO1p2lXaR/R7tbBdCx12Dq5Ost09ulc1/k0wnAEcwR/xOIR9SMuj3ivO1LXT5evW6rboHtN95MeXS9QL0dvhV6T3j19XN9WP0Z/qv4G/VP6fSO1RnqN5I4sHblv5G0D1MDWINZghsEWgw6DAUMjw2BDkeE6w5OGfUY6Rn5G2UarjY4a9RrTjH2MBcarjY8ZP6dr05n0XHoFvZ3eb2JgEmIiMdls0mny2dTKNMG02LTB9J4ZxYxhlmG22qzNrN/c2DzCfKZ5nfltC7IFwyLLYq3FGYv3llaWSZYLLZssn1npWrGtiqzqrO5aU619radY11hftSHaMGxybNbbXLJFbV1ts2yrbC/aoXZudgK79XZdowijPEYJR9WMumGvYs+0L7Svs3/goOMQ7lDs0OTwcrT56NTRK0afGf3N0dUx13Gr450xmmNCxxSPaR3z2snWietU5XTVmeoc5DzHudn5lYudC99lg8tNV5prhOtC1zbXr27ubmK3erded3P3NPdq9xsMLUY0YwnjrAfBw99jjsdhj4+ebp4Fnvs8//Ky98rx2un1bKzVWP7YrWMfeZt6c7w3e3f70H3SfDb5dPua+HJ8a3wf+pn58fy2+T1l2jCzmbuYL/0d/cX+B/3fszxZs1jHA7CA4IDSgM5AzcCEwMrA+0GmQZlBdUH9wa7BM4KPhxBCwkJWhNxgG7K57Fp2f6h76KzQ9jCVsLiwyrCH4bbh4vDWCDQiNGJVxN1Ii0hhZFMUiGJHrYq6F20VPSX6UAwxJjqmKuZJ7JjYmbFn4mhxk+J2xr2L949fFn8nwTpBktCWqJY4PrE28X1SQNLKpO7k0cmzki+k6KcIUppTSamJqdtSB8YFjlszrme86/iS8dcnWE2YNuHcRP2JuROPTFKbxJm0P42QlpS2M+0LJ4pTwxlIZ6dXp/dzWdy13Bc8P95qXi/fm7+S/zTDO2NlxrNM78xVmb1ZvlnlWX0ClqBS8Co7JHtj9vucqJztOYO5SbkNeUp5aXktQk1hjrB9stHkaZO7RHaiElH3FM8pa6b0i8PE2/KR/An5zQVa8Ee+Q2It+UXyoNCnsKrww9TEqfunaUwTTuuYbjt98fSnRUFFv83AZ3BntM00mTlv5oNZzFmbZyOz02e3zTGbs2BOz9zguTvmUeblzPu92LF4ZfHb+UnzWxcYLpi74NEvwb/UlaiWiEtuLPRauHERvkiwqHOx8+J1i7+V8krPlzmWlZd9WcJdcv7XMb9W/Dq4NGNp5zK3ZRuWE5cLl19f4btix0qNlUUrH62KWNW4mr66dPXbNZPWnCt3Kd+4lrJWsra7IryieZ35uuXrvlRmVV6r8q9qqDaoXlz9fj1v/eUNfhvqNxpuLNv4aZNg083NwZsbayxryrcQtxRuebI1ceuZ3xi/1W7T31a27et24fbuHbE72mvda2t3GuxcVofWSep6d43fdWl3wO7mevv6zQ06DWV7wB7Jnud70/Ze3xe2r20/Y3/9AYsD1QdpB0sbkcbpjf1NWU3dzSnNXS2hLW2tXq0HDzkc2n7Y5HDVEe0jy45Sji44Onis6NjAcdHxvhOZJx61TWq7czL55NX2mPbOU2Gnzp4OOn3yDPPMsbPeZw+f8zzXcp5xvumC24XGDteOg7+7/n6w062z8aL7xeZLHpdau8Z2Hb3se/nElYArp6+yr164Fnmt63rC9Zs3xt/ovsm7+exW7q1Xtwtvf74z9y7hbuk99Xvl9w3u1/xh80dDt1v3kQcBDzoexj2884j76MXj/MdfehY8oT4pf2r8tPaZ07PDvUG9l56Pe97zQvTic1/Jnxp/Vr+0fnngL7+/OvqT+3teiV8Nvl7yRu/N9rcub9sGogfuv8t79/l96Qe9Dzs+Mj6e+ZT06ennqV9IXyq+2nxt/Rb27e5g3uCgiCPmyH4FMFjRjAwAXm8HgJoCAA2ezyjj5Oc/WUHkZ1YZAv8Jy8+IsuIGQD38f4/pg383NwDYsxUev6C+2ngAoqkAxHsA1Nl5uA6d1WTnSmkhwnPApuiv6Xnp4N8U+Znzh7h/boFU1QX83P4L2JB8Uu+mibsAAAA4ZVhJZk1NACoAAAAIAAGHaQAEAAAAAQAAABoAAAAAAAKgAgAEAAAAAQAAAoqgAwAEAAAAAQAAAZAAAAAA9wLWsAAAQABJREFUeAHsvQd4HNd5LjyzvRfsAlj03tib2ERRIimqi1az3CTbclzlJE58S26eP/fGqb9TrhOn2E4sx7IsWcVqVqVIiZLYewVAEL0Du9jey+zMfc8MsATBRSUpgcQZQbuzM2dO+c7wvOfrrCAIDD0oBSgFKAUoBSgFKAXmEwVk86kztC+UApQClAKUApQClAKEAhSe6XtAKUApQClAKUApMO8oQOF53k0J7RClAKUApQClAKUAhWf6DlAKUApQClAKUArMOwpQeJ53U0I7RClAKUApQClAKUDhmb4DlAKUApQClAKUAvOOAhSe592U0A5RClAKUApQClAKUHim7wClAKUApQClAKXAvKMAhed5NyW0Q5QClAKUApQClAIUnuk7QClAKUApQClAKTDvKEDhed5NCe0QpQClAKUApQClAIVn+g5QClAKUApQClAKzDsKUHied1NCO0QpQClAKUApQClA4Zm+A5QClAKUApQClALzjgIUnufdlNAOUQpQClAKUApQClB4pu8ApQClAKUApQClwLyjgGLe9Yh2iFKAUmByCggCzwtMmidfOLg0+cQVLine truncated
|
||||
</defs>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 139 KiB |
@@ -0,0 +1,315 @@
|
||||
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
|
||||
<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">
|
||||
<svg xmlns="http://www.w3.org/2000/svg" version="1.1" viewBox="0.00 0.00 500.00 300.00">
|
||||
<path fill="#016299" d="
|
||||
M 158.03 92.18
|
||||
A 0.27 0.26 -50.8 0 0 157.56 92.23
|
||||
L 133.49 153.75
|
||||
Q 133.29 154.26 132.74 154.26
|
||||
L 117.81 154.27
|
||||
Q 117.04 154.27 116.75 153.55
|
||||
L 93.39 93.85
|
||||
Q 92.38 91.25 91.83 93.99
|
||||
L 79.83 153.77
|
||||
Q 79.73 154.26 79.23 154.26
|
||||
L 58.72 154.26
|
||||
A 0.45 0.45 0.0 0 1 58.28 153.72
|
||||
L 78.16 53.57
|
||||
Q 78.22 53.25 78.55 53.25
|
||||
L 98.56 53.25
|
||||
Q 99.17 53.25 99.41 53.82
|
||||
L 124.60 114.49
|
||||
Q 125.30 116.18 125.99 114.48
|
||||
L 151.01 53.62
|
||||
A 0.59 0.59 0.0 0 1 151.56 53.25
|
||||
L 171.54 53.25
|
||||
Q 172.10 53.25 172.21 53.80
|
||||
L 192.72 153.73
|
||||
A 0.47 0.46 -5.6 0 1 192.26 154.28
|
||||
L 170.98 154.26
|
||||
A 0.48 0.48 0.0 0 1 170.51 153.88
|
||||
Q 164.38 123.38 158.25 92.76
|
||||
Q 158.18 92.40 158.03 92.18
|
||||
Z"
|
||||
/>
|
||||
<rect fill="#016299" x="197.86" y="53.25" width="20.38" height="101.02" rx="0.38"/>
|
||||
<path fill="#016299" d="
|
||||
M 248.05 70.24
|
||||
A 0.57 0.57 0.0 0 0 247.49 69.57
|
||||
L 225.05 69.62
|
||||
Q 224.49 69.62 224.49 69.05
|
||||
L 224.49 53.50
|
||||
Q 224.49 53.25 224.75 53.25
|
||||
L 291.20 53.25
|
||||
A 0.46 0.45 -0.0 0 1 291.66 53.70
|
||||
L 291.69 69.02
|
||||
A 0.58 0.58 0.0 0 1 291.11 69.60
|
||||
L 268.55 69.58
|
||||
Q 267.89 69.58 267.89 70.24
|
||||
L 267.87 153.71
|
||||
Q 267.87 154.29 267.29 154.29
|
||||
L 248.53 154.26
|
||||
Q 247.99 154.26 247.98 153.71
|
||||
Q 247.90 113.33 247.96 71.39
|
||||
Q 247.96 70.81 248.05 70.24
|
||||
Z"
|
||||
/>
|
||||
<path fill="#016299" d="
|
||||
M 378.18 151.96
|
||||
L 378.20 53.90
|
||||
A 0.65 0.65 0.0 0 1 378.85 53.25
|
||||
L 439.77 53.25
|
||||
Q 440.30 53.25 440.30 53.77
|
||||
L 440.30 69.02
|
||||
Q 440.30 69.59 439.73 69.59
|
||||
L 399.08 69.59
|
||||
Q 398.49 69.59 398.49 70.17
|
||||
L 398.49 95.03
|
||||
A 0.54 0.54 0.0 0 0 399.03 95.57
|
||||
L 439.23 95.55
|
||||
A 0.69 0.68 -0.0 0 1 439.92 96.23
|
||||
L 439.95 111.28
|
||||
A 0.73 0.72 -89.6 0 1 439.22 112.01
|
||||
L 398.92 111.98
|
||||
A 0.43 0.43 0.0 0 0 398.49 112.41
|
||||
L 398.49 137.15
|
||||
A 0.65 0.65 0.0 0 0 399.15 137.80
|
||||
L 439.78 137.76
|
||||
Q 440.29 137.76 440.29 138.28
|
||||
L 440.30 153.73
|
||||
Q 440.30 154.27 439.76 154.27
|
||||
L 354.77 154.26
|
||||
Q 354.04 154.26 353.59 153.69
|
||||
L 322.21 113.37
|
||||
Q 321.59 112.58 321.59 111.57
|
||||
L 321.58 94.93
|
||||
Q 321.58 94.33 322.18 94.31
|
||||
Q 330.93 94.07 341.46 94.08
|
||||
C 347.32 94.08 353.98 90.87 355.04 84.56
|
||||
C 356.49 76.04 350.55 70.28 342.17 70.27
|
||||
Q 330.13 70.26 318.50 70.23
|
||||
A 0.36 0.36 0.0 0 0 318.14 70.59
|
||||
L 318.14 153.69
|
||||
Q 318.14 154.28 317.56 154.28
|
||||
L 298.50 154.26
|
||||
A 0.52 0.51 0.6 0 1 297.99 153.75
|
||||
L 297.98 53.63
|
||||
Q 297.98 53.20 298.41 53.21
|
||||
Q 318.18 53.37 340.34 53.16
|
||||
Q 348.47 53.08 354.39 54.64
|
||||
C 363.38 57.00 372.60 64.63 374.49 74.23
|
||||
C 376.35 83.66 375.47 94.49 368.51 101.41
|
||||
Q 358.96 110.89 344.12 111.94
|
||||
A 0.69 0.69 0.0 0 0 343.64 113.07
|
||||
L 376.85 152.45
|
||||
Q 378.18 154.02 378.18 151.96
|
||||
Z"
|
||||
/>
|
||||
<path fill="#c64128" d="
|
||||
M 230.30 202.72
|
||||
C 225.79 198.17 222.44 192.50 223.68 186.06
|
||||
Q 225.88 174.61 237.19 171.82
|
||||
C 243.35 170.31 250.25 172.62 254.56 177.46
|
||||
C 260.15 183.76 260.08 193.76 254.44 200.16
|
||||
Q 251.26 203.77 246.86 205.76
|
||||
A 0.90 0.90 0.0 0 0 246.56 207.18
|
||||
L 254.93 216.61
|
||||
A 0.69 0.68 39.0 0 0 256.04 216.50
|
||||
L 263.39 203.88
|
||||
Q 263.51 203.67 263.76 203.67
|
||||
L 274.57 203.66
|
||||
Q 274.82 203.66 274.70 203.88
|
||||
L 263.00 224.53
|
||||
Q 262.72 225.02 263.10 225.44
|
||||
L 275.42 238.78
|
||||
A 0.38 0.38 0.0 0 1 275.39 239.32
|
||||
L 268.56 245.42
|
||||
A 0.45 0.44 47.3 0 1 267.94 245.39
|
||||
L 258.30 234.72
|
||||
A 0.78 0.78 0.0 0 0 257.06 234.82
|
||||
C 251.41 243.84 242.45 248.65 231.77 245.21
|
||||
C 216.95 240.42 210.30 223.12 220.67 210.78
|
||||
C 223.18 207.79 226.82 205.56 230.20 203.52
|
||||
Q 230.76 203.18 230.30 202.72
|
||||
Z
|
||||
M 248.91 190.31
|
||||
C 249.51 185.51 247.25 181.73 242.19 181.06
|
||||
C 238.82 180.60 235.04 182.40 233.78 185.57
|
||||
C 231.59 191.08 235.32 195.52 239.43 199.17
|
||||
Q 239.81 199.50 240.25 199.27
|
||||
C 244.10 197.30 248.33 195.00 248.91 190.31
|
||||
Z
|
||||
M 248.77 224.33
|
||||
L 238.93 213.60
|
||||
A 4.22 4.22 0.0 0 0 232.97 213.34
|
||||
L 229.66 216.37
|
||||
A 11.43 11.41 47.5 0 0 228.97 232.50
|
||||
L 229.06 232.61
|
||||
A 11.43 11.41 47.5 0 0 245.19 233.33
|
||||
L 248.50 230.29
|
||||
A 4.22 4.22 0.0 0 0 248.77 224.33
|
||||
Z"
|
||||
/>
|
||||
<path fill="#c64128" d="
|
||||
M 316.53 236.21
|
||||
C 325.70 237.60 333.15 234.06 339.52 227.34
|
||||
Q 339.84 227.00 340.30 227.00
|
||||
L 351.79 226.98
|
||||
Q 352.78 226.97 352.26 227.81
|
||||
Q 343.43 242.15 327.68 245.58
|
||||
C 306.15 250.26 286.42 234.20 283.32 213.61
|
||||
C 279.76 189.93 301.11 168.47 324.78 171.76
|
||||
Q 343.44 174.35 352.65 190.63
|
||||
Q 352.99 191.23 352.30 191.23
|
||||
L 341.44 191.23
|
||||
A 2.35 2.32 -21.3 0 1 339.73 190.49
|
||||
C 330.13 180.10 315.42 177.80 304.03 186.97
|
||||
Q 295.74 193.64 294.02 204.40
|
||||
C 291.70 218.96 301.67 233.95 316.53 236.21
|
||||
Z"
|
||||
/>
|
||||
<path fill="#c64128" d="
|
||||
M 372.00 212.51
|
||||
Q 373.04 213.66 373.04 215.17
|
||||
Q 373.03 229.75 373.10 244.32
|
||||
Q 373.10 244.93 372.49 244.93
|
||||
L 362.91 244.88
|
||||
A 0.59 0.58 -90.0 0 1 362.33 244.29
|
||||
L 362.33 173.44
|
||||
A 0.48 0.48 0.0 0 1 362.81 172.96
|
||||
L 372.70 172.95
|
||||
Q 373.06 172.95 373.06 173.31
|
||||
Q 373.13 184.59 372.84 195.52
|
||||
C 372.74 198.97 373.39 202.37 373.05 205.87
|
||||
Q 372.81 208.40 374.27 206.32
|
||||
Q 378.12 200.83 382.18 195.74
|
||||
Q 386.47 190.36 390.19 185.21
|
||||
Q 394.58 179.13 398.83 173.21
|
||||
Q 398.94 173.06 399.12 173.04
|
||||
Q 400.52 172.93 411.21 172.92
|
||||
A 0.05 0.04 -69.3 0 1 411.24 173.00
|
||||
Q 397.61 190.69 384.61 207.81
|
||||
A 0.78 0.77 45.4 0 0 384.61 208.74
|
||||
Q 397.76 226.47 411.39 244.88
|
||||
A 0.04 0.04 0.0 0 1 411.36 244.94
|
||||
Q 399.76 244.99 399.30 244.89
|
||||
Q 399.13 244.85 399.03 244.72
|
||||
Q 387.57 228.88 375.97 212.45
|
||||
Q 375.60 211.92 374.96 211.91
|
||||
L 372.29 211.86
|
||||
A 0.39 0.39 0.0 0 0 372.00 212.51
|
||||
Z"
|
||||
/>
|
||||
<path fill="#c64128" d="
|
||||
M 78.48 225.70
|
||||
L 70.67 244.67
|
||||
A 0.43 0.43 0.0 0 1 70.27 244.94
|
||||
L 59.40 244.99
|
||||
A 0.43 0.43 0.0 0 1 59.00 244.39
|
||||
L 88.53 173.23
|
||||
A 0.43 0.43 0.0 0 1 88.93 172.97
|
||||
L 97.05 172.95
|
||||
A 0.43 0.43 0.0 0 1 97.45 173.21
|
||||
L 127.21 244.41
|
||||
A 0.43 0.43 0.0 0 1 126.81 245.01
|
||||
L 115.90 244.93
|
||||
A 0.43 0.43 0.0 0 1 115.50 244.67
|
||||
L 107.65 225.68
|
||||
A 0.43 0.43 0.0 0 0 107.25 225.41
|
||||
L 78.88 225.43
|
||||
A 0.43 0.43 0.0 0 0 78.48 225.70
|
||||
Z
|
||||
M 82.29 214.85
|
||||
A 0.40 0.40 0.0 0 0 82.67 215.39
|
||||
L 103.19 215.39
|
||||
A 0.40 0.40 0.0 0 0 103.57 214.85
|
||||
L 93.30 187.38
|
||||
A 0.40 0.40 0.0 0 0 92.56 187.38
|
||||
L 82.29 214.85
|
||||
Z"
|
||||
/>
|
||||
<path fill="#c64128" d="
|
||||
M 148.27 183.14
|
||||
L 148.27 244.56
|
||||
A 0.41 0.41 0.0 0 1 147.86 244.97
|
||||
L 137.95 244.91
|
||||
A 0.41 0.41 0.0 0 1 137.54 244.50
|
||||
L 137.54 183.14
|
||||
A 0.41 0.41 0.0 0 0 137.13 182.73
|
||||
L 121.27 182.75
|
||||
A 0.41 0.41 0.0 0 1 120.86 182.34
|
||||
L 120.84 173.37
|
||||
A 0.41 0.41 0.0 0 1 121.25 172.96
|
||||
L 164.97 172.94
|
||||
A 0.41 0.41 0.0 0 1 165.38 173.35
|
||||
L 165.38 182.35
|
||||
A 0.41 0.41 0.0 0 1 164.97 182.76
|
||||
L 148.68 182.73
|
||||
A 0.41 0.41 0.0 0 0 148.27 183.14
|
||||
Z"
|
||||
/>
|
||||
<path fill="#c64128" d="
|
||||
M 187.79 182.72
|
||||
L 171.91 182.75
|
||||
A 0.46 0.46 0.0 0 1 171.45 182.29
|
||||
L 171.44 173.41
|
||||
A 0.46 0.46 0.0 0 1 171.90 172.95
|
||||
L 215.60 172.96
|
||||
A 0.46 0.46 0.0 0 1 216.06 173.42
|
||||
L 216.01 182.28
|
||||
A 0.46 0.46 0.0 0 1 215.55 182.74
|
||||
L 199.38 182.74
|
||||
A 0.46 0.46 0.0 0 0 198.92 183.20
|
||||
L 198.94 244.47
|
||||
A 0.46 0.46 0.0 0 1 198.48 244.93
|
||||
L 188.67 244.94
|
||||
A 0.46 0.46 0.0 0 1 188.21 244.48
|
||||
L 188.25 183.18
|
||||
A 0.46 0.46 0.0 0 0 187.79 182.72
|
||||
Z"
|
||||
/>
|
||||
<path fill="#c64128" d="
|
||||
M 431.21 237.97
|
||||
A 0.56 0.56 0.0 0 0 430.42 238.50
|
||||
L 430.50 244.18
|
||||
A 0.84 0.83 -87.3 0 1 429.57 245.03
|
||||
L 429.02 244.97
|
||||
A 0.94 0.93 3.7 0 1 428.18 244.02
|
||||
L 428.39 234.99
|
||||
A 0.60 0.59 -1.3 0 0 427.74 234.38
|
||||
L 425.24 234.57
|
||||
Q 424.82 234.60 424.83 235.01
|
||||
L 424.97 243.97
|
||||
Q 424.99 244.87 424.09 244.97
|
||||
Q 423.71 245.01 423.62 245.02
|
||||
Q 422.73 245.12 422.73 244.22
|
||||
L 422.73 235.26
|
||||
Q 422.73 234.54 422.01 234.52
|
||||
L 420.93 234.50
|
||||
Q 420.12 234.48 420.12 233.68
|
||||
L 420.12 233.19
|
||||
A 0.69 0.69 0.0 0 1 420.81 232.50
|
||||
L 431.06 232.56
|
||||
A 0.80 0.79 -8.4 0 1 431.82 233.12
|
||||
Q 433.00 237.12 434.36 240.46
|
||||
Q 434.90 241.81 435.37 240.43
|
||||
L 437.85 233.10
|
||||
Q 438.05 232.51 438.68 232.50
|
||||
L 440.78 232.48
|
||||
Q 441.33 232.48 441.33 233.03
|
||||
L 441.25 244.31
|
||||
A 0.70 0.69 -85.1 0 1 440.44 245.00
|
||||
L 439.95 244.92
|
||||
Q 438.74 244.72 438.85 243.50
|
||||
Q 438.99 241.98 439.01 240.48
|
||||
Q 439.01 240.00 438.70 239.61
|
||||
Q 438.51 239.38 438.21 239.39
|
||||
Q 437.55 239.41 437.35 240.03
|
||||
L 436.04 244.05
|
||||
A 1.26 1.25 -89.5 0 1 435.20 244.88
|
||||
Q 434.04 245.23 433.63 244.13
|
||||
Q 432.61 241.40 431.70 238.52
|
||||
Q 431.57 238.12 431.21 237.97
|
||||
Z"
|
||||
/>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 8.3 KiB |
@@ -0,0 +1 @@
|
||||
<svg xmlns="http://www.w3.org/2000/svg" width="64" height="64"><path d="M12.506 8.407C5.603 8.407 0 14.01 0 20.912l.097 34.74h11.117l-.097-23.1v-11.63a1.4 1.4 0 0 1 1.25-1.39c.047-.005.09 0 .14 0 .383 0 .73.157.98.408L42.653 51.93c2.342 2.35 5.523 3.668 8.84 3.665C58.397 55.594 64 49.99 64 43.088V8.35H52.883V43.14a1.39 1.39 0 0 1-1.39 1.337c-.368 0-.72-.147-.98-.408L21.347 12.07c-2.342-2.35-5.524-3.668-8.84-3.664z"/></svg>
|
||||
|
After Width: | Height: | Size: 426 B |
@@ -0,0 +1,9 @@
|
||||
<svg width="40" height="45" viewBox="0 0 40 45" fill="none" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink">
|
||||
<rect width="40" height="44.8" fill="url(#pattern0)"/>
|
||||
<defs>
|
||||
<pattern id="pattern0" patternContentUnits="objectBoundingBox" width="1" height="1">
|
||||
<use xlink:href="#image0_407_5932" transform="matrix(0.00406504 0 0 0.0036295 0 0.109829)"/>
|
||||
</pattern>
|
||||
<image id="image0_407_5932" width="246" height="215" xlink:href="data:image/png;base64,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 truncated
|
||||
</defs>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 48 KiB |
@@ -0,0 +1 @@
|
||||
<svg id="svg" version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" width="400" height="400" viewBox="0, 0, 400,400"><g id="svgg"><path id="path1" d="M181.488 3.971 C 181.877 4.046,182.439 4.043,182.738 3.965 C 183.037 3.886,182.719 3.825,182.031 3.829 C 181.344 3.832,181.099 3.896,181.488 3.971 M207.578 3.974 C 208.051 4.045,208.824 4.045,209.297 3.974 C 209.770 3.902,209.383 3.844,208.438 3.844 C 207.492 3.844,207.105 3.902,207.578 3.974 M175.220 6.267 C 174.053 6.402,171.100 6.944,168.658 7.470 C 166.216 7.996,162.391 8.785,160.156 9.223 C 153.967 10.435,138.143 14.908,131.094 17.438 C 121.036 21.047,106.262 28.624,94.791 36.055 C 91.840 37.967,88.540 40.087,87.456 40.767 C 82.295 44.006,73.047 52.211,61.404 63.882 C 52.279 73.029,50.918 74.572,44.768 82.752 C 42.919 85.212,40.562 88.333,39.530 89.689 C 38.498 91.044,36.968 93.420,36.129 94.967 C 35.290 96.515,33.983 98.597,33.224 99.594 C 28.326 106.029,17.446 132.286,12.965 148.487 C 6.187 172.987,3.613 211.259,7.635 227.716 C 7.879 228.714,8.241 231.197,8.440 233.233 C 8.638 235.269,9.011 237.660,9.269 238.546 C 9.526 239.432,10.347 242.758,11.092 245.938 C 15.712 265.642,25.063 286.369,39.357 308.594 C 45.014 317.390,58.310 333.286,65.548 339.907 C 75.315 348.843,82.927 354.856,92.813 361.446 C 101.136 366.996,102.423 367.813,102.846 367.813 C 103.101 367.812,104.358 368.460,105.639 369.252 C 118.785 377.376,141.956 385.796,162.243 389.820 C 180.990 393.539,208.011 394.968,219.254 392.835 C 220.123 392.671,223.213 392.310,226.120 392.034 C 235.850 391.112,254.870 386.541,264.058 382.917 C 266.037 382.136,269.133 381.015,270.938 380.424 C 282.933 376.498,310.707 359.828,324.689 348.163 C 337.074 337.829,357.706 314.280,363.266 304.130 C 363.992 302.804,365.389 300.457,366.369 298.916 C 370.628 292.217,381.768 268.863,382.972 264.106 C 383.218 263.137,383.763 261.641,384.183 260.781 C 384.603 259.922,385.394 257.883,385.939 256.250 C 386.485 254.617,387.263 252.340,387.669 251.189 C 388.353 249.247,390.287 240.145,391.408 233.594 C 393.545 221.098,394.636 192.104,393.341 182.188 C 393.060 180.039,392.469 175.140,392.027 171.301 C 391.585 167.461,391.015 163.704,390.759 162.951 C 390.504 162.199,389.735 159.152,389.051 156.182 C 386.904 146.855,381.892 131.174,378.948 124.570 C 377.808 122.013,376.665 119.211,376.407 118.342 C 376.149 117.474,375.378 115.903,374.693 114.852 C 374.008 113.802,373.161 112.107,372.810 111.086 C 371.660 107.745,368.123 101.851,361.468 92.188 C 352.620 79.341,350.801 76.942,345.515 71.151 C 343.550 68.998,340.887 65.912,339.599 64.294 C 337.074 61.123,333.807 58.028,331.942 57.043 C 331.304 56.706,329.094 54.799,327.031 52.807 C 322.282 48.219,318.908 45.537,311.116 40.157 C 307.691 37.791,303.921 35.166,302.739 34.323 C 301.557 33.479,299.841 32.458,298.926 32.053 C 298.011 31.649,295.664 30.369,293.710 29.209 C 274.704 17.927,240.905 7.682,217.969 6.252 C 212.165 5.890,178.360 5.901,175.220 6.267 M214.688 9.715 C 217.180 9.890,220.555 10.240,222.188 10.493 C 223.820 10.746,226.492 11.160,228.125 11.413 C 254.033 15.426,274.205 22.353,293.095 33.722 C 295.672 35.273,298.676 36.948,299.770 37.444 C 305.667 40.118,323.277 53.681,332.300 62.500 C 341.110 71.110,355.938 88.597,355.938 90.376 C 355.938 90.565,357.040 92.280,358.388 94.187 C 363.109 100.869,366.878 107.925,374.759 124.844 C 379.890 135.857,380.102 136.520,385.165 157.344 C 386.585 163.188,387.970 168.742,388.241 169.688 C 389.371 173.620,389.993 185.280,389.990 202.500 C 389.988 214.364,389.957 214.790,388.329 225.469 C 387.909 228.219,387.326 232.297,387.033 234.531 C 386.463 238.882,385.270 243.971,384.558 245.094 C 384.318 245.472,383.819 246.906,383.450 248.281 C 383.080 249.656,381.724 254.086,380.436 258.125 C 375.460 273.726,376.212 271.744,372.430 279.219 C 371.473 281.109,369.974 284.133,369.099 285.938 C 368.224 287.742,367.152 289.781,366.718 290.469 C 366.283 291.156,365.834 292.000,365.720 292.344 C 365.282 293.665,363.316 297.075,360.976 300.574 C 359.635 302.579,357.656 305.623,356.577 307.340 C 355.498 309.056,353.928 311.212,353.089 312.131 C 352.249 313.049,351.559 313.965,351.555 314.166 C 351.550 314.367,350.812 315.402,349.914 316.467 C 349.016 317.532,346.529 320.485,344.388 323.029 C 337.377 331.361,322.581 345.644,315.000 351.399 C 309.427 355.630,295.492 364.688,294.556 364.688 C 294.501 364.687,293.066 365.476,291.368 366.440 C 286.032 369.469,276.772 373.979,273.876 374.959 C 272.346 375.477,269.887 376.460,268.412 377.142 C 262.659 379.805,247.103 384.423,239.844 385.623 C 238.984 385.765,237.719 386.091,237.031 386.348 C 236.344 386.606,234.094 386.982,232.031 387.186 C 229.969 387.389,227.438 387.744,226.406 387.973 C 223.251 388.676,217.053 389.208,204.531 389.853 C 166.381 391.817,116.169 375.617,84.844 351.237 C 73.837 342.671,58.784 328.831,58.277 326.812 C 58.169 326.384,57.465 325.518,56.712 324.889 C 49.407 318.782,33.808 294.264,25.868 276.406 C 7.215 234.457,4.544 183.113,18.813 140.781Line truncated
|
||||
|
After Width: | Height: | Size: 547 KiB |
@@ -0,0 +1,9 @@
|
||||
<svg width="41" height="45" viewBox="0 0 41 45" fill="none" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink">
|
||||
<rect x="0.333374" width="40" height="44.8" fill="url(#pattern0)"/>
|
||||
<defs>
|
||||
<pattern id="pattern0" patternContentUnits="objectBoundingBox" width="1" height="1">
|
||||
<use xlink:href="#image0_407_5966" transform="matrix(0.0024888 0 0 0.00222214 0.0431086 0.086682)"/>
|
||||
</pattern>
|
||||
<image id="image0_407_5966" width="375" height="372" xlink:href="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAXcAAAF0CAIAAABXNu4HAAAMPmlDQ1BJQ0MgUHJvZmlsZQAASImVVwdYU8kWnluSkEBoAQSkhN4EkRpASggt9N5shCRAKDEGgoodXVRw7SICNnRVRMFKsyN2FsXeFwsqyrpYsCtvUkDXfeV7831z57//nPnPmXNn7r0DgNpxjkiUi6oDkCcsEMcG+9OTU1LppKcABxggAy1gzuHmi5jR0eEAlqH27+XddYBI2yv2Uq1/9v/XosHj53MBQKIhTuflc/MgPgAAXs0ViQsAIEp5s6kFIimGFWiJYYAQL5LiTDmuluJ0Od4js4mPZUHcDoCSCocjzgRA9RLk6YXcTKih2g+xo5AnEAKgRofYJy9vMg/iNIitoY0IYqk+I/0Hncy/aaYPa3I4mcNYPhdZUQoQ5ItyOdP/z3T875KXKxnyYQmrSpY4JFY6Z5i3mzmTw6RYBeI+YXpkFMSaEH8Q8GT2EKOULElIgtweNeDms2DOgA7EjjxOQBjEBhAHCXMjwxV8eoYgiA0xXCHoNEEBOx5iXYgX8fMD4xQ2m8STYxW+0MYMMYup4M9yxDK/Ul/3JTkJTIX+6yw+W6GPqRZlxSdBTIHYvFCQGAmxKsQO+TlxYQqbsUVZrMghG7EkVhq/OcSxfGGwv1wfK8wQB8Uq7Evz8ofmi23KErAjFXhfQVZ8iDw/WDuXI4sfzgW7xBcyE4Z0+PnJ4UNz4fEDAuVzx57xhQlxCp0PogL/WPlYnCLKjVbY46b83GApbwqxS35hnGIsnlgAF6RcH88QFUTHy+PEi7I5odHyePDlIBywQACgAwms6WAyyAaCzr6mPngn7wkCHCAGmYAP7BXM0IgkWY8QXuNAEfgTIj7IHx7nL+vlg0LIfx1m5Vd7kCHrLZSNyAFPIM4DYSAX3ktko4TD3hLBY8gI/uGdAysXxpsLq7T/3/ND7HeGCZlwBSMZ8khXG7IkBhIDiCHEIKINro/74F54OLz6weqEM3CPoXl8tyc8IXQRHhKuEboJtyYJisU/RRkBuqF+kCIX6T/mAreEmq64P+4N1aEyroPrA3vcBfph4r7QsytkWYq4pVmh/6T9txn88DQUdmRHMkoeQfYjW/88UtVW1XVYRZrrH/MjjzV9ON+s4Z6f/bN+yD4PtmE/W2KLsP3YGewEdg47jDUBOnYMa8Y6sCNSPLy6HstW15C3WFk8OVBH8A9/Q09Wmsl8xzrHXscv8r4C/jTpOxqwJoumiwWZWQV0Jvwi8OlsIddhFN3J0ckZAOn3Rf76ehMj+24gOh3fufl/AOB9bHBw8NB3LvQYAHvd4fZv+c5ZM+CnQxmAsy1cibhQzuHSCwG+JdTgTtMDRsAMWMP5OAE34AX8QCAIBVEgHqSAiTD6LLjOxWAqmAnmgRJQBpaDNaASbARbwA6wG+wDTeAwOAFOgwvgErgG7sDV0wNegH7wDnxGEISEUBEaoocYIxaIHeKEMBAfJBAJR2KRFCQNyUSEiASZicxHypCVSCWyGalF9iItyAnkHNKF3EIeIL3Ia+QTiqEqqBZqiFqio1EGykTD0Hh0ApqJTkGL0AXoUrQCrUF3oY3oCfQCeg3tRl+gAxjAlDEdzASzxxgYC4vCUrEMTIzNxkqxcqwGq8da4XO+gnVjfdhHnIjTcDpuD1dwCJ6Ac/Ep+Gx8CV6J78Ab8Xb8Cv4A78e/EagEA4IdwZPAJiQTMglTCSWEcsI2wkHCKbiXegjviESiDtGK6A73YgoxmziDuIS4nthAPE7sIj4iDpBIJD2SHcmbFEXikApIJaR1pF2kY6TLpB7SByVlJWMlJ6UgpVQloVKxUrnSTqWjSpeVnip9JquTLcie5CgyjzydvIy8ldxKvkjuIX+maFCsKN6UeEo2ZR6lglJPOUW5S3mjrKxsquyhHKMsUJ6rXKG8R/ms8gPljyqaKrYqLJXxKhKVpSrbVY6r3FJ5Q6VSLal+1FRqAXUptZZ6knqf+kGVpuqgylblqc5RrVJtVL2s+lKNrGahxlSbqFakVq62X+2iWp86Wd1SnaXOUZ+tXqXeon5DfUCDpjFGI0ojT2OJxk6NcxrPNEmalpqBmjzNBZpbNE9qPqJhNDMai8alzadtpZ2i9WgRtay02FrZWmVau7U6tfq1NbVdtBO1p2lXaR/R7tbBdCx12Dq5Ost09ulc1/k0wnAEcwR/xOIR9SMuj3ivO1LXT5evW6rboHtN95MeXS9QL0dvhV6T3j19XN9WP0Z/qv4G/VP6fSO1RnqN5I4sHblv5G0D1MDWINZghsEWgw6DAUMjw2BDkeE6w5OGfUY6Rn5G2UarjY4a9RrTjH2MBcarjY8ZP6dr05n0XHoFvZ3eb2JgEmIiMdls0mny2dTKNMG02LTB9J4ZxYxhlmG22qzNrN/c2DzCfKZ5nfltC7IFwyLLYq3FGYv3llaWSZYLLZssn1npWrGtiqzqrO5aU619radY11hftSHaMGxybNbbXLJFbV1ts2yrbC/aoXZudgK79XZdowijPEYJR9WMumGvYs+0L7Svs3/goOMQ7lDs0OTwcrT56NTRK0afGf3N0dUx13Gr450xmmNCxxSPaR3z2snWietU5XTVmeoc5DzHudn5lYudC99lg8tNV5prhOtC1zbXr27ubmK3erded3P3NPdq9xsMLUY0YwnjrAfBw99jjsdhj4+ebp4Fnvs8//Ky98rx2un1bKzVWP7YrWMfeZt6c7w3e3f70H3SfDb5dPua+HJ8a3wf+pn58fy2+T1l2jCzmbuYL/0d/cX+B/3fszxZs1jHA7CA4IDSgM5AzcCEwMrA+0GmQZlBdUH9wa7BM4KPhxBCwkJWhNxgG7K57Fp2f6h76KzQ9jCVsLiwyrCH4bbh4vDWCDQiNGJVxN1Ii0hhZFMUiGJHrYq6F20VPSX6UAwxJjqmKuZJ7JjYmbFn4mhxk+J2xr2L949fFn8nwTpBktCWqJY4PrE28X1SQNLKpO7k0cmzki+k6KcIUppTSamJqdtSB8YFjlszrme86/iS8dcnWE2YNuHcRP2JuROPTFKbxJm0P42QlpS2M+0LJ4pTwxlIZ6dXp/dzWdy13Bc8P95qXi/fm7+S/zTDO2NlxrNM78xVmb1ZvlnlWX0ClqBS8Co7JHtj9vucqJztOYO5SbkNeUp5aXktQk1hjrB9stHkaZO7RHaiElH3FM8pa6b0i8PE2/KR/An5zQVa8Ee+Q2It+UXyoNCnsKrww9TEqfunaUwTTuuYbjt98fSnRUFFv83AZ3BntM00mTlv5oNZzFmbZyOz02e3zTGbs2BOz9zguTvmUeblzPu92LF4ZfHb+UnzWxcYLpi74NEvwb/UlaiWiEtuLPRauHERvkiwqHOx8+J1i7+V8krPlzmWlZd9WcJdcv7XMb9W/Dq4NGNp5zK3ZRuWE5cLl19f4btix0qNlUUrH62KWNW4mr66dPXbNZPWnCt3Kd+4lrJWsra7IryieZ35uuXrvlRmVV6r8q9qqDaoXlz9fj1v/eUNfhvqNxpuLNv4aZNg083NwZsbayxryrcQtxRuebI1ceuZ3xi/1W7T31a27et24fbuHbE72mvda2t3GuxcVofWSep6d43fdWl3wO7mevv6zQ06DWV7wB7Jnud70/Ze3xe2r20/Y3/9AYsD1QdpB0sbkcbpjf1NWU3dzSnNXS2hLW2tXq0HDzkc2n7Y5HDVEe0jy45Sji44Onis6NjAcdHxvhOZJx61TWq7czL55NX2mPbOU2Gnzp4OOn3yDPPMsbPeZw+f8zzXcp5xvumC24XGDteOg7+7/n6w062z8aL7xeZLHpdau8Z2Hb3se/nElYArp6+yr164Fnmt63rC9Zs3xt/ovsm7+exW7q1Xtwtvf74z9y7hbuk99Xvl9w3u1/xh80dDt1v3kQcBDzoexj2884j76MXj/MdfehY8oT4pf2r8tPaZ07PDvUG9l56Pe97zQvTic1/Jnxp/Vr+0fnngL7+/OvqT+3teiV8Nvl7yRu/N9rcub9sGogfuv8t79/l96Qe9Dzs+Mj6e+ZT06ennqV9IXyq+2nxt/Rb27e5g3uCgiCPmyH4FMFjRjAwAXm8HgJoCAA2ezyjj5Oc/WUHkZ1YZAv8Jy8+IsuIGQD38f4/pg383NwDYsxUev6C+2ngAoqkAxHsA1Nl5uA6d1WTnSmkhwnPApuiv6Xnp4N8U+Znzh7h/boFU1QX83P4L2JB8Uu+mibsAAAA4ZVhJZk1NACoAAAAIAAGHaQAEAAAAAQAAABoAAAAAAAKgAgAEAAAAAQAAAXegAwAEAAAAAQAAAXQAAAAADFbMRAAAQABJREFUeAHsvQmcZFdZ93/3e6uq91l69i07gQRCAsgawIAsIq6IIq+KvuDfF3hfX0VRcfmDirv4uoF+BGXxBRFQCWtM2AkJIXsymcxMZu1Zenqv5e73/T7nVFXXTKZDOumers7UyaT61q17zz3nuef8zrMfsygKo1dWEQWKzDBt2qtfG2+Pf5ZlmGlq2I6cz4zClDNSzOZlpvrW/MJxYUTcoiqx5HLDNkzTyOWqQt+pbjDljH5QbnScVz/qD1vfJdedfoG6V05TPXUbzeusPDVNaaduW2YY/OMxJfVwOanaaja7Z/BYhqipatBjVR9LDb2ySihg9lBmlbyp05rJW8sLU0OJmpXM1ZT5yIRVYMGE5x9gxDmNHUCRvlAmLcVqgoICm466O7FCT3W9DJmWhoGOS9Uh9fKXa3gwRT9DQwRfebxu1TxYGb60UoAlt2mw/OVbkXiOVeQWgNJ8EA+n/TaASWvbKNODGKHyais9lFllbyzPc6vJqOiW5wWzVKa3w/9pkyGRqa9muAmn0FHmkUIxDYIJ+hQskbpMsEIdm9RgyiRvlU74aZ2Tv3mhWJVcAUwGLine truncated
|
||||
</defs>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 174 KiB |
@@ -0,0 +1,4 @@
|
||||
export * from "./compliance/IconCompliance";
|
||||
export * from "./Icons";
|
||||
export * from "./prowler/ProwlerIcons";
|
||||
export * from "./services/IconServices";
|
||||
@@ -0,0 +1,42 @@
|
||||
import * as React from "react";
|
||||
|
||||
import { IconSvgProps } from "@/types";
|
||||
|
||||
export const AWSProviderBadge: React.FC<IconSvgProps> = ({
|
||||
size,
|
||||
width,
|
||||
height,
|
||||
...props
|
||||
}) => (
|
||||
<svg
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
aria-hidden="true"
|
||||
fill="none"
|
||||
focusable="false"
|
||||
height={size || height}
|
||||
role="presentation"
|
||||
viewBox="0 0 256 256"
|
||||
width={size || width}
|
||||
{...props}
|
||||
>
|
||||
<g fill="none">
|
||||
<rect width="256" height="256" fill="#f4f2ed" rx="60" />
|
||||
<path
|
||||
fill="#252f3e"
|
||||
d="M84.745 111.961c0 2.434.263 4.407.723 5.855a35 35 0 0 0 2.106 4.737c.329.526.46 1.052.46 1.513c0 .658-.395 1.316-1.25 1.973l-4.145 2.764c-.592.394-1.184.592-1.71.592c-.658 0-1.316-.329-1.974-.921a20.4 20.4 0 0 1-2.368-3.092a51 51 0 0 1-2.04-3.882q-7.697 9.08-19.342 9.079c-5.526 0-9.934-1.579-13.158-4.737c-3.223-3.158-4.868-7.368-4.868-12.631c0-5.593 1.974-10.132 5.987-13.553s9.342-5.132 16.118-5.132c2.237 0 4.54.198 6.974.527s4.934.855 7.566 1.447v-4.803c0-5-1.053-8.487-3.092-10.526c-2.106-2.04-5.658-3.026-10.724-3.026c-2.303 0-4.671.263-7.105.855s-4.803 1.316-7.106 2.237a19 19 0 0 1-2.302.855c-.46.132-.79.198-1.053.198c-.92 0-1.382-.658-1.382-2.04v-3.224c0-1.052.132-1.842.461-2.302s.921-.921 1.842-1.382q3.454-1.776 8.29-2.96c3.223-.856 6.644-1.25 10.263-1.25c7.829 0 13.552 1.776 17.237 5.328c3.618 3.553 5.46 8.948 5.46 16.185v21.316zm-26.71 10c2.17 0 4.407-.395 6.776-1.185c2.368-.789 4.473-2.237 6.25-4.21c1.052-1.25 1.842-2.632 2.236-4.211s.658-3.487.658-5.723v-2.764a55 55 0 0 0-6.052-1.118a50 50 0 0 0-6.185-.395c-4.408 0-7.631.856-9.802 2.632s-3.224 4.276-3.224 7.566c0 3.092.79 5.394 2.434 6.973c1.58 1.645 3.882 2.435 6.908 2.435m52.828 7.105c-1.184 0-1.974-.198-2.5-.658c-.526-.395-.987-1.316-1.381-2.566l-15.46-50.855c-.396-1.316-.593-2.171-.593-2.632c0-1.052.526-1.645 1.579-1.645h6.447c1.25 0 2.106.198 2.566.658c.526.395.921 1.316 1.316 2.566l11.052 43.553l10.264-43.553c.329-1.316.723-2.17 1.25-2.566c.526-.394 1.447-.657 2.631-.657h5.263c1.25 0 2.106.197 2.632.657c.526.395.987 1.316 1.25 2.566l10.395 44.079l11.381-44.079c.395-1.316.856-2.17 1.316-2.566c.526-.394 1.382-.657 2.566-.657h6.118c1.053 0 1.645.526 1.645 1.644c0 .33-.066.658-.132 1.053c-.065.395-.197.92-.46 1.645l-15.855 50.855q-.593 1.974-1.382 2.566c-.526.394-1.382.658-2.5.658h-5.658c-1.25 0-2.105-.198-2.631-.658c-.527-.461-.987-1.316-1.25-2.632l-10.198-42.434l-10.131 42.368c-.329 1.316-.724 2.171-1.25 2.632c-.527.46-1.448.658-2.632.658zm84.54 1.776c-3.421 0-6.842-.395-10.132-1.184c-3.289-.79-5.855-1.645-7.566-2.632c-1.052-.592-1.776-1.25-2.039-1.842a4.65 4.65 0 0 1-.395-1.842v-3.355c0-1.382.526-2.04 1.513-2.04q.593 0 1.184.198c.395.131.987.394 1.645.658a35.8 35.8 0 0 0 7.237 2.302a39.5 39.5 0 0 0 7.829.79c4.145 0 7.368-.724 9.605-2.171c2.237-1.448 3.421-3.553 3.421-6.25c0-1.842-.592-3.356-1.776-4.606s-3.421-2.368-6.645-3.421l-9.539-2.96c-4.803-1.513-8.356-3.75-10.527-6.71c-2.171-2.895-3.289-6.12-3.289-9.54q0-4.144 1.776-7.303c1.184-2.105 2.763-3.947 4.737-5.394c1.974-1.514 4.211-2.632 6.842-3.422c2.632-.79 5.395-1.118 8.29-1.118c1.447 0 2.96.066 4.408.263c1.513.197 2.894.46 4.276.724c1.316.329 2.566.658 3.75 1.053q1.776.591 2.763 1.184c.921.526 1.579 1.052 1.974 1.644q.592.79.592 2.172v3.092c0 1.381-.526 2.105-1.513 2.105c-.527 0-1.382-.263-2.5-.79q-5.625-2.565-12.632-2.565c-3.75 0-6.71.592-8.75 1.842s-3.092 3.158-3.092 5.855c0 1.842.658 3.421 1.974 4.671s3.75 2.5 7.237 3.618l9.342 2.96c4.736 1.514 8.158 3.619 10.197 6.317s3.026 5.789 3.026 9.21c0 2.829-.592 5.395-1.71 7.632c-1.184 2.237-2.763 4.21-4.803 5.789c-2.039 1.645-4.474 2.829-7.302 3.685c-2.961.921-6.053 1.381-9.408 1.381"
|
||||
/>
|
||||
<path
|
||||
fill="#f90"
|
||||
fillRule="evenodd"
|
||||
d="M207.837 162.816c-21.645 15.987-53.092 24.474-80.132 24.474c-37.894 0-72.04-14.014-97.829-37.303c-2.04-1.842-.197-4.342 2.237-2.895c27.895 16.184 62.303 25.987 97.895 25.987c24.013 0 50.395-5 74.671-15.263c3.618-1.645 6.71 2.368 3.158 5"
|
||||
clipRule="evenodd"
|
||||
/>
|
||||
<path
|
||||
fill="#f90"
|
||||
fillRule="evenodd"
|
||||
d="M216.85 152.553c-2.763-3.553-18.289-1.711-25.329-.856c-2.105.264-2.434-1.579-.526-2.96c12.368-8.684 32.697-6.184 35.066-3.29c2.368 2.961-.658 23.29-12.237 33.027c-1.777 1.513-3.487.723-2.698-1.25c2.632-6.513 8.487-21.185 5.724-24.671"
|
||||
clipRule="evenodd"
|
||||
/>
|
||||
</g>
|
||||
</svg>
|
||||
);
|
||||
@@ -0,0 +1,80 @@
|
||||
import * as React from "react";
|
||||
|
||||
import { IconSvgProps } from "@/types";
|
||||
|
||||
export const AzureProviderBadge: React.FC<IconSvgProps> = ({
|
||||
size,
|
||||
width,
|
||||
height,
|
||||
...props
|
||||
}) => (
|
||||
<svg
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
aria-hidden="true"
|
||||
fill="none"
|
||||
focusable="false"
|
||||
height={size || height}
|
||||
role="presentation"
|
||||
viewBox="0 0 256 256"
|
||||
width={size || width}
|
||||
{...props}
|
||||
>
|
||||
<g fill="none">
|
||||
<rect width="256" height="256" fill="#f4f2ed" rx="60" />
|
||||
<path
|
||||
fill="url(#skillIconsAzureLight0)"
|
||||
d="M94.674 34.002h59.182L92.42 216.032a9.44 9.44 0 0 1-8.94 6.419H37.422a9.42 9.42 0 0 1-9.318-8.026a9.4 9.4 0 0 1 .39-4.407L85.733 40.421A9.44 9.44 0 0 1 94.674 34z"
|
||||
/>
|
||||
<path
|
||||
fill="#0078d4"
|
||||
d="M180.674 156.095H86.826a4.34 4.34 0 0 0-4.045 2.75a4.34 4.34 0 0 0 1.079 4.771l60.305 56.287a9.48 9.48 0 0 0 6.468 2.548h53.141z"
|
||||
/>
|
||||
<path
|
||||
fill="url(#skillIconsAzureLight1)"
|
||||
d="M94.675 34.002a9.36 9.36 0 0 0-8.962 6.544L28.565 209.863a9.412 9.412 0 0 0 8.882 12.588h47.247a10.1 10.1 0 0 0 7.75-6.592l11.397-33.586l40.708 37.968a9.63 9.63 0 0 0 6.059 2.21h52.943l-23.22-66.355l-67.689.016l41.428-122.11z"
|
||||
/>
|
||||
<path
|
||||
fill="url(#skillIconsAzureLight2)"
|
||||
d="M170.264 40.412a9.42 9.42 0 0 0-8.928-6.41H95.379a9.42 9.42 0 0 1 8.928 6.41l57.241 169.604a9.43 9.43 0 0 1-1.273 8.509a9.43 9.43 0 0 1-7.655 3.928h65.959a9.43 9.43 0 0 0 7.654-3.929a9.42 9.42 0 0 0 1.272-8.508z"
|
||||
/>
|
||||
<defs>
|
||||
<linearGradient
|
||||
id="skillIconsAzureLight0"
|
||||
x1="116.244"
|
||||
x2="54.783"
|
||||
y1="47.967"
|
||||
y2="229.54"
|
||||
gradientUnits="userSpaceOnUse"
|
||||
>
|
||||
<stop stopColor="#114a8b" />
|
||||
<stop offset="1" stopColor="#0669bc" />
|
||||
</linearGradient>
|
||||
<linearGradient
|
||||
id="skillIconsAzureLight1"
|
||||
x1="135.444"
|
||||
x2="121.227"
|
||||
y1="132.585"
|
||||
y2="137.392"
|
||||
gradientUnits="userSpaceOnUse"
|
||||
>
|
||||
<stop stopOpacity="0.3" />
|
||||
<stop offset="0.071" stopOpacity="0.2" />
|
||||
<stop offset="0.321" stopOpacity="0.1" />
|
||||
<stop offset="0.623" stopOpacity="0.05" />
|
||||
<stop offset="1" stopOpacity="0" />
|
||||
</linearGradient>
|
||||
<linearGradient
|
||||
id="skillIconsAzureLight2"
|
||||
x1="127.625"
|
||||
x2="195.091"
|
||||
y1="42.671"
|
||||
y2="222.414"
|
||||
gradientUnits="userSpaceOnUse"
|
||||
>
|
||||
<stop stopColor="#3ccbf4" />
|
||||
<stop offset="1" stopColor="#2892df" />
|
||||
</linearGradient>
|
||||
</defs>
|
||||
</g>
|
||||
</svg>
|
||||
);
|
||||
@@ -0,0 +1,42 @@
|
||||
import * as React from "react";
|
||||
|
||||
import { IconSvgProps } from "@/types";
|
||||
|
||||
export const GCPProviderBadge: React.FC<IconSvgProps> = ({
|
||||
size,
|
||||
width,
|
||||
height,
|
||||
...props
|
||||
}) => (
|
||||
<svg
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
aria-hidden="true"
|
||||
fill="none"
|
||||
focusable="false"
|
||||
height={size || height}
|
||||
role="presentation"
|
||||
viewBox="0 0 256 256"
|
||||
width={size || width}
|
||||
{...props}
|
||||
>
|
||||
<g fill="none">
|
||||
<rect width="256" height="256" fill="#f4f2ed" rx="60" />
|
||||
<path
|
||||
fill="#ea4335"
|
||||
d="m161.009 92.39l17.385-17.386l1.159-7.32c-31.68-28.807-82.04-25.54-110.6 6.816c-7.932 8.986-13.817 20.19-16.955 31.76l6.226-.878l34.77-5.733l2.684-2.745c15.466-16.986 41.617-19.272 59.475-4.82z"
|
||||
/>
|
||||
<path
|
||||
fill="#4285f4"
|
||||
d="M203.16 105.749a78.3 78.3 0 0 0-23.607-38.064l-24.4 24.4a43.37 43.37 0 0 1 15.921 34.404v4.331c11.993 0 21.716 9.722 21.716 21.715s-9.723 21.473-21.716 21.473h-43.493l-4.27 4.636v26.047l4.27 4.087h43.493c31.195.243 56.681-24.605 56.924-55.8a56.48 56.48 0 0 0-24.838-47.229"
|
||||
/>
|
||||
<path
|
||||
fill="#34a853"
|
||||
d="M84.149 208.778h43.432v-34.77H84.149a21.3 21.3 0 0 1-8.906-1.952l-6.161 1.891l-17.507 17.385l-1.525 5.917c9.818 7.413 21.796 11.582 34.099 11.529"
|
||||
/>
|
||||
<path
|
||||
fill="#fbbc05"
|
||||
d="M84.149 95.989C52.953 96.175 27.815 121.615 28 152.81a56.49 56.49 0 0 0 22.049 44.438l25.193-25.193c-10.93-4.938-15.787-17.802-10.849-28.731s17.802-15.787 28.73-10.85a21.72 21.72 0 0 1 10.85 10.85l25.193-25.193a56.42 56.42 0 0 0-45.018-22.143"
|
||||
/>
|
||||
</g>
|
||||
</svg>
|
||||
);
|
||||
@@ -0,0 +1,32 @@
|
||||
import * as React from "react";
|
||||
|
||||
import { IconSvgProps } from "@/types";
|
||||
|
||||
export const KS8ProviderBadge: React.FC<IconSvgProps> = ({
|
||||
size,
|
||||
width,
|
||||
height,
|
||||
...props
|
||||
}) => (
|
||||
<svg
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
aria-hidden="true"
|
||||
fill="none"
|
||||
focusable="false"
|
||||
height={size || height}
|
||||
role="presentation"
|
||||
viewBox="0 0 256 256"
|
||||
width={size || width}
|
||||
{...props}
|
||||
>
|
||||
<g fill="none">
|
||||
<rect width="256" height="256" fill="#326ce5" rx="60" />
|
||||
<path
|
||||
fill="#fff"
|
||||
stroke="#fff"
|
||||
strokeWidth=".11"
|
||||
d="M128.073 30a6.014 6.014 0 0 0-5.589 6.314v1.605c.153 1.817.426 3.617.785 5.4a53 53 0 0 1 .563 10.326 6.23 6.23 0 0 1-1.86 2.943l-.128 2.407c-3.456.29-6.886.819-10.265 1.587a73.1 73.1 0 0 0-37.153 21.204l-2.047-1.45a4.42 4.42 0 0 1-3.37-.342 53 53 0 0 1-7.655-6.912 47 47 0 0 0-3.729-3.967l-1.263-1.007a6.82 6.82 0 0 0-3.95-1.493 5.46 5.46 0 0 0-4.531 2.013 6.02 6.02 0 0 0 1.4 8.388l1.177.939a47 47 0 0 0 4.71 2.756 49 49 0 0 1 8.516 5.973 6.3 6.3 0 0 1 1.134 3.276l1.86 1.707a73.54 73.54 0 0 0-11.587 51.248l-2.39.683a7.8 7.8 0 0 1-2.44 2.457 53 53 0 0 1-10.188 1.681 48 48 0 0 0-5.46.427l-1.511.341h-.17a5.716 5.716 0 0 0-4.791 6.924 5.7 5.7 0 0 0 1.488 2.736 5.72 5.72 0 0 0 5.836 1.407h.111l1.536-.17a46 46 0 0 0 5.103-1.86 53 53 0 0 1 9.915-2.901 6.2 6.2 0 0 1 3.26 1.151l2.56-.426a73.92 73.92 0 0 0 32.766 40.983l-1.041 2.176a5.7 5.7 0 0 1 .512 3.208 55 55 0 0 1-5.146 9.318 48 48 0 0 0-3.054 4.548l-.726 1.536a5.72 5.72 0 0 0 2.49 8.015 5.7 5.7 0 0 0 3.057.527 5.72 5.72 0 0 0 4.719-3.687l.707-1.45a47 47 0 0 0 1.639-5.205c1.51-3.729 2.33-7.731 4.394-10.206a4.6 4.6 0 0 1 2.441-1.194l1.28-2.33a73.55 73.55 0 0 0 52.443.128l1.134 2.176a4.44 4.44 0 0 1 2.902 1.749 54 54 0 0 1 3.891 9.557 48 48 0 0 0 1.655 5.214l.708 1.45a5.72 5.72 0 0 0 7.784 3.154 5.7 5.7 0 0 0 2.345-2.036 5.71 5.71 0 0 0 .136-5.981l-.742-1.536a47 47 0 0 0-3.055-4.531c-1.962-2.833-3.652-5.854-5.12-9.019a4.43 4.43 0 0 1 .581-3.414 20 20 0 0 1-.948-2.295 74.02 74.02 0 0 0 32.622-41.128l2.423.426a4.53 4.53 0 0 1 3.183-1.177c3.387.648 6.706 1.706 9.915 2.901a43 43 0 0 0 5.102 1.963c.41.111 1.007.204 1.468.315h.111a5.71 5.71 0 0 0 5.823-1.421 5.7 5.7 0 0 0 1.504-2.729 5.7 5.7 0 0 0-.151-3.111 5.72 5.72 0 0 0-4.642-3.806l-1.655-.392a48 48 0 0 0-5.461-.427 52 52 0 0 1-10.188-1.681 6.4 6.4 0 0 1-2.458-2.457l-2.304-.683a73.8 73.8 0 0 0-11.826-51.137l2.014-1.86a4.5 4.5 0 0 1 1.058-3.226 53.6 53.6 0 0 1 8.447-5.939 48 48 0 0 0 4.71-2.756l1.246-1.007a5.72 5.72 0 0 0 1.456-8.42 5.716 5.716 0 0 0-8.53-.463l-1.262 1.007a48 48 0 0 0-3.729 3.968 53.3 53.3 0 0 1-7.45 7.023 6.3 6.3 0 0 1-3.447.375l-2.159 1.536a74.55 74.55 0 0 0-47.229-22.783c0-.853-.111-2.133-.128-2.534a4.48 4.48 0 0 1-1.86-2.833 53 53 0 0 1 .648-10.3c.367-1.791.623-3.583.785-5.4v-1.707a6.01 6.01 0 0 0-5.589-6.314zm-7.117 44.08-1.706 29.806h-.128c-.086 1.843-1.169 3.413-2.833 4.301-1.664.887-3.635.623-5.12-.461L86.722 90.404a58.54 58.54 0 0 1 28.184-15.35 60 60 0 0 1 6.033-.973zm14.233 0a59.1 59.1 0 0 1 34.046 16.418l-24.216 17.211a5.02 5.02 0 0 1-5.274.614 5.02 5.02 0 0 1-2.867-4.471zm-57.34 27.536 22.355 19.95v.128a5.02 5.02 0 0 1 1.587 4.898 5.02 5.02 0 0 1-3.558 3.712v.085l-28.687 8.251a58.53 58.53 0 0 1 8.31-37.032zm100.286 0a59.58 59.58 0 0 1 8.55 36.922l-28.73-8.277v-.111a4.96 4.96 0 0 1-3.559-3.712 5.05 5.05 0 0 1 1.588-4.897l22.185-19.856zm-54.645 21.503h9.148l5.589 7.099-2.031 8.875-8.217 3.95-8.235-3.95-1.937-8.875zm29.302 24.216a5.3 5.3 0 0 1 1.152 0l29.584 4.992c-4.267 12.287-12.689 22.783-23.679 29.805l-11.434-27.68a5 5 0 0 1-.383-2.354 5.04 5.04 0 0 1 4.726-4.635zm-49.687.128a5.03 5.03 0 0 1 4.13 2.287 4.99 4.99 0 0 1 .401 4.693v.111l-11.365 27.459a58.7 58.7 0 0 1-23.534-29.498l29.327-4.975q.489-.051.99 0zm24.78 11.946a5.04 5.04 0 0 1 4.582 2.628h.111l14.455 26.085-5.777 1.707a58.83 58.83 0 0 1-32.067-1.655l14.506-26.085c.879-1.536 2.5-2.475 4.267-2.518z"
|
||||
/>
|
||||
</g>
|
||||
</svg>
|
||||
);
|
||||
@@ -0,0 +1,4 @@
|
||||
export * from "./AWSProviderBadge";
|
||||
export * from "./AzureProviderBadge";
|
||||
export * from "./GCPProviderBadge";
|
||||
export * from "./KS8ProviderBadge";
|
||||
@@ -0,0 +1,57 @@
|
||||
import React from "react";
|
||||
|
||||
import { IconSvgProps } from "../../../types/index";
|
||||
|
||||
export const ProwlerExtended: React.FC<IconSvgProps> = ({
|
||||
size,
|
||||
width = 216,
|
||||
height,
|
||||
...props
|
||||
}) => {
|
||||
return (
|
||||
<svg
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
viewBox="0 0 1233.67 204.4"
|
||||
fill="none"
|
||||
height={size || height}
|
||||
width={size || width}
|
||||
color="evenodd"
|
||||
{...props}
|
||||
>
|
||||
<path
|
||||
className="cls-1"
|
||||
d="M1169.38 132.04c20.76-12.21 34.44-34.9 34.44-59.79 0-38.18-31.06-69.25-69.25-69.25l-216.9.23V148.4h-64.8V3h-79.95l-47.14 95.97V3h-52.09l-47.14 95.97V3h-53.48v69.6C560.37 30.64 521.34 0 475.28 0c-42.63 0-79.24 26.25-94.54 63.43C376.39 29.4 347.26 3 312.07 3H212.06v47.43C202.9 22.91 176.91 3 146.35 3H0l46.34 46.33v151.64h53.47v-76.68l17.21 17.21h29.33c30.56 0 56.54-19.91 65.71-47.43v106.91h53.48v-81.51l76.01 81.51h69.62l-64.29-68.94c11.14-6.56 20.22-16.15 26.26-27.46 1.27 55.26 46.58 99.82 102.14 99.82 46.06 0 85.09-30.64 97.81-72.6v69.18h60.88l38.34-78.06v78.06h60.88l66.2-134.78v135.69h95.41l22.86-22.86v22.86h95.05l21.84-21.84v20.93h53.48v-81.5l76.01 81.5h69.62l-64.29-68.94ZM146.35 88.02H99.81V56.48h46.54c8.7 0 15.77 7.07 15.77 15.77s-7.07 15.77-15.77 15.77Zm165.72 0-46.54-.18V56.48h46.54c8.7 0 15.77 7.07 15.77 15.77s-7.08 15.77-15.77 15.77Zm163.21 62.9c-26.86 0-48.72-21.86-48.72-48.72s21.86-48.72 48.72-48.72S524 75.34 524 102.2s-21.86 48.72-48.72 48.72Zm559.28-2.51h-63.41v-20.35h42.91V77.18h-42.91V56.72h63.41v91.69Zm100.01-60.39-46.54-.18V56.48h46.54c8.7 0 15.77 7.07 15.77 15.77s-7.07 15.77-15.77 15.77Z"
|
||||
fill="currentColor"
|
||||
fillRule="evenodd"
|
||||
clipRule="evenodd"
|
||||
/>
|
||||
</svg>
|
||||
);
|
||||
};
|
||||
|
||||
export const ProwlerShort: React.FC<IconSvgProps> = ({
|
||||
size,
|
||||
width = 30,
|
||||
height,
|
||||
...props
|
||||
}) => (
|
||||
<svg
|
||||
id="Layer_1"
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
viewBox="0 0 432.08 396.77"
|
||||
fill="none"
|
||||
height={size || height}
|
||||
width={size || width}
|
||||
color="evenodd"
|
||||
{...props}
|
||||
>
|
||||
<path
|
||||
className="cls-1"
|
||||
d="M293.3.01H0s92.87,92.85,92.87,92.85v303.9h107.17v-153.68l34.48,34.49h58.78c76.52,0,138.78-62.26,138.78-138.78S369.82.01,293.3.01ZM293.3,170.4h-93.27v-63.21h93.27c17.43,0,31.6,14.18,31.6,31.6s-14.18,31.6-31.6,31.6Z"
|
||||
fill="currentColor"
|
||||
fillRule="evenodd"
|
||||
clipRule="evenodd"
|
||||
color="evenodd"
|
||||
/>
|
||||
</svg>
|
||||
);
|
||||
@@ -0,0 +1,923 @@
|
||||
import { IconSvgProps } from "@/types";
|
||||
|
||||
export const IAMAccessAnalyzerIcon: React.FC<IconSvgProps> = ({
|
||||
size = 32,
|
||||
width,
|
||||
height,
|
||||
className = "rounded-md",
|
||||
...props
|
||||
}) => (
|
||||
<svg
|
||||
aria-hidden="false"
|
||||
aria-label="IAM Access Analyzer logo"
|
||||
fill="none"
|
||||
focusable="false"
|
||||
height={size || height}
|
||||
role="presentation"
|
||||
viewBox="0 0 40 40"
|
||||
width={size || width}
|
||||
className={className}
|
||||
{...props}
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
>
|
||||
<g fill="none" fillRule="evenodd">
|
||||
<path fill="#DD344C" d="M0 0h40v40H0z" />
|
||||
<path
|
||||
fill="#FFF"
|
||||
d="m33.131 31.955-6.998-6.998a.501.501 0 0 1-.092-.58c.945-1.85.63-4.273-.732-5.635a4.629 4.629 0 0 0-3.855-1.33c-1.432.173-2.696 1.001-3.466 2.27a4.583 4.583 0 0 0 .103 4.868c1.354 2.06 3.977 2.781 6.094 1.681a.5.5 0 0 1 .584.091l1.194 1.194a.504.504 0 0 1 .146.39l-.089 1.258 1.38-.003h.001a.5.5 0 0 1 .353.147l.598.597a.502.502 0 0 1 .146.347l.017 1.406 1.231-.106a.502.502 0 0 1 .397.144l1.097 1.097 1.761.45.13-1.288Zm1.019-.135-.213 2.101a.5.5 0 0 1-.621.434l-2.456-.627a.499.499 0 0 1-.23-.13l-1.029-1.03-1.537.133a.499.499 0 0 1-.543-.493l-.021-1.74-.306-.306-1.709.004h-.001a.502.502 0 0 1-.499-.535l.11-1.569-.783-.783c-2.515 1.1-5.491.202-7.057-2.179a5.587 5.587 0 0 1-.122-5.937c.931-1.533 2.462-2.534 4.201-2.744a5.63 5.63 0 0 1 4.682 1.616c1.8 1.8 1.898 4.535 1.072 6.463l6.918 6.918a.5.5 0 0 1 .144.404ZM22.737 21.208a1.087 1.087 0 0 0-.774-.32c-.292 0-.567.113-.774.32a1.098 1.098 0 0 0 0 1.55 1.12 1.12 0 0 0 1.548 0 1.098 1.098 0 0 0 0-1.55Zm.707-.707a2.099 2.099 0 0 1 0 2.964 2.09 2.09 0 0 1-1.481.613 2.09 2.09 0 0 1-1.481-.613 2.099 2.099 0 0 1 0-2.964 2.097 2.097 0 0 1 2.962 0ZM9.662 13.312c0 .263.016.52.047.778a.504.504 0 0 1-.423.56C8.035 14.981 6 15.968 6 18.882c0 .107.006.213.011.315.135 2.461 2.487 3.794 4.633 3.8H15v1h-4.357c-3.063-.008-5.483-2.048-5.63-4.746A6.369 6.369 0 0 1 5 18.882c0-3.389 2.318-4.647 3.677-5.094a7.265 7.265 0 0 1-.015-.476c0-2.777 1.876-5.653 4.364-6.69 2.91-1.226 5.992-.618 8.245 1.625.591.581 1.348 1.451 1.88 2.511.566-.515 1.207-.768 1.941-.768 1.455 0 3.086 1.217 3.376 3.88 3.008.715 4.532 2.43 4.532 5.1 0 2.927-1.281 4.57-3.916 5.02l-.168-.987C30.352 22.758 32 22.08 32 18.97c0-3.018-2.34-3.843-4.099-4.2a.5.5 0 0 1-.4-.462c-.113-1.953-1.103-3.317-2.409-3.317-.664 0-1.186.302-1.691.981a.501.501 0 0 1-.872-.13c-.437-1.22-1.308-2.24-1.961-2.883-1.958-1.95-4.634-2.476-7.157-1.414-2.102.877-3.749 3.41-3.749 5.768Z"
|
||||
/>
|
||||
</g>
|
||||
</svg>
|
||||
);
|
||||
|
||||
export const AWSAccountIcon: React.FC<IconSvgProps> = ({
|
||||
size = 32,
|
||||
width,
|
||||
height,
|
||||
className = "rounded-md",
|
||||
...props
|
||||
}) => (
|
||||
<svg
|
||||
aria-hidden="false"
|
||||
aria-label="AWS Account logo"
|
||||
fill="none"
|
||||
focusable="false"
|
||||
height={size || height}
|
||||
role="presentation"
|
||||
viewBox="0 0 40 40"
|
||||
width={size || width}
|
||||
className={className}
|
||||
{...props}
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
>
|
||||
<g fill="none" fillRule="evenodd">
|
||||
<path fill="#E7157B" d="M0 0h40v40H0z" />
|
||||
<path
|
||||
fill="#FFF"
|
||||
d="M24.5 22c1.93 0 3.5 1.57 3.5 3.5S26.43 29 24.5 29 21 27.43 21 25.5s1.57-3.5 3.5-3.5Zm0 8c2.481 0 4.5-2.019 4.5-4.5S26.981 21 24.5 21a4.505 4.505 0 0 0-4.5 4.5c0 2.481 2.019 4.5 4.5 4.5Zm1.523-19.12L29.084 17h-6.121l3.06-6.12ZM22.154 18h7.739a.502.502 0 0 0 .447-.724l-3.869-7.738c-.17-.338-.725-.338-.895 0l-3.869 7.738a.503.503 0 0 0 .447.724ZM11 23h7v-7h-7v7Zm-.5 1h8a.5.5 0 0 0 .5-.5v-8a.5.5 0 0 0-.5-.5h-8a.5.5 0 0 0-.5.5v8a.5.5 0 0 0 .5.5ZM8 32h24V8H8v24ZM32.5 7h-25a.5.5 0 0 0-.5.5v25a.5.5 0 0 0 .5.5h25a.5.5 0 0 0 .5-.5v-25a.5.5 0 0 0-.5-.5Z"
|
||||
/>
|
||||
</g>
|
||||
</svg>
|
||||
);
|
||||
|
||||
export const AWSCertificateManagerIcon: React.FC<IconSvgProps> = ({
|
||||
size = 32,
|
||||
width,
|
||||
height,
|
||||
className = "rounded-md",
|
||||
...props
|
||||
}) => (
|
||||
<svg
|
||||
aria-hidden="false"
|
||||
aria-label="AWS Certificate Manager logo"
|
||||
fill="none"
|
||||
focusable="false"
|
||||
height={size || height}
|
||||
role="presentation"
|
||||
viewBox="0 0 40 40"
|
||||
width={size || width}
|
||||
className={className}
|
||||
{...props}
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
>
|
||||
<g
|
||||
id="Icon-Architecture/32/Arch_AWS-Certificate-Manager_32"
|
||||
stroke="none"
|
||||
strokeWidth="1"
|
||||
fill="none"
|
||||
fillRule="evenodd"
|
||||
>
|
||||
<g
|
||||
id="Icon-Architecture-BG/32/Security-Identity-Compliance"
|
||||
fill="#DD344C"
|
||||
>
|
||||
<rect id="Rectangle" x="0" y="0" width="40" height="40" />
|
||||
</g>
|
||||
<path
|
||||
d="M17.8323574,19.6308709 C17.9645126,19.7501051 18.0221441,19.9309436 17.9843855,20.1058203 L17.4706696,22.4676501 L19.7401611,21.076585 C19.8991448,20.9782168 20.0998616,20.9782168 20.2608325,21.076585 L22.513432,22.4646692 L22.0146208,20.0978714 C21.9788495,19.9259755 22.0354874,19.7481179 22.1646616,19.6288837 L24.1787856,17.7877097 L21.5138223,17.2730156 C21.3608006,17.2432071 21.2306327,17.1438453 21.162071,17.0027516 L19.9955286,14.6160813 L18.8021576,17.0097069 C18.7326023,17.1478198 18.6034281,17.2461879 18.4523936,17.2750029 L15.7953795,17.7926778 L17.8323574,19.6308709 Z M16.2524575,23.3946956 L16.9529792,20.1753736 L14.3913553,17.8632247 C14.2512509,17.7370352 14.1956067,17.5432797 14.2462827,17.3614476 C14.2959651,17.1806092 14.4450122,17.0434899 14.6288371,17.006726 L18.0211505,16.3469637 L19.5553426,13.2717163 C19.6398027,13.1028012 19.8405195,12.965682 20.0024841,12.9964841 C20.1912772,12.9974777 20.3641719,13.1057821 20.4466447,13.2756908 L21.9460591,16.3439829 L25.3373789,16.9997707 C25.5212037,17.0345473 25.6702509,17.170673 25.7209269,17.3525051 C25.771603,17.5323499 25.7169523,17.7261054 25.5788353,17.8532885 L23.0450335,20.1704055 L23.7246886,23.3927084 C23.7654282,23.5864639 23.68693,23.7871747 23.5249654,23.9014407 C23.3600199,24.0167004 23.1473793,24.0216685 22.9774655,23.9183323 L19.9995032,22.08312 L16.9976933,23.9233003 C16.9172078,23.9729812 16.8277796,23.9968281 16.7373576,23.9968281 C16.6369992,23.9968281 16.5356471,23.9660259 16.4501934,23.9054152 C16.2872352,23.7901555 16.2097307,23.5884511 16.2524575,23.3946956 L16.2524575,23.3946956 Z M32.9785301,10.0951198 L32.9755492,7.99361792 L6.99364775,7.99361792 L6.99364775,10.0951198 L32.9785301,10.0951198 Z M34,32.5021974 C34,32.6343486 33.9483303,32.7605381 33.8549274,32.8539382 C33.7615245,32.9473383 33.6353313,33 33.5031761,33 L29.9369743,33 L29.9369743,32.0063821 L33.0063522,32.0063821 L32.9795238,11.0887377 L6.99364775,11.0887377 L6.99364775,32.0063821 L25.9623833,32.0063821 L25.9623833,33 L6.49682388,33 C6.36466872,33 6.23847546,32.9473383 6.14507257,32.8549318 C6.05266333,32.7615317 6,32.6353422 6,32.503191 L6,7.49680896 C6,7.22257041 6.22158345,7 6.49682388,7 L33.4713794,7 C33.7466198,7 33.9682033,7.22257041 33.9682033,7.49680896 L34,32.5021974 Z M11.0576671,29.9754271 L15.0322581,29.9754271 L15.0322581,28.9818091 L11.0576671,28.9818091 L11.0576671,29.9754271 Z M17.0195536,29.9982803 L23.9750878,29.9982803 L23.9750878,29.0046624 L17.0195536,29.0046624 L17.0195536,29.9982803 Z M11.0576671,26.9985478 L15.0322581,26.9985478 L15.0322581,26.0049299 L11.0576671,26.0049299 L11.0576671,26.9985478 Z M17.0195536,26.9985478 L27.9496788,26.9985478 L27.9496788,26.0049299 L17.0195536,26.0049299 L17.0195536,26.9985478 Z"
|
||||
id="AWS-Certificate-Manager_Icon_32_Squid"
|
||||
fill="#FFFFFF"
|
||||
/>
|
||||
</g>
|
||||
</svg>
|
||||
);
|
||||
|
||||
export const AWSAthenaIcon: React.FC<IconSvgProps> = ({
|
||||
size = 32,
|
||||
width,
|
||||
height,
|
||||
className = "rounded-md",
|
||||
...props
|
||||
}) => (
|
||||
<svg
|
||||
aria-hidden="false"
|
||||
aria-label="Amazon Athena logo"
|
||||
fill="none"
|
||||
focusable="false"
|
||||
height={size || height}
|
||||
role="presentation"
|
||||
viewBox="0 0 40 40"
|
||||
width={size || width}
|
||||
className={className}
|
||||
{...props}
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
>
|
||||
<g fill="none" fillRule="evenodd">
|
||||
<path fill="#8C4FFF" d="M0 0h40v40H0z" />
|
||||
<path
|
||||
fill="#FFF"
|
||||
d="M18.726 14.285c1.8 0 2.982.285 3.42.5-.438.214-1.62.498-3.42.498-1.8 0-2.982-.284-3.42-.499.438-.214 1.62-.499 3.42-.499Zm.014 3.198c-.088-.027-.164-.079-.164-.181 0-.14.114-.253.256-.253.042 0 .072.026.107.043l-.199.391Zm2.939 4.156a1.203 1.203 0 0 1-.303.156 4.024 4.024 0 0 1-.566.166 9.261 9.261 0 0 1-1.978.202c-1.542 0-2.616-.322-2.846-.522l-.688-5.794c1.187.401 2.937.433 3.428.433.496 0 2.275-.033 3.464-.445l-.202 2.298a34.447 34.447 0 0 1-2.44-1.048.754.754 0 0 0-1.475.216.753.753 0 0 0 1.041.69c1.178.56 2.09.944 2.781 1.186l-.216 2.462Zm-7.525-6.797.822 6.891c0 1.411 3.698 1.427 3.856 1.427.78 0 1.564-.08 2.206-.226.269-.061.507-.133.71-.212.624-.241.94-.574.938-.946l.204-2.305c.299.068.534.098.715.098.478 0 .604-.189.69-.319l.077-.476c-.122-.492-1-1.187-1.297-1.404l.224-2.543-.005-.001c.001-.014.007-.027.007-.042 0-1.424-3.811-1.496-4.575-1.496-.764 0-4.575.072-4.575 1.496 0 .02.008.037.01.057h-.007Zm4.591-5.448c4.765 0 8.643 3.803 8.643 8.478s-3.878 8.478-8.643 8.478c-4.765 0-8.642-3.803-8.642-8.478s3.877-8.478 8.642-8.478ZM6.017 21.267v.998h4.177a9.69 9.69 0 0 0 8.551 5.082c5.326 0 9.66-4.25 9.66-9.475 0-5.224-4.334-9.475-9.66-9.475-4.41 0-8.132 2.917-9.283 6.886H6.017v.997h3.217a9.236 9.236 0 0 0-.148 1.592c0 .136.015.268.02.403H5v.997h4.203c.105.693.285 1.36.535 1.995H6.017Zm27.486 11.265c-.614.603-1.68.608-2.295.005l-5.253-5.152a12.068 12.068 0 0 0 2.34-2.246l5.214 5.142a1.566 1.566 0 0 1-.006 2.25Zm.726-2.955-5.334-5.26a11.64 11.64 0 0 0 1.953-6.445C30.848 11.326 25.418 6 18.745 6 13.95 6 9.6 8.782 7.665 13.087l.93.402c1.773-3.943 5.757-6.492 10.15-6.492 6.112 0 11.086 4.879 11.086 10.875s-4.974 10.876-11.086 10.876c-3.732 0-7.192-1.827-9.254-4.885l-.848.551c2.251 3.338 6.027 5.331 10.102 5.331 2.333 0 4.506-.662 6.356-1.788l5.388 5.286c.498.488 1.159.757 1.86.757a2.66 2.66 0 0 0 1.872-.761 2.55 2.55 0 0 0 .008-3.662Z"
|
||||
/>
|
||||
</g>
|
||||
</svg>
|
||||
);
|
||||
|
||||
export const AWSLambdaIcon: React.FC<IconSvgProps> = ({
|
||||
size = 32,
|
||||
width,
|
||||
height,
|
||||
className = "rounded-md",
|
||||
...props
|
||||
}) => (
|
||||
<svg
|
||||
aria-hidden="false"
|
||||
aria-label="AWS Lambda logo"
|
||||
fill="none"
|
||||
focusable="false"
|
||||
height={size || height}
|
||||
role="presentation"
|
||||
viewBox="0 0 40 40"
|
||||
width={size || width}
|
||||
className={className}
|
||||
{...props}
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
>
|
||||
<g fill="none" fillRule="evenodd">
|
||||
<path fill="#ED7100" d="M0 0h40v40H0z" />
|
||||
<path
|
||||
fill="#FFF"
|
||||
d="M14.386 33H8.27l6.763-14.426 3.064 6.44L14.387 33Zm1.085-15.798a.49.49 0 0 0-.442-.282h-.002a.493.493 0 0 0-.441.285l-7.538 16.08a.507.507 0 0 0 .028.482c.09.145.247.233.415.233h7.206c.19 0 .363-.111.445-.286l3.944-8.489a.508.508 0 0 0-.002-.432l-3.613-7.591ZM32.018 33h-5.882l-9.47-20.711a.491.491 0 0 0-.444-.289H12.37l.005-5h7.549l9.424 20.71c.08.177.256.29.446.29h2.224v5Zm.49-6h-2.4L20.684 6.29a.492.492 0 0 0-.446-.29h-8.353a.496.496 0 0 0-.491.5l-.006 6c0 .132.052.259.144.354a.488.488 0 0 0 .347.146h4.032l9.468 20.711c.08.176.254.289.445.289h6.686a.495.495 0 0 0 .491-.5v-6c0-.276-.219-.5-.491-.5Z"
|
||||
/>
|
||||
</g>
|
||||
</svg>
|
||||
);
|
||||
|
||||
export const AWSCloudFormationIcon: React.FC<IconSvgProps> = ({
|
||||
size = 32,
|
||||
width,
|
||||
height,
|
||||
className = "rounded-md",
|
||||
...props
|
||||
}) => (
|
||||
<svg
|
||||
aria-hidden="false"
|
||||
aria-label="AWS CloudFormation logo"
|
||||
fill="none"
|
||||
focusable="false"
|
||||
height={size || height}
|
||||
role="presentation"
|
||||
viewBox="0 0 40 40"
|
||||
width={size || width}
|
||||
className={className}
|
||||
{...props}
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
>
|
||||
<g fill="none" fillRule="evenodd">
|
||||
<path fill="#E7157B" d="M0 0h40v40H0z" />
|
||||
<path
|
||||
fill="#FFF"
|
||||
d="M27 19.982h3V18.98h-3v1.002Zm-13 6.009h3v-1.002h-3v1.002Zm-5 0h3v-1.002H9v1.002Zm0-3.005h6v-1.001H9v1.001Zm0-6.009h5v-1.001H9v1.001Zm0 3.005h16V18.98H9v1.002Zm9.968 11.016H7V13.973h11.968v3.021h1v-3.522a.5.5 0 0 0-.5-.5H6.5a.5.5 0 0 0-.5.5V31.5a.5.5 0 0 0 .5.501h12.968a.5.5 0 0 0 .5-.5v-9.498h-1v8.996ZM34 18.48c0 4.455-3.96 4.506-4 4.506h-8v-1.001h8c.305-.003 3-.122 3-3.505 0-2.848-2.569-3.425-3.083-3.513a.5.5 0 0 1-.415-.535l.003-.03c-.029-1.607-1.015-2.11-1.442-2.25-.799-.268-1.687-.012-2.158.618a.5.5 0 0 1-.871-.131c-.311-.87-.762-1.434-1.388-2.062-1.569-1.559-3.691-1.987-5.683-1.15-1.044.44-1.956 1.438-2.502 2.737l-.922-.388c.646-1.539 1.753-2.731 3.036-3.272 2.379-1.002 4.911-.491 6.777 1.364.534.536.978 1.057 1.323 1.734.749-.552 1.752-.717 2.704-.402 1.216.405 1.985 1.461 2.109 2.865C32.19 14.495 34 15.857 34 18.48Z"
|
||||
/>
|
||||
</g>
|
||||
</svg>
|
||||
);
|
||||
|
||||
export const AWSCloudTrailIcon: React.FC<IconSvgProps> = ({
|
||||
size = 32,
|
||||
width,
|
||||
height,
|
||||
className = "rounded-md",
|
||||
...props
|
||||
}) => (
|
||||
<svg
|
||||
aria-hidden="false"
|
||||
aria-label="AWS CloudTrail logo"
|
||||
fill="none"
|
||||
focusable="false"
|
||||
height={size || height}
|
||||
role="presentation"
|
||||
viewBox="0 0 40 40"
|
||||
width={size || width}
|
||||
className={className}
|
||||
{...props}
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
>
|
||||
<g fill="none" fillRule="evenodd">
|
||||
<path fill="#E7157B" d="M0 0h40v40H0z" />
|
||||
<path
|
||||
fill="#FFF"
|
||||
d="M14.027 24.131h4.013v-.97h-4.013v.97Zm15.959-5.31c-.11-1.476-.846-2.56-2.017-2.938-.927-.302-1.958-.084-2.746.536a10.025 10.025 0 0 0-1.813-2.395c-2.006-1.915-4.56-2.507-7.01-1.622-2.257.815-4.881 3.57-4.881 5.9v.029c-1.474.368-2.505 2.275-2.505 3.316h1.003c0-.752.969-2.408 2.003-2.408a.493.493 0 0 0 .502-.485v-.452c0-1.866 2.326-4.303 4.23-4.99 2.827-1.022 4.944.44 5.953 1.403.651.62 1.52 1.738 1.886 2.725.064.168.216.289.399.316a.517.517 0 0 0 .474-.188c.548-.704 1.424-1.01 2.187-.765.856.277 1.346 1.157 1.346 2.414 0 .238.178.44.42.478 1.238.2 3.58 1.28 3.58 3.95 0 3.321-3.357 3.383-3.498 3.384H18.04V28H29.5c1.557-.003 4.5-.916 4.5-4.354 0-3.047-2.432-4.427-4.014-4.824Zm-13.952 7.245h7.023v-.971h-7.023v.97ZM13.024 28h3.01v-.97h-3.01V28Zm-1.004-1.934h2.007v-.971H12.02v.97ZM7.003 24.13h5.017v-.97H7.003v.97ZM6 26.066h5.017v-.971H6v.97ZM8.007 28h3.01v-.97h-3.01V28Z"
|
||||
/>
|
||||
</g>
|
||||
</svg>
|
||||
);
|
||||
|
||||
export const AWSCloudWatchIcon: React.FC<IconSvgProps> = ({
|
||||
size = 32,
|
||||
width,
|
||||
height,
|
||||
className = "rounded-md",
|
||||
...props
|
||||
}) => (
|
||||
<svg
|
||||
aria-hidden="false"
|
||||
aria-label="AWS CloudWatch logo"
|
||||
fill="none"
|
||||
focusable="false"
|
||||
height={size || height}
|
||||
role="presentation"
|
||||
viewBox="0 0 40 40"
|
||||
width={size || width}
|
||||
className={className}
|
||||
{...props}
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
>
|
||||
<g fill="none" fillRule="evenodd">
|
||||
<path fill="#E7157B" d="M0 0h40v40H0z" />
|
||||
<path
|
||||
fill="#FFF"
|
||||
d="M27.63 24.124c0-1.903-1.58-3.452-3.522-3.452-1.943 0-3.523 1.549-3.523 3.452 0 1.904 1.58 3.452 3.523 3.452 1.942 0 3.522-1.548 3.522-3.452Zm1.006 0c0 2.447-2.032 4.439-4.528 4.439-2.497 0-4.53-1.992-4.53-4.439s2.033-4.438 4.53-4.438c2.496 0 4.528 1.991 4.528 4.438Zm4.276 6.579-3.387-2.99c-.289.418-.63.793-1.008 1.133l3.367 2.976a.781.781 0 0 0 1.085-.056.745.745 0 0 0-.057-1.063Zm-8.804-1.154c3.051 0 5.535-2.433 5.535-5.425 0-2.991-2.484-5.424-5.535-5.424-3.052 0-5.536 2.433-5.536 5.424 0 2.992 2.484 5.425 5.536 5.425Zm9.478.422a1.72 1.72 0 0 1 .13 2.455 1.79 1.79 0 0 1-1.32.574c-.423 0-.847-.147-1.185-.445l-3.494-3.089a6.592 6.592 0 0 1-3.61 1.07c-3.606 0-6.541-2.877-6.541-6.412s2.935-6.41 6.542-6.41c3.607 0 6.541 2.875 6.541 6.41 0 .968-.226 1.883-.62 2.707l3.557 3.14Zm-22.994-5.354h4.96v.987h-4.966c-.557-.006-1.156-.206-1.786-.596-1.044-.634-2.8-2.127-2.8-4.973 0-3.442 2.41-4.706 3.812-5.15a7.265 7.265 0 0 1-.016-.492c0-2.804 1.942-5.714 4.515-6.765 3.013-1.237 6.203-.623 8.531 1.638a8.456 8.456 0 0 1 1.786 2.563 3.404 3.404 0 0 1 2.177-.787c1.56 0 3.319 1.165 3.626 3.713C31.887 15.08 35 16.23 35 20.075c0 1.653-.567 2.99-1.687 3.972l-.672-.733c.898-.788 1.353-1.878 1.353-3.238 0-3.382-2.888-4.223-4.13-4.427a.5.5 0 0 1-.33-.207.486.486 0 0 1-.08-.378c-.147-2.074-1.438-3.036-2.65-3.036-.756 0-1.466.361-1.947.99a.513.513 0 0 1-.477.194.5.5 0 0 1-.398-.32c-.433-1.172-1.054-2.156-1.847-2.925-2.032-1.973-4.812-2.508-7.437-1.43-2.184.894-3.895 3.465-3.895 5.856 0 .268.016.536.048.794a.486.486 0 0 1-.122.387.51.51 0 0 1-.29.16c-1.297.327-3.433 1.32-3.433 4.301 0 2.25 1.266 3.492 2.327 4.138.473.292.896.44 1.26.444Z"
|
||||
/>
|
||||
</g>
|
||||
</svg>
|
||||
);
|
||||
|
||||
export const AWSConfigIcon: React.FC<IconSvgProps> = ({
|
||||
size = 32,
|
||||
width,
|
||||
height,
|
||||
className = "rounded-md",
|
||||
...props
|
||||
}) => (
|
||||
<svg
|
||||
aria-hidden="false"
|
||||
aria-label="AWS Config logo"
|
||||
fill="none"
|
||||
focusable="false"
|
||||
height={size || height}
|
||||
role="presentation"
|
||||
viewBox="0 0 40 40"
|
||||
width={size || width}
|
||||
className={className}
|
||||
{...props}
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
>
|
||||
<g fill="none" fillRule="evenodd">
|
||||
<path fill="#E7157B" d="M0 0h40v40H0z" />
|
||||
<path
|
||||
fill="#FFF"
|
||||
d="m29.765 24.019.945.333-.592 1.68a.502.502 0 0 1-.526.332l-1.915-.205.105-.996.908.096a2.472 2.472 0 0 0-2.005-1.042 2.48 2.48 0 0 0-2.421 1.978l-.983-.2a3.487 3.487 0 0 1 3.404-2.78c1.157 0 2.2.587 2.838 1.492l.242-.688Zm-.657 3.165.982.2a3.488 3.488 0 0 1-3.405 2.78 3.474 3.474 0 0 1-2.718-1.331l-.12.544-.979-.217.395-1.777a.503.503 0 0 1 .562-.387l1.808.27-.147.99-.79-.117a2.474 2.474 0 0 0 1.99 1.024 2.48 2.48 0 0 0 2.422-1.979Zm3.89.36-.594-.035a.487.487 0 0 0-.517.39 5.286 5.286 0 0 1-.682 1.65.502.502 0 0 0 .089.64l.444.396-1.153 1.153-.394-.442a.502.502 0 0 0-.641-.09 5.25 5.25 0 0 1-1.65.684.5.5 0 0 0-.39.518l.033.59h-1.63l.034-.59a.5.5 0 0 0-.389-.519 5.198 5.198 0 0 1-1.65-.684.503.503 0 0 0-.64.09l-.396.443-1.153-1.152.443-.395a.5.5 0 0 0 .09-.642 5.272 5.272 0 0 1-.683-1.65.49.49 0 0 0-.516-.39l-.594.034v-1.63l.596.033a.483.483 0 0 0 .516-.39 5.27 5.27 0 0 1 .685-1.646.501.501 0 0 0-.09-.642l-.447-.398 1.153-1.152.398.445a.5.5 0 0 0 .64.09 5.26 5.26 0 0 1 1.648-.682.5.5 0 0 0 .389-.517l-.034-.597h1.63l-.033.597a.501.501 0 0 0 .39.518c.585.132 1.138.361 1.645.682a.5.5 0 0 0 .64-.09l.4-.447 1.153 1.153-.446.397a.502.502 0 0 0-.09.642c.322.508.552 1.063.684 1.647.054.238.254.415.517.39l.595-.033v1.63Zm.845-2.526a.53.53 0 0 0-.373-.137l-.715.042a6.254 6.254 0 0 0-.49-1.181l.535-.477a.499.499 0 0 0 .02-.729l-1.902-1.903a.602.602 0 0 0-.368-.146.496.496 0 0 0-.36.167l-.48.538a6.197 6.197 0 0 0-1.176-.49l.04-.718a.5.5 0 0 0-.5-.53h-2.691a.493.493 0 0 0-.364.158.498.498 0 0 0-.136.373l.04.717a6.215 6.215 0 0 0-1.178.489l-.478-.537a.498.498 0 0 0-.36-.167.553.553 0 0 0-.369.146l-1.902 1.903a.501.501 0 0 0 .02.729l.536.479c-.203.376-.367.77-.49 1.179l-.715-.042a.537.537 0 0 0-.373.137.503.503 0 0 0-.156.364v2.691c0 .139.057.27.156.365a.49.49 0 0 0 .373.135l.713-.04c.122.411.285.806.489 1.183l-.533.475a.502.502 0 0 0-.02.727l1.902 1.904a.502.502 0 0 0 .728-.021l.476-.533c.376.205.772.37 1.182.491l-.041.712a.5.5 0 0 0 .5.529h2.69a.501.501 0 0 0 .5-.53l-.04-.71c.41-.123.805-.286 1.183-.49l.475.531a.5.5 0 0 0 .36.168.56.56 0 0 0 .367-.147l1.903-1.904a.5.5 0 0 0-.021-.727l-.533-.477c.203-.377.366-.772.489-1.18l.714.04a.503.503 0 0 0 .53-.5v-2.692a.5.5 0 0 0-.157-.364ZM8.002 27.973h9.049v1.002h-9.55a.501.501 0 0 1-.501-.5V6.5C7 6.224 7.224 6 7.5 6h23.108c.276 0 .5.224.5.501v11.484h-1.001V7.002H8.002v20.971Zm16.547-12.995h-.494V12.97H27.101v2.008h-2.552Zm.501-3.01h.986V9.988h-.986v1.982Zm1.988 6.017V15.98h.564c.276 0 .5-.224.5-.5v-3.011a.501.501 0 0 0-.5-.501h-.564V9.485a.5.5 0 0 0-.501-.5h-1.988a.5.5 0 0 0-.5.5v2.483h-.495a.5.5 0 0 0-.5.5v3.011a.5.5 0 0 0 .5.501h.494v2.005h1.002V15.98h.986v2.005h1.002Zm-9.518.955h-.57v-1.91h3.106v1.91H17.52Zm.5-2.913h1.034v-6.04H18.02v6.04Zm2.037 5.903v-1.988h.5c.277 0 .502-.225.502-.501v-2.912a.501.501 0 0 0-.501-.502h-.501V9.485a.5.5 0 0 0-.501-.5H17.52a.5.5 0 0 0-.501.5v6.542h-.57c-.276 0-.5.225-.5.502v2.912c0 .276.224.5.5.5h.57v5.955h1.002v-5.954h1.034v1.988h1.002Zm-9.071-8.878h.986V9.987h-.986v3.065Zm0 11.979h.986v-8.083h-.986v8.083Zm-.994-10.977H12.966v1.891H9.992v-1.89Zm.493 11.979h1.988a.5.5 0 0 0 .501-.501v-8.585h.493a.5.5 0 0 0 .501-.5v-2.894a.5.5 0 0 0-.5-.5h-.494V9.484a.5.5 0 0 0-.5-.5h-1.99a.5.5 0 0 0-.5.5v3.567H9.49a.5.5 0 0 0-.501.501v2.893a.5.5 0 0 0 .5.501h.494v8.585a.5.5 0 0 0 .5.5Z"
|
||||
/>
|
||||
</g>
|
||||
</svg>
|
||||
);
|
||||
|
||||
export const AWSDatabaseMigrationServiceIcon: React.FC<IconSvgProps> = ({
|
||||
size = 32,
|
||||
width,
|
||||
height,
|
||||
className = "rounded-md",
|
||||
...props
|
||||
}) => (
|
||||
<svg
|
||||
aria-hidden="false"
|
||||
aria-label="AWS Database Migration Service logo"
|
||||
fill="none"
|
||||
focusable="false"
|
||||
height={size || height}
|
||||
role="presentation"
|
||||
viewBox="0 0 40 40"
|
||||
width={size || width}
|
||||
className={className}
|
||||
{...props}
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
>
|
||||
<g fill="none" fillRule="evenodd">
|
||||
<path fill="#C925D1" d="M0 0h40v40H0z" />
|
||||
<path
|
||||
fill="#FFF"
|
||||
d="M22.024 33h1v-2.997h-1V33Zm-5.019 0h1v-2.997h-1V33ZM26 32.001h1v-2.996h-1V32Zm-13 0h1v-2.996h-1V32Zm7.018-14.96c-3.717 0-6.018-.958-6.018-1.847v-3.548c1.173.885 3.304 1.418 6.018 1.418 2.604 0 4.782-.583 5.982-1.49v3.62c0 .908-2.238 1.847-5.982 1.847Zm0 5.019c-3.547 0-6.018-1.084-6.018-2.057V16.8c1.34.892 3.805 1.24 6.018 1.24 2.725 0 4.825-.462 5.982-1.25v3.213c0 .973-2.456 2.057-5.982 2.057Zm0 5.006c-3.491 0-6.018-1.503-6.018-2.516v-2.9c1.294.928 3.664 1.408 6.018 1.408 2.635 0 4.793-.547 5.982-1.416v2.908c0 1-2.386 2.516-5.982 2.516Zm0-19.067c3.695 0 5.982.989 5.982 1.905 0 .903-2.276 2.161-5.982 2.161-3.43 0-6.018-.929-6.018-2.161 0-.778 2.143-1.905 6.018-1.905Zm0-.999C16.638 7 13 7.909 13 9.904V24.55c0 1.873 3.279 3.515 7.018 3.515 3.719 0 6.982-1.642 6.982-3.515V9.904C27 7.898 23.493 7 20.018 7Z"
|
||||
/>
|
||||
</g>
|
||||
</svg>
|
||||
);
|
||||
|
||||
export const AmazonEC2Icon: React.FC<IconSvgProps> = ({
|
||||
size = 32,
|
||||
width,
|
||||
height,
|
||||
className = "rounded-md",
|
||||
...props
|
||||
}) => (
|
||||
<svg
|
||||
aria-hidden="false"
|
||||
aria-label="Amazon EC2 logo"
|
||||
fill="none"
|
||||
focusable="false"
|
||||
height={size || height}
|
||||
role="presentation"
|
||||
viewBox="0 0 40 40"
|
||||
width={size || width}
|
||||
className={className}
|
||||
{...props}
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
>
|
||||
<g fill="none" fillRule="evenodd">
|
||||
<path fill="#ED7100" d="M0 0h40v40H0z" />
|
||||
<path
|
||||
fill="#FFF"
|
||||
d="M26.052 27 26 13.948 13 14v13.052L26.052 27ZM27 14h2v1h-2v2h2v1h-2v2h2v1h-2v2h2v1h-2v2h2v1h-2v.052a.95.95 0 0 1-.948.948H26v2h-1v-2h-2v2h-1v-2h-2v2h-1v-2h-2v2h-1v-2h-2v2h-1v-2h-.052a.95.95 0 0 1-.948-.948V27h-2v-1h2v-2h-2v-1h2v-2h-2v-1h2v-2h-2v-1h2v-2h-2v-1h2v-.052a.95.95 0 0 1 .948-.948H13v-2h1v2h2v-2h1v2h2v-2h1v2h2v-2h1v2h2v-2h1v2h.052a.95.95 0 0 1 .948.948V14Zm-6 19H7V19h2v-1H7.062C6.477 18 6 18.477 6 19.062v13.876C6 33.523 6.477 34 7.062 34h13.877c.585 0 1.061-.477 1.061-1.062V31h-1v2ZM34 7.062v13.876c0 .585-.476 1.062-1.061 1.062H30v-1h3V7H19v3h-1V7.062C18 6.477 18.477 6 19.062 6h13.877C33.524 6 34 6.477 34 7.062Z"
|
||||
/>
|
||||
</g>
|
||||
</svg>
|
||||
);
|
||||
|
||||
export const AmazonEMRIcon: React.FC<IconSvgProps> = ({
|
||||
size = 32,
|
||||
width,
|
||||
height,
|
||||
className = "rounded-md",
|
||||
...props
|
||||
}) => (
|
||||
<svg
|
||||
aria-hidden="false"
|
||||
aria-label="Amazon EMR logo"
|
||||
fill="none"
|
||||
focusable="false"
|
||||
height={size || height}
|
||||
role="presentation"
|
||||
viewBox="0 0 40 40"
|
||||
width={size || width}
|
||||
className={className}
|
||||
{...props}
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
>
|
||||
<g fill="none" fillRule="evenodd">
|
||||
<path fill="#8C4FFF" d="M0 0h40v40H0z" />
|
||||
<path
|
||||
fill="#FFF"
|
||||
d="M32.011 25.364a2.01 2.01 0 0 0-.584-1.423 1.984 1.984 0 0 0-2.82 0 2.025 2.025 0 0 0 0 2.844c.753.76 2.067.761 2.82 0 .376-.38.584-.884.584-1.421Zm-4.777-1.07c.14-.372.353-.722.646-1.026l-1.058-2.03-1.316 2.507 1.728.55Zm-3.159.043-6.866-2.189a5.531 5.531 0 0 1-1.405 1.654l3.386 4.737a2.949 2.949 0 0 1 2.832-.29l2.053-3.912Zm-1.226 6.668a1.993 1.993 0 0 0-1.981-1.996c-.508 0-1.015.194-1.401.584-.374.378-.58.879-.58 1.412 0 .534.206 1.035.58 1.413.772.778 2.03.778 2.801 0 .375-.378.58-.88.58-1.413Zm-10.401-7.027c2.458 0 4.457-2.015 4.457-4.495 0-2.478-2-4.495-4.457-4.495-2.458 0-4.457 2.017-4.457 4.495 0 2.48 2 4.495 4.457 4.495Zm6.439-14.983c0 .534.206 1.035.58 1.413.772.779 2.03.779 2.801 0 .375-.378.58-.88.58-1.413a1.993 1.993 0 0 0-1.98-1.997 1.993 1.993 0 0 0-1.981 1.997Zm3.016 2.801a2.981 2.981 0 0 1-1.035.195 2.947 2.947 0 0 1-1.563-.455l-2.974 4.1a5.511 5.511 0 0 1 1.321 2.222l6.374-1.985-2.123-4.077Zm-4.007 7.687c0 .612-.103 1.197-.286 1.746l6.936 2.21 1.717-3.272-1.768-3.395-6.64 2.068c.024.212.041.426.041.643Zm7.562-3.01 1.368 2.625 1.292-2.463c-.07-.06-.145-.108-.212-.175a2.985 2.985 0 0 1-.453-.609l-1.995.622Zm3.149-.72c.753.76 2.067.762 2.82 0 .376-.379.584-.883.584-1.42a2.01 2.01 0 0 0-.584-1.423 1.984 1.984 0 0 0-2.82 0 2.025 2.025 0 0 0 0 2.844Zm3.52 7.482a3.03 3.03 0 0 1 0 4.256 2.957 2.957 0 0 1-2.11.88 2.96 2.96 0 0 1-2.11-.88 3.01 3.01 0 0 1-.865-2.21l-2.007-.638-2.18 4.15c.037.034.079.058.114.094.56.565.87 1.318.87 2.118 0 .8-.31 1.554-.87 2.119-.58.584-1.34.876-2.101.876a2.947 2.947 0 0 1-2.101-.876 2.987 2.987 0 0 1-.871-2.119c0-.643.208-1.25.577-1.76l-3.5-4.898c-.756.4-1.614.63-2.525.63C9.445 24.977 7 22.513 7 19.483c0-3.028 2.445-5.493 5.448-5.493 1.163 0 2.24.372 3.125 1l2.992-4.124a2.98 2.98 0 0 1-.669-1.87c0-.801.309-1.553.87-2.12a2.956 2.956 0 0 1 4.203 0c.56.567.87 1.319.87 2.12a2.99 2.99 0 0 1-.87 2.118c-.066.067-.142.117-.213.176l2.232 4.284 2.103-.656a3.028 3.028 0 0 1 .815-2.714 2.97 2.97 0 0 1 4.221 0 3.03 3.03 0 0 1 0 4.256 2.957 2.957 0 0 1-2.11.88c-.355 0-.709-.07-1.046-.196l-1.588 3.025 1.309 2.513a2.96 2.96 0 0 1 3.435.553Zm-19.184-4.251h1.981v.999h-1.98v1.998h-.991v-1.998H9.972v-1h1.98v-1.997h.991v1.998Z"
|
||||
/>
|
||||
</g>
|
||||
</svg>
|
||||
);
|
||||
|
||||
export const AWSGlueIcon: React.FC<IconSvgProps> = ({
|
||||
size = 32,
|
||||
width,
|
||||
height,
|
||||
className = "rounded-md",
|
||||
...props
|
||||
}) => (
|
||||
<svg
|
||||
aria-hidden="false"
|
||||
aria-label="AWS Glue logo"
|
||||
fill="none"
|
||||
focusable="false"
|
||||
height={size || height}
|
||||
role="presentation"
|
||||
viewBox="0 0 40 40"
|
||||
width={size || width}
|
||||
className={className}
|
||||
{...props}
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
>
|
||||
<g fill="none" fillRule="evenodd">
|
||||
<rect width="40" height="40" fill="#8C4FFF" />
|
||||
<path
|
||||
fill="#FFF"
|
||||
d="M27.163 15.543c-1.839.412-4.673.495-6.663.495-1.977 0-4.785-.082-6.625-.486l5.539 8.197a.504.504 0 0 1 .086.281v1.068c.701.202 1.349.205 2 .007V24.03c0-.1.03-.2.087-.282l5.576-8.205Zm1.69-.771.03.02-6.383 9.392v1.276a.5.5 0 0 1-.314.464 4.382 4.382 0 0 1-1.653.329 4.909 4.909 0 0 1-1.706-.324.501.501 0 0 1-.327-.47v-1.275l-6.395-9.465A.572.572 0 0 1 12 14.41c0-1.425 4.692-1.689 7.488-1.72l.012 1.002c-3.343.036-5.421.41-6.212.7.943.309 3.533.644 7.212.644 3.45 0 5.943-.295 7.017-.587-.5-.133-1.416-.315-3.078-.519l.121-.994c4.122.503 4.44.928 4.44 1.474 0 .131-.06.25-.147.362ZM16.5 11.008h1v-1.001h-1v1.001Zm-1 .501V9.506a.5.5 0 0 1 .5-.501h2a.5.5 0 0 1 .5.5v2.004a.5.5 0 0 1-.5.501h-2a.5.5 0 0 1-.5-.5Zm5-3.506h1V7.002h-1v1.001Zm-1 .501V6.501A.5.5 0 0 1 20 6h2a.5.5 0 0 1 .5.5v2.004a.5.5 0 0 1-.5.501h-2a.5.5 0 0 1-.5-.5Zm2 4.508h1V12.01h-1v1.002Zm-.5-2.004h2a.5.5 0 0 1 .5.501v2.004a.5.5 0 0 1-.5.5h-2a.5.5 0 0 1-.5-.5v-2.004a.5.5 0 0 1 .5-.5Zm3.424 18.325a.5.5 0 0 1-.079.536l-3.469 3.96a.5.5 0 0 1-.752 0l-3.469-3.96a.5.5 0 0 1 .376-.83h1.453v-1.002h1v1.503a.5.5 0 0 1-.5.5h-.849L20.5 32.74l2.365-2.699H22a.5.5 0 0 1-.5-.5v-1.503h1v1.002h1.469c.196 0 .374.114.455.294Z"
|
||||
/>
|
||||
</g>
|
||||
</svg>
|
||||
);
|
||||
|
||||
export const AmazonGuardDutyIcon: React.FC<IconSvgProps> = ({
|
||||
size = 32,
|
||||
width,
|
||||
height,
|
||||
className = "rounded-md",
|
||||
...props
|
||||
}) => (
|
||||
<svg
|
||||
aria-hidden="false"
|
||||
aria-label="Amazon GuardDuty logo"
|
||||
fill="none"
|
||||
focusable="false"
|
||||
height={size || height}
|
||||
role="presentation"
|
||||
viewBox="0 0 40 40"
|
||||
width={size || width}
|
||||
className={className}
|
||||
{...props}
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
>
|
||||
<g fill="none" fillRule="evenodd">
|
||||
<rect width="40" height="40" fill="#DD344C" />
|
||||
<path
|
||||
fill="#FFF"
|
||||
d="M25 21.814c-.001.19-.074 4.475-4 4.818V14.594l4 1.734v5.486Zm-9-.015v-5.471l4-1.734v12.038c-3.927-.344-3.999-4.643-4-4.833Zm9.699-6.258-5-2.167a.5.5 0 0 0-.398 0l-5 2.167A.499.499 0 0 0 15 16v5.799c0 .059.062 5.867 5.5 5.867 5.437 0 5.5-5.792 5.5-5.851V16c0-.2-.118-.38-.301-.459ZM34 22.752l-1.794-.102a.479.479 0 0 0-.516.389 11.379 11.379 0 0 1-1.482 3.577.498.498 0 0 0 .09.64l1.342 1.197-3.188 3.185-1.191-1.336a.501.501 0 0 0-.64-.09 11.361 11.361 0 0 1-3.582 1.483.502.502 0 0 0-.389.517L22.753 34h-4.506l.103-1.789a.503.503 0 0 0-.389-.517 11.348 11.348 0 0 1-3.578-1.484.505.505 0 0 0-.641.089l-1.194 1.339-3.188-3.186 1.339-1.194a.497.497 0 0 0 .09-.639A11.351 11.351 0 0 1 9.31 23.04c-.054-.238-.245-.394-.517-.39L7 22.752v-4.506l1.797.103a.482.482 0 0 0 .515-.389 11.411 11.411 0 0 1 1.485-3.572.498.498 0 0 0-.09-.64L9.36 12.547l3.188-3.187 1.199 1.345c.162.181.434.22.64.09a11.405 11.405 0 0 1 3.574-1.479.5.5 0 0 0 .389-.516L18.247 7h4.506l-.103 1.802a.502.502 0 0 0 .389.516c1.268.287 2.47.784 3.571 1.48a.5.5 0 0 0 .64-.09l1.202-1.348 3.188 3.187-1.344 1.198a.499.499 0 0 0-.09.64 11.42 11.42 0 0 1 1.482 3.575.489.489 0 0 0 .516.389L34 18.246v4.506Zm.844-5.398a.516.516 0 0 0-.372-.136l-1.909.109a12.42 12.42 0 0 0-1.291-3.113L32.7 12.94a.497.497 0 0 0 .021-.726l-3.936-3.935a.497.497 0 0 0-.726.021l-1.278 1.431a12.348 12.348 0 0 0-3.109-1.288l.109-1.915A.501.501 0 0 0 23.282 6h-5.564a.5.5 0 0 0-.499.528l.109 1.913a12.376 12.376 0 0 0-3.111 1.288L12.941 8.3a.497.497 0 0 0-.358-.167.59.59 0 0 0-.368.146l-3.936 3.935a.5.5 0 0 0 .021.726l1.43 1.276a12.394 12.394 0 0 0-1.292 3.111l-1.91-.109a.544.544 0 0 0-.372.136.5.5 0 0 0-.156.363v5.565a.502.502 0 0 0 .528.499l1.906-.109a12.33 12.33 0 0 0 1.289 3.117L8.3 28.059a.497.497 0 0 0-.021.726l3.936 3.935a.497.497 0 0 0 .726-.021l1.27-1.423a12.35 12.35 0 0 0 3.116 1.293l-.108 1.902a.501.501 0 0 0 .499.529h5.564a.5.5 0 0 0 .499-.529l-.108-1.901a12.374 12.374 0 0 0 3.119-1.292l1.267 1.421a.497.497 0 0 0 .358.167.473.473 0 0 0 .368-.146l3.936-3.935a.5.5 0 0 0-.021-.726l-1.426-1.272a12.275 12.275 0 0 0 1.29-3.115l1.908.109a.502.502 0 0 0 .528-.499v-5.565a.5.5 0 0 0-.156-.363Z"
|
||||
/>
|
||||
</g>
|
||||
</svg>
|
||||
);
|
||||
|
||||
export const AWSIAMIcon: React.FC<IconSvgProps> = ({
|
||||
size = 32,
|
||||
width,
|
||||
height,
|
||||
className = "rounded-md",
|
||||
...props
|
||||
}) => (
|
||||
<svg
|
||||
aria-hidden="false"
|
||||
aria-label="AWS IAM logo"
|
||||
fill="none"
|
||||
focusable="false"
|
||||
height={size || height}
|
||||
role="presentation"
|
||||
viewBox="0 0 40 40"
|
||||
width={size || width}
|
||||
className={className}
|
||||
{...props}
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
>
|
||||
<g fill="none" fillRule="evenodd">
|
||||
<rect fill="#DD344C" width="40" height="40" />
|
||||
<path
|
||||
fill="#FFF"
|
||||
d="m33.131 31.955-6.998-6.998a.501.501 0 0 1-.092-.58c.945-1.85.63-4.273-.732-5.635a4.629 4.629 0 0 0-3.855-1.33c-1.432.173-2.696 1.001-3.466 2.27a4.583 4.583 0 0 0 .103 4.868c1.354 2.06 3.977 2.781 6.094 1.681a.5.5 0 0 1 .584.091l1.194 1.194a.504.504 0 0 1 .146.39l-.089 1.258 1.38-.003h.001a.5.5 0 0 1 .353.147l.598.597a.502.502 0 0 1 .146.347l.017 1.406 1.231-.106a.502.502 0 0 1 .397.144l1.097 1.097 1.761.45.13-1.288Zm1.019-.135-.213 2.101a.5.5 0 0 1-.621.434l-2.456-.627a.499.499 0 0 1-.23-.13l-1.029-1.03-1.537.133a.499.499 0 0 1-.543-.493l-.021-1.74-.306-.306-1.709.004h-.001a.502.502 0 0 1-.499-.535l.11-1.569-.783-.783c-2.515 1.1-5.491.202-7.057-2.179a5.587 5.587 0 0 1-.122-5.937c.931-1.533 2.462-2.534 4.201-2.744a5.63 5.63 0 0 1 4.682 1.616c1.8 1.8 1.898 4.535 1.072 6.463l6.918 6.918a.5.5 0 0 1 .144.404ZM22.737 21.208a1.087 1.087 0 0 0-.774-.32c-.292 0-.567.113-.774.32a1.098 1.098 0 0 0 0 1.55 1.12 1.12 0 0 0 1.548 0 1.098 1.098 0 0 0 0-1.55Zm.707-.707a2.099 2.099 0 0 1 0 2.964 2.09 2.09 0 0 1-1.481.613 2.09 2.09 0 0 1-1.481-.613 2.099 2.099 0 0 1 0-2.964 2.097 2.097 0 0 1 2.962 0ZM9.662 13.312c0 .263.016.52.047.778a.504.504 0 0 1-.423.56C8.035 14.981 6 15.968 6 18.882c0 .107.006.213.011.315.135 2.461 2.487 3.794 4.633 3.8H15v1h-4.357c-3.063-.008-5.483-2.048-5.63-4.746A6.369 6.369 0 0 1 5 18.882c0-3.389 2.318-4.647 3.677-5.094a7.265 7.265 0 0 1-.015-.476c0-2.777 1.876-5.653 4.364-6.69 2.91-1.226 5.992-.618 8.245 1.625.591.581 1.348 1.451 1.88 2.511.566-.515 1.207-.768 1.941-.768 1.455 0 3.086 1.217 3.376 3.88 3.008.715 4.532 2.43 4.532 5.1 0 2.927-1.281 4.57-3.916 5.02l-.168-.987C30.352 22.758 32 22.08 32 18.97c0-3.018-2.34-3.843-4.099-4.2a.5.5 0 0 1-.4-.462c-.113-1.953-1.103-3.317-2.409-3.317-.664 0-1.186.302-1.691.981a.501.501 0 0 1-.872-.13c-.437-1.22-1.308-2.24-1.961-2.883-1.958-1.95-4.634-2.476-7.157-1.414-2.102.877-3.749 3.41-3.749 5.768Z"
|
||||
/>
|
||||
</g>
|
||||
</svg>
|
||||
);
|
||||
|
||||
export const AmazonInspectorIcon: React.FC<IconSvgProps> = ({
|
||||
size = 32,
|
||||
width,
|
||||
height,
|
||||
className = "rounded-md",
|
||||
...props
|
||||
}) => (
|
||||
<svg
|
||||
aria-hidden="false"
|
||||
aria-label="Amazon Inspector logo"
|
||||
fill="none"
|
||||
focusable="false"
|
||||
height={size || height}
|
||||
role="presentation"
|
||||
viewBox="0 0 40 40"
|
||||
width={size || width}
|
||||
className={className}
|
||||
{...props}
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
>
|
||||
<g fill="none" fillRule="evenodd">
|
||||
<rect width="40" height="40" fill="#DD344C" />
|
||||
<path
|
||||
fill="#FFF"
|
||||
d="M17.75 15.605c-.66 0-1.196-.547-1.196-1.218 0-.672.536-1.219 1.196-1.219.66 0 1.196.547 1.196 1.22 0 .67-.537 1.217-1.196 1.217m-.888 3.797c1.1 0 1.996.912 1.996 2.034 0 1.121-.895 2.035-1.996 2.035-1.1 0-1.996-.914-1.996-2.035 0-1.122.895-2.034 1.996-2.034m.044 5.956c-3.918 0-7.106-3.25-7.106-7.243 0-3.993 3.188-7.241 7.106-7.241 3.917 0 7.106 3.248 7.106 7.241 0 1.037-.22 2.021-.607 2.914l-3.728-.553a3.016 3.016 0 0 0-1.434-1.718v-2.21a2.215 2.215 0 0 0 1.689-2.16c0-1.227-.98-2.225-2.182-2.225-1.203 0-2.182.998-2.182 2.224 0 1.052.724 1.932 1.689 2.16v1.89c-.131-.017-.26-.04-.395-.04-.783 0-1.492.315-2.025.82l-1.233-1.268c.343-.494.549-1.092.549-1.741 0-1.035-.51-1.986-1.364-2.545l-.533.846a2.02 2.02 0 0 1 .911 1.699c0 1.113-.89 2.02-1.983 2.02v1.005c.644 0 1.238-.215 1.725-.572l1.327 1.366c-.22.424-.356.898-.356 1.409 0 1.676 1.338 3.04 2.982 3.04 1.617 0 2.932-1.323 2.974-2.961l3.073.455c-1.26 2.031-3.477 3.388-6.003 3.388m0-15.489c-4.462 0-8.092 3.7-8.092 8.246 0 4.548 3.63 8.248 8.092 8.248 4.461 0 8.092-3.7 8.092-8.248 0-4.547-3.63-8.246-8.092-8.246M32.593 32.44a1.64 1.64 0 0 1-2.338.126l-6.405-5.888c.852-.72 1.59-1.57 2.194-2.517l6.426 5.898c.676.623.73 1.692.123 2.381M6.986 18.115c0-5.574 4.45-10.11 9.92-10.11 5.469 0 9.919 4.536 9.919 10.11 0 5.575-4.45 10.11-9.92 10.11s-9.919-4.535-9.919-10.11m26.145 11.198-6.576-6.036a11.213 11.213 0 0 0 1.256-5.162C27.81 11.986 22.918 7 16.906 7 10.892 7 6 11.986 6 18.115c0 6.13 4.892 11.116 10.906 11.116 2.276 0 4.391-.718 6.141-1.939l6.548 6.02a2.62 2.62 0 0 0 3.73-.199 2.737 2.737 0 0 0-.194-3.8"
|
||||
/>
|
||||
</g>
|
||||
</svg>
|
||||
);
|
||||
|
||||
export const AmazonMacieIcon: React.FC<IconSvgProps> = ({
|
||||
size = 32,
|
||||
width,
|
||||
height,
|
||||
className = "rounded-md",
|
||||
...props
|
||||
}) => (
|
||||
<svg
|
||||
aria-hidden="false"
|
||||
aria-label="Amazon Macie logo"
|
||||
fill="none"
|
||||
focusable="false"
|
||||
height={size || height}
|
||||
role="presentation"
|
||||
viewBox="0 0 40 40"
|
||||
width={size || width}
|
||||
className={className}
|
||||
{...props}
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
>
|
||||
<g fill="none" fillRule="evenodd">
|
||||
<rect width="40" height="40" fill="#DD344C" />
|
||||
<path
|
||||
fill="#FFF"
|
||||
d="M28.002 20.905c-.99-.79-1.822-1.451-2.522-1.996.825-1.51 1.788-3.223 2.222-3.599 1.257.812 5.098 7.709 5.33 9.376-.922-.497-3.262-2.369-5.03-3.781m-7.55 4.089c-.288-.139-.885-1.005-1.574-2.13l.44-.726c.892-1.474 2.368-3.91 2.904-4.25.311.104 1.057.624 1.959 1.304-1.124 2.065-3.116 5.702-3.73 5.802m-3.947-.353c-.336-.407-.929-1.507-1.304-2.202-.96-1.782-1.318-2.4-1.832-2.418H13.346c-.407 0-.884.408-2.647 2.068-.675.636-1.66 1.563-2.36 2.12 1.012-2.256 3.974-7.633 4.978-8.98.458.67 1.374 2.315 2.134 3.683.912 1.64 1.646 2.937 2.249 3.949-.468.756-.926 1.466-1.196 1.78m16.791-2.111c-.916-2.129-4.267-8.28-5.607-8.28-.698 0-1.353 1.008-3.016 4.042-1.313-.985-2.04-1.423-2.454-1.438h-.025c-.734 0-1.544 1.144-3.724 4.746l-.175.288c-.692-1.177-1.413-2.474-1.974-3.48-2.188-3.936-2.494-4.389-2.971-4.407L13.34 14c-1.148 0-5.871 9.652-6.164 10.413-.143.372-.32.835.015 1.13.623.551 1.536-.21 4.185-2.704.65-.612 1.504-1.415 1.906-1.71.262.353.72 1.206 1.041 1.802 1.104 2.048 1.576 2.823 2.173 2.84.429-.028.798-.373 1.79-1.951C19.294 25.412 19.87 26 20.364 26h.007c1.111-.013 2.328-1.994 4.617-6.189.8.621 1.651 1.301 2.398 1.899 5.065 4.048 5.837 4.519 6.381 3.916.302-.337.455-.945-.472-3.096"
|
||||
/>
|
||||
</g>
|
||||
</svg>
|
||||
);
|
||||
|
||||
export const AWSNetworkFirewallIcon: React.FC<IconSvgProps> = ({
|
||||
size = 32,
|
||||
width,
|
||||
height,
|
||||
className = "rounded-md",
|
||||
...props
|
||||
}) => (
|
||||
<svg
|
||||
aria-hidden="false"
|
||||
aria-label="AWS Network Firewall logo"
|
||||
fill="none"
|
||||
focusable="false"
|
||||
height={size || height}
|
||||
role="presentation"
|
||||
viewBox="0 0 40 40"
|
||||
width={size || width}
|
||||
className={className}
|
||||
{...props}
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
>
|
||||
<g fill="none" fillRule="evenodd">
|
||||
<rect width="40" height="40" fill="#DD344C" />
|
||||
<path
|
||||
fill="#FFF"
|
||||
d="M33.007 29.006h-7v-3h7v3Zm-6 4h-6v-3h6v3Zm-10.257-1.74a6.062 6.062 0 0 1-5.137-2.823c-.896-1.41-.912-3.23-.01-4.802 1.049-1.593.672-3.807.336-5.027.964.493 1.838 1.755 2.147 2.311a.486.486 0 0 0 .478.256.497.497 0 0 0 .429-.327c.967-2.655.31-4.611-.4-5.776 2.07.699 5.66 2.6 5.66 7.379 0 .136.056.266.154.361a.484.484 0 0 0 .368.138c.59-.025 1.651-.473 2.16-1.886.044.133.072.279.072.436v3.5h-5.5a.5.5 0 0 0-.5.5v4a.5.5 0 0 0 .5.5h2.5v.384c-.855.561-1.999.876-3.257.876Zm-7.691-8.609c-.976-.646-2.139-1.874-2.139-4.059 0-2.988 2.079-3.968 3.318-4.287a.498.498 0 0 0 .375-.514l-.049-.821c0-2.33 1.735-6.026 6.391-6.026 1.896 0 3.399.545 4.466 1.619.763.766 1.356 1.745 1.767 2.909a.5.5 0 0 0 .874.131c.62-.842 1.69-1.194 2.659-.875 1.098.36 1.726 1.437 1.723 2.936a.5.5 0 0 0 .411.563c2.794.481 4.152 1.827 4.152 4.113 0 1.322-.341 2.333-1.016 3.084a.493.493 0 0 0-.484-.424h-7.559c-.206-.937-.921-1.499-.956-1.526a.496.496 0 0 0-.502-.062.496.496 0 0 0-.298.407c-.124 1.181-.589 1.708-.962 1.944-.465-6.83-7.828-8.036-7.906-8.048a.5.5 0 0 0-.388.884c.093.076 2.086 1.74 1.409 4.904-.67-.891-1.824-2.098-3.16-2.098a.5.5 0 0 0-.464.686c.013.032 1.201 3.068.093 4.909h-.564c-.434 0-.847-.121-1.191-.349Zm16.448 2.349h-1.5v-3h7v3h-5.5Zm-.5 4h-7v-3h7v3Zm8.5-4h-1.5v-2.241c1.324-.963 2-2.446 2-4.419 0-1.868-.806-4.221-4.57-5.019-.105-1.766-.987-3.077-2.404-3.543a3.354 3.354 0 0 0-3.197.618 8.365 8.365 0 0 0-1.706-2.539c-1.262-1.269-3.003-1.913-5.175-1.913-5.098 0-7.391 4.109-7.39 7.056l.027.453c-1.352.444-3.672 1.708-3.672 5.139 0 2.768 1.62 4.254 2.587 4.893a3.145 3.145 0 0 0 1.743.515h.075c-.641 1.656-.496 3.495.445 4.974a7.059 7.059 0 0 0 5.98 3.286c1.203 0 2.325-.26 3.257-.726v1.966a.5.5 0 0 0 .5.5h7a.5.5 0 0 0 .5-.5v-3.5h5.5a.5.5 0 0 0 .5-.5v-4a.5.5 0 0 0-.5-.5Z"
|
||||
/>
|
||||
</g>
|
||||
</svg>
|
||||
);
|
||||
|
||||
export const AWSOrganizationsIcon: React.FC<IconSvgProps> = ({
|
||||
size = 32,
|
||||
width,
|
||||
height,
|
||||
className = "rounded-md",
|
||||
...props
|
||||
}) => (
|
||||
<svg
|
||||
aria-hidden="false"
|
||||
aria-label="AWS Organizations logo"
|
||||
fill="none"
|
||||
focusable="false"
|
||||
height={size || height}
|
||||
role="presentation"
|
||||
viewBox="0 0 40 40"
|
||||
width={size || width}
|
||||
className={className}
|
||||
{...props}
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
>
|
||||
<g fill="none" fillRule="evenodd">
|
||||
<rect width="40" height="40" fill="#E7157B" />
|
||||
<path
|
||||
fill="#FFF"
|
||||
d="M28.986 32.001h3.016v-3.039h-3.016v3.039Zm-10.025 0h3.077v-3.039h-3.077v3.039Zm-9.963 0h3.037v-3.039H8.998v3.039Zm23.503-4.038h-1.498v-2.497a.5.5 0 0 0-.499-.5H21.02V22.97h-.998v1.997h-9.484c-.277 0-.5.224-.5.5v2.497H8.5c-.276 0-.499.224-.499.5V32.5c0 .275.223.499.5.499h4.034a.5.5 0 0 0 .5-.5v-4.037a.5.5 0 0 0-.5-.5h-1.497v-1.998h8.985v1.998h-1.56a.5.5 0 0 0-.5.5V32.5a.5.5 0 0 0 .5.499h4.076c.276 0 .499-.224.499-.5v-4.037c0-.276-.223-.5-.5-.5H21.02v-1.998h8.985v1.998h-1.518a.5.5 0 0 0-.5.5V32.5a.5.5 0 0 0 .5.499H32.5a.5.5 0 0 0 .499-.5v-4.037a.5.5 0 0 0-.5-.5ZM20.537 9.04l4.788 1.983-4.803 2.397-4.775-2.396 4.79-1.984Zm.497 11.6-.013-6.353 5.007-2.499v5.882l-4.994 2.97Zm-5.988-8.85 4.977 2.497.013 6.351-4.99-2.968v-5.88Zm5.235 10.157a.51.51 0 0 0 .512 0l5.99-3.563a.501.501 0 0 0 .243-.43v-6.973a.5.5 0 0 0-.307-.461l-5.99-2.482a.497.497 0 0 0-.383 0l-5.99 2.482a.5.5 0 0 0-.308.461v6.974c0 .176.093.34.243.43l5.99 3.562Z"
|
||||
/>
|
||||
</g>
|
||||
</svg>
|
||||
);
|
||||
|
||||
export const AmazonRDSIcon: React.FC<IconSvgProps> = ({
|
||||
size = 32,
|
||||
width,
|
||||
height,
|
||||
className = "rounded-md",
|
||||
...props
|
||||
}) => (
|
||||
<svg
|
||||
aria-hidden="false"
|
||||
aria-label="Amazon RDS logo"
|
||||
fill="none"
|
||||
focusable="false"
|
||||
height={size || height}
|
||||
role="presentation"
|
||||
viewBox="0 0 40 40"
|
||||
width={size || width}
|
||||
className={className}
|
||||
{...props}
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
>
|
||||
<g fill="none" fillRule="evenodd">
|
||||
<rect width="40" height="40" fill="#C925D1" />
|
||||
<path
|
||||
fill="#FFF"
|
||||
d="M11.854 28.854 7.708 33H10.5v1h-4a.5.5 0 0 1-.5-.5v-4h1v2.793l4.147-4.146.707.707ZM33 29.5h1v4c0 .277-.223.5-.5.5h-4v-1h2.793l-4.146-4.146.707-.707L33 32.293V29.5Zm1-23v4h-1V7.708l-4.146 4.146-.707-.707L32.293 7H29.5V6h4a.5.5 0 0 1 .5.5Zm-27 4H6v-4a.5.5 0 0 1 .5-.5h4v1H7.527l4.319 4.14-.691.721L7 7.88v2.62Zm25.726 8.9c0-1.558-1.806-3.1-4.83-4.123l.32-.947c3.502 1.185 5.51 3.033 5.51 5.07 0 2.037-2.008 3.886-5.51 5.071l-.32-.948c3.024-1.023 4.83-2.565 4.83-4.123Zm-24.989 0c0 1.492 1.69 2.993 4.521 4.014l-.34.94c-3.293-1.187-5.181-2.993-5.181-4.954 0-1.961 1.888-3.767 5.181-4.955l.34.941c-2.831 1.021-4.521 2.522-4.521 4.014Zm12.286-3.681c-3.136 0-4.891-.799-4.917-1.125.026-.326 1.781-1.125 4.917-1.125 3.133 0 4.89.798 4.917 1.125-.027.326-1.784 1.125-4.917 1.125Zm0 3.555c-3.182 0-4.917-.926-4.917-1.402v-2.03c1.135.595 3.069.877 4.917.877 1.848 0 3.782-.282 4.917-.877v2.03c0 .476-1.735 1.402-4.917 1.402Zm0 3.737c-3.182 0-4.917-.927-4.917-1.403v-2.343c1.119.665 3.023 1.009 4.917 1.009 1.894 0 3.798-.344 4.917-1.009v2.343c0 .476-1.735 1.403-4.917 1.403Zm0 3.279c-3.182 0-4.917-.915-4.917-1.385v-1.904c1.119.666 3.023 1.01 4.917 1.01 1.894 0 3.798-.344 4.917-1.01v1.904c0 .47-1.735 1.385-4.917 1.385Zm0-13.821c-2.85 0-5.917.665-5.917 2.125v10.311c0 1.566 2.977 2.385 5.917 2.385s5.917-.819 5.917-2.385V14.594c0-1.46-3.067-2.125-5.917-2.125Z"
|
||||
/>
|
||||
</g>
|
||||
</svg>
|
||||
);
|
||||
|
||||
export const AWSResourceExplorerIcon: React.FC<IconSvgProps> = ({
|
||||
size = 32,
|
||||
width,
|
||||
height,
|
||||
className = "rounded-md",
|
||||
...props
|
||||
}) => (
|
||||
<svg
|
||||
aria-hidden="false"
|
||||
aria-label="AWS Resource Explorer logo"
|
||||
fill="none"
|
||||
focusable="false"
|
||||
height={size || height}
|
||||
role="presentation"
|
||||
viewBox="0 0 40 40"
|
||||
width={size || width}
|
||||
className={className}
|
||||
{...props}
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
>
|
||||
<g fill="none" fillRule="evenodd">
|
||||
<rect width="40" height="40" fill="#E7157B" />
|
||||
<path
|
||||
fill="#FFF"
|
||||
d="m32.746 30.427-5.431-5.48a7.535 7.535 0 0 1-2.217 2.277l5.346 5.515c.214.213.493.3.833.247.37-.057.76-.273 1.097-.61.576-.577.889-1.431.372-1.95ZM26.396 30l-2.201-2.27a7.424 7.424 0 0 1-3.212.735c-.334 0-.66-.03-.983-.073v4.35L26.396 30ZM7 27.18l12 5.538V28.19c-3.163-.872-5.496-3.767-5.496-7.204 0-1.524.461-2.942 1.247-4.125L7 13.283V27.18Zm.693-14.68 7.687 3.547a7.459 7.459 0 0 1 5.603-2.542c1.751 0 3.359.61 4.635 1.62l5.688-2.624L19.5 7.05l-11.807 5.45Zm19.77 8.485a6.487 6.487 0 0 0-6.48-6.48 6.487 6.487 0 0 0-6.479 6.48 6.486 6.486 0 0 0 6.479 6.48 6.487 6.487 0 0 0 6.48-6.48Zm3.833 6.558.704-.351v-13.91l-5.585 2.578a7.424 7.424 0 0 1 1.395 8.166l3.486 3.517Zm2.159 2.178c.864.866.707 2.28-.374 3.362-.486.486-1.073.803-1.651.892a2.299 2.299 0 0 1-.336.026c-.522 0-.996-.194-1.363-.56l-2.59-2.672-7.444 3.19a.5.5 0 0 1-.407-.005l-13-6A.5.5 0 0 1 6 27.5v-15a.5.5 0 0 1 .29-.454l13-6a.497.497 0 0 1 .42 0l13 6a.5.5 0 0 1 .29.455v15a.503.503 0 0 1-.276.447l-.687.343 1.418 1.43ZM19 23h1v-2h-1v2Zm0 3h1v-2h-1v2Zm3.415-9.395.42.907 1.267-.585-.419-.909-1.268.587Zm-1.353.622.42.909L20 18.82V20h-1v-1.18l-1.967-.907.42-.909 2.047.945 1.562-.722Z"
|
||||
/>
|
||||
</g>
|
||||
</svg>
|
||||
);
|
||||
|
||||
export const AmazonRoute53Icon: React.FC<IconSvgProps> = ({
|
||||
size = 32,
|
||||
width,
|
||||
height,
|
||||
className = "rounded-md",
|
||||
...props
|
||||
}) => (
|
||||
<svg
|
||||
aria-hidden="false"
|
||||
aria-label="Amazon Route 53 logo"
|
||||
fill="none"
|
||||
focusable="false"
|
||||
height={size || height}
|
||||
role="presentation"
|
||||
viewBox="0 0 40 40"
|
||||
width={size || width}
|
||||
className={className}
|
||||
{...props}
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
>
|
||||
<g fill="none" fillRule="evenodd">
|
||||
<path fill="#8C4FFF" d="M0 0h40v40H0z" />
|
||||
<path
|
||||
fill="#FFF"
|
||||
d="M24.024 20.314c.343.317.514.74.514 1.272 0 .58-.208 1.042-.624 1.388-.416.345-.977.518-1.68.518a4.112 4.112 0 0 1-1.647-.354v-.71c.643.214 1.193.32 1.648.32.448 0 .794-.101 1.036-.302.242-.2.363-.488.363-.86 0-.715-.452-1.072-1.355-1.072a8.13 8.13 0 0 0-.842.044v-.585l1.86-2.03h-2.622v-.726h3.607v.7l-1.826 1.932a.447.447 0 0 1 .089-.009h.088c.584 0 1.048.159 1.391.474m-5.147-.154c.359.336.54.8.54 1.39 0 .58-.21 1.049-.63 1.405-.42.358-.972.537-1.656.537a4.09 4.09 0 0 1-1.692-.354v-.71c.655.214 1.216.32 1.683.32.448 0 .793-.102 1.032-.306.239-.204.36-.498.36-.882 0-.42-.113-.725-.338-.913-.224-.189-.59-.284-1.099-.284-.366 0-.823.03-1.373.09v-.587l.169-2.65h3.233v.727h-2.489l-.116 1.8c.326-.06.618-.09.878-.09.638 0 1.138.17 1.498.507m6.653 6.462c-2.242.403-4.207 1.313-5.53 2.059-1.323-.746-3.288-1.656-5.53-2.06-.627-.112-3.755-.764-3.755-2.558 0-.836.301-1.392.877-2.385.696-1.2 1.562-2.693 1.562-4.848 0-1.528-.399-2.996-1.187-4.368l.25-.306c2.61 1.293 5.533 1.118 7.783-.304 2.25 1.421 5.173 1.597 7.783.304l.25.306c-.788 1.372-1.188 2.84-1.188 4.368 0 2.155.866 3.648 1.563 4.848.576.993.876 1.549.876 2.385 0 1.794-3.127 2.446-3.754 2.559m2.312-9.792c0-1.454.41-2.849 1.22-4.146a.502.502 0 0 0-.036-.58l-.726-.893a.497.497 0 0 0-.63-.123c-1.134.627-2.319.945-3.518.945-1.448 0-2.714-.39-3.868-1.19a.502.502 0 0 0-.568 0c-1.155.8-2.42 1.19-3.868 1.19-1.2 0-2.384-.318-3.52-.945a.495.495 0 0 0-.628.123l-.726.893a.5.5 0 0 0-.036.58c.809 1.297 1.219 2.692 1.219 4.146 0 1.887-.791 3.25-1.428 4.347-.626 1.08-1.011 1.798-1.011 2.886 0 2.524 3.502 3.348 4.575 3.54 2.246.404 4.207 1.356 5.456 2.084a.493.493 0 0 0 .502 0c1.25-.728 3.21-1.68 5.455-2.083 1.074-.193 4.575-1.017 4.575-3.541 0-1.088-.384-1.806-1.01-2.886-.637-1.096-1.429-2.46-1.429-4.347M26.01 29.297c-2.822.507-5.19 2.016-6.01 2.588-.82-.572-3.188-2.08-6.01-2.588-1.406-.252-5.992-1.376-5.992-5.234 0-1.606.631-2.696 1.244-3.75.587-1.013 1.195-2.06 1.195-3.483 0-2.217-1.265-3.791-1.913-4.452.676-.821 2.314-2.818 3.147-3.89 1.263 1.18 2.728 1.824 4.177 1.824 1.61 0 2.942-.65 4.152-2.036 1.21 1.387 2.543 2.036 4.152 2.036 1.449 0 2.914-.643 4.176-1.824.833 1.072 2.472 3.069 3.148 3.89-.649.66-1.913 2.235-1.913 4.452 0 1.423.608 2.47 1.195 3.483.612 1.054 1.244 2.144 1.244 3.75 0 3.858-4.587 4.982-5.992 5.234m5.611-9.485c-.57-.98-1.06-1.828-1.06-2.982 0-2.43 1.892-4.004 1.912-4.02a.503.503 0 0 0 .07-.705c-.03-.037-3.066-3.716-3.759-4.668a.497.497 0 0 0-.768-.047c-1.16 1.24-2.532 1.924-3.864 1.924-1.471 0-2.63-.656-3.756-2.128a.516.516 0 0 0-.793 0c-1.126 1.472-2.285 2.128-3.755 2.128-1.332 0-2.704-.683-3.864-1.924a.497.497 0 0 0-.768.047c-.693.952-3.728 4.63-3.76 4.668a.502.502 0 0 0 .072.705c.019.016 1.911 1.575 1.911 4.02 0 1.154-.49 2.001-1.061 2.982C7.732 20.926 7 22.188 7 24.062c0 3.127 2.546 5.451 6.813 6.217 3.19.574 5.857 2.597 5.883 2.617a.499.499 0 0 0 .608 0c.026-.02 2.694-2.043 5.883-2.617C30.453 29.513 33 27.19 33 24.063c0-1.875-.732-3.137-1.379-4.25"
|
||||
/>
|
||||
</g>
|
||||
</svg>
|
||||
);
|
||||
|
||||
export const AmazonS3Icon: React.FC<IconSvgProps> = ({
|
||||
size = 32,
|
||||
width,
|
||||
height,
|
||||
className = "rounded-md",
|
||||
...props
|
||||
}) => (
|
||||
<svg
|
||||
aria-hidden="false"
|
||||
aria-label="Amazon S3 logo"
|
||||
fill="none"
|
||||
focusable="false"
|
||||
height={size || height}
|
||||
role="presentation"
|
||||
viewBox="0 0 32 32"
|
||||
width={size || width}
|
||||
className={className}
|
||||
{...props}
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
>
|
||||
<g clipPath="url(#a)">
|
||||
<rect width="32" height="32" fill="#7AA116" />
|
||||
<path
|
||||
fill="#fff"
|
||||
fillRule="evenodd"
|
||||
d="m24.426 17.113.157-1.167c1.674.959 1.708 1.355 1.708 1.366-.004.002-.284.226-1.865-.2Zm-.775-.23c-2.273-.718-5.328-2.058-7.072-2.88 0-.005.003-.01.003-.016a.964.964 0 0 0-.963-.962.963.963 0 0 0 0 1.925.947.947 0 0 0 .604-.23c1.015.475 4.637 2.14 7.32 2.97l-.944 6.99c0 .693-2.939 1.72-6.999 1.72s-6.999-1.027-7.003-1.773L6.627 10.05C8.367 11.324 12.059 12 15.6 12c3.541 0 7.235-.676 8.975-1.95l-.924 6.832ZM6.403 8.39c.023-.704 3.28-2.79 9.197-2.79 5.916 0 9.176 2.086 9.2 2.79v.091c-.152 1.303-3.89 2.718-9.2 2.718-5.31 0-9.033-1.415-9.185-2.717l-.012-.092Zm19.197.01c0-1.469-3.895-3.601-10-3.601s-10 2.132-10 3.6v.054L7.801 24.68c0 1.637 4.018 2.52 7.8 2.52 3.78 0 7.798-.883 7.794-2.466l.922-6.822c.657.171 1.188.262 1.597.262.474 0 .795-.115.989-.346a.78.78 0 0 0 .173-.665c-.11-.59-.838-1.228-2.364-2.067l-.017.02.905-6.662V8.4Z"
|
||||
clipRule="evenodd"
|
||||
/>
|
||||
</g>
|
||||
<defs>
|
||||
<clipPath id="a">
|
||||
<rect width="32" height="32" fill="#fff" rx="4" />
|
||||
</clipPath>
|
||||
</defs>
|
||||
</svg>
|
||||
);
|
||||
|
||||
export const AWSSecurityHubIcon: React.FC<IconSvgProps> = ({
|
||||
size = 32,
|
||||
width,
|
||||
height,
|
||||
className = "rounded-md",
|
||||
...props
|
||||
}) => (
|
||||
<svg
|
||||
aria-hidden="false"
|
||||
aria-label="AWS Security Hub logo"
|
||||
fill="none"
|
||||
focusable="false"
|
||||
height={size || height}
|
||||
role="presentation"
|
||||
viewBox="0 0 40 40"
|
||||
width={size || width}
|
||||
className={className}
|
||||
{...props}
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
>
|
||||
<g fill="none" fillRule="evenodd">
|
||||
<path fill="#DD344C" d="M0 0h40v40H0z" />
|
||||
<path
|
||||
fill="#FFF"
|
||||
d="M22.034 20.429c0 .086-.034 1.908-1.507 2.258v-5.498l1.507.653v2.587Zm-4.014-.008v-2.579l1.507-.653v5.5c-1.435-.335-1.506-2.052-1.507-2.268Zm4.713-3.367-2.507-1.085a.5.5 0 0 0-.398 0l-2.507 1.085a.501.501 0 0 0-.301.459v2.908c0 1.155.629 3.339 3.007 3.339s3.007-2.179 3.007-3.331v-2.916a.501.501 0 0 0-.301-.459Zm6.657 9.792c-.882 0-1.6-.718-1.6-1.601s.718-1.601 1.6-1.601c.883 0 1.601.718 1.601 1.601s-.718 1.601-1.601 1.601Zm-9.315-2.101a4.988 4.988 0 0 1-4.983-4.983 4.988 4.988 0 0 1 4.983-4.984 4.99 4.99 0 0 1 4.984 4.984 4.989 4.989 0 0 1-4.984 4.983Zm1.553 6.058c0 .882-.718 1.601-1.601 1.601s-1.6-.719-1.6-1.601a1.602 1.602 0 0 1 3.201 0ZM18.427 8.601c0-.882.717-1.601 1.6-1.601.883 0 1.601.719 1.601 1.601a1.602 1.602 0 0 1-3.201 0ZM10.6 26.24c-.882 0-1.6-.718-1.6-1.601 0-.882.718-1.601 1.6-1.601.883 0 1.601.719 1.601 1.601 0 .883-.718 1.601-1.601 1.601Zm.408-10.629a1.603 1.603 0 0 1-1.601-1.601c0-.883.718-1.601 1.601-1.601.882 0 1.601.718 1.601 1.601s-.719 1.601-1.601 1.601Zm18.446-3.457a1.602 1.602 0 0 1 0 3.201 1.602 1.602 0 0 1 0-3.201Zm-.064 10.49c-.718 0-1.37.294-1.841.767l-1.969-1.305c.308-.72.479-1.512.479-2.344a5.942 5.942 0 0 0-.806-2.988l2.253-1.315c.477.545 1.17.896 1.948.896a2.604 2.604 0 0 0 2.601-2.601c0-1.434-1.167-2.6-2.601-2.6a2.603 2.603 0 0 0-2.601 2.6c0 .296.061.575.152.841l-2.322 1.354a5.97 5.97 0 0 0-4.156-2.148v-2.65a2.604 2.604 0 0 0 2.101-2.55A2.604 2.604 0 0 0 20.027 6a2.604 2.604 0 0 0-2.6 2.601c0 1.263.905 2.316 2.1 2.55v2.654a5.978 5.978 0 0 0-4.26 2.41l-1.857-1.211c.127-.307.199-.642.199-.994a2.604 2.604 0 0 0-2.601-2.601 2.604 2.604 0 0 0-2.601 2.601 2.604 2.604 0 0 0 2.601 2.601 2.59 2.59 0 0 0 1.847-.774l1.886 1.229a5.933 5.933 0 0 0-.649 2.696c0 .739.14 1.444.386 2.098l-1.917 1.09a2.584 2.584 0 0 0-1.961-.912A2.604 2.604 0 0 0 8 24.639a2.603 2.603 0 0 0 2.6 2.601 2.604 2.604 0 0 0 2.601-2.601c0-.288-.059-.56-.145-.819l1.853-1.055a5.984 5.984 0 0 0 4.618 2.952v2.536a2.603 2.603 0 0 0-2.1 2.55 2.604 2.604 0 0 0 2.6 2.601 2.604 2.604 0 0 0 2.601-2.601 2.604 2.604 0 0 0-2.101-2.55v-2.531a5.979 5.979 0 0 0 4.577-2.73l1.888 1.25a2.604 2.604 0 0 0 2.398 3.604 2.604 2.604 0 0 0 2.601-2.601 2.604 2.604 0 0 0-2.601-2.601Z"
|
||||
/>
|
||||
</g>
|
||||
</svg>
|
||||
);
|
||||
|
||||
export const AmazonSNSIcon: React.FC<IconSvgProps> = ({
|
||||
size = 32,
|
||||
width,
|
||||
height,
|
||||
className = "rounded-md",
|
||||
...props
|
||||
}) => (
|
||||
<svg
|
||||
aria-hidden="false"
|
||||
aria-label="Amazon Simple Notification Service logo"
|
||||
fill="none"
|
||||
focusable="false"
|
||||
height={size || height}
|
||||
role="presentation"
|
||||
viewBox="0 0 40 40"
|
||||
width={size || width}
|
||||
className={className}
|
||||
{...props}
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
>
|
||||
<g fill="none" fillRule="evenodd">
|
||||
<path fill="#E7157B" d="M0 0h40v40H0z" />
|
||||
<path
|
||||
fill="#FFF"
|
||||
d="M7.01 20.078a1.1 1.1 0 0 1 1.105-1.093 1.1 1.1 0 0 1 1.104 1.093 1.1 1.1 0 0 1-1.104 1.093 1.1 1.1 0 0 1-1.105-1.093ZM20.776 33C14.813 33 9.645 28.375 8.47 22.136a2.1 2.1 0 0 0 1.69-1.558h2.949v-1h-2.95a2.104 2.104 0 0 0-1.653-1.554C9.72 12.252 14.838 8 20.776 8c2.933 0 5.354.643 7.194 1.911l.575-.821C26.534 7.703 23.92 7 20.776 7c-6.51 0-12.104 4.726-13.308 11.096C6.62 18.368 6 19.149 6 20.078c0 .916.602 1.688 1.431 1.971C8.591 28.894 14.24 34 20.776 34c3.285 0 6.788-1.667 8.786-3.094l-.59-.811C26.947 31.541 23.627 33 20.777 33ZM14.79 18.242c1.111.274 2.523.321 3.343.321.833 0 2.271-.047 3.402-.32l-2.401 5.014a.507.507 0 0 0-.048.215v2.324l-1.957.915v-3.239a.514.514 0 0 0-.044-.206l-2.295-5.024Zm3.343-1.757c2.314 0 3.554.311 3.951.52-.417.234-1.745.558-3.95.558-2.184 0-3.483-.327-3.873-.558.37-.206 1.582-.52 3.872-.52Zm-1.78 11.438a.511.511 0 0 0 .486.03l2.968-1.388a.5.5 0 0 0 .288-.452v-2.529l2.909-6.074a.806.806 0 0 0 .189-.51c0-1.252-2.751-1.515-5.06-1.515-2.266 0-4.969.263-4.969 1.515 0 .19.067.355.18.502l2.775 6.077V27.5c0 .172.088.331.235.423ZM30.877 27a1.1 1.1 0 0 1 1.104 1.093 1.1 1.1 0 0 1-1.104 1.093 1.1 1.1 0 0 1-1.104-1.093A1.1 1.1 0 0 1 30.876 27Zm0-16.03a1.1 1.1 0 0 1 1.104 1.093 1.1 1.1 0 0 1-1.104 1.093 1.1 1.1 0 0 1-1.104-1.093 1.1 1.1 0 0 1 1.104-1.093Zm1.01 8.015a1.1 1.1 0 0 1 1.104 1.093 1.1 1.1 0 0 1-1.104 1.093 1.1 1.1 0 0 1-1.104-1.093 1.1 1.1 0 0 1 1.104-1.093Zm-4.607 1.593h2.561a2.108 2.108 0 0 0 2.046 1.593A2.106 2.106 0 0 0 34 20.078a2.106 2.106 0 0 0-2.114-2.093c-.992 0-1.818.681-2.046 1.593H27.28v-7.015h1.551a2.108 2.108 0 0 0 2.046 1.593 2.106 2.106 0 0 0 2.114-2.093 2.106 2.106 0 0 0-2.114-2.093c-.991 0-1.818.681-2.046 1.593h-2.056a.502.502 0 0 0-.505.5v7.515h-3.061v1h3.061v7.515c0 .277.226.5.505.5h2.056a2.108 2.108 0 0 0 2.046 1.593 2.106 2.106 0 0 0 2.114-2.093A2.106 2.106 0 0 0 30.876 26c-.991 0-1.818.681-2.046 1.593H27.28v-7.015Z"
|
||||
/>
|
||||
</g>
|
||||
</svg>
|
||||
);
|
||||
|
||||
export const AWSSystemsManagerIncidentManagerIcon: React.FC<IconSvgProps> = ({
|
||||
size = 32,
|
||||
width,
|
||||
height,
|
||||
className = "rounded-md",
|
||||
...props
|
||||
}) => (
|
||||
<svg
|
||||
aria-hidden="false"
|
||||
aria-label="AWS Systems Manager Incident Manager logo"
|
||||
fill="none"
|
||||
focusable="false"
|
||||
height={size || height}
|
||||
role="presentation"
|
||||
viewBox="0 0 40 40"
|
||||
width={size || width}
|
||||
className={className}
|
||||
{...props}
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
>
|
||||
<g fill="none" fillRule="evenodd">
|
||||
<path fill="#E7157B" d="M0 0h40v40H0z" />
|
||||
<path
|
||||
fill="#FFF"
|
||||
d="M24 27h5v1h-5v1h-1v-1h-2v-1h2v-1h1v1Zm4-5.001h1v1h-1v1h-1v-1h-6v-1h6v-1h1v1Zm-17.643 1H15v1h-4.643c-.531 0-1.081 0-1.647-.353C7.698 23.019 6 21.55 6 18.764c0-3.376 2.33-4.615 3.689-5.05l-.026-.437c-.001-2.783 1.875-5.633 4.363-6.661 2.908-1.213 5.988-.611 8.243 1.606a8.21 8.21 0 0 1 1.718 2.498 3.409 3.409 0 0 1 3.245-.602c1.398.466 2.27 1.744 2.38 3.455 1.631.274 4.388.86 4.388 4.425h-1c0-2.64-1.691-3.132-3.734-3.47l-.238-.038a.499.499 0 0 1-.402-.608c-.002-1.404-.625-2.453-1.71-2.816a2.422 2.422 0 0 0-2.703.853.498.498 0 0 1-.869-.13c-.416-1.146-1.013-2.105-1.776-2.854-1.959-1.926-4.634-2.447-7.158-1.396-2.102.869-3.748 3.375-3.748 5.708l.05.808a.501.501 0 0 1-.378.516C9.089 14.88 7 15.837 7 18.764c0 2.186 1.217 3.4 2.238 4.033.309.192.626.202 1.119.202ZM33 26.159l-.882-.05a.515.515 0 0 0-.516.39 6.684 6.684 0 0 1-.873 2.11.5.5 0 0 0 .089.64l.66.587-1.642 1.64-.585-.655a.501.501 0 0 0-.641-.091 6.671 6.671 0 0 1-2.112.876.5.5 0 0 0-.389.517l.051.877h-2.32l.051-.878a.502.502 0 0 0-.389-.517 6.686 6.686 0 0 1-2.112-.876.502.502 0 0 0-.64.09l-.586.658-1.642-1.64.659-.588a.5.5 0 0 0 .09-.64 6.683 6.683 0 0 1-.875-2.11c-.053-.239-.245-.396-.515-.39l-.881.05v-2.32l.884.05c.271.006.462-.151.515-.39a6.72 6.72 0 0 1 .875-2.106.5.5 0 0 0-.089-.64l-.663-.59 1.642-1.642.59.662a.503.503 0 0 0 .64.09 6.702 6.702 0 0 1 2.108-.873.502.502 0 0 0 .389-.517l-.051-.885h2.32l-.051.886a.502.502 0 0 0 .389.517 6.713 6.713 0 0 1 2.107.873.5.5 0 0 0 .64-.09l.591-.663 1.642 1.641-.662.59a.501.501 0 0 0-.089.64 6.68 6.68 0 0 1 .875 2.108.479.479 0 0 0 .515.389l.883-.05v2.32Zm.472-3.348-1 .057a7.68 7.68 0 0 0-.682-1.645l.748-.668a.497.497 0 0 0 .021-.726l-2.39-2.39a.5.5 0 0 0-.727.021l-.67.751a7.617 7.617 0 0 0-1.641-.68l.057-1.004a.5.5 0 0 0-.499-.53h-3.378a.5.5 0 0 0-.499.53l.057 1.002a7.697 7.697 0 0 0-1.642.68l-.669-.749a.5.5 0 0 0-.359-.167.532.532 0 0 0-.368.146l-2.39 2.39a.5.5 0 0 0 .021.726l.749.67a7.71 7.71 0 0 0-.681 1.643l-1.002-.057a.529.529 0 0 0-.372.135.505.505 0 0 0-.156.364v3.378a.5.5 0 0 0 .528.5l.998-.058c.163.576.392 1.127.681 1.647l-.745.665a.497.497 0 0 0-.021.727l2.39 2.39a.527.527 0 0 0 .368.146.5.5 0 0 0 .359-.167l.664-.746a7.72 7.72 0 0 0 1.647.684l-.057.995a.502.502 0 0 0 .499.529h3.378a.5.5 0 0 0 .499-.53l-.057-.993a7.716 7.716 0 0 0 1.648-.684l.663.745a.5.5 0 0 0 .727.02l2.39-2.39a.5.5 0 0 0-.021-.726l-.747-.666a7.686 7.686 0 0 0 .682-1.646l.999.057a.5.5 0 0 0 .528-.499V23.31a.505.505 0 0 0-.156-.364.529.529 0 0 0-.372-.135Z"
|
||||
/>
|
||||
</g>
|
||||
</svg>
|
||||
);
|
||||
|
||||
export const AWSTrustedAdvisorIcon: React.FC<IconSvgProps> = ({
|
||||
size = 32,
|
||||
width,
|
||||
height,
|
||||
className = "rounded-md",
|
||||
...props
|
||||
}) => (
|
||||
<svg
|
||||
aria-hidden="false"
|
||||
aria-label="AWS Trusted Advisor logo"
|
||||
fill="none"
|
||||
focusable="false"
|
||||
height={size || height}
|
||||
role="presentation"
|
||||
viewBox="0 0 64 64"
|
||||
width={size || width}
|
||||
className={className}
|
||||
{...props}
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
>
|
||||
<g fill="none" fillRule="evenodd">
|
||||
<path fill="#E7157B" d="M0 0h64v64H0z" />
|
||||
<path
|
||||
fill="#FFF"
|
||||
d="m26 18.662 5-2.115v17.396c-4.854-.555-5-5.125-5-5.175V18.662Zm12 10.106c0 .05-.146 4.62-5 5.175V16.547l5 2.115v10.106ZM32 36c6.563 0 8-5.219 8-7.23v-10.77a.998.998 0 0 0-.61-.92l-7-2.962a1.005 1.005 0 0 0-.78 0l-7 2.962A.998.998 0 0 0 24 18v10.77c0 2.011 1.438 7.23 8 7.23ZM22 15.773l10-3.707 10 3.707v12.188C42 31.711 40.701 38 32 38c-9.518 0-10-8.362-10-10.038V15.773ZM32 40c11.135 0 12-9.214 12-12.038V15.078a1 1 0 0 0-.652-.938l-11-4.078a1.004 1.004 0 0 0-.696 0l-11 4.078a1 1 0 0 0-.652.938v12.883C20 29.193 20.337 40 32 40Zm17 6c-1.103 0-2-.897-2-2s.897-2 2-2 2 .897 2 2-.897 2-2 2Zm-15 4c0 1.103-.897 2-2 2s-2-.897-2-2 .897-2 2-2 2 .897 2 2Zm-19-4c-1.103 0-2-.897-2-2s.897-2 2-2 2 .897 2 2-.897 2-2 2Zm34-6c-.997 0-1.899.38-2.601.986l-1.672-1.674c2.5-2.055 4.626-4.714 6.171-7.872l-1.796-.88C45.646 37.616 39.093 42 32 42c-7.359 0-14.804-4.704-18.102-11.44l-1.796.88c1.488 3.04 3.69 5.664 6.32 7.725l-1.402 1.402A3.966 3.966 0 0 0 15 40c-2.206 0-4 1.795-4 4 0 2.206 1.794 4 4 4s4-1.794 4-4c0-.739-.216-1.424-.566-2.019l1.633-1.633c3.269 2.13 7.055 3.422 10.933 3.614v2.18c-1.721.448-3 2-3 3.858 0 2.206 1.794 4 4 4s4-1.794 4-4c0-1.858-1.279-3.41-3-3.858v-2.18c3.625-.189 7.09-1.392 10.112-3.435l2.135 2.135c-.15.42-.247.867-.247 1.338 0 2.206 1.794 4 4 4s4-1.794 4-4c0-2.205-1.794-4-4-4Z"
|
||||
/>
|
||||
</g>
|
||||
</svg>
|
||||
);
|
||||
|
||||
export const AmazonVPCIcon: React.FC<IconSvgProps> = ({
|
||||
size = 32,
|
||||
width,
|
||||
height,
|
||||
className = "rounded-md",
|
||||
...props
|
||||
}) => (
|
||||
<svg
|
||||
aria-hidden="false"
|
||||
aria-label="Amazon VPC logo"
|
||||
fill="none"
|
||||
focusable="false"
|
||||
height={size || height}
|
||||
role="presentation"
|
||||
viewBox="0 0 40 40"
|
||||
width={size || width}
|
||||
className={className}
|
||||
{...props}
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
>
|
||||
<g fill="none" fillRule="evenodd">
|
||||
<path fill="#8C4FFF" d="M0 0h40v40H0z" />
|
||||
<path
|
||||
fill="#FFF"
|
||||
d="m30.97 21.03-2.943-1.264v10.49c2.545-.353 2.932-2.969 2.948-3.088l-.004-6.139Zm-3.943 9.24V19.76l-3.035 1.272v6.201c.013.054.445 2.767 3.035 3.036Zm.306-11.723a.5.5 0 0 1 .39.001l3.945 1.692a.5.5 0 0 1 .303.46v6.533c-.183 1.447-1.357 4.063-4.527 4.063-3.075 0-4.254-2.612-4.448-3.994l-.004-6.603c0-.2.12-.383.306-.46l4.035-1.692Zm5.65.637-5.461-2.406-5.53 2.327v7.128c-.001.042-.054 2.868 1.657 4.623.917.941 2.194 1.42 3.795 1.42 1.602 0 2.887-.48 3.819-1.423 1.735-1.758 1.72-4.585 1.72-4.613v-7.056ZM31.98 31.55c-1.127 1.144-2.654 1.725-4.536 1.725-1.884 0-3.404-.58-4.517-1.727-2.005-2.063-1.94-5.197-1.935-5.329v-7.446a.5.5 0 0 1 .305-.46l6.035-2.54a.5.5 0 0 1 .396.003l5.956 2.625c.182.08.299.26.299.457v7.375c.002.125.027 3.255-2.003 5.317Zm-20.988-7.314h8v1h-8c-2.811 0-4.811-2.016-4.98-5.016A3.745 3.745 0 0 1 6 19.841c0-2.509 1.318-4.223 3.817-4.979a8.352 8.352 0 0 1-.032-.647c0-2.916 1.577-5.445 4.017-6.445 3.298-1.348 7.042-.894 9.106 1.104a8.232 8.232 0 0 1 1.76 2.485c.609-.45 1.4-.66 2.349-.614 1.78.09 3.149 1.713 3.433 4.007 1.498.124 2.485.883 3.01 2.308l-.937.346c-.428-1.157-1.208-1.673-2.531-1.673a.5.5 0 0 1-.5-.47c-.138-2.338-1.406-3.463-2.526-3.519-.945-.053-1.645.22-2.08.791a.504.504 0 0 1-.472.193.503.503 0 0 1-.395-.323 7.378 7.378 0 0 0-1.807-2.814c-1.788-1.73-5.09-2.099-8.031-.895-2.063.845-3.396 3.011-3.396 5.52 0 .272.035.695.066.958a.498.498 0 0 1-.376.544C8.169 16.29 7 17.678 7 19.841c0 .101-.001.201.009.302.14 2.495 1.703 4.093 3.983 4.093Z"
|
||||
/>
|
||||
</g>
|
||||
</svg>
|
||||
);
|
||||
|
||||
export const getAWSIcon = (serviceAlias: string) => {
|
||||
switch (serviceAlias) {
|
||||
case "Amazon EC2":
|
||||
return <AmazonEC2Icon />;
|
||||
case "Amazon EMR":
|
||||
return <AmazonEMRIcon />;
|
||||
case "Amazon GuardDuty":
|
||||
return <AmazonGuardDutyIcon />;
|
||||
case "Amazon Inspector":
|
||||
return <AmazonInspectorIcon />;
|
||||
case "Amazon Macie":
|
||||
return <AmazonMacieIcon />;
|
||||
case "Amazon RDS":
|
||||
return <AmazonRDSIcon />;
|
||||
case "Amazon Route 53":
|
||||
return <AmazonRoute53Icon />;
|
||||
case "Amazon S3":
|
||||
return <AmazonS3Icon />;
|
||||
case "Amazon SNS":
|
||||
return <AmazonSNSIcon />;
|
||||
case "Amazon VPC":
|
||||
return <AmazonVPCIcon />;
|
||||
case "AWS Account":
|
||||
return <AWSAccountIcon />;
|
||||
case "AWS Athena":
|
||||
return <AWSAthenaIcon />;
|
||||
case "AWS Certificate Manager":
|
||||
return <AWSCertificateManagerIcon />;
|
||||
case "AWS CloudFormation":
|
||||
return <AWSCloudFormationIcon />;
|
||||
case "AWS CloudTrail":
|
||||
return <AWSCloudTrailIcon />;
|
||||
case "AWS CloudWatch":
|
||||
return <AWSCloudWatchIcon />;
|
||||
case "AWS Config":
|
||||
return <AWSConfigIcon />;
|
||||
case "AWS Database Migration":
|
||||
return <AWSDatabaseMigrationServiceIcon />;
|
||||
case "AWS Glue":
|
||||
return <AWSGlueIcon />;
|
||||
case "AWS IAM":
|
||||
return <AWSIAMIcon />;
|
||||
case "AWS Lambda":
|
||||
return <AWSLambdaIcon />;
|
||||
case "AWS Network Firewall":
|
||||
return <AWSNetworkFirewallIcon />;
|
||||
case "AWS Organizations":
|
||||
return <AWSOrganizationsIcon />;
|
||||
case "AWS Resource Explorer":
|
||||
return <AWSResourceExplorerIcon />;
|
||||
case "AWS Security Hub":
|
||||
return <AWSSecurityHubIcon />;
|
||||
case "AWS Systems Manager":
|
||||
return <AWSSystemsManagerIncidentManagerIcon />;
|
||||
case "AWS Trusted Advisor":
|
||||
return <AWSTrustedAdvisorIcon />;
|
||||
case "IAM Access Analyzer":
|
||||
return <IAMAccessAnalyzerIcon />;
|
||||
default:
|
||||
return null;
|
||||
}
|
||||
};
|
||||
@@ -0,0 +1,95 @@
|
||||
"use client";
|
||||
|
||||
import { zodResolver } from "@hookform/resolvers/zod";
|
||||
import React, { Dispatch, SetStateAction } from "react";
|
||||
import { useForm } from "react-hook-form";
|
||||
import * as z from "zod";
|
||||
|
||||
import { revokeInvite } from "@/actions/invitations/invitation";
|
||||
import { DeleteIcon } from "@/components/icons";
|
||||
import { useToast } from "@/components/ui";
|
||||
import { CustomButton } from "@/components/ui/custom";
|
||||
import { Form } from "@/components/ui/form";
|
||||
|
||||
const formSchema = z.object({
|
||||
invitationId: z.string(),
|
||||
});
|
||||
|
||||
export const DeleteForm = ({
|
||||
invitationId,
|
||||
setIsOpen,
|
||||
}: {
|
||||
invitationId: string;
|
||||
setIsOpen: Dispatch<SetStateAction<boolean>>;
|
||||
}) => {
|
||||
const form = useForm<z.infer<typeof formSchema>>({
|
||||
resolver: zodResolver(formSchema),
|
||||
defaultValues: {
|
||||
invitationId,
|
||||
},
|
||||
});
|
||||
const { toast } = useToast();
|
||||
const isLoading = form.formState.isSubmitting;
|
||||
|
||||
async function onSubmitClient(values: z.infer<typeof formSchema>) {
|
||||
const formData = new FormData();
|
||||
|
||||
Object.entries(values).forEach(
|
||||
([key, value]) => value !== undefined && formData.append(key, value),
|
||||
);
|
||||
// client-side validation
|
||||
const data = await revokeInvite(formData);
|
||||
|
||||
if (data?.errors && data.errors.length > 0) {
|
||||
const error = data.errors[0];
|
||||
const errorMessage = `${error.detail}`;
|
||||
// show error
|
||||
toast({
|
||||
variant: "destructive",
|
||||
title: "Oops! Something went wrong",
|
||||
description: errorMessage,
|
||||
});
|
||||
} else {
|
||||
toast({
|
||||
title: "Success!",
|
||||
description: "The invitation was revoked successfully.",
|
||||
});
|
||||
}
|
||||
setIsOpen(false); // Close the modal on success
|
||||
}
|
||||
|
||||
return (
|
||||
<Form {...form}>
|
||||
<form onSubmit={form.handleSubmit(onSubmitClient)}>
|
||||
<input type="hidden" name="id" value={invitationId} />
|
||||
<div className="flex w-full justify-center sm:space-x-6">
|
||||
<CustomButton
|
||||
type="button"
|
||||
ariaLabel="Cancel"
|
||||
className="w-full bg-transparent"
|
||||
variant="faded"
|
||||
size="lg"
|
||||
radius="lg"
|
||||
onPress={() => setIsOpen(false)}
|
||||
isDisabled={isLoading}
|
||||
>
|
||||
<span>Cancel</span>
|
||||
</CustomButton>
|
||||
|
||||
<CustomButton
|
||||
type="submit"
|
||||
ariaLabel="Revoke"
|
||||
className="w-full"
|
||||
variant="solid"
|
||||
color="danger"
|
||||
size="lg"
|
||||
isLoading={isLoading}
|
||||
startContent={!isLoading && <DeleteIcon size={24} />}
|
||||
>
|
||||
{isLoading ? <>Loading</> : <span>Revoke</span>}
|
||||
</CustomButton>
|
||||
</div>
|
||||
</form>
|
||||
</Form>
|
||||
);
|
||||
};
|
||||
@@ -0,0 +1,118 @@
|
||||
"use client";
|
||||
|
||||
import { zodResolver } from "@hookform/resolvers/zod";
|
||||
import { Dispatch, SetStateAction } from "react";
|
||||
import { useForm } from "react-hook-form";
|
||||
import * as z from "zod";
|
||||
|
||||
import { updateInvite } from "@/actions/invitations/invitation";
|
||||
import { SaveIcon } from "@/components/icons";
|
||||
import { useToast } from "@/components/ui";
|
||||
import { CustomButton, CustomInput } from "@/components/ui/custom";
|
||||
import { Form } from "@/components/ui/form";
|
||||
import { editInviteFormSchema } from "@/types";
|
||||
|
||||
export const EditForm = ({
|
||||
invitationId,
|
||||
invitationEmail,
|
||||
setIsOpen,
|
||||
}: {
|
||||
invitationId: string;
|
||||
invitationEmail?: string;
|
||||
setIsOpen: Dispatch<SetStateAction<boolean>>;
|
||||
}) => {
|
||||
const formSchema = editInviteFormSchema;
|
||||
|
||||
const form = useForm<z.infer<typeof formSchema>>({
|
||||
resolver: zodResolver(formSchema),
|
||||
defaultValues: {
|
||||
invitationId,
|
||||
invitationEmail: invitationEmail,
|
||||
},
|
||||
});
|
||||
|
||||
const { toast } = useToast();
|
||||
|
||||
const isLoading = form.formState.isSubmitting;
|
||||
|
||||
const onSubmitClient = async (values: z.infer<typeof formSchema>) => {
|
||||
const formData = new FormData();
|
||||
console.log(values);
|
||||
|
||||
Object.entries(values).forEach(
|
||||
([key, value]) => value !== undefined && formData.append(key, value),
|
||||
);
|
||||
|
||||
const data = await updateInvite(formData);
|
||||
|
||||
if (data?.error) {
|
||||
const errorMessage = `${data.error}`;
|
||||
toast({
|
||||
variant: "destructive",
|
||||
title: "Oops! Something went wrong",
|
||||
description: errorMessage,
|
||||
});
|
||||
} else {
|
||||
toast({
|
||||
title: "Success!",
|
||||
description: "The invitation was updated successfully.",
|
||||
});
|
||||
setIsOpen(false); // Close the modal on success
|
||||
}
|
||||
};
|
||||
|
||||
return (
|
||||
<Form {...form}>
|
||||
<form
|
||||
onSubmit={form.handleSubmit(onSubmitClient)}
|
||||
className="flex flex-col space-y-4"
|
||||
>
|
||||
<div className="text-md">
|
||||
Current email: <span className="font-bold">{invitationEmail}</span>
|
||||
</div>
|
||||
<div>
|
||||
<CustomInput
|
||||
control={form.control}
|
||||
name="invitationEmail"
|
||||
type="email"
|
||||
label="Email"
|
||||
labelPlacement="outside"
|
||||
placeholder={invitationEmail}
|
||||
variant="bordered"
|
||||
isRequired={false}
|
||||
isInvalid={!!form.formState.errors.invitationEmail}
|
||||
/>
|
||||
</div>
|
||||
<input type="hidden" name="invitationId" value={invitationId} />
|
||||
|
||||
<div className="flex w-full justify-center sm:space-x-6">
|
||||
<CustomButton
|
||||
type="button"
|
||||
ariaLabel="Cancel"
|
||||
className="w-full bg-transparent"
|
||||
variant="faded"
|
||||
size="lg"
|
||||
radius="lg"
|
||||
onPress={() => setIsOpen(false)}
|
||||
isDisabled={isLoading}
|
||||
>
|
||||
<span>Cancel</span>
|
||||
</CustomButton>
|
||||
|
||||
<CustomButton
|
||||
type="submit"
|
||||
ariaLabel="Save"
|
||||
className="w-full"
|
||||
variant="solid"
|
||||
color="action"
|
||||
size="lg"
|
||||
isLoading={isLoading}
|
||||
startContent={!isLoading && <SaveIcon size={24} />}
|
||||
>
|
||||
{isLoading ? <>Loading</> : <span>Save</span>}
|
||||
</CustomButton>
|
||||
</div>
|
||||
</form>
|
||||
</Form>
|
||||
);
|
||||
};
|
||||
@@ -0,0 +1,2 @@
|
||||
export * from "./delete-form";
|
||||
export * from "./edit-form";
|
||||
@@ -0,0 +1,2 @@
|
||||
export * from "./invitation-details";
|
||||
export * from "./send-invitation-button";
|
||||
@@ -0,0 +1,111 @@
|
||||
"use client";
|
||||
|
||||
import { Card, CardBody, Divider, Snippet } from "@nextui-org/react";
|
||||
|
||||
import { AddIcon } from "../icons";
|
||||
import { CustomButton } from "../ui/custom";
|
||||
import { DateWithTime } from "../ui/entities";
|
||||
|
||||
interface InvitationDetailsProps {
|
||||
attributes: {
|
||||
email: string;
|
||||
state: string;
|
||||
token: string;
|
||||
expires_at: string;
|
||||
inserted_at: string;
|
||||
updated_at: string;
|
||||
};
|
||||
relationships?: {
|
||||
inviter: {
|
||||
data: {
|
||||
id: string;
|
||||
};
|
||||
};
|
||||
};
|
||||
selfLink: string;
|
||||
}
|
||||
|
||||
export const InvitationDetails = ({ attributes }: InvitationDetailsProps) => {
|
||||
const baseURL = process.env.SITE_URL || "http://localhost:3000";
|
||||
const invitationLink = `${baseURL}/sign-up?invitation_token=${attributes.token}`;
|
||||
return (
|
||||
<div className="flex flex-col gap-x-4 gap-y-8">
|
||||
<Card
|
||||
isBlurred
|
||||
className="border-none bg-background/60 dark:bg-prowler-blue-800"
|
||||
shadow="sm"
|
||||
>
|
||||
<CardBody>
|
||||
<h2 className="text-2xl font-bold text-foreground/90">
|
||||
Invitation Details
|
||||
</h2>
|
||||
<Divider className="my-4" />
|
||||
|
||||
<div className="space-y-3">
|
||||
<div className="flex items-center justify-between">
|
||||
<strong className="text-default-500">Email:</strong>
|
||||
<span>{attributes.email}</span>
|
||||
</div>
|
||||
|
||||
<div className="flex items-center justify-between">
|
||||
<strong className="text-default-500">State:</strong>
|
||||
<span className="capitalize">{attributes.state}</span>
|
||||
</div>
|
||||
|
||||
<div className="flex items-center justify-between">
|
||||
<strong className="text-default-500">Token:</strong>
|
||||
<span>{attributes.token}</span>
|
||||
</div>
|
||||
|
||||
<div className="flex items-center justify-between">
|
||||
<strong className="text-default-500">Expires At:</strong>
|
||||
<DateWithTime dateTime={attributes.expires_at} />
|
||||
</div>
|
||||
|
||||
<div className="flex items-center justify-between">
|
||||
<strong className="text-default-500">Inserted At:</strong>
|
||||
<DateWithTime dateTime={attributes.inserted_at} />
|
||||
</div>
|
||||
|
||||
<div className="flex items-center justify-between">
|
||||
<strong className="text-default-500">Updated At:</strong>
|
||||
<DateWithTime dateTime={attributes.updated_at} />
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<Divider className="my-4" />
|
||||
<h3 className="pb-2 text-xl font-bold text-foreground/90">
|
||||
Share this link with the user:
|
||||
</h3>
|
||||
|
||||
<div className="flex flex-col items-start justify-between">
|
||||
<Snippet
|
||||
classNames={{
|
||||
base: "mx-auto",
|
||||
}}
|
||||
hideSymbol
|
||||
variant="bordered"
|
||||
className="overflow-hidden text-ellipsis whitespace-nowrap"
|
||||
>
|
||||
<p className="no-scrollbar w-96 overflow-hidden overflow-x-scroll text-ellipsis whitespace-nowrap text-sm">
|
||||
{invitationLink}
|
||||
</p>
|
||||
</Snippet>
|
||||
</div>
|
||||
</CardBody>
|
||||
</Card>
|
||||
<div className="flex w-full items-center justify-end">
|
||||
<CustomButton
|
||||
asLink="/invitations/"
|
||||
ariaLabel="Send Invitation"
|
||||
variant="solid"
|
||||
color="action"
|
||||
size="md"
|
||||
endContent={<AddIcon size={20} />}
|
||||
>
|
||||
Back to Invitations
|
||||
</CustomButton>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
};
|
||||
@@ -0,0 +1,21 @@
|
||||
"use client";
|
||||
|
||||
import { AddIcon } from "../icons";
|
||||
import { CustomButton } from "../ui/custom";
|
||||
|
||||
export const SendInvitationButton = () => {
|
||||
return (
|
||||
<div className="flex w-full items-center justify-end">
|
||||
<CustomButton
|
||||
asLink="/invitations/new"
|
||||
ariaLabel="Send Invitation"
|
||||
variant="solid"
|
||||
color="action"
|
||||
size="md"
|
||||
endContent={<AddIcon size={20} />}
|
||||
>
|
||||
Send Invitation
|
||||
</CustomButton>
|
||||
</div>
|
||||
);
|
||||
};
|
||||
@@ -0,0 +1,72 @@
|
||||
"use client";
|
||||
|
||||
import { ColumnDef } from "@tanstack/react-table";
|
||||
|
||||
import { DateWithTime } from "@/components/ui/entities";
|
||||
import { DataTableColumnHeader } from "@/components/ui/table";
|
||||
import { InvitationProps } from "@/types";
|
||||
|
||||
import { DataTableRowActions } from "./data-table-row-actions";
|
||||
|
||||
const getInvitationData = (row: { original: InvitationProps }) => {
|
||||
return row.original.attributes;
|
||||
};
|
||||
|
||||
export const ColumnsInvitation: ColumnDef<InvitationProps>[] = [
|
||||
{
|
||||
accessorKey: "email",
|
||||
header: () => <div className="text-left">Email</div>,
|
||||
cell: ({ row }) => {
|
||||
const data = getInvitationData(row);
|
||||
return <p className="font-semibold">{data?.email || "N/A"}</p>;
|
||||
},
|
||||
},
|
||||
{
|
||||
accessorKey: "state",
|
||||
header: ({ column }) => (
|
||||
<DataTableColumnHeader column={column} title={"State"} param="state" />
|
||||
),
|
||||
cell: ({ row }) => {
|
||||
const { state } = getInvitationData(row);
|
||||
return <p className="font-semibold">{state}</p>;
|
||||
},
|
||||
},
|
||||
{
|
||||
accessorKey: "inserted_at",
|
||||
header: ({ column }) => (
|
||||
<DataTableColumnHeader
|
||||
column={column}
|
||||
title={"Inserted At"}
|
||||
param="inserted_at"
|
||||
/>
|
||||
),
|
||||
cell: ({ row }) => {
|
||||
const { inserted_at } = getInvitationData(row);
|
||||
return <DateWithTime dateTime={inserted_at} showTime={false} />;
|
||||
},
|
||||
},
|
||||
|
||||
{
|
||||
accessorKey: "expires_at",
|
||||
header: ({ column }) => (
|
||||
<DataTableColumnHeader
|
||||
column={column}
|
||||
title={"Expires At"}
|
||||
param="expires_at"
|
||||
/>
|
||||
),
|
||||
cell: ({ row }) => {
|
||||
const { expires_at } = getInvitationData(row);
|
||||
return <DateWithTime dateTime={expires_at} showTime={false} />;
|
||||
},
|
||||
},
|
||||
|
||||
{
|
||||
accessorKey: "actions",
|
||||
header: () => <div className="text-right">Actions</div>,
|
||||
id: "actions",
|
||||
cell: ({ row }) => {
|
||||
return <DataTableRowActions row={row} />;
|
||||
},
|
||||
},
|
||||
];
|
||||
@@ -0,0 +1,120 @@
|
||||
"use client";
|
||||
|
||||
import {
|
||||
Button,
|
||||
Dropdown,
|
||||
DropdownItem,
|
||||
DropdownMenu,
|
||||
DropdownSection,
|
||||
DropdownTrigger,
|
||||
} from "@nextui-org/react";
|
||||
import {
|
||||
AddNoteBulkIcon,
|
||||
DeleteDocumentBulkIcon,
|
||||
EditDocumentBulkIcon,
|
||||
} from "@nextui-org/shared-icons";
|
||||
import { Row } from "@tanstack/react-table";
|
||||
import clsx from "clsx";
|
||||
import { useState } from "react";
|
||||
|
||||
import { VerticalDotsIcon } from "@/components/icons";
|
||||
import { CustomAlertModal } from "@/components/ui/custom";
|
||||
|
||||
import { DeleteForm, EditForm } from "../forms";
|
||||
|
||||
interface DataTableRowActionsProps<InvitationProps> {
|
||||
row: Row<InvitationProps>;
|
||||
}
|
||||
const iconClasses =
|
||||
"text-2xl text-default-500 pointer-events-none flex-shrink-0";
|
||||
|
||||
export function DataTableRowActions<InvitationProps>({
|
||||
row,
|
||||
}: DataTableRowActionsProps<InvitationProps>) {
|
||||
const [isEditOpen, setIsEditOpen] = useState(false);
|
||||
const [isDeleteOpen, setIsDeleteOpen] = useState(false);
|
||||
const invitationId = (row.original as { id: string }).id;
|
||||
const invitationEmail = (row.original as any).attributes?.email;
|
||||
return (
|
||||
<>
|
||||
<CustomAlertModal
|
||||
isOpen={isEditOpen}
|
||||
onOpenChange={setIsEditOpen}
|
||||
title="Edit Invitation"
|
||||
description={"Edit the invitation details"}
|
||||
>
|
||||
<EditForm
|
||||
invitationId={invitationId}
|
||||
invitationEmail={invitationEmail}
|
||||
setIsOpen={setIsEditOpen}
|
||||
/>
|
||||
</CustomAlertModal>
|
||||
<CustomAlertModal
|
||||
isOpen={isDeleteOpen}
|
||||
onOpenChange={setIsDeleteOpen}
|
||||
title="Are you absolutely sure?"
|
||||
description="This action cannot be undone. This will permanently revoke your invitation."
|
||||
>
|
||||
<DeleteForm invitationId={invitationId} setIsOpen={setIsDeleteOpen} />
|
||||
</CustomAlertModal>
|
||||
|
||||
<div className="relative flex items-center justify-end gap-2">
|
||||
<Dropdown
|
||||
className="shadow-xl dark:bg-prowler-blue-800"
|
||||
placement="bottom"
|
||||
>
|
||||
<DropdownTrigger>
|
||||
<Button isIconOnly radius="full" size="sm" variant="light">
|
||||
<VerticalDotsIcon className="text-default-400" />
|
||||
</Button>
|
||||
</DropdownTrigger>
|
||||
<DropdownMenu
|
||||
closeOnSelect
|
||||
aria-label="Actions"
|
||||
color="default"
|
||||
variant="flat"
|
||||
>
|
||||
<DropdownSection title="Actions">
|
||||
<DropdownItem
|
||||
href={`http://localhost:3000/invitations/check-details?id=${invitationId}`}
|
||||
key="check-details"
|
||||
description="View invitation details"
|
||||
textValue="Check Details"
|
||||
startContent={<AddNoteBulkIcon className={iconClasses} />}
|
||||
>
|
||||
Check Details
|
||||
</DropdownItem>
|
||||
|
||||
<DropdownItem
|
||||
key="edit"
|
||||
description="Allows you to edit the invitation"
|
||||
textValue="Edit Invitation"
|
||||
startContent={<EditDocumentBulkIcon className={iconClasses} />}
|
||||
onClick={() => setIsEditOpen(true)}
|
||||
>
|
||||
Edit Invitation
|
||||
</DropdownItem>
|
||||
</DropdownSection>
|
||||
<DropdownSection title="Danger zone">
|
||||
<DropdownItem
|
||||
key="delete"
|
||||
className="text-danger"
|
||||
color="danger"
|
||||
description="Delete the invitation permanently"
|
||||
textValue="Delete Invitation"
|
||||
startContent={
|
||||
<DeleteDocumentBulkIcon
|
||||
className={clsx(iconClasses, "!text-danger")}
|
||||
/>
|
||||
}
|
||||
onClick={() => setIsDeleteOpen(true)}
|
||||
>
|
||||
Revoke Invitation
|
||||
</DropdownItem>
|
||||
</DropdownSection>
|
||||
</DropdownMenu>
|
||||
</Dropdown>
|
||||
</div>
|
||||
</>
|
||||
);
|
||||
}
|
||||
@@ -0,0 +1,3 @@
|
||||
export * from "./column-invitations";
|
||||
export * from "./data-table-row-actions";
|
||||
export * from "./skeleton-table-invitations";
|
||||
@@ -0,0 +1,59 @@
|
||||
import { Card, Skeleton } from "@nextui-org/react";
|
||||
import React from "react";
|
||||
|
||||
export const SkeletonTableInvitation = () => {
|
||||
return (
|
||||
<Card className="h-full w-full space-y-5 p-4" radius="sm">
|
||||
{/* Table headers */}
|
||||
<div className="hidden justify-between md:flex">
|
||||
<Skeleton className="w-2/12 rounded-lg">
|
||||
<div className="h-8 bg-default-200"></div>
|
||||
</Skeleton>
|
||||
<Skeleton className="w-2/12 rounded-lg">
|
||||
<div className="h-8 bg-default-200"></div>
|
||||
</Skeleton>
|
||||
<Skeleton className="w-2/12 rounded-lg">
|
||||
<div className="h-8 bg-default-200"></div>
|
||||
</Skeleton>
|
||||
<Skeleton className="w-2/12 rounded-lg">
|
||||
<div className="h-8 bg-default-200"></div>
|
||||
</Skeleton>
|
||||
<Skeleton className="w-2/12 rounded-lg">
|
||||
<div className="h-8 bg-default-200"></div>
|
||||
</Skeleton>
|
||||
<Skeleton className="w-1/12 rounded-lg">
|
||||
<div className="h-8 bg-default-200"></div>
|
||||
</Skeleton>
|
||||
</div>
|
||||
|
||||
{/* Table body */}
|
||||
<div className="space-y-3">
|
||||
{[...Array(10)].map((_, index) => (
|
||||
<div
|
||||
key={index}
|
||||
className="flex flex-col items-center justify-between space-x-0 md:flex-row md:space-x-4"
|
||||
>
|
||||
<Skeleton className="mb-2 w-full rounded-lg md:mb-0 md:w-2/12">
|
||||
<div className="h-12 bg-default-300"></div>
|
||||
</Skeleton>
|
||||
<Skeleton className="mb-2 w-full rounded-lg md:mb-0 md:w-2/12">
|
||||
<div className="h-12 bg-default-300"></div>
|
||||
</Skeleton>
|
||||
<Skeleton className="mb-2 hidden rounded-lg sm:flex md:mb-0 md:w-2/12">
|
||||
<div className="h-12 bg-default-300"></div>
|
||||
</Skeleton>
|
||||
<Skeleton className="mb-2 hidden rounded-lg sm:flex md:mb-0 md:w-2/12">
|
||||
<div className="h-12 bg-default-300"></div>
|
||||
</Skeleton>
|
||||
<Skeleton className="mb-2 hidden rounded-lg sm:flex md:mb-0 md:w-2/12">
|
||||
<div className="h-12 bg-default-300"></div>
|
||||
</Skeleton>
|
||||
<Skeleton className="mb-2 hidden rounded-lg sm:flex md:mb-0 md:w-1/12">
|
||||
<div className="h-12 bg-default-300"></div>
|
||||
</Skeleton>
|
||||
</div>
|
||||
))}
|
||||
</div>
|
||||
</Card>
|
||||
);
|
||||
};
|
||||
@@ -0,0 +1 @@
|
||||
export * from "./send-invitation-form";
|
||||
@@ -0,0 +1,107 @@
|
||||
"use client";
|
||||
|
||||
import { zodResolver } from "@hookform/resolvers/zod";
|
||||
import { SaveIcon } from "lucide-react";
|
||||
import { useRouter } from "next/navigation";
|
||||
import { useForm } from "react-hook-form";
|
||||
import * as z from "zod";
|
||||
|
||||
import { sendInvite } from "@/actions/invitations/invitation";
|
||||
import { useToast } from "@/components/ui";
|
||||
import { CustomButton, CustomInput } from "@/components/ui/custom";
|
||||
import { Form } from "@/components/ui/form";
|
||||
import { ApiError } from "@/types";
|
||||
|
||||
const sendInvitationFormSchema = z.object({
|
||||
email: z.string().email("Please enter a valid email"),
|
||||
});
|
||||
|
||||
export type FormValues = z.infer<typeof sendInvitationFormSchema>;
|
||||
|
||||
export const SendInvitationForm = () => {
|
||||
const { toast } = useToast();
|
||||
const router = useRouter();
|
||||
|
||||
const form = useForm<FormValues>({
|
||||
resolver: zodResolver(sendInvitationFormSchema),
|
||||
defaultValues: {
|
||||
email: "",
|
||||
},
|
||||
});
|
||||
|
||||
const isLoading = form.formState.isSubmitting;
|
||||
|
||||
const onSubmitClient = async (values: FormValues) => {
|
||||
const formData = new FormData();
|
||||
formData.append("email", values.email);
|
||||
|
||||
try {
|
||||
const data = await sendInvite(formData);
|
||||
|
||||
if (data?.errors && data.errors.length > 0) {
|
||||
data.errors.forEach((error: ApiError) => {
|
||||
const errorMessage = error.detail;
|
||||
switch (error.source.pointer) {
|
||||
case "/data/attributes/email":
|
||||
form.setError("email", {
|
||||
type: "server",
|
||||
message: errorMessage,
|
||||
});
|
||||
break;
|
||||
default:
|
||||
toast({
|
||||
variant: "destructive",
|
||||
title: "Oops! Something went wrong",
|
||||
description: errorMessage,
|
||||
});
|
||||
}
|
||||
});
|
||||
} else {
|
||||
const invitationId = data?.data?.id || "";
|
||||
router.push(`/invitations/check-details/?id=${invitationId}`);
|
||||
}
|
||||
} catch (error) {
|
||||
toast({
|
||||
variant: "destructive",
|
||||
title: "Error",
|
||||
description: "An unexpected error occurred. Please try again.",
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
return (
|
||||
<Form {...form}>
|
||||
<form
|
||||
onSubmit={form.handleSubmit(onSubmitClient)}
|
||||
className="flex flex-col space-y-4"
|
||||
>
|
||||
<CustomInput
|
||||
control={form.control}
|
||||
name="email"
|
||||
type="email"
|
||||
label="Email"
|
||||
labelPlacement="inside"
|
||||
placeholder="Enter the email address"
|
||||
variant="bordered"
|
||||
isRequired
|
||||
isInvalid={!!form.formState.errors.email}
|
||||
/>
|
||||
|
||||
<div className="flex w-full justify-end sm:space-x-6">
|
||||
<CustomButton
|
||||
type="submit"
|
||||
ariaLabel="Send Invitation"
|
||||
className="w-1/2"
|
||||
variant="solid"
|
||||
color="action"
|
||||
size="lg"
|
||||
isLoading={isLoading}
|
||||
startContent={!isLoading && <SaveIcon size={24} />}
|
||||
>
|
||||
{isLoading ? <>Loading</> : <span>Send Invitation</span>}
|
||||
</CustomButton>
|
||||
</div>
|
||||
</form>
|
||||
</Form>
|
||||
);
|
||||
};
|
||||
@@ -0,0 +1,3 @@
|
||||
export * from "./skeleton-invitation-info";
|
||||
export * from "./vertical-steps";
|
||||
export * from "./workflow-send-invite";
|
||||
@@ -0,0 +1,65 @@
|
||||
import { Card, Skeleton } from "@nextui-org/react";
|
||||
import React from "react";
|
||||
|
||||
export const SkeletonInvitationInfo = () => {
|
||||
return (
|
||||
<Card className="h-full w-full space-y-5 p-4" radius="sm">
|
||||
{/* Table headers */}
|
||||
<div className="hidden justify-between md:flex">
|
||||
<Skeleton className="w-1/12 rounded-lg">
|
||||
<div className="h-8 bg-default-200"></div>
|
||||
</Skeleton>
|
||||
<Skeleton className="w-2/12 rounded-lg">
|
||||
<div className="h-8 bg-default-200"></div>
|
||||
</Skeleton>
|
||||
<Skeleton className="w-2/12 rounded-lg">
|
||||
<div className="h-8 bg-default-200"></div>
|
||||
</Skeleton>
|
||||
<Skeleton className="w-2/12 rounded-lg">
|
||||
<div className="h-8 bg-default-200"></div>
|
||||
</Skeleton>
|
||||
<Skeleton className="w-2/12 rounded-lg">
|
||||
<div className="h-8 bg-default-200"></div>
|
||||
</Skeleton>
|
||||
<Skeleton className="w-1/12 rounded-lg">
|
||||
<div className="h-8 bg-default-200"></div>
|
||||
</Skeleton>
|
||||
<Skeleton className="w-1/12 rounded-lg">
|
||||
<div className="h-8 bg-default-200"></div>
|
||||
</Skeleton>
|
||||
</div>
|
||||
|
||||
{/* Table body */}
|
||||
<div className="space-y-3">
|
||||
{[...Array(3)].map((_, index) => (
|
||||
<div
|
||||
key={index}
|
||||
className="flex flex-col items-center justify-between space-x-0 md:flex-row md:space-x-4"
|
||||
>
|
||||
<Skeleton className="mb-2 w-full rounded-lg md:mb-0 md:w-1/12">
|
||||
<div className="h-12 bg-default-300"></div>
|
||||
</Skeleton>
|
||||
<Skeleton className="mb-2 w-full rounded-lg md:mb-0 md:w-2/12">
|
||||
<div className="h-12 bg-default-300"></div>
|
||||
</Skeleton>
|
||||
<Skeleton className="mb-2 hidden rounded-lg sm:flex md:mb-0 md:w-2/12">
|
||||
<div className="h-12 bg-default-300"></div>
|
||||
</Skeleton>
|
||||
<Skeleton className="mb-2 hidden rounded-lg sm:flex md:mb-0 md:w-2/12">
|
||||
<div className="h-12 bg-default-300"></div>
|
||||
</Skeleton>
|
||||
<Skeleton className="mb-2 hidden rounded-lg sm:flex md:mb-0 md:w-2/12">
|
||||
<div className="h-12 bg-default-300"></div>
|
||||
</Skeleton>
|
||||
<Skeleton className="mb-2 hidden rounded-lg sm:flex md:mb-0 md:w-1/12">
|
||||
<div className="h-12 bg-default-300"></div>
|
||||
</Skeleton>
|
||||
<Skeleton className="mb-2 hidden rounded-lg sm:flex md:mb-0 md:w-1/12">
|
||||
<div className="h-12 bg-default-300"></div>
|
||||
</Skeleton>
|
||||
</div>
|
||||
))}
|
||||
</div>
|
||||
</Card>
|
||||
);
|
||||
};
|
||||
@@ -0,0 +1,291 @@
|
||||
"use client";
|
||||
|
||||
import type { ButtonProps } from "@nextui-org/react";
|
||||
import { cn } from "@nextui-org/react";
|
||||
import { useControlledState } from "@react-stately/utils";
|
||||
import { domAnimation, LazyMotion, m } from "framer-motion";
|
||||
import type { ComponentProps } from "react";
|
||||
import React from "react";
|
||||
|
||||
export type VerticalStepProps = {
|
||||
className?: string;
|
||||
description?: React.ReactNode;
|
||||
title?: React.ReactNode;
|
||||
};
|
||||
|
||||
export interface VerticalStepsProps
|
||||
extends React.HTMLAttributes<HTMLButtonElement> {
|
||||
/**
|
||||
* An array of steps.
|
||||
*
|
||||
* @default []
|
||||
*/
|
||||
steps?: VerticalStepProps[];
|
||||
/**
|
||||
* The color of the steps.
|
||||
*
|
||||
* @default "primary"
|
||||
*/
|
||||
color?: ButtonProps["color"];
|
||||
/**
|
||||
* The current step index.
|
||||
*/
|
||||
currentStep?: number;
|
||||
/**
|
||||
* The default step index.
|
||||
*
|
||||
* @default 0
|
||||
*/
|
||||
defaultStep?: number;
|
||||
/**
|
||||
* Whether to hide the progress bars.
|
||||
*
|
||||
* @default false
|
||||
*/
|
||||
hideProgressBars?: boolean;
|
||||
/**
|
||||
* The custom class for the steps wrapper.
|
||||
*/
|
||||
className?: string;
|
||||
/**
|
||||
* The custom class for the step.
|
||||
*/
|
||||
stepClassName?: string;
|
||||
/**
|
||||
* Callback function when the step index changes.
|
||||
*/
|
||||
onStepChange?: (stepIndex: number) => void;
|
||||
}
|
||||
|
||||
function CheckIcon(props: ComponentProps<"svg">) {
|
||||
return (
|
||||
<svg
|
||||
{...props}
|
||||
fill="none"
|
||||
stroke="currentColor"
|
||||
strokeWidth={2}
|
||||
viewBox="0 0 24 24"
|
||||
>
|
||||
<m.path
|
||||
animate={{ pathLength: 1 }}
|
||||
d="M5 13l4 4L19 7"
|
||||
initial={{ pathLength: 0 }}
|
||||
strokeLinecap="round"
|
||||
strokeLinejoin="round"
|
||||
transition={{
|
||||
delay: 0.2,
|
||||
type: "tween",
|
||||
ease: "easeOut",
|
||||
duration: 0.3,
|
||||
}}
|
||||
/>
|
||||
</svg>
|
||||
);
|
||||
}
|
||||
|
||||
export const VerticalSteps = React.forwardRef<
|
||||
HTMLButtonElement,
|
||||
VerticalStepsProps
|
||||
>(
|
||||
(
|
||||
{
|
||||
color = "primary",
|
||||
steps = [],
|
||||
defaultStep = 0,
|
||||
onStepChange,
|
||||
currentStep: currentStepProp,
|
||||
hideProgressBars = false,
|
||||
stepClassName,
|
||||
className,
|
||||
...props
|
||||
},
|
||||
ref,
|
||||
) => {
|
||||
const [currentStep, setCurrentStep] = useControlledState(
|
||||
currentStepProp,
|
||||
defaultStep,
|
||||
onStepChange,
|
||||
);
|
||||
|
||||
const colors = React.useMemo(() => {
|
||||
let userColor;
|
||||
let fgColor;
|
||||
|
||||
const colorsVars = [
|
||||
"[--active-fg-color:var(--step-fg-color)]",
|
||||
"[--active-border-color:var(--step-color)]",
|
||||
"[--active-color:var(--step-color)]",
|
||||
"[--complete-background-color:var(--step-color)]",
|
||||
"[--complete-border-color:var(--step-color)]",
|
||||
"[--inactive-border-color:hsl(var(--nextui-default-300))]",
|
||||
"[--inactive-color:hsl(var(--nextui-default-300))]",
|
||||
];
|
||||
|
||||
switch (color) {
|
||||
case "primary":
|
||||
userColor = "[--step-color:hsl(var(--nextui-primary))]";
|
||||
fgColor = "[--step-fg-color:hsl(var(--nextui-primary-foreground))]";
|
||||
break;
|
||||
case "secondary":
|
||||
userColor = "[--step-color:hsl(var(--nextui-secondary))]";
|
||||
fgColor = "[--step-fg-color:hsl(var(--nextui-secondary-foreground))]";
|
||||
break;
|
||||
case "success":
|
||||
userColor = "[--step-color:hsl(var(--nextui-success))]";
|
||||
fgColor = "[--step-fg-color:hsl(var(--nextui-success-foreground))]";
|
||||
break;
|
||||
case "warning":
|
||||
userColor = "[--step-color:hsl(var(--nextui-warning))]";
|
||||
fgColor = "[--step-fg-color:hsl(var(--nextui-warning-foreground))]";
|
||||
break;
|
||||
case "danger":
|
||||
userColor = "[--step-color:hsl(var(--nextui-error))]";
|
||||
fgColor = "[--step-fg-color:hsl(var(--nextui-error-foreground))]";
|
||||
break;
|
||||
case "default":
|
||||
userColor = "[--step-color:hsl(var(--nextui-default))]";
|
||||
fgColor = "[--step-fg-color:hsl(var(--nextui-default-foreground))]";
|
||||
break;
|
||||
default:
|
||||
userColor = "[--step-color:hsl(var(--nextui-primary))]";
|
||||
fgColor = "[--step-fg-color:hsl(var(--nextui-primary-foreground))]";
|
||||
break;
|
||||
}
|
||||
|
||||
if (!className?.includes("--step-fg-color")) colorsVars.unshift(fgColor);
|
||||
if (!className?.includes("--step-color")) colorsVars.unshift(userColor);
|
||||
if (!className?.includes("--inactive-bar-color"))
|
||||
colorsVars.push(
|
||||
"[--inactive-bar-color:hsl(var(--nextui-default-300))]",
|
||||
);
|
||||
|
||||
return colorsVars;
|
||||
}, [color, className]);
|
||||
|
||||
return (
|
||||
<nav aria-label="Progress" className="max-w-fit">
|
||||
<ol className={cn("flex flex-col gap-y-3", colors, className)}>
|
||||
{steps?.map((step, stepIdx) => {
|
||||
const status =
|
||||
currentStep === stepIdx
|
||||
? "active"
|
||||
: currentStep < stepIdx
|
||||
? "inactive"
|
||||
: "complete";
|
||||
|
||||
return (
|
||||
<li key={stepIdx} className="relative">
|
||||
<div className="flex w-full max-w-full items-center">
|
||||
<button
|
||||
key={stepIdx}
|
||||
ref={ref}
|
||||
aria-current={status === "active" ? "step" : undefined}
|
||||
className={cn(
|
||||
"group flex w-full cursor-pointer items-center justify-center gap-4 rounded-large px-3 py-2.5",
|
||||
stepClassName,
|
||||
)}
|
||||
onClick={() => setCurrentStep(stepIdx)}
|
||||
{...props}
|
||||
>
|
||||
<div className="flex h-full items-center">
|
||||
<LazyMotion features={domAnimation}>
|
||||
<div className="relative">
|
||||
<m.div
|
||||
animate={status}
|
||||
className={cn(
|
||||
"relative flex h-[34px] w-[34px] items-center justify-center rounded-full border-medium text-large font-semibold text-default-foreground",
|
||||
{
|
||||
"shadow-lg": status === "complete",
|
||||
},
|
||||
)}
|
||||
data-status={status}
|
||||
initial={false}
|
||||
transition={{ duration: 0.25 }}
|
||||
variants={{
|
||||
inactive: {
|
||||
backgroundColor: "transparent",
|
||||
borderColor: "var(--inactive-border-color)",
|
||||
color: "var(--inactive-color)",
|
||||
},
|
||||
active: {
|
||||
backgroundColor: "transparent",
|
||||
borderColor: "var(--active-border-color)",
|
||||
color: "var(--active-color)",
|
||||
},
|
||||
complete: {
|
||||
backgroundColor:
|
||||
"var(--complete-background-color)",
|
||||
borderColor: "var(--complete-border-color)",
|
||||
},
|
||||
}}
|
||||
>
|
||||
<div className="flex items-center justify-center">
|
||||
{status === "complete" ? (
|
||||
<CheckIcon className="h-6 w-6 text-[var(--active-fg-color)]" />
|
||||
) : (
|
||||
<span>{stepIdx + 1}</span>
|
||||
)}
|
||||
</div>
|
||||
</m.div>
|
||||
</div>
|
||||
</LazyMotion>
|
||||
</div>
|
||||
<div className="flex-1 text-left">
|
||||
<div>
|
||||
<div
|
||||
className={cn(
|
||||
"text-medium font-medium text-default-foreground transition-[color,opacity] duration-300 group-active:opacity-70",
|
||||
{
|
||||
"text-default-500": status === "inactive",
|
||||
},
|
||||
)}
|
||||
>
|
||||
{step.title}
|
||||
</div>
|
||||
<div
|
||||
className={cn(
|
||||
"text-tiny text-default-600 transition-[color,opacity] duration-300 group-active:opacity-70 lg:text-small",
|
||||
{
|
||||
"text-default-500": status === "inactive",
|
||||
},
|
||||
)}
|
||||
>
|
||||
{step.description}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</button>
|
||||
</div>
|
||||
{stepIdx < steps.length - 1 && !hideProgressBars && (
|
||||
<div
|
||||
aria-hidden="true"
|
||||
className={cn(
|
||||
"pointer-events-none absolute left-3 top-[calc(64px_*_var(--idx)_+_1)] flex h-1/2 -translate-y-1/3 items-center px-4",
|
||||
)}
|
||||
style={{
|
||||
// eslint-disable-next-line @typescript-eslint/ban-ts-comment
|
||||
// @ts-expect-error
|
||||
"--idx": stepIdx,
|
||||
}}
|
||||
>
|
||||
<div
|
||||
className={cn(
|
||||
"relative h-full w-0.5 bg-[var(--inactive-bar-color)] transition-colors duration-300",
|
||||
"after:absolute after:block after:h-0 after:w-full after:bg-[var(--active-border-color)] after:transition-[height] after:duration-300 after:content-['']",
|
||||
{
|
||||
"after:h-full": stepIdx < currentStep,
|
||||
},
|
||||
)}
|
||||
/>
|
||||
</div>
|
||||
)}
|
||||
</li>
|
||||
);
|
||||
})}
|
||||
</ol>
|
||||
</nav>
|
||||
);
|
||||
},
|
||||
);
|
||||
|
||||
VerticalSteps.displayName = "VerticalSteps";
|
||||
@@ -0,0 +1,64 @@
|
||||
"use client";
|
||||
|
||||
import { Progress, Spacer } from "@nextui-org/react";
|
||||
import { usePathname } from "next/navigation";
|
||||
import React from "react";
|
||||
|
||||
import { VerticalSteps } from "./vertical-steps";
|
||||
|
||||
const steps = [
|
||||
{
|
||||
title: "Send Invitation",
|
||||
description:
|
||||
"Enter the email address of the person you want to invite and send the invitation.",
|
||||
href: "/invitations/new",
|
||||
},
|
||||
{
|
||||
title: "Review Invitation Details",
|
||||
description:
|
||||
"Review the invitation details and share the information required for the person to accept the invitation.",
|
||||
href: "/invitations/check-details",
|
||||
},
|
||||
];
|
||||
|
||||
export const WorkflowSendInvite = () => {
|
||||
const pathname = usePathname();
|
||||
|
||||
// Calculate current step based on pathname
|
||||
const currentStepIndex = steps.findIndex((step) =>
|
||||
pathname.endsWith(step.href),
|
||||
);
|
||||
const currentStep = currentStepIndex === -1 ? 0 : currentStepIndex;
|
||||
|
||||
return (
|
||||
<section className="max-w-sm">
|
||||
<h1 className="mb-2 text-xl font-medium" id="getting-started">
|
||||
Send invitation
|
||||
</h1>
|
||||
<p className="mb-5 text-small text-default-500">
|
||||
Follow the steps to send an invitation to the users.
|
||||
</p>
|
||||
<Progress
|
||||
classNames={{
|
||||
base: "px-0.5 mb-5",
|
||||
label: "text-small",
|
||||
value: "text-small text-default-400",
|
||||
}}
|
||||
label="Steps"
|
||||
maxValue={steps.length - 1}
|
||||
minValue={0}
|
||||
showValueLabel={true}
|
||||
size="md"
|
||||
value={currentStep}
|
||||
valueLabel={`${currentStep + 1} of ${steps.length}`}
|
||||
/>
|
||||
<VerticalSteps
|
||||
hideProgressBars
|
||||
currentStep={currentStep}
|
||||
stepClassName="border border-default-200 dark:border-default-50 aria-[current]:bg-default-100 dark:aria-[current]:bg-prowler-blue-800 cursor-default"
|
||||
steps={steps}
|
||||
/>
|
||||
<Spacer y={4} />
|
||||
</section>
|
||||
);
|
||||
};
|
||||
@@ -0,0 +1,44 @@
|
||||
import React from "react";
|
||||
|
||||
import { ActionCard } from "@/components/ui";
|
||||
|
||||
const cardData = [
|
||||
{
|
||||
findings: 3,
|
||||
title: "Internet Exposed Resources",
|
||||
},
|
||||
{
|
||||
findings: 15,
|
||||
title: "Exposed Secrets",
|
||||
},
|
||||
{
|
||||
findings: 0,
|
||||
title: "IAM Policies Leading to Privilege Escalation",
|
||||
},
|
||||
{
|
||||
findings: 0,
|
||||
title: "EC2 with Metadata Service V1 (IMDSv1)",
|
||||
},
|
||||
];
|
||||
|
||||
export const AttackSurface = () => {
|
||||
return (
|
||||
<div className="flex flex-col gap-2">
|
||||
{cardData.map((card, index) => (
|
||||
<ActionCard
|
||||
key={index}
|
||||
color={card.findings > 0 ? "fail" : "success"}
|
||||
icon={
|
||||
card.findings > 0
|
||||
? "solar:danger-triangle-bold"
|
||||
: "heroicons:shield-check-solid"
|
||||
}
|
||||
title={card.title}
|
||||
description={
|
||||
card.findings > 0 ? "Review Required" : "No Issues Found"
|
||||
}
|
||||
/>
|
||||
))}
|
||||
</div>
|
||||
);
|
||||
};
|
||||
@@ -0,0 +1,3 @@
|
||||
export * from "./AttackSurface";
|
||||
export * from "./provider-overview/provider-overview";
|
||||
export * from "./provider-overview/skeleton-provider-overview";
|
||||
@@ -0,0 +1,150 @@
|
||||
"use client";
|
||||
|
||||
import { Card, CardBody, CardHeader } from "@nextui-org/react";
|
||||
|
||||
import { AddIcon } from "@/components/icons/Icons";
|
||||
import {
|
||||
AWSProviderBadge,
|
||||
AzureProviderBadge,
|
||||
GCPProviderBadge,
|
||||
KS8ProviderBadge,
|
||||
} from "@/components/icons/providers-badge";
|
||||
import { CustomButton } from "@/components/ui/custom/custom-button";
|
||||
import { ProviderOverviewProps } from "@/types";
|
||||
|
||||
export const ProvidersOverview = ({
|
||||
providersOverview,
|
||||
}: {
|
||||
providersOverview: ProviderOverviewProps;
|
||||
}) => {
|
||||
console.log(providersOverview);
|
||||
if (!providersOverview || !Array.isArray(providersOverview.data)) {
|
||||
return <p>No provider data available</p>;
|
||||
}
|
||||
|
||||
const calculatePassingPercentage = (pass: number, total: number) =>
|
||||
total > 0 ? ((pass / total) * 100).toFixed(2) : "0.00";
|
||||
|
||||
const renderProviderBadge = (providerId: string) => {
|
||||
switch (providerId) {
|
||||
case "aws":
|
||||
return <AWSProviderBadge width={30} height={30} />;
|
||||
case "azure":
|
||||
return <AzureProviderBadge width={30} height={30} />;
|
||||
case "gcp":
|
||||
return <GCPProviderBadge width={30} height={30} />;
|
||||
case "kubernetes":
|
||||
return <KS8ProviderBadge width={30} height={30} />;
|
||||
default:
|
||||
return null;
|
||||
}
|
||||
};
|
||||
|
||||
const providers = [
|
||||
{ id: "aws", name: "AWS" },
|
||||
{ id: "azure", name: "Azure" },
|
||||
{ id: "gcp", name: "GCP" },
|
||||
{ id: "kubernetes", name: "Kubernetes" },
|
||||
];
|
||||
|
||||
return (
|
||||
<Card className="dark:bg-prowler-blue-400">
|
||||
<CardHeader>
|
||||
<h3 className="text-sm font-bold">Providers Overview</h3>
|
||||
</CardHeader>
|
||||
<CardBody>
|
||||
<div className="grid grid-cols-1 gap-3">
|
||||
<div className="grid grid-cols-4 border-b pb-2 text-xs font-semibold">
|
||||
<span className="text-center">Provider</span>
|
||||
<span className="flex flex-col items-center text-center">
|
||||
<span>Percent</span>
|
||||
<span>Passing</span>
|
||||
</span>
|
||||
<span className="flex flex-col items-center text-center">
|
||||
<span>Failing</span>
|
||||
<span>Checks</span>
|
||||
</span>
|
||||
<span className="flex flex-col items-center text-center">
|
||||
<span>Total</span>
|
||||
<span>Resources</span>
|
||||
</span>
|
||||
</div>
|
||||
|
||||
{providers.map((providerTemplate) => {
|
||||
const providerData = providersOverview.data.find(
|
||||
(p) => p.id === providerTemplate.id,
|
||||
);
|
||||
|
||||
return (
|
||||
<div
|
||||
key={providerTemplate.id}
|
||||
className="grid grid-cols-4 items-center border-b py-2 text-sm"
|
||||
>
|
||||
<span className="flex items-center justify-center px-4">
|
||||
{renderProviderBadge(providerTemplate.id)}
|
||||
</span>
|
||||
<span className="text-center">
|
||||
{providerData
|
||||
? calculatePassingPercentage(
|
||||
providerData.attributes.findings.pass,
|
||||
providerData.attributes.findings.total,
|
||||
)
|
||||
: "0.00"}
|
||||
%
|
||||
</span>
|
||||
<span className="text-center">
|
||||
{providerData ? providerData.attributes.findings.fail : "-"}
|
||||
</span>
|
||||
<span className="text-center">
|
||||
{providerData ? providerData.attributes.resources.total : "-"}
|
||||
</span>
|
||||
</div>
|
||||
);
|
||||
})}
|
||||
|
||||
{/* Totals row */}
|
||||
<div className="grid grid-cols-4 items-center border-b py-2 text-sm font-semibold">
|
||||
<span className="flex items-center justify-center px-4">Total</span>
|
||||
<span className="text-center">
|
||||
{calculatePassingPercentage(
|
||||
providersOverview.data.reduce(
|
||||
(sum, provider) => sum + provider.attributes.findings.pass,
|
||||
0,
|
||||
),
|
||||
providersOverview.data.reduce(
|
||||
(sum, provider) => sum + provider.attributes.findings.total,
|
||||
0,
|
||||
),
|
||||
)}
|
||||
%
|
||||
</span>
|
||||
<span className="text-center">
|
||||
{providersOverview.data.reduce(
|
||||
(sum, provider) => sum + provider.attributes.findings.fail,
|
||||
0,
|
||||
)}
|
||||
</span>
|
||||
<span className="text-center">
|
||||
{providersOverview.data.reduce(
|
||||
(sum, provider) => sum + provider.attributes.resources.total,
|
||||
0,
|
||||
)}
|
||||
</span>
|
||||
</div>
|
||||
</div>
|
||||
<div className="mt-4 flex w-full items-center justify-end">
|
||||
<CustomButton
|
||||
asLink="/providers/connect-account"
|
||||
ariaLabel="Go to Providers page"
|
||||
variant="solid"
|
||||
color="action"
|
||||
size="sm"
|
||||
endContent={<AddIcon size={20} />}
|
||||
>
|
||||
Add Provider
|
||||
</CustomButton>
|
||||
</div>
|
||||
</CardBody>
|
||||
</Card>
|
||||
);
|
||||
};
|
||||
@@ -0,0 +1,64 @@
|
||||
import { Card, CardBody, CardHeader, Skeleton } from "@nextui-org/react";
|
||||
|
||||
export const SkeletonProvidersOverview = () => {
|
||||
const rows = 4;
|
||||
|
||||
return (
|
||||
<Card>
|
||||
<CardHeader>
|
||||
<Skeleton className="h-6 w-1/3 rounded-lg">
|
||||
<div className="h-6 bg-default-200"></div>
|
||||
</Skeleton>
|
||||
</CardHeader>
|
||||
<CardBody>
|
||||
<div className="grid grid-cols-1 gap-4">
|
||||
{/* Header Skeleton */}
|
||||
<div className="grid grid-cols-4 border-b pb-2 text-sm font-semibold">
|
||||
<Skeleton className="h-5 w-full rounded-lg">
|
||||
<div className="h-5 bg-default-200"></div>
|
||||
</Skeleton>
|
||||
<Skeleton className="h-5 w-full rounded-lg">
|
||||
<div className="h-5 bg-default-200"></div>
|
||||
</Skeleton>
|
||||
<Skeleton className="h-5 w-full rounded-lg">
|
||||
<div className="h-5 bg-default-200"></div>
|
||||
</Skeleton>
|
||||
<Skeleton className="h-5 w-full rounded-lg">
|
||||
<div className="h-5 bg-default-200"></div>
|
||||
</Skeleton>
|
||||
</div>
|
||||
|
||||
{/* Row Skeletons */}
|
||||
{Array.from({ length: rows }).map((_, index) => (
|
||||
<div
|
||||
key={index}
|
||||
className="grid grid-cols-4 items-center border-b py-2 text-sm"
|
||||
>
|
||||
{/* Provider Name */}
|
||||
<div className="flex items-center space-x-2">
|
||||
<Skeleton className="h-5 w-5 rounded-lg">
|
||||
<div className="h-5 w-5 bg-default-200"></div>
|
||||
</Skeleton>
|
||||
<Skeleton className="h-5 w-1/3 rounded-lg">
|
||||
<div className="h-5 bg-default-200"></div>
|
||||
</Skeleton>
|
||||
</div>
|
||||
{/* Percent Passing */}
|
||||
<Skeleton className="h-5 w-1/4 rounded-lg">
|
||||
<div className="h-5 bg-default-200"></div>
|
||||
</Skeleton>
|
||||
{/* Failing Checks */}
|
||||
<Skeleton className="h-5 w-1/4 rounded-lg">
|
||||
<div className="h-5 bg-default-200"></div>
|
||||
</Skeleton>
|
||||
{/* Total Resources */}
|
||||
<Skeleton className="h-5 w-1/4 rounded-lg">
|
||||
<div className="h-5 bg-default-200"></div>
|
||||
</Skeleton>
|
||||
</div>
|
||||
))}
|
||||
</div>
|
||||
</CardBody>
|
||||
</Card>
|
||||
);
|
||||
};
|
||||
@@ -0,0 +1,53 @@
|
||||
import { tv } from "tailwind-variants";
|
||||
|
||||
export const title = tv({
|
||||
base: "tracking-tight inline font-semibold",
|
||||
variants: {
|
||||
color: {
|
||||
violet: "from-[#FF1CF7] to-[#b249f8]",
|
||||
yellow: "from-[#FF705B] to-[#FFB457]",
|
||||
blue: "from-[#5EA2EF] to-[#0072F5]",
|
||||
cyan: "from-[#00b7fa] to-[#01cfea]",
|
||||
green: "from-[#6FEE8D] to-[#17c964]",
|
||||
pink: "from-[#FF72E1] to-[#F54C7A]",
|
||||
foreground: "dark:from-[#FFFFFF] dark:to-[#4B4B4B]",
|
||||
},
|
||||
size: {
|
||||
sm: "text-3xl lg:text-4xl",
|
||||
md: "text-[2.3rem] lg:text-5xl leading-9",
|
||||
lg: "text-4xl lg:text-6xl",
|
||||
},
|
||||
fullWidth: {
|
||||
true: "w-full block",
|
||||
},
|
||||
},
|
||||
defaultVariants: {
|
||||
size: "md",
|
||||
},
|
||||
compoundVariants: [
|
||||
{
|
||||
color: [
|
||||
"violet",
|
||||
"yellow",
|
||||
"blue",
|
||||
"cyan",
|
||||
"green",
|
||||
"pink",
|
||||
"foreground",
|
||||
],
|
||||
class: "bg-clip-text text-transparent bg-gradient-to-b",
|
||||
},
|
||||
],
|
||||
});
|
||||
|
||||
export const subtitle = tv({
|
||||
base: "w-full md:w-1/2 my-2 text-lg lg:text-xl text-default-600 block max-w-full",
|
||||
variants: {
|
||||
fullWidth: {
|
||||
true: "!w-full",
|
||||
},
|
||||
},
|
||||
defaultVariants: {
|
||||
fullWidth: true,
|
||||
},
|
||||
});
|
||||
@@ -0,0 +1,21 @@
|
||||
"use client";
|
||||
|
||||
import { AddIcon } from "../icons";
|
||||
import { CustomButton } from "../ui/custom";
|
||||
|
||||
export const AddProvider = () => {
|
||||
return (
|
||||
<div className="flex w-full items-center justify-end">
|
||||
<CustomButton
|
||||
asLink="/providers/connect-account"
|
||||
ariaLabel="Add Account"
|
||||
variant="solid"
|
||||
color="action"
|
||||
size="md"
|
||||
endContent={<AddIcon size={20} />}
|
||||
>
|
||||
Add Account
|
||||
</CustomButton>
|
||||
</div>
|
||||
);
|
||||
};
|
||||
@@ -0,0 +1,87 @@
|
||||
"use client";
|
||||
|
||||
import { zodResolver } from "@hookform/resolvers/zod";
|
||||
import React, { Dispatch, SetStateAction } from "react";
|
||||
import { useForm } from "react-hook-form";
|
||||
import * as z from "zod";
|
||||
|
||||
import { deleteProvider } from "@/actions/providers";
|
||||
import { DeleteIcon } from "@/components/icons";
|
||||
import { useToast } from "@/components/ui";
|
||||
import { CustomButton } from "@/components/ui/custom";
|
||||
import { Form } from "@/components/ui/form";
|
||||
|
||||
const formSchema = z.object({
|
||||
providerId: z.string(),
|
||||
});
|
||||
|
||||
export const DeleteForm = ({
|
||||
providerId,
|
||||
setIsOpen,
|
||||
}: {
|
||||
providerId: string;
|
||||
setIsOpen: Dispatch<SetStateAction<boolean>>;
|
||||
}) => {
|
||||
const form = useForm<z.infer<typeof formSchema>>({
|
||||
resolver: zodResolver(formSchema),
|
||||
});
|
||||
const { toast } = useToast();
|
||||
const isLoading = form.formState.isSubmitting;
|
||||
|
||||
async function onSubmitClient(formData: FormData) {
|
||||
// client-side validation
|
||||
const data = await deleteProvider(formData);
|
||||
|
||||
if (data?.errors && data.errors.length > 0) {
|
||||
const error = data.errors[0];
|
||||
const errorMessage = `${error.detail}`;
|
||||
// show error
|
||||
toast({
|
||||
variant: "destructive",
|
||||
title: "Oops! Something went wrong",
|
||||
description: errorMessage,
|
||||
});
|
||||
} else {
|
||||
toast({
|
||||
title: "Success!",
|
||||
description: "The provider was removed successfully.",
|
||||
});
|
||||
}
|
||||
setIsOpen(false); // Close the modal on success
|
||||
}
|
||||
|
||||
return (
|
||||
<Form {...form}>
|
||||
<form action={onSubmitClient}>
|
||||
<input type="hidden" name="id" value={providerId} />
|
||||
<div className="flex w-full justify-center sm:space-x-6">
|
||||
<CustomButton
|
||||
type="button"
|
||||
ariaLabel="Cancel"
|
||||
className="w-full bg-transparent"
|
||||
variant="faded"
|
||||
size="lg"
|
||||
radius="lg"
|
||||
onPress={() => setIsOpen(false)}
|
||||
isDisabled={isLoading}
|
||||
>
|
||||
<span>Cancel</span>
|
||||
</CustomButton>
|
||||
|
||||
<CustomButton
|
||||
type="submit"
|
||||
ariaLabel="Delete"
|
||||
className="w-full"
|
||||
variant="solid"
|
||||
color="danger"
|
||||
size="lg"
|
||||
isLoading={isLoading}
|
||||
startContent={!isLoading && <DeleteIcon size={24} />}
|
||||
>
|
||||
{isLoading ? <>Loading</> : <span>Delete</span>}
|
||||
</CustomButton>
|
||||
</div>
|
||||
</form>
|
||||
</Form>
|
||||
);
|
||||
};
|
||||
@@ -0,0 +1,119 @@
|
||||
"use client";
|
||||
|
||||
import { zodResolver } from "@hookform/resolvers/zod";
|
||||
import { Dispatch, SetStateAction } from "react";
|
||||
import { useForm } from "react-hook-form";
|
||||
import * as z from "zod";
|
||||
|
||||
import { updateProvider } from "@/actions/providers";
|
||||
import { SaveIcon } from "@/components/icons";
|
||||
import { useToast } from "@/components/ui";
|
||||
import { CustomButton, CustomInput } from "@/components/ui/custom";
|
||||
import { Form } from "@/components/ui/form";
|
||||
import { editProviderFormSchema } from "@/types";
|
||||
|
||||
export const EditForm = ({
|
||||
providerId,
|
||||
providerAlias,
|
||||
setIsOpen,
|
||||
}: {
|
||||
providerId: string;
|
||||
providerAlias?: string;
|
||||
setIsOpen: Dispatch<SetStateAction<boolean>>;
|
||||
}) => {
|
||||
const formSchema = editProviderFormSchema(providerAlias ?? "");
|
||||
|
||||
const form = useForm<z.infer<typeof formSchema>>({
|
||||
resolver: zodResolver(formSchema),
|
||||
defaultValues: {
|
||||
providerId: providerId,
|
||||
alias: providerAlias,
|
||||
},
|
||||
});
|
||||
|
||||
const { toast } = useToast();
|
||||
|
||||
const isLoading = form.formState.isSubmitting;
|
||||
|
||||
const onSubmitClient = async (values: z.infer<typeof formSchema>) => {
|
||||
const formData = new FormData();
|
||||
|
||||
Object.entries(values).forEach(
|
||||
([key, value]) => value !== undefined && formData.append(key, value),
|
||||
);
|
||||
|
||||
const data = await updateProvider(formData);
|
||||
|
||||
if (data?.errors && data.errors.length > 0) {
|
||||
const error = data.errors[0];
|
||||
const errorMessage = `${error.detail}`;
|
||||
// show error
|
||||
toast({
|
||||
variant: "destructive",
|
||||
title: "Oops! Something went wrong",
|
||||
description: errorMessage,
|
||||
});
|
||||
} else {
|
||||
toast({
|
||||
title: "Success!",
|
||||
description: "The provider was updated successfully.",
|
||||
});
|
||||
setIsOpen(false); // Close the modal on success
|
||||
}
|
||||
};
|
||||
|
||||
return (
|
||||
<Form {...form}>
|
||||
<form
|
||||
onSubmit={form.handleSubmit(onSubmitClient)}
|
||||
className="flex flex-col space-y-4"
|
||||
>
|
||||
<div className="text-md">
|
||||
Current alias: <span className="font-bold">{providerAlias}</span>
|
||||
</div>
|
||||
<div>
|
||||
<CustomInput
|
||||
control={form.control}
|
||||
name="alias"
|
||||
type="text"
|
||||
label="Alias"
|
||||
labelPlacement="outside"
|
||||
placeholder={providerAlias}
|
||||
variant="bordered"
|
||||
isRequired={false}
|
||||
isInvalid={!!form.formState.errors.alias}
|
||||
/>
|
||||
</div>
|
||||
<input type="hidden" name="providerId" value={providerId} />
|
||||
|
||||
<div className="flex w-full justify-center sm:space-x-6">
|
||||
<CustomButton
|
||||
type="button"
|
||||
ariaLabel="Cancel"
|
||||
className="w-full bg-transparent"
|
||||
variant="faded"
|
||||
size="lg"
|
||||
radius="lg"
|
||||
onPress={() => setIsOpen(false)}
|
||||
isDisabled={isLoading}
|
||||
>
|
||||
<span>Cancel</span>
|
||||
</CustomButton>
|
||||
|
||||
<CustomButton
|
||||
type="submit"
|
||||
ariaLabel="Save"
|
||||
className="w-full"
|
||||
variant="solid"
|
||||
color="action"
|
||||
size="lg"
|
||||
isLoading={isLoading}
|
||||
startContent={!isLoading && <SaveIcon size={24} />}
|
||||
>
|
||||
{isLoading ? <>Loading</> : <span>Save</span>}
|
||||
</CustomButton>
|
||||
</div>
|
||||
</form>
|
||||
</Form>
|
||||
);
|
||||
};
|
||||
@@ -0,0 +1,2 @@
|
||||
export * from "./delete-form";
|
||||
export * from "./edit-form";
|
||||
@@ -0,0 +1,4 @@
|
||||
export * from "./add-provider";
|
||||
export * from "./forms/delete-form";
|
||||
export * from "./provider-info";
|
||||
export * from "./radio-group-provider";
|
||||
@@ -0,0 +1,78 @@
|
||||
import React from "react";
|
||||
|
||||
import { ConnectionFalse, ConnectionPending, ConnectionTrue } from "../icons";
|
||||
import {
|
||||
AWSProviderBadge,
|
||||
AzureProviderBadge,
|
||||
GCPProviderBadge,
|
||||
KS8ProviderBadge,
|
||||
} from "../icons/providers-badge";
|
||||
|
||||
interface ProviderInfoProps {
|
||||
connected: boolean | null;
|
||||
provider: "aws" | "azure" | "gcp" | "kubernetes";
|
||||
providerAlias: string;
|
||||
}
|
||||
|
||||
export const ProviderInfo: React.FC<ProviderInfoProps> = ({
|
||||
connected,
|
||||
provider,
|
||||
providerAlias,
|
||||
}) => {
|
||||
const getIcon = () => {
|
||||
switch (connected) {
|
||||
case true:
|
||||
return (
|
||||
<div className="flex items-center justify-center rounded-medium border-2 border-system-success bg-system-success-lighter p-1">
|
||||
<ConnectionTrue className="text-system-success" size={24} />
|
||||
</div>
|
||||
);
|
||||
case false:
|
||||
return (
|
||||
<div className="flex items-center justify-center rounded-medium border-2 border-danger bg-system-error-lighter p-1">
|
||||
<ConnectionFalse className="text-danger" size={24} />
|
||||
</div>
|
||||
);
|
||||
case null:
|
||||
return (
|
||||
<div className="bg-info-lighter border-info-lighter flex items-center justify-center rounded-medium border p-1">
|
||||
<ConnectionPending className="text-info" size={24} />
|
||||
</div>
|
||||
);
|
||||
default:
|
||||
return <ConnectionPending size={24} />;
|
||||
}
|
||||
};
|
||||
|
||||
const getProviderLogo = () => {
|
||||
switch (provider) {
|
||||
case "aws":
|
||||
return <AWSProviderBadge width={35} height={35} />;
|
||||
case "azure":
|
||||
return <AzureProviderBadge width={35} height={35} />;
|
||||
case "gcp":
|
||||
return <GCPProviderBadge width={35} height={35} />;
|
||||
case "kubernetes":
|
||||
return <KS8ProviderBadge width={35} height={35} />;
|
||||
default:
|
||||
return null;
|
||||
}
|
||||
};
|
||||
|
||||
return (
|
||||
<div className="max-w-48">
|
||||
<div className="flex items-center justify-between space-x-4">
|
||||
<div className="flex items-center space-x-4">
|
||||
<div className="flex-shrink-0">{getProviderLogo()}</div>
|
||||
<div className="flex-shrink-0">{getIcon()}</div>
|
||||
<div className="flex flex-col">
|
||||
<span className="text-md max-w-24 overflow-hidden text-ellipsis font-semibold lg:max-w-36">
|
||||
{providerAlias}
|
||||
</span>
|
||||
{/* <CustomLoader size="small" /> */}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
};
|
||||
@@ -0,0 +1,75 @@
|
||||
"use client";
|
||||
|
||||
import { RadioGroup } from "@nextui-org/react";
|
||||
import React from "react";
|
||||
import { Control, Controller } from "react-hook-form";
|
||||
import { z } from "zod";
|
||||
|
||||
import { addProviderFormSchema } from "@/types";
|
||||
|
||||
import { AWSProviderBadge, AzureProviderBadge } from "../icons/providers-badge";
|
||||
import { GCPProviderBadge } from "../icons/providers-badge/GCPProviderBadge";
|
||||
import { KS8ProviderBadge } from "../icons/providers-badge/KS8ProviderBadge";
|
||||
import { CustomRadio } from "../ui/custom";
|
||||
import { FormMessage } from "../ui/form";
|
||||
|
||||
interface RadioGroupProviderProps {
|
||||
control: Control<z.infer<typeof addProviderFormSchema>>;
|
||||
isInvalid: boolean;
|
||||
errorMessage?: string;
|
||||
}
|
||||
|
||||
export const RadioGroupProvider: React.FC<RadioGroupProviderProps> = ({
|
||||
control,
|
||||
isInvalid,
|
||||
errorMessage,
|
||||
}) => {
|
||||
return (
|
||||
<Controller
|
||||
name="providerType"
|
||||
control={control}
|
||||
render={({ field }) => (
|
||||
<>
|
||||
<RadioGroup
|
||||
className="flex flex-wrap"
|
||||
isInvalid={isInvalid}
|
||||
{...field}
|
||||
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="Kubernetes" value="kubernetes">
|
||||
<div className="flex items-center">
|
||||
<KS8ProviderBadge size={26} />
|
||||
<span className="ml-2">Kubernetes</span>
|
||||
</div>
|
||||
</CustomRadio>
|
||||
</div>
|
||||
</RadioGroup>
|
||||
{errorMessage && (
|
||||
<FormMessage className="text-system-error dark:text-system-error">
|
||||
{errorMessage}
|
||||
</FormMessage>
|
||||
)}
|
||||
</>
|
||||
)}
|
||||
/>
|
||||
);
|
||||
};
|
||||
@@ -0,0 +1,97 @@
|
||||
"use client";
|
||||
|
||||
import { ColumnDef } from "@tanstack/react-table";
|
||||
|
||||
import { DateWithTime, SnippetId } from "@/components/ui/entities";
|
||||
import { DataTableColumnHeader, StatusBadge } from "@/components/ui/table";
|
||||
import { ProviderProps } from "@/types";
|
||||
|
||||
import { ProviderInfo } from "../provider-info";
|
||||
import { DataTableRowActions } from "./data-table-row-actions";
|
||||
|
||||
const getProviderData = (row: { original: ProviderProps }) => {
|
||||
return row.original;
|
||||
};
|
||||
|
||||
export const ColumnProviders: ColumnDef<ProviderProps>[] = [
|
||||
// {
|
||||
// header: " ",
|
||||
// cell: ({ row }) => <p className="text-medium">{row.index + 1}</p>,
|
||||
// },
|
||||
{
|
||||
accessorKey: "account",
|
||||
header: ({ column }) => (
|
||||
<DataTableColumnHeader column={column} title={"Account"} param="alias" />
|
||||
),
|
||||
cell: ({ row }) => {
|
||||
const {
|
||||
attributes: { connection, provider, alias },
|
||||
} = getProviderData(row);
|
||||
return (
|
||||
<ProviderInfo
|
||||
connected={connection.connected}
|
||||
provider={provider}
|
||||
providerAlias={alias}
|
||||
/>
|
||||
);
|
||||
},
|
||||
},
|
||||
{
|
||||
accessorKey: "uid",
|
||||
header: ({ column }) => (
|
||||
<DataTableColumnHeader column={column} title={"Id"} param="uid" />
|
||||
),
|
||||
cell: ({ row }) => {
|
||||
const {
|
||||
attributes: { uid },
|
||||
} = getProviderData(row);
|
||||
return <SnippetId className="h-7 max-w-48" entityId={uid} />;
|
||||
},
|
||||
},
|
||||
{
|
||||
accessorKey: "status",
|
||||
header: "Scan Status",
|
||||
cell: () => {
|
||||
// Temporarily overwriting the value until the API is functional.
|
||||
return <StatusBadge status={"completed"} />;
|
||||
},
|
||||
},
|
||||
{
|
||||
accessorKey: "lastScan",
|
||||
header: ({ column }) => (
|
||||
<DataTableColumnHeader
|
||||
column={column}
|
||||
title={"Last Scan"}
|
||||
param="updated_at"
|
||||
/>
|
||||
),
|
||||
cell: ({ row }) => {
|
||||
const {
|
||||
attributes: { updated_at },
|
||||
} = getProviderData(row);
|
||||
return <DateWithTime dateTime={updated_at} />;
|
||||
},
|
||||
},
|
||||
{
|
||||
accessorKey: "added",
|
||||
header: ({ column }) => (
|
||||
<DataTableColumnHeader
|
||||
column={column}
|
||||
title={"Added"}
|
||||
param="inserted_at"
|
||||
/>
|
||||
),
|
||||
cell: ({ row }) => {
|
||||
const {
|
||||
attributes: { inserted_at },
|
||||
} = getProviderData(row);
|
||||
return <DateWithTime dateTime={inserted_at} showTime={false} />;
|
||||
},
|
||||
},
|
||||
{
|
||||
id: "actions",
|
||||
cell: ({ row }) => {
|
||||
return <DataTableRowActions row={row} />;
|
||||
},
|
||||
},
|
||||
];
|
||||
@@ -0,0 +1,121 @@
|
||||
"use client";
|
||||
|
||||
import {
|
||||
Button,
|
||||
Dropdown,
|
||||
DropdownItem,
|
||||
DropdownMenu,
|
||||
DropdownSection,
|
||||
DropdownTrigger,
|
||||
} from "@nextui-org/react";
|
||||
import {
|
||||
AddNoteBulkIcon,
|
||||
DeleteDocumentBulkIcon,
|
||||
EditDocumentBulkIcon,
|
||||
} from "@nextui-org/shared-icons";
|
||||
import { Row } from "@tanstack/react-table";
|
||||
import clsx from "clsx";
|
||||
import { useState } from "react";
|
||||
|
||||
import { VerticalDotsIcon } from "@/components/icons";
|
||||
import { CustomAlertModal } from "@/components/ui/custom";
|
||||
|
||||
import { EditForm } from "../forms";
|
||||
import { DeleteForm } from "../forms/delete-form";
|
||||
|
||||
interface DataTableRowActionsProps<ProviderProps> {
|
||||
row: Row<ProviderProps>;
|
||||
}
|
||||
const iconClasses =
|
||||
"text-2xl text-default-500 pointer-events-none flex-shrink-0";
|
||||
|
||||
export function DataTableRowActions<ProviderProps>({
|
||||
row,
|
||||
}: DataTableRowActionsProps<ProviderProps>) {
|
||||
const [isEditOpen, setIsEditOpen] = useState(false);
|
||||
const [isDeleteOpen, setIsDeleteOpen] = useState(false);
|
||||
const providerId = (row.original as { id: string }).id;
|
||||
const providerType = (row.original as any).attributes?.provider;
|
||||
const providerAlias = (row.original as any).attributes?.alias;
|
||||
return (
|
||||
<>
|
||||
<CustomAlertModal
|
||||
isOpen={isEditOpen}
|
||||
onOpenChange={setIsEditOpen}
|
||||
title="Edit Provider"
|
||||
description={"Edit the provider details"}
|
||||
>
|
||||
<EditForm
|
||||
providerId={providerId}
|
||||
providerAlias={providerAlias}
|
||||
setIsOpen={setIsEditOpen}
|
||||
/>
|
||||
</CustomAlertModal>
|
||||
<CustomAlertModal
|
||||
isOpen={isDeleteOpen}
|
||||
onOpenChange={setIsDeleteOpen}
|
||||
title="Are you absolutely sure?"
|
||||
description="This action cannot be undone. This will permanently delete your provider account and remove your data from the server."
|
||||
>
|
||||
<DeleteForm providerId={providerId} setIsOpen={setIsDeleteOpen} />
|
||||
</CustomAlertModal>
|
||||
|
||||
<div className="relative flex items-center justify-end gap-2">
|
||||
<Dropdown
|
||||
className="shadow-xl dark:bg-prowler-blue-800"
|
||||
placement="bottom"
|
||||
>
|
||||
<DropdownTrigger>
|
||||
<Button isIconOnly radius="full" size="sm" variant="light">
|
||||
<VerticalDotsIcon className="text-default-400" />
|
||||
</Button>
|
||||
</DropdownTrigger>
|
||||
<DropdownMenu
|
||||
closeOnSelect
|
||||
aria-label="Actions"
|
||||
color="default"
|
||||
variant="flat"
|
||||
>
|
||||
<DropdownSection title="Actions">
|
||||
<DropdownItem
|
||||
href={`/providers/test-connection?type=${providerType}&id=${providerId}`}
|
||||
key="new"
|
||||
description="Check the connection to the provider"
|
||||
textValue="Check Connection"
|
||||
startContent={<AddNoteBulkIcon className={iconClasses} />}
|
||||
>
|
||||
Test Connection
|
||||
</DropdownItem>
|
||||
<DropdownItem
|
||||
key="edit"
|
||||
description="Allows you to edit the provider"
|
||||
textValue="Edit Provider"
|
||||
startContent={<EditDocumentBulkIcon className={iconClasses} />}
|
||||
onClick={() => setIsEditOpen(true)}
|
||||
>
|
||||
Edit Provider
|
||||
</DropdownItem>
|
||||
</DropdownSection>
|
||||
<DropdownSection title="Danger zone">
|
||||
<DropdownItem
|
||||
key="delete"
|
||||
className="text-danger"
|
||||
color="danger"
|
||||
description="Delete the provider permanently"
|
||||
textValue="Delete Provider"
|
||||
startContent={
|
||||
<DeleteDocumentBulkIcon
|
||||
className={clsx(iconClasses, "!text-danger")}
|
||||
/>
|
||||
}
|
||||
onClick={() => setIsDeleteOpen(true)}
|
||||
>
|
||||
Delete Provider
|
||||
</DropdownItem>
|
||||
</DropdownSection>
|
||||
</DropdownMenu>
|
||||
</Dropdown>
|
||||
</div>
|
||||
</>
|
||||
);
|
||||
}
|
||||
@@ -0,0 +1,3 @@
|
||||
export * from "./column-providers";
|
||||
export * from "./data-table-row-actions";
|
||||
export * from "./skeleton-table-provider";
|
||||
@@ -0,0 +1,65 @@
|
||||
import { Card, Skeleton } from "@nextui-org/react";
|
||||
import React from "react";
|
||||
|
||||
export const SkeletonTableProviders = () => {
|
||||
return (
|
||||
<Card className="h-full w-full space-y-5 p-4" radius="sm">
|
||||
{/* Table headers */}
|
||||
<div className="hidden justify-between md:flex">
|
||||
<Skeleton className="w-1/12 rounded-lg">
|
||||
<div className="h-8 bg-default-200"></div>
|
||||
</Skeleton>
|
||||
<Skeleton className="w-2/12 rounded-lg">
|
||||
<div className="h-8 bg-default-200"></div>
|
||||
</Skeleton>
|
||||
<Skeleton className="w-2/12 rounded-lg">
|
||||
<div className="h-8 bg-default-200"></div>
|
||||
</Skeleton>
|
||||
<Skeleton className="w-2/12 rounded-lg">
|
||||
<div className="h-8 bg-default-200"></div>
|
||||
</Skeleton>
|
||||
<Skeleton className="w-2/12 rounded-lg">
|
||||
<div className="h-8 bg-default-200"></div>
|
||||
</Skeleton>
|
||||
<Skeleton className="w-1/12 rounded-lg">
|
||||
<div className="h-8 bg-default-200"></div>
|
||||
</Skeleton>
|
||||
<Skeleton className="w-1/12 rounded-lg">
|
||||
<div className="h-8 bg-default-200"></div>
|
||||
</Skeleton>
|
||||
</div>
|
||||
|
||||
{/* Table body */}
|
||||
<div className="space-y-3">
|
||||
{[...Array(3)].map((_, index) => (
|
||||
<div
|
||||
key={index}
|
||||
className="flex flex-col items-center justify-between space-x-0 md:flex-row md:space-x-4"
|
||||
>
|
||||
<Skeleton className="mb-2 w-full rounded-lg md:mb-0 md:w-1/12">
|
||||
<div className="h-12 bg-default-300"></div>
|
||||
</Skeleton>
|
||||
<Skeleton className="mb-2 w-full rounded-lg md:mb-0 md:w-2/12">
|
||||
<div className="h-12 bg-default-300"></div>
|
||||
</Skeleton>
|
||||
<Skeleton className="mb-2 hidden rounded-lg sm:flex md:mb-0 md:w-2/12">
|
||||
<div className="h-12 bg-default-300"></div>
|
||||
</Skeleton>
|
||||
<Skeleton className="mb-2 hidden rounded-lg sm:flex md:mb-0 md:w-2/12">
|
||||
<div className="h-12 bg-default-300"></div>
|
||||
</Skeleton>
|
||||
<Skeleton className="mb-2 hidden rounded-lg sm:flex md:mb-0 md:w-2/12">
|
||||
<div className="h-12 bg-default-300"></div>
|
||||
</Skeleton>
|
||||
<Skeleton className="mb-2 hidden rounded-lg sm:flex md:mb-0 md:w-1/12">
|
||||
<div className="h-12 bg-default-300"></div>
|
||||
</Skeleton>
|
||||
<Skeleton className="mb-2 hidden rounded-lg sm:flex md:mb-0 md:w-1/12">
|
||||
<div className="h-12 bg-default-300"></div>
|
||||
</Skeleton>
|
||||
</div>
|
||||
))}
|
||||
</div>
|
||||
</Card>
|
||||
);
|
||||
};
|
||||
@@ -0,0 +1,226 @@
|
||||
"use client";
|
||||
|
||||
import { zodResolver } from "@hookform/resolvers/zod";
|
||||
import { ChevronLeftIcon, ChevronRightIcon, SaveIcon } from "lucide-react";
|
||||
import { useRouter } from "next/navigation";
|
||||
import { useState } from "react";
|
||||
import { useForm } from "react-hook-form";
|
||||
import * as z from "zod";
|
||||
|
||||
import { useToast } from "@/components/ui";
|
||||
import { CustomButton, CustomInput } from "@/components/ui/custom";
|
||||
import { Form } from "@/components/ui/form";
|
||||
|
||||
import { addProvider } from "../../../../actions/providers/providers";
|
||||
import { addProviderFormSchema, ApiError } from "../../../../types";
|
||||
import { RadioGroupProvider } from "../../radio-group-provider";
|
||||
import { RadioGroupAWSViaCredentialsForm } from "./radio-group-aws-via-credentials-form";
|
||||
|
||||
export type FormValues = z.infer<typeof addProviderFormSchema>;
|
||||
|
||||
export const ConnectAccountForm = () => {
|
||||
const { toast } = useToast();
|
||||
const [prevStep, setPrevStep] = useState(1);
|
||||
const router = useRouter();
|
||||
|
||||
const formSchema = addProviderFormSchema;
|
||||
|
||||
const form = useForm<FormValues>({
|
||||
resolver: zodResolver(formSchema),
|
||||
defaultValues: {
|
||||
providerType: undefined,
|
||||
providerUid: "",
|
||||
providerAlias: "",
|
||||
awsCredentialsType: "",
|
||||
},
|
||||
});
|
||||
const providerType = form.watch("providerType");
|
||||
const isLoading = form.formState.isSubmitting;
|
||||
|
||||
const onSubmitClient = async (values: FormValues) => {
|
||||
const formValues = { ...values };
|
||||
|
||||
// If providerAlias is empty, set default value
|
||||
if (!formValues.providerAlias.trim()) {
|
||||
const date = new Date();
|
||||
const month = (date.getMonth() + 1).toString().padStart(2, "0");
|
||||
const day = date.getDate().toString().padStart(2, "0");
|
||||
const year = date.getFullYear();
|
||||
formValues.providerAlias = `${formValues.providerType}:${month}/${day}/${year}`;
|
||||
}
|
||||
|
||||
const formData = new FormData();
|
||||
|
||||
Object.entries(formValues).forEach(
|
||||
([key, value]) => value !== undefined && formData.append(key, value),
|
||||
);
|
||||
|
||||
const data = await addProvider(formData);
|
||||
|
||||
if (data?.errors && data.errors.length > 0) {
|
||||
data.errors.forEach((error: ApiError) => {
|
||||
const errorMessage = error.detail;
|
||||
const pointer = error.source?.pointer;
|
||||
|
||||
switch (pointer) {
|
||||
case "/data/attributes/provider":
|
||||
form.setError("providerType", {
|
||||
type: "server",
|
||||
message: errorMessage,
|
||||
});
|
||||
break;
|
||||
case "/data/attributes/uid":
|
||||
case "/data/attributes/__all__":
|
||||
form.setError("providerUid", {
|
||||
type: "server",
|
||||
message: errorMessage,
|
||||
});
|
||||
break;
|
||||
case "/data/attributes/alias":
|
||||
form.setError("providerAlias", {
|
||||
type: "server",
|
||||
message: errorMessage,
|
||||
});
|
||||
break;
|
||||
default:
|
||||
toast({
|
||||
variant: "destructive",
|
||||
title: "Oops! Something went wrong",
|
||||
description: errorMessage,
|
||||
});
|
||||
}
|
||||
});
|
||||
setPrevStep(1);
|
||||
} else {
|
||||
const {
|
||||
id,
|
||||
attributes: { provider: providerType },
|
||||
} = data.data;
|
||||
const credentialsParam = values.awsCredentialsType
|
||||
? `&via=${values.awsCredentialsType}`
|
||||
: "";
|
||||
router.push(
|
||||
`/providers/add-credentials?type=${providerType}&id=${id}${credentialsParam}`,
|
||||
);
|
||||
}
|
||||
};
|
||||
|
||||
const handleNextStep = () => {
|
||||
setPrevStep((prev) => prev + 1);
|
||||
};
|
||||
|
||||
const handleBackStep = () => {
|
||||
setPrevStep((prev) => prev - 1);
|
||||
};
|
||||
|
||||
return (
|
||||
<Form {...form}>
|
||||
<form
|
||||
onSubmit={form.handleSubmit(onSubmitClient)}
|
||||
className="flex flex-col space-y-4"
|
||||
>
|
||||
{prevStep === 1 && (
|
||||
<>
|
||||
{/* Select a provider */}
|
||||
<RadioGroupProvider
|
||||
control={form.control}
|
||||
isInvalid={!!form.formState.errors.providerType}
|
||||
errorMessage={form.formState.errors.providerType?.message}
|
||||
/>
|
||||
{/* Provider UID */}
|
||||
<CustomInput
|
||||
control={form.control}
|
||||
name="providerUid"
|
||||
type="text"
|
||||
label="Provider UID"
|
||||
labelPlacement="inside"
|
||||
placeholder={"Enter the provider UID"}
|
||||
variant="bordered"
|
||||
isRequired
|
||||
isInvalid={!!form.formState.errors.providerUid}
|
||||
/>
|
||||
{/* Provider alias */}
|
||||
<CustomInput
|
||||
control={form.control}
|
||||
name="providerAlias"
|
||||
type="text"
|
||||
label="Provider alias (optional)"
|
||||
labelPlacement="inside"
|
||||
placeholder={"Enter the provider alias"}
|
||||
variant="bordered"
|
||||
isRequired={false}
|
||||
isInvalid={!!form.formState.errors.providerAlias}
|
||||
/>
|
||||
</>
|
||||
)}
|
||||
|
||||
{prevStep === 2 && (
|
||||
<>
|
||||
{/* Select AWS credentials type */}
|
||||
<RadioGroupAWSViaCredentialsForm
|
||||
control={form.control}
|
||||
isInvalid={!!form.formState.errors.awsCredentialsType}
|
||||
errorMessage={form.formState.errors.awsCredentialsType?.message}
|
||||
/>
|
||||
</>
|
||||
)}
|
||||
|
||||
<div className="flex w-full justify-end sm:space-x-6">
|
||||
{prevStep === 2 && (
|
||||
<CustomButton
|
||||
type="button"
|
||||
ariaLabel="Back"
|
||||
className="w-1/2 bg-transparent"
|
||||
variant="faded"
|
||||
size="lg"
|
||||
radius="lg"
|
||||
onPress={handleBackStep}
|
||||
startContent={!isLoading && <ChevronLeftIcon size={24} />}
|
||||
isDisabled={isLoading}
|
||||
>
|
||||
<span>Back</span>
|
||||
</CustomButton>
|
||||
)}
|
||||
|
||||
<CustomButton
|
||||
type="button"
|
||||
ariaLabel={
|
||||
prevStep === 1 && providerType === "aws" ? "Next" : "Save"
|
||||
}
|
||||
className="w-1/2"
|
||||
variant="solid"
|
||||
color="action"
|
||||
size="lg"
|
||||
isLoading={isLoading}
|
||||
startContent={
|
||||
!isLoading &&
|
||||
!(prevStep === 1 && providerType === "aws") && (
|
||||
<SaveIcon size={24} />
|
||||
)
|
||||
}
|
||||
endContent={
|
||||
!isLoading &&
|
||||
prevStep === 1 &&
|
||||
providerType === "aws" && <ChevronRightIcon size={24} />
|
||||
}
|
||||
onPress={() => {
|
||||
if (prevStep === 1 && providerType === "aws") {
|
||||
handleNextStep();
|
||||
} else {
|
||||
form.handleSubmit(onSubmitClient)();
|
||||
}
|
||||
}}
|
||||
>
|
||||
{isLoading ? (
|
||||
<>Loading</>
|
||||
) : (
|
||||
<span>
|
||||
{prevStep === 1 && providerType === "aws" ? "Next" : "Save"}
|
||||
</span>
|
||||
)}
|
||||
</CustomButton>
|
||||
</div>
|
||||
</form>
|
||||
</Form>
|
||||
);
|
||||
};
|
||||
@@ -0,0 +1,6 @@
|
||||
export * from "./connect-account-form";
|
||||
export * from "./launch-scan-form";
|
||||
export * from "./radio-group-aws-via-credentials-form";
|
||||
export * from "./test-connection-form";
|
||||
export * from "./via-credentials-form";
|
||||
export * from "./via-role-form";
|
||||
@@ -0,0 +1,162 @@
|
||||
"use client";
|
||||
|
||||
import { zodResolver } from "@hookform/resolvers/zod";
|
||||
import { useRouter } from "next/navigation";
|
||||
import { useState } from "react";
|
||||
import { useForm } from "react-hook-form";
|
||||
import { z } from "zod";
|
||||
|
||||
import { scanOnDemand } from "@/actions/scans/scans";
|
||||
import { AddIcon } from "@/components/icons";
|
||||
import { CustomButton } from "@/components/ui/custom";
|
||||
import { Form } from "@/components/ui/form";
|
||||
import { ProviderProps } from "@/types"; // Asegúrate de importar la interfaz correcta
|
||||
import { launchScanFormSchema } from "@/types/formSchemas";
|
||||
|
||||
import { ProviderInfo } from "../../provider-info";
|
||||
|
||||
type FormValues = z.infer<ReturnType<typeof launchScanFormSchema>>;
|
||||
|
||||
interface LaunchScanFormProps {
|
||||
searchParams: { type: string; id: string };
|
||||
providerData: {
|
||||
data: {
|
||||
type: string;
|
||||
id: string;
|
||||
attributes: ProviderProps["attributes"];
|
||||
};
|
||||
};
|
||||
}
|
||||
|
||||
export const LaunchScanForm = ({
|
||||
searchParams,
|
||||
providerData,
|
||||
}: LaunchScanFormProps) => {
|
||||
const providerType = searchParams.type;
|
||||
const providerId = searchParams.id;
|
||||
|
||||
const [apiErrorMessage, setApiErrorMessage] = useState<string | null>(null);
|
||||
const router = useRouter();
|
||||
|
||||
const formSchema = launchScanFormSchema();
|
||||
|
||||
const form = useForm<FormValues>({
|
||||
resolver: zodResolver(formSchema),
|
||||
defaultValues: {
|
||||
providerId,
|
||||
providerType,
|
||||
scannerArgs: {
|
||||
checksToExecute: [],
|
||||
},
|
||||
},
|
||||
});
|
||||
|
||||
// const isLoading = form.formState.isSubmitting;
|
||||
|
||||
const onSubmitClient = async (values: FormValues) => {
|
||||
const formData = new FormData();
|
||||
formData.append("providerId", values.providerId);
|
||||
|
||||
// Generate default scan name using provider type and current date
|
||||
const date = new Date();
|
||||
const month = (date.getMonth() + 1).toString().padStart(2, "0");
|
||||
const day = date.getDate().toString().padStart(2, "0");
|
||||
const year = date.getFullYear();
|
||||
const defaultScanName = `${providerType}:${month}/${day}/${year}`;
|
||||
|
||||
formData.append("scanName", defaultScanName);
|
||||
|
||||
try {
|
||||
const data = await scanOnDemand(formData);
|
||||
|
||||
if (data.error) {
|
||||
setApiErrorMessage(data.error);
|
||||
form.setError("providerId", {
|
||||
type: "server",
|
||||
message: data.error,
|
||||
});
|
||||
} else {
|
||||
router.push("/scans");
|
||||
}
|
||||
} catch (error) {
|
||||
form.setError("providerId", {
|
||||
type: "server",
|
||||
message: "An unexpected error occurred. Please try again.",
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
return (
|
||||
<Form {...form}>
|
||||
<form
|
||||
onSubmit={form.handleSubmit(onSubmitClient)}
|
||||
className="flex flex-col space-y-4"
|
||||
>
|
||||
<div className="text-left">
|
||||
<div className="text-2xl font-bold leading-9 text-default-foreground">
|
||||
Scan started
|
||||
</div>
|
||||
<div className="py-2 text-default-500">
|
||||
The scan has just started. From now on, a new scan will be launched
|
||||
every 24 hours, starting from this moment.
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{apiErrorMessage && (
|
||||
<div className="mt-4 rounded-md bg-red-100 p-3 text-red-700">
|
||||
<p>{apiErrorMessage.toLowerCase()}</p>
|
||||
</div>
|
||||
)}
|
||||
|
||||
<ProviderInfo
|
||||
connected={providerData.data.attributes.connection.connected}
|
||||
provider={providerData.data.attributes.provider}
|
||||
providerAlias={providerData.data.attributes.alias}
|
||||
/>
|
||||
|
||||
<input type="hidden" name="providerId" value={providerId} />
|
||||
<input type="hidden" name="providerType" value={providerType} />
|
||||
|
||||
{/* <div className="flex w-full justify-end sm:space-x-6">
|
||||
<CustomButton
|
||||
type="submit"
|
||||
ariaLabel={"Save"}
|
||||
className="w-1/2"
|
||||
variant="solid"
|
||||
color="action"
|
||||
size="lg"
|
||||
isLoading={isLoading}
|
||||
startContent={!isLoading && <ScheduleIcon size={24} />}
|
||||
isDisabled={true}
|
||||
>
|
||||
<span>Schedule</span>
|
||||
</CustomButton>
|
||||
<CustomButton
|
||||
type="submit"
|
||||
ariaLabel={"Save"}
|
||||
className="w-1/2"
|
||||
variant="solid"
|
||||
color="action"
|
||||
size="lg"
|
||||
isLoading={isLoading}
|
||||
endContent={!isLoading && <RocketIcon size={24} />}
|
||||
>
|
||||
{isLoading ? <>Loading</> : <span>Start now</span>}
|
||||
</CustomButton>
|
||||
</div> */}
|
||||
<div className="flex w-full items-center justify-end">
|
||||
<CustomButton
|
||||
asLink="/scans"
|
||||
ariaLabel="Go to Scans page"
|
||||
variant="solid"
|
||||
color="action"
|
||||
size="md"
|
||||
endContent={<AddIcon size={20} />}
|
||||
>
|
||||
Go to Scans
|
||||
</CustomButton>
|
||||
</div>
|
||||
</form>
|
||||
</Form>
|
||||
);
|
||||
};
|
||||
@@ -0,0 +1,64 @@
|
||||
"use client";
|
||||
|
||||
import { RadioGroup } from "@nextui-org/react";
|
||||
import React from "react";
|
||||
import { Control, Controller } from "react-hook-form";
|
||||
|
||||
import { CustomRadio } from "@/components/ui/custom";
|
||||
import { FormMessage } from "@/components/ui/form";
|
||||
|
||||
import { FormValues } from "./connect-account-form";
|
||||
|
||||
type RadioGroupAWSViaCredentialsFormProps = {
|
||||
control: Control<FormValues>;
|
||||
isInvalid: boolean;
|
||||
errorMessage?: string;
|
||||
};
|
||||
|
||||
export const RadioGroupAWSViaCredentialsForm = ({
|
||||
control,
|
||||
isInvalid,
|
||||
errorMessage,
|
||||
}: RadioGroupAWSViaCredentialsFormProps) => {
|
||||
return (
|
||||
<Controller
|
||||
name="awsCredentialsType"
|
||||
control={control}
|
||||
render={({ field }) => (
|
||||
<>
|
||||
<RadioGroup
|
||||
className="flex flex-wrap"
|
||||
isInvalid={isInvalid}
|
||||
{...field}
|
||||
value={field.value || ""}
|
||||
>
|
||||
<div className="flex flex-col gap-4">
|
||||
<span className="text-sm text-default-500">Using IAM Role</span>
|
||||
<CustomRadio description="Connect assuming IAM Role" value="role">
|
||||
<div className="flex items-center">
|
||||
<span className="ml-2">Connect assuming IAM Role</span>
|
||||
</div>
|
||||
</CustomRadio>
|
||||
<span className="text-sm text-default-500">
|
||||
Using Credentials
|
||||
</span>
|
||||
<CustomRadio
|
||||
description="Connect via Credentials"
|
||||
value="credentials"
|
||||
>
|
||||
<div className="flex items-center">
|
||||
<span className="ml-2">Connect via Credentials</span>
|
||||
</div>
|
||||
</CustomRadio>
|
||||
</div>
|
||||
</RadioGroup>
|
||||
{errorMessage && (
|
||||
<FormMessage className="text-system-error dark:text-system-error">
|
||||
{errorMessage}
|
||||
</FormMessage>
|
||||
)}
|
||||
</>
|
||||
)}
|
||||
/>
|
||||
);
|
||||
};
|
||||
@@ -0,0 +1,286 @@
|
||||
"use client";
|
||||
|
||||
import { zodResolver } from "@hookform/resolvers/zod";
|
||||
import { Icon } from "@iconify/react";
|
||||
import Link from "next/link";
|
||||
import { useRouter } from "next/navigation";
|
||||
import { useState } from "react";
|
||||
import { useForm } from "react-hook-form";
|
||||
import { z } from "zod";
|
||||
|
||||
import {
|
||||
checkConnectionProvider,
|
||||
deleteCredentials,
|
||||
} from "@/actions/providers";
|
||||
import { scanOnDemand } from "@/actions/scans";
|
||||
import { getTask } from "@/actions/task/tasks";
|
||||
import { CheckIcon, SaveIcon } from "@/components/icons";
|
||||
import { useToast } from "@/components/ui";
|
||||
import { CustomButton } from "@/components/ui/custom";
|
||||
import { Form } from "@/components/ui/form";
|
||||
import { checkTaskStatus } from "@/lib/helper";
|
||||
import { ApiError, testConnectionFormSchema } from "@/types";
|
||||
|
||||
import { ProviderInfo } from "../..";
|
||||
|
||||
type FormValues = z.infer<typeof testConnectionFormSchema>;
|
||||
|
||||
export const TestConnectionForm = ({
|
||||
searchParams,
|
||||
providerData,
|
||||
}: {
|
||||
searchParams: { type: string; id: string };
|
||||
providerData: {
|
||||
data: {
|
||||
id: string;
|
||||
type: string;
|
||||
attributes: {
|
||||
connection: {
|
||||
connected: boolean | null;
|
||||
last_checked_at: string | null;
|
||||
};
|
||||
provider: "aws" | "azure" | "gcp" | "kubernetes";
|
||||
alias: string;
|
||||
scanner_args: Record<string, any>;
|
||||
};
|
||||
relationships: {
|
||||
secret: {
|
||||
data: {
|
||||
type: string;
|
||||
id: string;
|
||||
} | null;
|
||||
};
|
||||
};
|
||||
};
|
||||
};
|
||||
}) => {
|
||||
const { toast } = useToast();
|
||||
const router = useRouter();
|
||||
const providerType = searchParams.type;
|
||||
const providerId = searchParams.id;
|
||||
console.log({ providerData }, "providerData from test connection form");
|
||||
const formSchema = testConnectionFormSchema;
|
||||
const [apiErrorMessage, setApiErrorMessage] = useState<string | null>(null);
|
||||
const [connectionStatus, setConnectionStatus] = useState<{
|
||||
connected: boolean;
|
||||
error: string | null;
|
||||
} | null>(null);
|
||||
const [isResettingCredentials, setIsResettingCredentials] = useState(false);
|
||||
|
||||
const form = useForm<FormValues>({
|
||||
resolver: zodResolver(formSchema),
|
||||
defaultValues: {
|
||||
providerId,
|
||||
},
|
||||
});
|
||||
|
||||
const isLoading = form.formState.isSubmitting;
|
||||
|
||||
const onSubmitClient = async (values: FormValues) => {
|
||||
console.log({ values }, "values from test connection form");
|
||||
const formData = new FormData();
|
||||
formData.append("providerId", values.providerId);
|
||||
|
||||
const data = await checkConnectionProvider(formData);
|
||||
|
||||
if (data?.errors && data.errors.length > 0) {
|
||||
data.errors.forEach((error: ApiError) => {
|
||||
const errorMessage = error.detail;
|
||||
|
||||
switch (errorMessage) {
|
||||
case "Not found.":
|
||||
setApiErrorMessage(errorMessage);
|
||||
break;
|
||||
default:
|
||||
toast({
|
||||
variant: "destructive",
|
||||
title: `Error ${error.status}`,
|
||||
description: errorMessage,
|
||||
});
|
||||
}
|
||||
});
|
||||
} else {
|
||||
const taskId = data.data.id;
|
||||
setApiErrorMessage(null);
|
||||
|
||||
// Use the helper function to check the task status
|
||||
const taskResult = await checkTaskStatus(taskId);
|
||||
|
||||
if (taskResult.completed) {
|
||||
const task = await getTask(taskId);
|
||||
const { connected, error } = task.data.attributes.result;
|
||||
|
||||
setConnectionStatus({
|
||||
connected,
|
||||
error: connected ? null : error || "Unknown error",
|
||||
});
|
||||
|
||||
if (connected) {
|
||||
try {
|
||||
const data = await scanOnDemand(formData);
|
||||
|
||||
if (data.error) {
|
||||
setApiErrorMessage(data.error);
|
||||
form.setError("providerId", {
|
||||
type: "server",
|
||||
message: data.error,
|
||||
});
|
||||
} else {
|
||||
router.push(
|
||||
`/providers/launch-scan?type=${providerType}&id=${providerId}`,
|
||||
);
|
||||
}
|
||||
} catch (error) {
|
||||
form.setError("providerId", {
|
||||
type: "server",
|
||||
message: "An unexpected error occurred. Please try again.",
|
||||
});
|
||||
}
|
||||
} else {
|
||||
setConnectionStatus({
|
||||
connected: false,
|
||||
error: error || "Connection failed, please review credentials.",
|
||||
});
|
||||
}
|
||||
} else {
|
||||
setConnectionStatus({
|
||||
connected: false,
|
||||
error: taskResult.error || "Unknown error",
|
||||
});
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
const onResetCredentials = async () => {
|
||||
setIsResettingCredentials(true);
|
||||
|
||||
// Check if provider the provider has no credentials
|
||||
const providerSecretId =
|
||||
providerData?.data?.relationships?.secret?.data?.id;
|
||||
const hasNoCredentials = !providerSecretId;
|
||||
|
||||
if (hasNoCredentials) {
|
||||
// If no credentials, redirect to add credentials page
|
||||
router.push(
|
||||
`/providers/add-credentials?type=${providerType}&id=${providerId}`,
|
||||
);
|
||||
return;
|
||||
}
|
||||
|
||||
// If provider has credentials, delete them first
|
||||
try {
|
||||
await deleteCredentials(providerSecretId);
|
||||
// After successful deletion, redirect to add credentials page
|
||||
router.push(
|
||||
`/providers/add-credentials?type=${providerType}&id=${providerId}`,
|
||||
);
|
||||
} catch (error) {
|
||||
console.error("Failed to delete credentials:", error);
|
||||
} finally {
|
||||
setIsResettingCredentials(false);
|
||||
}
|
||||
};
|
||||
|
||||
return (
|
||||
<Form {...form}>
|
||||
<form
|
||||
onSubmit={form.handleSubmit(onSubmitClient)}
|
||||
className="flex flex-col space-y-4"
|
||||
>
|
||||
<div className="text-left">
|
||||
<div className="text-2xl font-bold leading-9 text-default-foreground">
|
||||
Test connection
|
||||
</div>
|
||||
<p className="py-2 text-default-500">
|
||||
Ensure all required credentials and configurations are completed
|
||||
accurately. A successful connection will enable the option to
|
||||
initiate a scan in the following step.
|
||||
</p>
|
||||
</div>
|
||||
|
||||
{apiErrorMessage && (
|
||||
<div className="mt-4 rounded-md bg-red-100 p-3 text-danger">
|
||||
<p>{`Provider ID ${apiErrorMessage.toLowerCase()}. Please check and try again.`}</p>
|
||||
</div>
|
||||
)}
|
||||
|
||||
{connectionStatus && !connectionStatus.connected && (
|
||||
<>
|
||||
<div className="flex items-center gap-4 rounded-lg border border-red-200 bg-red-50 p-4">
|
||||
<div className="flex items-center">
|
||||
<Icon
|
||||
icon="heroicons:exclamation-circle"
|
||||
className="h-5 w-5 text-danger"
|
||||
/>
|
||||
</div>
|
||||
<div className="flex items-center">
|
||||
<p className="text-danger">
|
||||
{connectionStatus.error || "Unknown error"}
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
<p className="text-md text-danger">
|
||||
It seems there was an issue with your credentials. Please review
|
||||
your credentials and try again.
|
||||
</p>
|
||||
</>
|
||||
)}
|
||||
|
||||
<ProviderInfo
|
||||
connected={providerData.data.attributes.connection.connected}
|
||||
provider={providerData.data.attributes.provider}
|
||||
providerAlias={providerData.data.attributes.alias}
|
||||
/>
|
||||
|
||||
<input type="hidden" name="providerId" value={providerId} />
|
||||
|
||||
<div className="flex w-full justify-end sm:space-x-6">
|
||||
{apiErrorMessage ? (
|
||||
<Link
|
||||
href="/providers"
|
||||
className="mr-3 flex w-fit items-center justify-center space-x-2 rounded-lg border border-solid border-gray-200 px-4 py-2 hover:bg-gray-200 dark:hover:bg-gray-700"
|
||||
>
|
||||
<Icon
|
||||
icon="icon-park-outline:close-small"
|
||||
className="h-5 w-5 text-gray-600 dark:text-gray-400"
|
||||
/>
|
||||
<span>Back to providers</span>
|
||||
</Link>
|
||||
) : connectionStatus?.error ? (
|
||||
<CustomButton
|
||||
onPress={onResetCredentials}
|
||||
type="button"
|
||||
ariaLabel={"Save"}
|
||||
className="w-1/2"
|
||||
variant="solid"
|
||||
color="warning"
|
||||
size="lg"
|
||||
isLoading={isResettingCredentials}
|
||||
startContent={!isResettingCredentials && <CheckIcon size={24} />}
|
||||
isDisabled={isResettingCredentials}
|
||||
>
|
||||
{isResettingCredentials ? (
|
||||
<>Loading</>
|
||||
) : (
|
||||
<span>Reset credentials</span>
|
||||
)}
|
||||
</CustomButton>
|
||||
) : (
|
||||
<CustomButton
|
||||
type="submit"
|
||||
ariaLabel={"Save"}
|
||||
className="w-1/2"
|
||||
variant="solid"
|
||||
color="action"
|
||||
size="lg"
|
||||
isLoading={isLoading}
|
||||
startContent={!isLoading && <SaveIcon size={24} />}
|
||||
>
|
||||
{isLoading ? <>Loading</> : <span>Test connection</span>}
|
||||
</CustomButton>
|
||||
)}
|
||||
</div>
|
||||
</form>
|
||||
</Form>
|
||||
);
|
||||
};
|
||||
@@ -0,0 +1,207 @@
|
||||
"use client";
|
||||
|
||||
import { zodResolver } from "@hookform/resolvers/zod";
|
||||
import { SaveIcon } from "lucide-react";
|
||||
import { useRouter } from "next/navigation";
|
||||
import { Control, useForm } from "react-hook-form";
|
||||
import * as z from "zod";
|
||||
|
||||
import { addCredentialsProvider } from "@/actions/providers/providers";
|
||||
import { useToast } from "@/components/ui";
|
||||
import { CustomButton } from "@/components/ui/custom";
|
||||
import { Form } from "@/components/ui/form";
|
||||
import {
|
||||
addCredentialsFormSchema,
|
||||
ApiError,
|
||||
AWSCredentials,
|
||||
AzureCredentials,
|
||||
GCPCredentials,
|
||||
KubernetesCredentials,
|
||||
} from "@/types";
|
||||
|
||||
import { AWScredentialsForm } from "./via-credentials/aws-credentials-form";
|
||||
import { AzureCredentialsForm } from "./via-credentials/azure-credentials-form";
|
||||
import { GCPcredentialsForm } from "./via-credentials/gcp-credentials-form";
|
||||
import { KubernetesCredentialsForm } from "./via-credentials/k8s-credentials-form";
|
||||
|
||||
type CredentialsFormSchema = z.infer<
|
||||
ReturnType<typeof addCredentialsFormSchema>
|
||||
>;
|
||||
|
||||
// Add this type intersection to include all fields
|
||||
type FormType = CredentialsFormSchema &
|
||||
AWSCredentials &
|
||||
AzureCredentials &
|
||||
GCPCredentials &
|
||||
KubernetesCredentials;
|
||||
|
||||
export const ViaCredentialsForm = ({
|
||||
searchParams,
|
||||
}: {
|
||||
searchParams: { type: string; id: string };
|
||||
}) => {
|
||||
const router = useRouter();
|
||||
const { toast } = useToast();
|
||||
|
||||
const providerType = searchParams.type;
|
||||
const providerId = searchParams.id;
|
||||
const formSchema = addCredentialsFormSchema(providerType);
|
||||
|
||||
const form = useForm<FormType>({
|
||||
resolver: zodResolver(formSchema),
|
||||
defaultValues: {
|
||||
providerId,
|
||||
providerType,
|
||||
...(providerType === "aws"
|
||||
? {
|
||||
aws_access_key_id: "",
|
||||
aws_secret_access_key: "",
|
||||
aws_session_token: "",
|
||||
}
|
||||
: providerType === "azure"
|
||||
? {
|
||||
client_id: "",
|
||||
client_secret: "",
|
||||
tenant_id: "",
|
||||
}
|
||||
: providerType === "gcp"
|
||||
? {
|
||||
client_id: "",
|
||||
client_secret: "",
|
||||
refresh_token: "",
|
||||
}
|
||||
: providerType === "kubernetes"
|
||||
? {
|
||||
kubeconfig_content: "",
|
||||
}
|
||||
: {}),
|
||||
},
|
||||
});
|
||||
|
||||
const isLoading = form.formState.isSubmitting;
|
||||
|
||||
const onSubmitClient = async (values: FormType) => {
|
||||
console.log("via credentials form", values);
|
||||
const formData = new FormData();
|
||||
|
||||
Object.entries(values).forEach(
|
||||
([key, value]) => value !== undefined && formData.append(key, value),
|
||||
);
|
||||
|
||||
const data = await addCredentialsProvider(formData);
|
||||
|
||||
if (data?.errors && data.errors.length > 0) {
|
||||
data.errors.forEach((error: ApiError) => {
|
||||
const errorMessage = error.detail;
|
||||
switch (error.source.pointer) {
|
||||
case "/data/attributes/secret/aws_access_key_id":
|
||||
form.setError("aws_access_key_id", {
|
||||
type: "server",
|
||||
message: errorMessage,
|
||||
});
|
||||
break;
|
||||
case "/data/attributes/secret/aws_secret_access_key":
|
||||
form.setError("aws_secret_access_key", {
|
||||
type: "server",
|
||||
message: errorMessage,
|
||||
});
|
||||
break;
|
||||
case "/data/attributes/secret/aws_session_token":
|
||||
form.setError("aws_session_token", {
|
||||
type: "server",
|
||||
message: errorMessage,
|
||||
});
|
||||
break;
|
||||
case "/data/attributes/secret/client_id":
|
||||
form.setError("client_id", {
|
||||
type: "server",
|
||||
message: errorMessage,
|
||||
});
|
||||
break;
|
||||
case "/data/attributes/secret/client_secret":
|
||||
form.setError("client_secret", {
|
||||
type: "server",
|
||||
message: errorMessage,
|
||||
});
|
||||
break;
|
||||
case "/data/attributes/secret/tenant_id":
|
||||
form.setError("tenant_id", {
|
||||
type: "server",
|
||||
message: errorMessage,
|
||||
});
|
||||
break;
|
||||
case "/data/attributes/secret/kubeconfig_content":
|
||||
form.setError("kubeconfig_content", {
|
||||
type: "server",
|
||||
message: errorMessage,
|
||||
});
|
||||
break;
|
||||
case "/data/attributes/name":
|
||||
form.setError("secretName", {
|
||||
type: "server",
|
||||
message: errorMessage,
|
||||
});
|
||||
break;
|
||||
default:
|
||||
toast({
|
||||
variant: "destructive",
|
||||
title: "Oops! Something went wrong",
|
||||
description: errorMessage,
|
||||
});
|
||||
}
|
||||
});
|
||||
} else {
|
||||
router.push(
|
||||
`/providers/test-connection?type=${providerType}&id=${providerId}`,
|
||||
);
|
||||
}
|
||||
};
|
||||
|
||||
return (
|
||||
<Form {...form}>
|
||||
<form
|
||||
onSubmit={form.handleSubmit(onSubmitClient)}
|
||||
className="flex flex-col space-y-4"
|
||||
>
|
||||
<input type="hidden" name="providerId" value={providerId} />
|
||||
<input type="hidden" name="providerType" value={providerType} />
|
||||
|
||||
{providerType === "aws" && (
|
||||
<AWScredentialsForm
|
||||
control={form.control as unknown as Control<AWSCredentials>}
|
||||
/>
|
||||
)}
|
||||
{providerType === "azure" && (
|
||||
<AzureCredentialsForm
|
||||
control={form.control as unknown as Control<AzureCredentials>}
|
||||
/>
|
||||
)}
|
||||
{providerType === "gcp" && (
|
||||
<GCPcredentialsForm
|
||||
control={form.control as unknown as Control<GCPCredentials>}
|
||||
/>
|
||||
)}
|
||||
{providerType === "kubernetes" && (
|
||||
<KubernetesCredentialsForm
|
||||
control={form.control as unknown as Control<KubernetesCredentials>}
|
||||
/>
|
||||
)}
|
||||
|
||||
<div className="flex w-full justify-end sm:space-x-6">
|
||||
<CustomButton
|
||||
type="submit"
|
||||
ariaLabel={"Save"}
|
||||
className="w-1/2"
|
||||
variant="solid"
|
||||
color="action"
|
||||
size="lg"
|
||||
isLoading={isLoading}
|
||||
startContent={!isLoading && <SaveIcon size={24} />}
|
||||
>
|
||||
{isLoading ? <>Loading</> : <span>Save</span>}
|
||||
</CustomButton>
|
||||
</div>
|
||||
</form>
|
||||
</Form>
|
||||
);
|
||||
};
|
||||
@@ -0,0 +1,56 @@
|
||||
import { Control } from "react-hook-form";
|
||||
|
||||
import { CustomInput } from "@/components/ui/custom";
|
||||
import { AWSCredentials } from "@/types";
|
||||
|
||||
export const AWScredentialsForm = ({
|
||||
control,
|
||||
}: {
|
||||
control: Control<AWSCredentials>;
|
||||
}) => {
|
||||
return (
|
||||
<>
|
||||
<div className="text-left">
|
||||
<div className="text-2xl font-bold leading-9 text-default-foreground">
|
||||
Connect via Credentials
|
||||
</div>
|
||||
<div className="py-2 text-default-500">
|
||||
Please provide the information for your AWS credentials.
|
||||
</div>
|
||||
</div>
|
||||
<CustomInput
|
||||
control={control}
|
||||
name="aws_access_key_id"
|
||||
type="password"
|
||||
label="AWS Access Key ID"
|
||||
labelPlacement="inside"
|
||||
placeholder="Enter the AWS Access Key ID"
|
||||
variant="bordered"
|
||||
isRequired
|
||||
isInvalid={!!control._formState.errors.aws_access_key_id}
|
||||
/>
|
||||
<CustomInput
|
||||
control={control}
|
||||
name="aws_secret_access_key"
|
||||
type="password"
|
||||
label="AWS Secret Access Key"
|
||||
labelPlacement="inside"
|
||||
placeholder="Enter the AWS Secret Access Key"
|
||||
variant="bordered"
|
||||
isRequired
|
||||
isInvalid={!!control._formState.errors.aws_secret_access_key}
|
||||
/>
|
||||
<CustomInput
|
||||
control={control}
|
||||
name="aws_session_token"
|
||||
type="password"
|
||||
label="AWS Session Token"
|
||||
labelPlacement="inside"
|
||||
placeholder="Enter the AWS Session Token"
|
||||
variant="bordered"
|
||||
isRequired={false}
|
||||
isInvalid={!!control._formState.errors.aws_session_token}
|
||||
/>
|
||||
</>
|
||||
);
|
||||
};
|
||||
@@ -0,0 +1,56 @@
|
||||
import { Control } from "react-hook-form";
|
||||
|
||||
import { CustomInput } from "@/components/ui/custom";
|
||||
import { AzureCredentials } from "@/types";
|
||||
|
||||
export const AzureCredentialsForm = ({
|
||||
control,
|
||||
}: {
|
||||
control: Control<AzureCredentials>;
|
||||
}) => {
|
||||
return (
|
||||
<>
|
||||
<div className="text-left">
|
||||
<div className="text-2xl font-bold leading-9 text-default-foreground">
|
||||
Connect via Credentials
|
||||
</div>
|
||||
<div className="py-2 text-default-500">
|
||||
Please provide the information for your Azure credentials.
|
||||
</div>
|
||||
</div>
|
||||
<CustomInput
|
||||
control={control}
|
||||
name="client_id"
|
||||
type="text"
|
||||
label="Client ID"
|
||||
labelPlacement="inside"
|
||||
placeholder="Enter the Client ID"
|
||||
variant="bordered"
|
||||
isRequired
|
||||
isInvalid={!!control._formState.errors.client_id}
|
||||
/>
|
||||
<CustomInput
|
||||
control={control}
|
||||
name="client_secret"
|
||||
type="password"
|
||||
label="Client Secret"
|
||||
labelPlacement="inside"
|
||||
placeholder="Enter the Client Secret"
|
||||
variant="bordered"
|
||||
isRequired
|
||||
isInvalid={!!control._formState.errors.client_secret}
|
||||
/>
|
||||
<CustomInput
|
||||
control={control}
|
||||
name="tenant_id"
|
||||
type="text"
|
||||
label="Tenant ID"
|
||||
labelPlacement="inside"
|
||||
placeholder="Enter the Tenant ID"
|
||||
variant="bordered"
|
||||
isRequired
|
||||
isInvalid={!!control._formState.errors.tenant_id}
|
||||
/>
|
||||
</>
|
||||
);
|
||||
};
|
||||
@@ -0,0 +1,56 @@
|
||||
import { Control } from "react-hook-form";
|
||||
|
||||
import { CustomInput } from "@/components/ui/custom";
|
||||
import { GCPCredentials } from "@/types";
|
||||
|
||||
export const GCPcredentialsForm = ({
|
||||
control,
|
||||
}: {
|
||||
control: Control<GCPCredentials>;
|
||||
}) => {
|
||||
return (
|
||||
<>
|
||||
<div className="text-left">
|
||||
<div className="text-2xl font-bold leading-9 text-default-foreground">
|
||||
Connect via Credentials
|
||||
</div>
|
||||
<div className="py-2 text-default-500">
|
||||
Please provide the information for your GCP credentials.
|
||||
</div>
|
||||
</div>
|
||||
<CustomInput
|
||||
control={control}
|
||||
name="client_id"
|
||||
type="text"
|
||||
label="Client ID"
|
||||
labelPlacement="inside"
|
||||
placeholder="Enter the Client ID"
|
||||
variant="bordered"
|
||||
isRequired
|
||||
isInvalid={!!control._formState.errors.client_id}
|
||||
/>
|
||||
<CustomInput
|
||||
control={control}
|
||||
name="client_secret"
|
||||
type="password"
|
||||
label="Client Secret"
|
||||
labelPlacement="inside"
|
||||
placeholder="Enter the Client Secret"
|
||||
variant="bordered"
|
||||
isRequired
|
||||
isInvalid={!!control._formState.errors.client_secret}
|
||||
/>
|
||||
<CustomInput
|
||||
control={control}
|
||||
name="refresh_token"
|
||||
type="password"
|
||||
label="Refresh Token"
|
||||
labelPlacement="inside"
|
||||
placeholder="Enter the Refresh Token"
|
||||
variant="bordered"
|
||||
isRequired
|
||||
isInvalid={!!control._formState.errors.refresh_token}
|
||||
/>
|
||||
</>
|
||||
);
|
||||
};
|
||||
@@ -0,0 +1,4 @@
|
||||
export * from "./aws-credentials-form";
|
||||
export * from "./azure-credentials-form";
|
||||
export * from "./gcp-credentials-form";
|
||||
export * from "./k8s-credentials-form";
|
||||
@@ -0,0 +1,34 @@
|
||||
import { Control } from "react-hook-form";
|
||||
|
||||
import { CustomInput } from "@/components/ui/custom";
|
||||
import { KubernetesCredentials } from "@/types";
|
||||
|
||||
export const KubernetesCredentialsForm = ({
|
||||
control,
|
||||
}: {
|
||||
control: Control<KubernetesCredentials>;
|
||||
}) => {
|
||||
return (
|
||||
<>
|
||||
<div className="text-left">
|
||||
<div className="text-2xl font-bold leading-9 text-default-foreground">
|
||||
Connect via Credentials
|
||||
</div>
|
||||
<div className="py-2 text-default-500">
|
||||
Please provide the information for your Kubernetes credentials.
|
||||
</div>
|
||||
</div>
|
||||
<CustomInput
|
||||
control={control}
|
||||
name="kubeconfig_content"
|
||||
type="text"
|
||||
label="Kubeconfig Content"
|
||||
labelPlacement="inside"
|
||||
placeholder="Enter the Kubeconfig Content"
|
||||
variant="bordered"
|
||||
isRequired
|
||||
isInvalid={!!control._formState.errors.kubeconfig_content}
|
||||
/>
|
||||
</>
|
||||
);
|
||||
};
|
||||
@@ -0,0 +1,125 @@
|
||||
"use client";
|
||||
|
||||
import { zodResolver } from "@hookform/resolvers/zod";
|
||||
import { SaveIcon } from "lucide-react";
|
||||
import { useRouter } from "next/navigation";
|
||||
import { Control, useForm } from "react-hook-form";
|
||||
import * as z from "zod";
|
||||
|
||||
import { addCredentialsProvider } from "@/actions/providers/providers";
|
||||
import { useToast } from "@/components/ui";
|
||||
import { CustomButton } from "@/components/ui/custom";
|
||||
import { Form } from "@/components/ui/form";
|
||||
import {
|
||||
addCredentialsRoleFormSchema,
|
||||
ApiError,
|
||||
AWSCredentialsRole,
|
||||
} from "@/types";
|
||||
|
||||
import { AWSCredentialsRoleForm } from "./via-role/aws-role-form";
|
||||
|
||||
export const ViaRoleForm = ({
|
||||
searchParams,
|
||||
}: {
|
||||
searchParams: { type: string; id: string };
|
||||
}) => {
|
||||
const router = useRouter();
|
||||
const { toast } = useToast();
|
||||
|
||||
const providerType = searchParams.type;
|
||||
const providerId = searchParams.id;
|
||||
|
||||
const formSchema = addCredentialsRoleFormSchema(providerType);
|
||||
type FormSchemaType = z.infer<typeof formSchema>;
|
||||
|
||||
const form = useForm<FormSchemaType>({
|
||||
resolver: zodResolver(formSchema),
|
||||
defaultValues: {
|
||||
providerId,
|
||||
providerType,
|
||||
...(providerType === "aws"
|
||||
? {
|
||||
role_arn: "",
|
||||
aws_access_key_id: "",
|
||||
aws_secret_access_key: "",
|
||||
aws_session_token: "",
|
||||
session_duration: 3600,
|
||||
external_id: "",
|
||||
role_session_name: "",
|
||||
}
|
||||
: {}),
|
||||
},
|
||||
});
|
||||
|
||||
const isLoading = form.formState.isSubmitting;
|
||||
|
||||
const onSubmitClient = async (values: FormSchemaType) => {
|
||||
console.log("via ROLE form", values);
|
||||
const formData = new FormData();
|
||||
|
||||
Object.entries(values).forEach(
|
||||
([key, value]) =>
|
||||
value !== undefined && formData.append(key, String(value)),
|
||||
);
|
||||
|
||||
const data = await addCredentialsProvider(formData);
|
||||
|
||||
if (data?.errors && data.errors.length > 0) {
|
||||
data.errors.forEach((error: ApiError) => {
|
||||
const errorMessage = error.detail;
|
||||
switch (error.source.pointer) {
|
||||
case "/data/attributes/secret/role_arn":
|
||||
form.setError("role_arn" as keyof FormSchemaType, {
|
||||
type: "server",
|
||||
message: errorMessage,
|
||||
});
|
||||
break;
|
||||
|
||||
default:
|
||||
toast({
|
||||
variant: "destructive",
|
||||
title: "Oops! Something went wrong",
|
||||
description: errorMessage,
|
||||
});
|
||||
}
|
||||
});
|
||||
} else {
|
||||
router.push(
|
||||
`/providers/test-connection?type=${providerType}&id=${providerId}`,
|
||||
);
|
||||
}
|
||||
};
|
||||
|
||||
return (
|
||||
<Form {...form}>
|
||||
<form
|
||||
onSubmit={form.handleSubmit(onSubmitClient)}
|
||||
className="flex flex-col space-y-4"
|
||||
>
|
||||
<input type="hidden" name="providerId" value={providerId} />
|
||||
<input type="hidden" name="providerType" value={providerType} />
|
||||
|
||||
{providerType === "aws" && (
|
||||
<AWSCredentialsRoleForm
|
||||
control={form.control as unknown as Control<AWSCredentialsRole>}
|
||||
/>
|
||||
)}
|
||||
|
||||
<div className="flex w-full justify-end sm:space-x-6">
|
||||
<CustomButton
|
||||
type="submit"
|
||||
ariaLabel={"Save"}
|
||||
className="w-1/2"
|
||||
variant="solid"
|
||||
color="action"
|
||||
size="lg"
|
||||
isLoading={isLoading}
|
||||
startContent={!isLoading && <SaveIcon size={24} />}
|
||||
>
|
||||
{isLoading ? <>Loading</> : <span>Save</span>}
|
||||
</CustomButton>
|
||||
</div>
|
||||
</form>
|
||||
</Form>
|
||||
);
|
||||
};
|
||||
@@ -0,0 +1,105 @@
|
||||
import { Control } from "react-hook-form";
|
||||
|
||||
import { CustomInput } from "@/components/ui/custom";
|
||||
import { AWSCredentialsRole } from "@/types";
|
||||
|
||||
export const AWSCredentialsRoleForm = ({
|
||||
control,
|
||||
}: {
|
||||
control: Control<AWSCredentialsRole>;
|
||||
}) => {
|
||||
return (
|
||||
<>
|
||||
<div className="mb-4 text-left">
|
||||
<div className="text-2xl font-bold leading-9 text-default-foreground">
|
||||
Connect assuming IAM Role
|
||||
</div>
|
||||
<div className="py-2 text-default-500">
|
||||
Please provide the information for your AWS credentials.
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<CustomInput
|
||||
control={control}
|
||||
name="role_arn"
|
||||
type="text"
|
||||
label="Role ARN"
|
||||
labelPlacement="inside"
|
||||
placeholder="Enter the Role ARN"
|
||||
variant="bordered"
|
||||
isRequired
|
||||
isInvalid={!!control._formState.errors.role_arn}
|
||||
/>
|
||||
<span className="text-sm text-default-500">Optional fields</span>
|
||||
<CustomInput
|
||||
control={control}
|
||||
name="aws_access_key_id"
|
||||
type="password"
|
||||
label="AWS Access Key ID"
|
||||
labelPlacement="inside"
|
||||
placeholder="Enter the AWS Access Key ID"
|
||||
variant="bordered"
|
||||
isRequired={false}
|
||||
isInvalid={!!control._formState.errors.aws_access_key_id}
|
||||
/>
|
||||
<CustomInput
|
||||
control={control}
|
||||
name="aws_secret_access_key"
|
||||
type="password"
|
||||
label="AWS Secret Access Key"
|
||||
labelPlacement="inside"
|
||||
placeholder="Enter the AWS Secret Access Key"
|
||||
variant="bordered"
|
||||
isRequired={false}
|
||||
isInvalid={!!control._formState.errors.aws_secret_access_key}
|
||||
/>
|
||||
<CustomInput
|
||||
control={control}
|
||||
name="aws_session_token"
|
||||
type="password"
|
||||
label="AWS Session Token"
|
||||
labelPlacement="inside"
|
||||
placeholder="Enter the AWS Session Token"
|
||||
variant="bordered"
|
||||
isRequired={false}
|
||||
isInvalid={!!control._formState.errors.aws_session_token}
|
||||
/>
|
||||
<CustomInput
|
||||
control={control}
|
||||
name="external_id"
|
||||
type="text"
|
||||
label="External ID"
|
||||
labelPlacement="inside"
|
||||
placeholder="Enter the External ID"
|
||||
variant="bordered"
|
||||
isRequired={false}
|
||||
isInvalid={!!control._formState.errors.external_id}
|
||||
/>
|
||||
|
||||
<div className="mt-4 grid grid-cols-1 gap-4 md:grid-cols-2">
|
||||
<CustomInput
|
||||
control={control}
|
||||
name="role_session_name"
|
||||
type="text"
|
||||
label="Role Session Name"
|
||||
labelPlacement="inside"
|
||||
placeholder="Enter the Role Session Name"
|
||||
variant="bordered"
|
||||
isRequired={false}
|
||||
isInvalid={!!control._formState.errors.role_session_name}
|
||||
/>
|
||||
<CustomInput
|
||||
control={control}
|
||||
name="session_duration"
|
||||
type="number"
|
||||
label="Session Duration (seconds)"
|
||||
labelPlacement="inside"
|
||||
placeholder="Enter the session duration (default: 3600)"
|
||||
variant="bordered"
|
||||
isRequired={false}
|
||||
isInvalid={!!control._formState.errors.session_duration}
|
||||
/>
|
||||
</div>
|
||||
</>
|
||||
);
|
||||
};
|
||||
@@ -0,0 +1 @@
|
||||
export * from "./aws-role-form";
|
||||
@@ -0,0 +1,2 @@
|
||||
export * from "./vertical-steps";
|
||||
export * from "./workflow-add-provider";
|
||||