mirror of
https://github.com/prowler-cloud/prowler.git
synced 2026-10-09 21:14:22 +00:00
feat: upgrade to React 19, Next.js 15, React Compiler, HeroUI and Tailwind 4 (#8748)
Co-authored-by: Alan Buscaglia <alanbuscaglia@MacBook-Pro.local> Co-authored-by: alejandrobailo <alejandrobailo94@gmail.com> Co-authored-by: César Arroba <cesar@prowler.com> Co-authored-by: Alejandro Bailo <59607668+alejandrobailo@users.noreply.github.com>
This commit is contained in:
261 files changed
+6339
-6126
No files matched your search
@@ -1,6 +1,7 @@
|
||||
"use client";
|
||||
|
||||
import { SwitchProps, useSwitch } from "@nextui-org/react";
|
||||
import type { SwitchProps } from "@heroui/switch";
|
||||
import { useSwitch } from "@heroui/switch";
|
||||
import { useIsSSR } from "@react-aria/ssr";
|
||||
import { VisuallyHidden } from "@react-aria/visually-hidden";
|
||||
import clsx from "clsx";
|
||||
|
||||
@@ -1,8 +1,10 @@
|
||||
"use client";
|
||||
|
||||
import { Button } from "@heroui/button";
|
||||
import { Checkbox } from "@heroui/checkbox";
|
||||
import { Divider } from "@heroui/divider";
|
||||
import { zodResolver } from "@hookform/resolvers/zod";
|
||||
import { Icon } from "@iconify/react";
|
||||
import { Button, Checkbox, Divider } from "@nextui-org/react";
|
||||
import { useRouter, useSearchParams } from "next/navigation";
|
||||
import { useEffect } from "react";
|
||||
import { useForm } from "react-hook-form";
|
||||
@@ -190,9 +192,9 @@ export const AuthForm = ({
|
||||
{/* 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="absolute h-full w-full bg-[radial-gradient(#6af400_1px,transparent_1px)] mask-[radial-gradient(ellipse_50%_50%_at_50%_50%,#000_10%,transparent_80%)] bg-size-[16px_16px]"></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">
|
||||
<div className="rounded-large border-divider shadow-small dark:bg-background/85 relative z-10 flex w-full max-w-sm flex-col gap-4 border bg-white/90 px-8 py-10 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} />
|
||||
@@ -350,7 +352,7 @@ export const AuthForm = ({
|
||||
<>
|
||||
<div className="flex items-center gap-4 py-2">
|
||||
<Divider className="flex-1" />
|
||||
<p className="shrink-0 text-tiny text-default-500">OR</p>
|
||||
<p className="text-tiny text-default-500 shrink-0">OR</p>
|
||||
<Divider className="flex-1" />
|
||||
</div>
|
||||
<div className="flex flex-col gap-2">
|
||||
@@ -387,7 +389,7 @@ export const AuthForm = ({
|
||||
<>
|
||||
<div className="flex items-center gap-4 py-2">
|
||||
<Divider className="flex-1" />
|
||||
<p className="shrink-0 text-tiny text-default-500">OR</p>
|
||||
<p className="text-tiny text-default-500 shrink-0">OR</p>
|
||||
<Divider className="flex-1" />
|
||||
</div>
|
||||
<div className="flex flex-col gap-2">
|
||||
@@ -401,14 +403,14 @@ export const AuthForm = ({
|
||||
</>
|
||||
)}
|
||||
{type === "sign-in" ? (
|
||||
<p className="text-center text-small">
|
||||
<p className="text-small text-center">
|
||||
Need to create an account?
|
||||
<CustomLink size="base" href="/sign-up" target="_self">
|
||||
Sign up
|
||||
</CustomLink>
|
||||
</p>
|
||||
) : (
|
||||
<p className="text-center text-small">
|
||||
<p className="text-small text-center">
|
||||
Already have an account?
|
||||
<CustomLink size="base" href="/sign-in" target="_self">
|
||||
Log in
|
||||
|
||||
@@ -69,25 +69,28 @@ export const PasswordRequirementsMessage = ({
|
||||
{allRequirementsMet ? (
|
||||
<div className="flex items-center gap-2">
|
||||
<CheckCircle
|
||||
className="h-4 w-4 flex-shrink-0 text-system-success"
|
||||
className="text-system-success h-4 w-4 shrink-0"
|
||||
aria-hidden="true"
|
||||
/>
|
||||
<p className="text-xs font-medium leading-tight text-system-success">
|
||||
<p className="text-system-success text-xs leading-tight font-medium">
|
||||
Password meets all requirements
|
||||
</p>
|
||||
</div>
|
||||
) : (
|
||||
<div className="space-y-1">
|
||||
<div className="flex flex-col gap-1">
|
||||
<div className="flex items-center gap-2">
|
||||
<AlertCircle
|
||||
className="h-4 w-4 flex-shrink-0 text-red-600"
|
||||
className="h-4 w-4 shrink-0 text-red-600"
|
||||
aria-hidden="true"
|
||||
/>
|
||||
<p className="text-xs font-medium leading-tight text-red-700">
|
||||
<p className="text-xs leading-tight font-medium text-red-700">
|
||||
Password must include:
|
||||
</p>
|
||||
</div>
|
||||
<ul className="ml-6 space-y-0.5" aria-label="Password requirements">
|
||||
<ul
|
||||
className="ml-6 flex flex-col gap-0.5"
|
||||
aria-label="Password requirements"
|
||||
>
|
||||
{results.map((req) => (
|
||||
<li
|
||||
key={req.key}
|
||||
@@ -95,7 +98,7 @@ export const PasswordRequirementsMessage = ({
|
||||
>
|
||||
<div className="flex items-center gap-2">
|
||||
<div
|
||||
className={`h-2 w-2 flex-shrink-0 rounded-full ${
|
||||
className={`h-2 w-2 shrink-0 rounded-full ${
|
||||
req.isMet ? "bg-system-success" : "bg-red-400"
|
||||
}`}
|
||||
aria-hidden="true"
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
import { Button } from "@heroui/button";
|
||||
import { Tooltip } from "@heroui/tooltip";
|
||||
import { Icon } from "@iconify/react";
|
||||
import { Button, Tooltip } from "@nextui-org/react";
|
||||
|
||||
import { CustomLink } from "@/components/ui/custom/custom-link";
|
||||
|
||||
@@ -24,7 +25,7 @@ export const SocialButtons = ({
|
||||
</CustomLink>
|
||||
</div>
|
||||
}
|
||||
placement="right-start"
|
||||
placement="top"
|
||||
shadow="sm"
|
||||
isDisabled={isGoogleOAuthEnabled}
|
||||
className="w-96"
|
||||
@@ -51,7 +52,7 @@ export const SocialButtons = ({
|
||||
</CustomLink>
|
||||
</div>
|
||||
}
|
||||
placement="right-start"
|
||||
placement="top"
|
||||
shadow="sm"
|
||||
isDisabled={isGithubOAuthEnabled}
|
||||
className="w-96"
|
||||
|
||||
@@ -116,7 +116,7 @@ export const ClientAccordionContent = ({
|
||||
return (
|
||||
<div className="w-full">
|
||||
{renderDetails()}
|
||||
<p className="mb-1 mt-3 text-sm font-medium text-gray-800 dark:text-gray-200">
|
||||
<p className="mt-3 mb-1 text-sm font-medium text-gray-800 dark:text-gray-200">
|
||||
⚠️ This requirement has no checks; therefore, there are no findings.
|
||||
</p>
|
||||
</div>
|
||||
@@ -127,7 +127,7 @@ export const ClientAccordionContent = ({
|
||||
const checksList = (
|
||||
<div className="flex items-center px-2 text-sm">
|
||||
<div className="w-full flex-col">
|
||||
<div className="mb-1 mt-[-8px] h-1 w-full border-b border-gray-200 dark:border-gray-800" />
|
||||
<div className="mt-[-8px] mb-1 h-1 w-full border-b border-gray-200 dark:border-gray-800" />
|
||||
<span className="text-gray-600 dark:text-gray-200" aria-label="Checks">
|
||||
{checks.join(", ")}
|
||||
</span>
|
||||
@@ -170,7 +170,7 @@ export const ClientAccordionContent = ({
|
||||
}
|
||||
|
||||
return (
|
||||
<div className="mb-1 mt-3 text-sm font-medium text-gray-800 dark:text-gray-200">
|
||||
<div className="mt-3 mb-1 text-sm font-medium text-gray-800 dark:text-gray-200">
|
||||
⚠️ There are no findings for these regions
|
||||
</div>
|
||||
);
|
||||
@@ -186,7 +186,7 @@ export const ClientAccordionContent = ({
|
||||
items={accordionChecksItems}
|
||||
variant="light"
|
||||
defaultExpandedKeys={[""]}
|
||||
className="rounded-lg bg-gray-50 dark:bg-prowler-blue-400"
|
||||
className="dark:bg-prowler-blue-400 rounded-lg bg-gray-50"
|
||||
/>
|
||||
</div>
|
||||
)}
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import { Tooltip } from "@nextui-org/react";
|
||||
import { Tooltip } from "@heroui/tooltip";
|
||||
|
||||
interface ComplianceAccordionTitleProps {
|
||||
label: string;
|
||||
@@ -24,7 +24,7 @@ export const ComplianceAccordionTitle = ({
|
||||
<div className="flex flex-col items-start justify-between gap-1 md:flex-row md:items-center md:gap-2">
|
||||
<div className="overflow-hidden md:min-w-0 md:flex-1">
|
||||
<span
|
||||
className="block max-w-[600px] overflow-hidden truncate text-ellipsis text-sm"
|
||||
className="block max-w-[600px] truncate overflow-hidden text-sm text-ellipsis"
|
||||
title={label}
|
||||
>
|
||||
{label.charAt(0).toUpperCase() + label.slice(1)}
|
||||
@@ -33,7 +33,7 @@ export const ComplianceAccordionTitle = ({
|
||||
<div className="mr-4 flex items-center gap-2">
|
||||
<div className="hidden lg:block">
|
||||
{total > 0 && isParentLevel && (
|
||||
<span className="whitespace-nowrap text-xs font-medium text-gray-600">
|
||||
<span className="text-xs font-medium whitespace-nowrap text-gray-600">
|
||||
Requirements:
|
||||
</span>
|
||||
)}
|
||||
@@ -127,7 +127,7 @@ export const ComplianceAccordionTitle = ({
|
||||
size="sm"
|
||||
placement="top"
|
||||
>
|
||||
<div className="min-w-[32px] text-center text-xs font-medium text-default-600">
|
||||
<div className="text-default-600 min-w-[32px] text-center text-xs font-medium">
|
||||
{total > 0 ? total : "—"}
|
||||
</div>
|
||||
</Tooltip>
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
"use client";
|
||||
|
||||
import { Card, CardBody, Progress } from "@nextui-org/react";
|
||||
import { Card, CardBody } from "@heroui/card";
|
||||
import { Progress } from "@heroui/progress";
|
||||
import Image from "next/image";
|
||||
import { useRouter, useSearchParams } from "next/navigation";
|
||||
import React, { useState } from "react";
|
||||
@@ -94,6 +95,11 @@ export const ComplianceCard: React.FC<ComplianceCardProps> = ({
|
||||
);
|
||||
}
|
||||
|
||||
const regionFilter = searchParams.get("filter[region__in]");
|
||||
if (regionFilter) {
|
||||
params.set("filter[region__in]", regionFilter);
|
||||
}
|
||||
|
||||
router.push(`${path}?${params.toString()}`);
|
||||
};
|
||||
const handleDownload = async () => {
|
||||
@@ -106,22 +112,19 @@ export const ComplianceCard: React.FC<ComplianceCardProps> = ({
|
||||
};
|
||||
|
||||
return (
|
||||
<Card
|
||||
fullWidth
|
||||
isHoverable
|
||||
shadow="sm"
|
||||
isPressable
|
||||
onPress={navigateToDetail}
|
||||
>
|
||||
<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">
|
||||
<Card fullWidth isHoverable shadow="sm">
|
||||
<CardBody
|
||||
className="dark:bg-prowler-blue-800 flex cursor-pointer flex-row items-center justify-between gap-4"
|
||||
onClick={navigateToDetail}
|
||||
>
|
||||
<div className="flex w-full items-center gap-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"
|
||||
className="h-10 w-10 min-w-10 rounded-md border border-gray-300 bg-white object-contain p-1"
|
||||
/>
|
||||
<div className="flex w-full flex-col">
|
||||
<h4 className="mb-1 text-small font-bold leading-5">
|
||||
<h4 className="text-small mb-1 leading-5 font-bold">
|
||||
{formatTitle(title)}
|
||||
{version ? ` - ${version}` : ""}
|
||||
</h4>
|
||||
@@ -146,13 +149,24 @@ export const ComplianceCard: React.FC<ComplianceCardProps> = ({
|
||||
Passing Requirements
|
||||
</small>
|
||||
|
||||
<DownloadIconButton
|
||||
paramId={complianceId}
|
||||
onDownload={handleDownload}
|
||||
textTooltip="Download compliance CSV report"
|
||||
isDisabled={hasRegionFilter}
|
||||
isDownloading={isDownloading}
|
||||
/>
|
||||
<div
|
||||
onClick={(e) => e.stopPropagation()}
|
||||
onKeyDown={(e) => {
|
||||
if (e.key === "Enter" || e.key === " ") {
|
||||
e.stopPropagation();
|
||||
}
|
||||
}}
|
||||
role="button"
|
||||
tabIndex={0}
|
||||
>
|
||||
<DownloadIconButton
|
||||
paramId={complianceId}
|
||||
onDownload={handleDownload}
|
||||
textTooltip="Download compliance CSV report"
|
||||
isDisabled={hasRegionFilter}
|
||||
isDownloading={isDownloading}
|
||||
/>
|
||||
</div>
|
||||
{/* <small>{getScanChange()}</small> */}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@@ -43,7 +43,7 @@ interface FailedSectionsListProps {
|
||||
}
|
||||
|
||||
const title = (
|
||||
<h3 className="mb-2 whitespace-nowrap text-xs font-semibold uppercase tracking-wide">
|
||||
<h3 className="mb-2 text-xs font-semibold tracking-wide whitespace-nowrap uppercase">
|
||||
Top Failed Sections
|
||||
</h3>
|
||||
);
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
"use client";
|
||||
|
||||
import { cn } from "@nextui-org/react";
|
||||
import { cn } from "@heroui/theme";
|
||||
import { useTheme } from "next-themes";
|
||||
import { useState } from "react";
|
||||
|
||||
@@ -30,7 +30,7 @@ const capitalizeFirstLetter = (text: string): string => {
|
||||
};
|
||||
|
||||
const title = (
|
||||
<h3 className="mb-2 whitespace-nowrap text-xs font-semibold uppercase tracking-wide">
|
||||
<h3 className="mb-2 text-xs font-semibold tracking-wide whitespace-nowrap uppercase">
|
||||
Sections Failure Rate
|
||||
</h3>
|
||||
);
|
||||
@@ -135,13 +135,30 @@ export const HeatmapChart = ({ categories = [] }: HeatmapChartProps) => {
|
||||
color: theme === "dark" ? "white" : "black",
|
||||
}}
|
||||
>
|
||||
<div className="mb-1 font-semibold">
|
||||
<div
|
||||
className="mb-1 font-semibold"
|
||||
style={{ color: theme === "dark" ? "white" : "black" }}
|
||||
>
|
||||
{capitalizeFirstLetter(hoveredItem.name)}
|
||||
</div>
|
||||
<div>Failure Rate: {hoveredItem.failurePercentage}%</div>
|
||||
<div>
|
||||
Failed: {hoveredItem.failedRequirements}/
|
||||
{hoveredItem.totalRequirements}
|
||||
<span
|
||||
style={{
|
||||
color: getHeatmapColor(hoveredItem.failurePercentage),
|
||||
}}
|
||||
>
|
||||
Failure Rate: {hoveredItem.failurePercentage}%
|
||||
</span>
|
||||
</div>
|
||||
<div>
|
||||
<span
|
||||
style={{
|
||||
color: getHeatmapColor(hoveredItem.failurePercentage),
|
||||
}}
|
||||
>
|
||||
Failed: {hoveredItem.failedRequirements}/
|
||||
{hoveredItem.totalRequirements}
|
||||
</span>
|
||||
</div>
|
||||
</div>
|
||||
)}
|
||||
|
||||
@@ -113,7 +113,7 @@ export const PieChart = ({ pass, fail, manual }: PieChartProps) => {
|
||||
|
||||
return (
|
||||
<div className="flex h-[320px] flex-col items-center justify-between">
|
||||
<h3 className="whitespace-nowrap text-xs font-semibold uppercase tracking-wide">
|
||||
<h3 className="text-xs font-semibold tracking-wide whitespace-nowrap uppercase">
|
||||
Requirements Status
|
||||
</h3>
|
||||
|
||||
@@ -176,15 +176,15 @@ export const PieChart = ({ pass, fail, manual }: PieChartProps) => {
|
||||
<div className="mt-2 grid grid-cols-3 gap-4">
|
||||
<div className="flex flex-col items-center">
|
||||
<div className="text-muted-foreground text-sm">Pass</div>
|
||||
<div className="font-semibold text-system-success-medium">{pass}</div>
|
||||
<div className="text-system-success-medium font-semibold">{pass}</div>
|
||||
</div>
|
||||
<div className="flex flex-col items-center">
|
||||
<div className="text-muted-foreground text-sm">Fail</div>
|
||||
<div className="font-semibold text-system-error-medium">{fail}</div>
|
||||
<div className="text-system-error-medium font-semibold">{fail}</div>
|
||||
</div>
|
||||
<div className="flex flex-col items-center">
|
||||
<div className="text-muted-foreground text-sm">Manual</div>
|
||||
<div className="font-semibold text-prowler-grey-light">{manual}</div>
|
||||
<div className="text-prowler-grey-light font-semibold">{manual}</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@@ -117,7 +117,7 @@ export const CISCustomDetails = ({ requirement }: CISDetailsProps) => {
|
||||
|
||||
{requirement.references && (
|
||||
<ComplianceDetailSection title="References">
|
||||
<div className="space-y-1">
|
||||
<div className="flex flex-col gap-1">
|
||||
{processReferences(requirement.references).map(
|
||||
(url: string, index: number) => (
|
||||
<div key={index}>
|
||||
|
||||
@@ -71,9 +71,12 @@ export const MITRECustomDetails = ({
|
||||
|
||||
{cloudServices && cloudServices.length > 0 && (
|
||||
<ComplianceDetailSection title="Cloud Security Mappings">
|
||||
<div className="space-y-4">
|
||||
<div className="flex flex-col gap-4">
|
||||
{cloudServices.map((service, index) => (
|
||||
<div key={index} className="space-y-3 rounded-lg border p-4">
|
||||
<div
|
||||
key={index}
|
||||
className="flex flex-col gap-3 rounded-lg border p-4"
|
||||
>
|
||||
<div className="flex flex-wrap items-center gap-3">
|
||||
<ComplianceBadge
|
||||
label="Service"
|
||||
|
||||
@@ -5,7 +5,7 @@ export const ComplianceDetailContainer = ({
|
||||
}: {
|
||||
children: React.ReactNode;
|
||||
}) => {
|
||||
return <div className="space-y-4">{children}</div>;
|
||||
return <div className="flex flex-col gap-4">{children}</div>;
|
||||
};
|
||||
|
||||
export const ComplianceDetailSection = ({
|
||||
@@ -107,7 +107,7 @@ export const ComplianceBulletList = ({
|
||||
|
||||
return (
|
||||
<ComplianceDetailSection title={title}>
|
||||
<div className="space-y-2">
|
||||
<div className="flex flex-col gap-2">
|
||||
{items.map((item: string, index: number) => (
|
||||
<div key={index} className="flex items-start gap-2">
|
||||
<span className="text-muted-foreground mt-1 text-xs">•</span>
|
||||
@@ -134,7 +134,7 @@ export const ComplianceChipContainer = ({
|
||||
{items.map((item: string, index: number) => (
|
||||
<span
|
||||
key={index}
|
||||
className="inline-flex items-center rounded-md bg-gray-50 px-2 py-1 text-xs font-medium text-gray-600 ring-1 ring-inset ring-gray-500/10 dark:bg-gray-400/10 dark:text-gray-400 dark:ring-gray-400/20"
|
||||
className="inline-flex items-center rounded-md bg-gray-50 px-2 py-1 text-xs font-medium text-gray-600 ring-1 ring-gray-500/10 ring-inset dark:bg-gray-400/10 dark:text-gray-400 dark:ring-gray-400/20"
|
||||
>
|
||||
{item}
|
||||
</span>
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
"use client";
|
||||
|
||||
import { Spacer } from "@nextui-org/react";
|
||||
import { Spacer } from "@heroui/spacer";
|
||||
|
||||
import { FilterControls } from "@/components/filters";
|
||||
import { DataTableFilterCustom } from "@/components/ui/table/data-table-filter-custom";
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
import { Divider, Tooltip } from "@nextui-org/react";
|
||||
import { Divider } from "@heroui/divider";
|
||||
import { Tooltip } from "@heroui/tooltip";
|
||||
|
||||
import { DateWithTime, EntityInfoShort } from "@/components/ui/entities";
|
||||
import { ProviderType } from "@/types";
|
||||
@@ -34,7 +35,7 @@ export const ComplianceScanInfo = ({ scan }: ComplianceScanInfoProps) => {
|
||||
placement="top"
|
||||
size="sm"
|
||||
>
|
||||
<p className="text-xs text-default-500">
|
||||
<p className="text-default-500 text-xs">
|
||||
{scan.attributes.name || "- -"}
|
||||
</p>
|
||||
</Tooltip>
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import { Select, SelectItem } from "@nextui-org/react";
|
||||
import { Select, SelectItem } from "@heroui/select";
|
||||
|
||||
import { ProviderType, ScanProps } from "@/types";
|
||||
|
||||
|
||||
@@ -9,7 +9,7 @@ export const NoScansAvailable = () => {
|
||||
return (
|
||||
<div className="flex h-full min-h-[calc(100vh-56px)] items-center justify-center">
|
||||
<div className="mx-auto w-full max-w-2xl">
|
||||
<div className="flex items-center justify-start rounded-lg border border-gray-200 bg-white p-6 dark:border-gray-700 dark:bg-prowler-blue-400">
|
||||
<div className="dark:bg-prowler-blue-400 flex items-center justify-start rounded-lg border border-gray-200 bg-white p-6 dark:border-gray-700">
|
||||
<div className="flex w-full items-center justify-between gap-6">
|
||||
<div className="flex items-start gap-4">
|
||||
<InfoIcon className="mt-1 h-5 w-5 text-gray-400 dark:text-gray-300" />
|
||||
@@ -25,7 +25,7 @@ export const NoScansAvailable = () => {
|
||||
</div>
|
||||
<CustomButton
|
||||
asLink="/scans"
|
||||
className="flex-shrink-0"
|
||||
className="shrink-0"
|
||||
ariaLabel="Go to Scans page"
|
||||
variant="solid"
|
||||
color="action"
|
||||
|
||||
@@ -1,20 +1,20 @@
|
||||
"use client";
|
||||
|
||||
import { Skeleton } from "@nextui-org/react";
|
||||
import { Skeleton } from "@heroui/skeleton";
|
||||
|
||||
export const BarChartSkeleton = () => {
|
||||
return (
|
||||
<div className="flex w-[400px] flex-col items-center justify-between">
|
||||
{/* Title skeleton */}
|
||||
<Skeleton className="h-4 w-40 rounded-lg">
|
||||
<div className="h-4 bg-default-200" />
|
||||
<div className="bg-default-200 h-4" />
|
||||
</Skeleton>
|
||||
|
||||
{/* Chart area skeleton */}
|
||||
<div className="ml-24 flex h-full flex-col justify-center space-y-2 p-4">
|
||||
<div className="ml-24 flex h-full flex-col justify-center gap-2 p-4">
|
||||
{/* Bar chart skeleton - 5 horizontal bars */}
|
||||
{Array.from({ length: 5 }).map((_, index) => (
|
||||
<div key={index} className="flex items-center space-x-4">
|
||||
<div key={index} className="flex items-center gap-4">
|
||||
{/* Bar skeleton with varying widths */}
|
||||
<Skeleton
|
||||
className={`h-10 rounded-lg ${
|
||||
@@ -29,20 +29,20 @@ export const BarChartSkeleton = () => {
|
||||
: "w-16"
|
||||
}`}
|
||||
>
|
||||
<div className="h-6 bg-default-200" />
|
||||
<div className="bg-default-200 h-6" />
|
||||
</Skeleton>
|
||||
</div>
|
||||
))}
|
||||
|
||||
{/* Legend skeleton */}
|
||||
<div className="flex justify-center space-x-4 pt-2">
|
||||
<div className="flex justify-center gap-4 pt-2">
|
||||
{Array.from({ length: 3 }).map((_, index) => (
|
||||
<div key={index} className="flex items-center space-x-1">
|
||||
<div key={index} className="flex items-center gap-1">
|
||||
<Skeleton className="h-3 w-3 rounded-full">
|
||||
<div className="h-3 w-3 bg-default-200" />
|
||||
<div className="bg-default-200 h-3 w-3" />
|
||||
</Skeleton>
|
||||
<Skeleton className="h-3 w-16 rounded-lg">
|
||||
<div className="h-3 bg-default-200" />
|
||||
<div className="bg-default-200 h-3" />
|
||||
</Skeleton>
|
||||
</div>
|
||||
))}
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import { Skeleton } from "@nextui-org/react";
|
||||
import { Skeleton } from "@heroui/skeleton";
|
||||
import React from "react";
|
||||
|
||||
interface SkeletonAccordionProps {
|
||||
@@ -16,7 +16,7 @@ export const SkeletonAccordion = ({
|
||||
|
||||
return (
|
||||
<div
|
||||
className={`w-full space-y-2 ${className} rounded-xl border border-gray-300 p-2 dark:border-gray-700`}
|
||||
className={`flex w-full flex-col gap-2 ${className} rounded-xl border border-gray-300 p-2 dark:border-gray-700`}
|
||||
>
|
||||
{[...Array(itemCount)].map((_, index) => (
|
||||
<Skeleton key={index} className="rounded-lg">
|
||||
|
||||
@@ -1,14 +1,15 @@
|
||||
import { Card, Skeleton } from "@nextui-org/react";
|
||||
import { Card } from "@heroui/card";
|
||||
import { Skeleton } from "@heroui/skeleton";
|
||||
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">
|
||||
<div className="3xl:grid-cols-4 grid grid-cols-1 gap-4 sm:grid-cols-2 lg:grid-cols-3 xl:grid-cols-3">
|
||||
{[...Array(28)].map((_, index) => (
|
||||
<div key={index} className="flex flex-col space-y-4">
|
||||
<div key={index} className="flex flex-col gap-4">
|
||||
<Skeleton className="h-28 rounded-lg">
|
||||
<div className="h-full bg-default-300"></div>
|
||||
<div className="bg-default-300 h-full"></div>
|
||||
</Skeleton>
|
||||
</div>
|
||||
))}
|
||||
|
||||
@@ -1,13 +1,13 @@
|
||||
"use client";
|
||||
|
||||
import { Skeleton } from "@nextui-org/react";
|
||||
import { Skeleton } from "@heroui/skeleton";
|
||||
|
||||
export const HeatmapChartSkeleton = () => {
|
||||
return (
|
||||
<div className="flex h-[320px] w-[400px] flex-col items-center justify-between lg:w-[400px]">
|
||||
{/* Title skeleton */}
|
||||
<Skeleton className="h-4 w-36 rounded-lg">
|
||||
<div className="h-4 bg-default-200" />
|
||||
<div className="bg-default-200 h-4" />
|
||||
</Skeleton>
|
||||
|
||||
{/* Heatmap area skeleton - 3x3 grid like the real component */}
|
||||
@@ -18,7 +18,7 @@ export const HeatmapChartSkeleton = () => {
|
||||
key={index}
|
||||
className="flex items-center justify-center rounded border"
|
||||
>
|
||||
<div className="h-full w-full bg-default-200" />
|
||||
<div className="bg-default-200 h-full w-full" />
|
||||
</Skeleton>
|
||||
))}
|
||||
</div>
|
||||
|
||||
@@ -1,32 +1,32 @@
|
||||
"use client";
|
||||
|
||||
import { Skeleton } from "@nextui-org/react";
|
||||
import { Skeleton } from "@heroui/skeleton";
|
||||
|
||||
export const PieChartSkeleton = () => {
|
||||
return (
|
||||
<div className="flex h-[320px] flex-col items-center justify-between">
|
||||
{/* Title skeleton */}
|
||||
<Skeleton className="h-4 w-32 rounded-lg">
|
||||
<div className="h-4 bg-default-200" />
|
||||
<div className="bg-default-200 h-4" />
|
||||
</Skeleton>
|
||||
|
||||
{/* Pie chart skeleton */}
|
||||
<div className="relative flex aspect-square w-[200px] min-w-[200px] items-center justify-center">
|
||||
{/* Outer circle */}
|
||||
<Skeleton className="absolute h-[200px] w-[200px] rounded-full">
|
||||
<div className="h-[200px] w-[200px] bg-default-200" />
|
||||
<div className="bg-default-200 h-[200px] w-[200px]" />
|
||||
</Skeleton>
|
||||
|
||||
{/* Inner circle (donut hole) */}
|
||||
<div className="absolute h-[140px] w-[140px] rounded-full bg-background"></div>
|
||||
<div className="bg-background absolute h-[140px] w-[140px] rounded-full"></div>
|
||||
|
||||
{/* Center text skeleton */}
|
||||
<div className="absolute flex flex-col items-center">
|
||||
<Skeleton className="h-6 w-8 rounded-lg">
|
||||
<div className="h-6 bg-default-300" />
|
||||
<div className="bg-default-300 h-6" />
|
||||
</Skeleton>
|
||||
<Skeleton className="mt-1 h-3 w-6 rounded-lg">
|
||||
<div className="h-3 bg-default-300" />
|
||||
<div className="bg-default-300 h-3" />
|
||||
</Skeleton>
|
||||
</div>
|
||||
</div>
|
||||
@@ -35,26 +35,26 @@ export const PieChartSkeleton = () => {
|
||||
<div className="mt-2 grid grid-cols-3 gap-4">
|
||||
<div className="flex flex-col items-center">
|
||||
<Skeleton className="h-4 w-8 rounded-lg">
|
||||
<div className="h-4 bg-default-200" />
|
||||
<div className="bg-default-200 h-4" />
|
||||
</Skeleton>
|
||||
<Skeleton className="mt-1 h-5 w-6 rounded-lg">
|
||||
<div className="h-5 bg-default-200" />
|
||||
<div className="bg-default-200 h-5" />
|
||||
</Skeleton>
|
||||
</div>
|
||||
<div className="flex flex-col items-center">
|
||||
<Skeleton className="h-4 w-6 rounded-lg">
|
||||
<div className="h-4 bg-default-200" />
|
||||
<div className="bg-default-200 h-4" />
|
||||
</Skeleton>
|
||||
<Skeleton className="mt-1 h-5 w-6 rounded-lg">
|
||||
<div className="h-5 bg-default-200" />
|
||||
<div className="bg-default-200 h-5" />
|
||||
</Skeleton>
|
||||
</div>
|
||||
<div className="flex flex-col items-center">
|
||||
<Skeleton className="h-4 w-12 rounded-lg">
|
||||
<div className="h-4 bg-default-200" />
|
||||
<div className="bg-default-200 h-4" />
|
||||
</Skeleton>
|
||||
<Skeleton className="mt-1 h-5 w-6 rounded-lg">
|
||||
<div className="h-5 bg-default-200" />
|
||||
<div className="bg-default-200 h-5" />
|
||||
</Skeleton>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@@ -53,7 +53,7 @@ export const FeedsDetail = () => {
|
||||
<Icon size={18} />
|
||||
{/* TODO: Update this condition once the RSS data response structure is finalized */}
|
||||
{feed.length > 0 && (
|
||||
<span className="absolute right-0 top-0 h-2 w-2 rounded-full bg-red-500 dark:bg-gray-400"></span>
|
||||
<span className="absolute top-0 right-0 h-2 w-2 rounded-full bg-red-500 dark:bg-gray-400"></span>
|
||||
)}
|
||||
</Button>
|
||||
</DropdownMenuTrigger>
|
||||
@@ -72,7 +72,7 @@ export const FeedsDetail = () => {
|
||||
target="_blank"
|
||||
className="flex flex-col"
|
||||
>
|
||||
<h3 className="text-small font-medium leading-none">
|
||||
<h3 className="text-small leading-none font-medium">
|
||||
{item.title}
|
||||
</h3>
|
||||
<p className="text-sm text-gray-500">{item.description}</p>
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
"use client";
|
||||
import { Select, SelectItem } from "@nextui-org/react";
|
||||
import { Select, SelectItem } from "@heroui/select";
|
||||
|
||||
const accounts = [
|
||||
{ key: "audit-test-1", label: "740350143844" },
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
"use client";
|
||||
|
||||
import { Checkbox } from "@nextui-org/react";
|
||||
import { Checkbox } from "@heroui/checkbox";
|
||||
import { useSearchParams } from "next/navigation";
|
||||
import { useState } from "react";
|
||||
|
||||
|
||||
@@ -1,12 +1,13 @@
|
||||
"use client";
|
||||
|
||||
import { Button, ButtonGroup } from "@heroui/button";
|
||||
import { DatePicker } from "@heroui/date-picker";
|
||||
import {
|
||||
getLocalTimeZone,
|
||||
startOfMonth,
|
||||
startOfWeek,
|
||||
today,
|
||||
} from "@internationalized/date";
|
||||
import { Button, ButtonGroup, DatePicker } from "@nextui-org/react";
|
||||
import { useLocale } from "@react-aria/i18n";
|
||||
import { useSearchParams } from "next/navigation";
|
||||
import React, { useCallback, useEffect, useRef } from "react";
|
||||
@@ -66,10 +67,10 @@ export const CustomDatePicker = () => {
|
||||
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"
|
||||
className="bg-content1 dark:bg-prowler-blue-400 [&>button]:border-default-200/60 [&>button]:text-default-500 px-3 pt-3 pb-2"
|
||||
radius="full"
|
||||
size="sm"
|
||||
variant="bordered"
|
||||
variant="flat"
|
||||
>
|
||||
<Button onPress={() => handleDateChange(now)}>Today</Button>
|
||||
<Button onPress={() => handleDateChange(nextWeek)}>
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
"use client";
|
||||
|
||||
import { Select, SelectItem } from "@nextui-org/react";
|
||||
import { Select, SelectItem } from "@heroui/select";
|
||||
import { useRouter, useSearchParams } from "next/navigation";
|
||||
import React, { useCallback, useMemo } from "react";
|
||||
|
||||
|
||||
@@ -1,8 +1,7 @@
|
||||
import { Input } from "@nextui-org/react";
|
||||
import debounce from "lodash.debounce";
|
||||
import { Input } from "@heroui/input";
|
||||
import { SearchIcon, XCircle } from "lucide-react";
|
||||
import { useSearchParams } from "next/navigation";
|
||||
import React, { useCallback, useEffect, useState } from "react";
|
||||
import React, { useCallback, useEffect, useRef, useState } from "react";
|
||||
|
||||
import { useUrlFilters } from "@/hooks/use-url-filters";
|
||||
|
||||
@@ -10,6 +9,7 @@ export const CustomSearchInput: React.FC = () => {
|
||||
const searchParams = useSearchParams();
|
||||
const { updateFilter } = useUrlFilters();
|
||||
const [searchQuery, setSearchQuery] = useState("");
|
||||
const debounceTimeoutRef = useRef<NodeJS.Timeout | null>(null);
|
||||
|
||||
const applySearch = useCallback(
|
||||
(query: string) => {
|
||||
@@ -24,7 +24,12 @@ export const CustomSearchInput: React.FC = () => {
|
||||
|
||||
const debouncedChangeHandler = useCallback(
|
||||
(value: string) => {
|
||||
debounce((val) => applySearch(val), 300)(value);
|
||||
if (debounceTimeoutRef.current) {
|
||||
clearTimeout(debounceTimeoutRef.current);
|
||||
}
|
||||
debounceTimeoutRef.current = setTimeout(() => {
|
||||
applySearch(value);
|
||||
}, 300);
|
||||
},
|
||||
[applySearch],
|
||||
);
|
||||
@@ -39,11 +44,19 @@ export const CustomSearchInput: React.FC = () => {
|
||||
setSearchQuery(searchFromUrl);
|
||||
}, [searchParams]);
|
||||
|
||||
useEffect(() => {
|
||||
return () => {
|
||||
if (debounceTimeoutRef.current) {
|
||||
clearTimeout(debounceTimeoutRef.current);
|
||||
}
|
||||
};
|
||||
}, []);
|
||||
|
||||
return (
|
||||
<Input
|
||||
variant="flat"
|
||||
classNames={{
|
||||
label: "tracking-tight font-light !text-default-600 text-sm !z-0 pb-1",
|
||||
label: "tracking-tight font-light !text-default-600 text-sm z-0! pb-1",
|
||||
}}
|
||||
aria-label="Search"
|
||||
label="Search"
|
||||
@@ -59,7 +72,7 @@ export const CustomSearchInput: React.FC = () => {
|
||||
endContent={
|
||||
searchQuery && (
|
||||
<button onClick={clearIconSearch} className="focus:outline-none">
|
||||
<XCircle className="h-4 w-4 text-default-400" />
|
||||
<XCircle className="text-default-400 h-4 w-4" />
|
||||
</button>
|
||||
)
|
||||
}
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
"use client";
|
||||
|
||||
import { Select, SelectItem } from "@nextui-org/react";
|
||||
import { Select, SelectItem } from "@heroui/select";
|
||||
import { useRouter, useSearchParams } from "next/navigation";
|
||||
import React, { useCallback, useMemo } from "react";
|
||||
|
||||
@@ -85,7 +85,7 @@ export const CustomSelectProvider: React.FC = () => {
|
||||
placeholder="Select a provider"
|
||||
classNames={{
|
||||
selectorIcon: "right-2",
|
||||
label: "!z-0 mb-2",
|
||||
label: "z-0! mb-2",
|
||||
}}
|
||||
label="Provider"
|
||||
labelPlacement="inside"
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
"use client";
|
||||
|
||||
import { Spacer } from "@nextui-org/react";
|
||||
import { Spacer } from "@heroui/spacer";
|
||||
import { useSearchParams } from "next/navigation";
|
||||
import React, { useEffect, useState } from "react";
|
||||
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import { Tooltip } from "@nextui-org/react";
|
||||
import { Tooltip } from "@heroui/tooltip";
|
||||
|
||||
import { MutedIcon } from "../icons";
|
||||
|
||||
@@ -15,8 +15,8 @@ export const Muted = ({
|
||||
|
||||
return (
|
||||
<Tooltip content={mutedReason} className="text-xs">
|
||||
<div className="w-fit rounded-full border border-system-severity-critical/40 p-1">
|
||||
<MutedIcon className="h-4 w-4 text-system-severity-critical" />
|
||||
<div className="border-system-severity-critical/40 w-fit rounded-full border p-1">
|
||||
<MutedIcon className="text-system-severity-critical h-4 w-4" />
|
||||
</div>
|
||||
</Tooltip>
|
||||
);
|
||||
|
||||
@@ -1,7 +1,9 @@
|
||||
"use client";
|
||||
|
||||
import { Input } from "@heroui/input";
|
||||
import { Select, SelectItem } from "@heroui/select";
|
||||
import { zodResolver } from "@hookform/resolvers/zod";
|
||||
import { Input, Select, type Selection, SelectItem } from "@nextui-org/react";
|
||||
import type { Selection } from "@react-types/shared";
|
||||
import { Search, Send } from "lucide-react";
|
||||
import {
|
||||
type Dispatch,
|
||||
@@ -222,7 +224,10 @@ export const SendToJiraModal = ({
|
||||
}
|
||||
>
|
||||
<Form {...form}>
|
||||
<form onSubmit={form.handleSubmit(handleSubmit)} className="space-y-4">
|
||||
<form
|
||||
onSubmit={form.handleSubmit(handleSubmit)}
|
||||
className="flex flex-col gap-4"
|
||||
>
|
||||
{/* Integration Selection */}
|
||||
{integrations.length > 1 && (
|
||||
<FormField
|
||||
@@ -256,7 +261,7 @@ export const SendToJiraModal = ({
|
||||
trigger: "min-h-12",
|
||||
popoverContent: "dark:bg-gray-800",
|
||||
label:
|
||||
"tracking-tight font-light !text-default-500 text-xs !z-0",
|
||||
"tracking-tight font-light !text-default-500 text-xs z-0!",
|
||||
value: "text-default-500 text-small dark:text-gray-300",
|
||||
}}
|
||||
>
|
||||
@@ -277,7 +282,7 @@ export const SendToJiraModal = ({
|
||||
))}
|
||||
</Select>
|
||||
</FormControl>
|
||||
<FormMessage className="text-xs text-system-error" />
|
||||
<FormMessage className="text-system-error text-xs" />
|
||||
</>
|
||||
)}
|
||||
/>
|
||||
@@ -312,13 +317,13 @@ export const SendToJiraModal = ({
|
||||
popoverContent: "dark:bg-gray-800",
|
||||
listboxWrapper: "max-h-[300px] dark:bg-gray-800",
|
||||
label:
|
||||
"tracking-tight font-light !text-default-500 text-xs !z-0",
|
||||
"tracking-tight font-light !text-default-500 text-xs z-0!",
|
||||
value: "text-default-500 text-small dark:text-gray-300",
|
||||
}}
|
||||
listboxProps={{
|
||||
topContent:
|
||||
filteredProjects.length > 5 ? (
|
||||
<div className="sticky top-0 z-10 bg-content1 py-2 dark:bg-gray-800">
|
||||
<div className="bg-content1 sticky top-0 z-10 py-2 dark:bg-gray-800">
|
||||
<Input
|
||||
isClearable
|
||||
placeholder="Search projects..."
|
||||
@@ -350,7 +355,7 @@ export const SendToJiraModal = ({
|
||||
<span className="text-tiny text-default-500">
|
||||
-
|
||||
</span>
|
||||
<span className="truncate text-small">
|
||||
<span className="text-small truncate">
|
||||
{name}
|
||||
</span>
|
||||
</div>
|
||||
@@ -361,7 +366,7 @@ export const SendToJiraModal = ({
|
||||
))}
|
||||
</Select>
|
||||
</FormControl>
|
||||
<FormMessage className="text-xs text-system-error" />
|
||||
<FormMessage className="text-system-error text-xs" />
|
||||
</>
|
||||
)}
|
||||
/>
|
||||
@@ -393,7 +398,7 @@ export const SendToJiraModal = ({
|
||||
popoverContent: "dark:bg-gray-800",
|
||||
listboxWrapper: "max-h-[300px] dark:bg-gray-800",
|
||||
label:
|
||||
"tracking-tight font-light !text-default-500 text-xs !z-0",
|
||||
"tracking-tight font-light !text-default-500 text-xs z-0!",
|
||||
value: "text-default-500 text-small dark:text-gray-300",
|
||||
}}
|
||||
listboxProps={{
|
||||
|
||||
@@ -109,18 +109,18 @@ export const ColumnFindings: ColumnDef<FindingProps>[] = [
|
||||
const { delta } = row.original.attributes;
|
||||
|
||||
return (
|
||||
<div className="relative flex max-w-[410px] flex-row items-center gap-2 3xl:max-w-[660px]">
|
||||
<div className="3xl:max-w-[660px] relative flex max-w-[410px] flex-row items-center gap-2">
|
||||
<div className="flex flex-row items-center gap-4">
|
||||
{delta === "new" || delta === "changed" ? (
|
||||
<DeltaIndicator delta={delta} />
|
||||
) : (
|
||||
<div className="w-2" />
|
||||
)}
|
||||
<p className="mr-7 whitespace-normal break-words text-sm">
|
||||
<p className="mr-7 text-sm break-words whitespace-normal">
|
||||
{checktitle}
|
||||
</p>
|
||||
</div>
|
||||
<span className="absolute -right-2 top-1/2 -translate-y-1/2">
|
||||
<span className="absolute top-1/2 -right-2 -translate-y-1/2">
|
||||
<Muted isMuted={muted} mutedReason={muted_reason || ""} />
|
||||
</span>
|
||||
</div>
|
||||
|
||||
@@ -1,13 +1,13 @@
|
||||
"use client";
|
||||
|
||||
import { Button } from "@heroui/button";
|
||||
import {
|
||||
Button,
|
||||
Dropdown,
|
||||
DropdownItem,
|
||||
DropdownMenu,
|
||||
DropdownSection,
|
||||
DropdownTrigger,
|
||||
} from "@nextui-org/react";
|
||||
} from "@heroui/dropdown";
|
||||
import { Row } from "@tanstack/react-table";
|
||||
import { useState } from "react";
|
||||
|
||||
@@ -38,7 +38,7 @@ export function DataTableRowActions({ row }: DataTableRowActionsProps) {
|
||||
|
||||
<div className="relative flex items-center justify-end gap-2">
|
||||
<Dropdown
|
||||
className="shadow-xl dark:bg-prowler-blue-800"
|
||||
className="dark:bg-prowler-blue-800 shadow-xl"
|
||||
placement="bottom"
|
||||
>
|
||||
<DropdownTrigger>
|
||||
@@ -60,7 +60,7 @@ export function DataTableRowActions({ row }: DataTableRowActionsProps) {
|
||||
startContent={
|
||||
<JiraIcon
|
||||
size={20}
|
||||
className="pointer-events-none flex-shrink-0 text-default-500"
|
||||
className="text-default-500 pointer-events-none shrink-0"
|
||||
/>
|
||||
}
|
||||
onPress={() => setIsJiraModalOpen(true)}
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import { Tooltip } from "@nextui-org/react";
|
||||
import { Tooltip } from "@heroui/tooltip";
|
||||
|
||||
import { CustomButton } from "@/components/ui/custom/custom-button";
|
||||
import { cn } from "@/lib/utils";
|
||||
@@ -22,7 +22,7 @@ export const DeltaIndicator = ({ delta }: DeltaIndicatorProps) => {
|
||||
ariaLabel="Learn more about findings"
|
||||
color="transparent"
|
||||
size="sm"
|
||||
className="h-auto min-w-0 p-0 text-primary"
|
||||
className="text-primary h-auto min-w-0 p-0"
|
||||
asLink="https://docs.prowler.com/projects/prowler-open-source/en/latest/tutorials/prowler-app/#step-8-analyze-the-findings"
|
||||
target="_blank"
|
||||
>
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
"use client";
|
||||
|
||||
import { Snippet } from "@nextui-org/react";
|
||||
import { Snippet } from "@heroui/snippet";
|
||||
import ReactMarkdown from "react-markdown";
|
||||
|
||||
import { CodeSnippet } from "@/components/ui/code-snippet/code-snippet";
|
||||
@@ -20,7 +20,7 @@ import { DeltaIndicator } from "./delta-indicator";
|
||||
|
||||
const MarkdownContainer = ({ children }: { children: string }) => {
|
||||
return (
|
||||
<div className="prose prose-sm max-w-none whitespace-normal break-words dark:prose-invert">
|
||||
<div className="prose prose-sm dark:prose-invert max-w-none break-words whitespace-normal">
|
||||
<ReactMarkdown>{children}</ReactMarkdown>
|
||||
</div>
|
||||
);
|
||||
@@ -65,7 +65,7 @@ export const FindingDetail = ({
|
||||
{/* Header */}
|
||||
<div className="flex items-center justify-between">
|
||||
<div>
|
||||
<h2 className="line-clamp-2 text-lg font-medium leading-tight text-gray-800 dark:text-prowler-theme-pale/90">
|
||||
<h2 className="dark:text-prowler-theme-pale/90 line-clamp-2 text-lg leading-tight font-medium text-gray-800">
|
||||
{renderValue(attributes.check_metadata.checktitle)}
|
||||
<CopyLinkButton url={url} />
|
||||
</h2>
|
||||
@@ -82,7 +82,7 @@ export const FindingDetail = ({
|
||||
? "bg-green-100 text-green-600"
|
||||
: attributes.status === "MANUAL"
|
||||
? "bg-gray-100 text-gray-600"
|
||||
: "bg-red-100 text-system-severity-critical"
|
||||
: "text-system-severity-critical bg-red-100"
|
||||
}`}
|
||||
>
|
||||
{renderValue(attributes.status)}
|
||||
@@ -159,7 +159,7 @@ export const FindingDetail = ({
|
||||
|
||||
{attributes.check_metadata.remediation && (
|
||||
<div className="flex flex-col gap-4">
|
||||
<h4 className="text-sm font-bold text-gray-700 dark:text-prowler-theme-pale/90">
|
||||
<h4 className="dark:text-prowler-theme-pale/90 text-sm font-bold text-gray-700">
|
||||
Remediation Details
|
||||
</h4>
|
||||
|
||||
@@ -189,7 +189,7 @@ export const FindingDetail = ({
|
||||
{attributes.check_metadata.remediation.code.cli && (
|
||||
<InfoField label="CLI Command" variant="simple">
|
||||
<Snippet className="bg-gray-50 py-1 dark:bg-slate-800">
|
||||
<span className="whitespace-pre-line text-xs">
|
||||
<span className="text-xs whitespace-pre-line">
|
||||
{attributes.check_metadata.remediation.code.cli}
|
||||
</span>
|
||||
</Snippet>
|
||||
@@ -216,7 +216,7 @@ export const FindingDetail = ({
|
||||
key={idx}
|
||||
href={link}
|
||||
size="sm"
|
||||
className="!whitespace-normal break-all"
|
||||
className="break-all whitespace-normal!"
|
||||
>
|
||||
{link}
|
||||
</CustomLink>
|
||||
@@ -237,7 +237,7 @@ export const FindingDetail = ({
|
||||
<CustomSection title="Resource Details">
|
||||
<InfoField label="Resource ID" variant="simple">
|
||||
<Snippet className="bg-gray-50 py-1 dark:bg-slate-800" hideSymbol>
|
||||
<span className="whitespace-pre-line text-xs">
|
||||
<span className="text-xs whitespace-pre-line">
|
||||
{renderValue(resource.uid)}
|
||||
</span>
|
||||
</Snippet>
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
"use client";
|
||||
|
||||
import { Card, CardBody, CardHeader } from "@nextui-org/react";
|
||||
import { Card, CardBody, CardHeader } from "@heroui/card";
|
||||
import { SettingsIcon } from "lucide-react";
|
||||
|
||||
import { JiraIcon } from "@/components/icons/services/IconServices";
|
||||
@@ -19,7 +19,7 @@ export const JiraIntegrationCard = () => {
|
||||
Jira
|
||||
</h4>
|
||||
<div className="flex flex-col items-start gap-2 sm:flex-row sm:items-center">
|
||||
<p className="text-nowrap text-xs text-gray-500 dark:text-gray-300">
|
||||
<p className="text-xs text-nowrap text-gray-500 dark:text-gray-300">
|
||||
Create and manage security issues in Jira.
|
||||
</p>
|
||||
<CustomLink
|
||||
|
||||
@@ -222,11 +222,11 @@ export const JiraIntegrationForm = ({
|
||||
<Form {...form}>
|
||||
<form
|
||||
onSubmit={form.handleSubmit(onSubmit)}
|
||||
className="flex flex-col space-y-6"
|
||||
className="flex flex-col gap-6"
|
||||
>
|
||||
<div className="flex flex-col space-y-4">
|
||||
<div className="flex flex-col gap-4">
|
||||
<div className="flex flex-col items-start gap-2 sm:flex-row sm:items-center">
|
||||
<p className="flex items-center gap-2 text-sm text-default-500">
|
||||
<p className="text-default-500 flex items-center gap-2 text-sm">
|
||||
Need help configuring your Jira integration?
|
||||
</p>
|
||||
<CustomLink
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
"use client";
|
||||
|
||||
import { Card, CardBody, CardHeader } from "@nextui-org/react";
|
||||
import { Card, CardBody, CardHeader } from "@heroui/card";
|
||||
import { format } from "date-fns";
|
||||
import { PlusIcon, Trash2Icon } from "lucide-react";
|
||||
import { useState } from "react";
|
||||
@@ -214,7 +214,7 @@ export const JiraIntegrationsManager = ({
|
||||
title="Delete Jira Integration"
|
||||
description="This action cannot be undone. This will permanently delete your Jira integration."
|
||||
>
|
||||
<div className="flex w-full justify-center space-x-6">
|
||||
<div className="flex w-full justify-center gap-6">
|
||||
<CustomButton
|
||||
type="button"
|
||||
ariaLabel="Cancel"
|
||||
@@ -265,7 +265,7 @@ export const JiraIntegrationsManager = ({
|
||||
/>
|
||||
</CustomAlertModal>
|
||||
|
||||
<div className="space-y-6">
|
||||
<div className="flex flex-col gap-6">
|
||||
{/* Header with Add Button */}
|
||||
<div className="flex items-center justify-between">
|
||||
<div>
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
"use client";
|
||||
|
||||
import { Card, CardBody, CardHeader } from "@nextui-org/react";
|
||||
import { Card, CardBody, CardHeader } from "@heroui/card";
|
||||
import { SettingsIcon } from "lucide-react";
|
||||
|
||||
import { AmazonS3Icon } from "@/components/icons/services/IconServices";
|
||||
@@ -19,7 +19,7 @@ export const S3IntegrationCard = () => {
|
||||
Amazon S3
|
||||
</h4>
|
||||
<div className="flex flex-col items-start gap-2 sm:flex-row sm:items-center">
|
||||
<p className="text-nowrap text-xs text-gray-500 dark:text-gray-300">
|
||||
<p className="text-xs text-nowrap text-gray-500 dark:text-gray-300">
|
||||
Export security findings to Amazon S3 buckets.
|
||||
</p>
|
||||
<CustomLink
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
"use client";
|
||||
|
||||
import { Divider } from "@heroui/divider";
|
||||
import { zodResolver } from "@hookform/resolvers/zod";
|
||||
import { Divider } from "@nextui-org/react";
|
||||
import { ArrowLeftIcon, ArrowRightIcon } from "lucide-react";
|
||||
import { useSession } from "next-auth/react";
|
||||
import { useState } from "react";
|
||||
@@ -275,7 +275,7 @@ export const S3IntegrationForm = ({
|
||||
return (
|
||||
<>
|
||||
{/* Provider Selection */}
|
||||
<div className="space-y-4">
|
||||
<div className="flex flex-col gap-4">
|
||||
<EnhancedProviderSelector
|
||||
control={form.control}
|
||||
name="providers"
|
||||
@@ -291,7 +291,7 @@ export const S3IntegrationForm = ({
|
||||
<Divider />
|
||||
|
||||
{/* S3 Configuration */}
|
||||
<div className="space-y-4">
|
||||
<div className="flex flex-col gap-4">
|
||||
<CustomInput
|
||||
control={form.control}
|
||||
name="bucket_name"
|
||||
@@ -386,11 +386,11 @@ export const S3IntegrationForm = ({
|
||||
? handleNext
|
||||
: form.handleSubmit(onSubmit)
|
||||
}
|
||||
className="flex flex-col space-y-6"
|
||||
className="flex flex-col gap-6"
|
||||
>
|
||||
<div className="flex flex-col space-y-4">
|
||||
<div className="flex flex-col gap-4">
|
||||
<div className="flex flex-col items-start gap-2 sm:flex-row sm:items-center">
|
||||
<p className="flex items-center gap-2 text-sm text-default-500">
|
||||
<p className="text-default-500 flex items-center gap-2 text-sm">
|
||||
Need help configuring your Amazon S3 integration?
|
||||
</p>
|
||||
<CustomLink
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
"use client";
|
||||
|
||||
import { Card, CardBody, CardHeader } from "@nextui-org/react";
|
||||
import { Card, CardBody, CardHeader } from "@heroui/card";
|
||||
import { format } from "date-fns";
|
||||
import { PlusIcon, Trash2Icon } from "lucide-react";
|
||||
import { useState } from "react";
|
||||
@@ -214,7 +214,7 @@ export const S3IntegrationsManager = ({
|
||||
title="Delete S3 Integration"
|
||||
description="This action cannot be undone. This will permanently delete your S3 integration."
|
||||
>
|
||||
<div className="flex w-full justify-center space-x-6">
|
||||
<div className="flex w-full justify-center gap-6">
|
||||
<CustomButton
|
||||
type="button"
|
||||
ariaLabel="Cancel"
|
||||
@@ -271,7 +271,7 @@ export const S3IntegrationsManager = ({
|
||||
/>
|
||||
</CustomAlertModal>
|
||||
|
||||
<div className="space-y-6">
|
||||
<div className="flex flex-col gap-6">
|
||||
{/* Header with Add Button */}
|
||||
<div className="flex items-center justify-between">
|
||||
<div>
|
||||
|
||||
@@ -1,7 +1,13 @@
|
||||
"use client";
|
||||
|
||||
import { Dispatch, SetStateAction, useEffect, useRef, useState } from "react";
|
||||
import { useFormState } from "react-dom";
|
||||
import {
|
||||
Dispatch,
|
||||
SetStateAction,
|
||||
useActionState,
|
||||
useEffect,
|
||||
useRef,
|
||||
useState,
|
||||
} from "react";
|
||||
import { z } from "zod";
|
||||
|
||||
import { createSamlConfig, updateSamlConfig } from "@/actions/integrations";
|
||||
@@ -110,7 +116,7 @@ export const SamlConfigForm = ({
|
||||
setIsOpen: Dispatch<SetStateAction<boolean>>;
|
||||
samlConfig?: any;
|
||||
}) => {
|
||||
const [state, formAction, isPending] = useFormState(
|
||||
const [state, formAction, isPending] = useActionState(
|
||||
samlConfig?.id ? updateSamlConfig : createSamlConfig,
|
||||
null,
|
||||
);
|
||||
@@ -251,7 +257,7 @@ export const SamlConfigForm = ({
|
||||
: `${apiBaseUrl}/accounts/saml/your-domain.com/acs/`;
|
||||
|
||||
return (
|
||||
<form ref={formRef} action={formAction} className="flex flex-col space-y-2">
|
||||
<form ref={formRef} action={formAction} className="flex flex-col gap-2">
|
||||
<div className="py-1 text-xs">
|
||||
Need help configuring SAML SSO?{" "}
|
||||
<CustomLink
|
||||
@@ -287,14 +293,14 @@ export const SamlConfigForm = ({
|
||||
}}
|
||||
/>
|
||||
|
||||
<div className="space-y-4 rounded-lg bg-gray-50 p-4 dark:bg-gray-800">
|
||||
<div className="flex flex-col gap-4 rounded-lg bg-gray-50 p-4 dark:bg-gray-800">
|
||||
<h3 className="text-lg font-semibold">
|
||||
Identity Provider Configuration
|
||||
</h3>
|
||||
|
||||
<div className="space-y-4">
|
||||
<div className="flex flex-col gap-4">
|
||||
<div>
|
||||
<span className="mb-2 block text-sm font-medium text-default-500">
|
||||
<span className="text-default-500 mb-2 block text-sm font-medium">
|
||||
ACS URL:
|
||||
</span>
|
||||
<SnippetChip
|
||||
@@ -305,7 +311,7 @@ export const SamlConfigForm = ({
|
||||
</div>
|
||||
|
||||
<div>
|
||||
<span className="mb-2 block text-sm font-medium text-default-500">
|
||||
<span className="text-default-500 mb-2 block text-sm font-medium">
|
||||
Audience:
|
||||
</span>
|
||||
<SnippetChip
|
||||
@@ -316,19 +322,19 @@ export const SamlConfigForm = ({
|
||||
</div>
|
||||
|
||||
<div>
|
||||
<span className="mb-2 block text-sm font-medium text-default-500">
|
||||
<span className="text-default-500 mb-2 block text-sm font-medium">
|
||||
Name ID Format:
|
||||
</span>
|
||||
<span className="w-full text-sm text-default-600">
|
||||
<span className="text-default-600 w-full text-sm">
|
||||
urn:oasis:names:tc:SAML:1.1:nameid-format:emailAddress
|
||||
</span>
|
||||
</div>
|
||||
|
||||
<div>
|
||||
<span className="mb-2 block text-sm font-medium text-default-500">
|
||||
<span className="text-default-500 mb-2 block text-sm font-medium">
|
||||
Supported Assertion Attributes:
|
||||
</span>
|
||||
<ul className="ml-4 space-y-1 text-sm text-default-600">
|
||||
<ul className="text-default-600 ml-4 flex flex-col gap-1 text-sm">
|
||||
<li>• firstName</li>
|
||||
<li>• lastName</li>
|
||||
<li>• userType</li>
|
||||
@@ -347,8 +353,8 @@ export const SamlConfigForm = ({
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div className="flex flex-col items-start space-y-2">
|
||||
<span className="text-xs text-default-500">
|
||||
<div className="flex flex-col items-start gap-2">
|
||||
<span className="text-default-500 text-xs">
|
||||
Metadata XML File <span className="text-red-500">*</span>
|
||||
</span>
|
||||
<CustomButton
|
||||
@@ -364,7 +370,7 @@ export const SamlConfigForm = ({
|
||||
}
|
||||
}}
|
||||
startContent={<AddIcon size={20} />}
|
||||
className={`h-10 justify-start rounded-medium border-2 text-default-500 ${
|
||||
className={`rounded-medium text-default-500 h-10 justify-start border-2 ${
|
||||
(
|
||||
clientErrors.metadata_xml === null
|
||||
? undefined
|
||||
@@ -378,7 +384,7 @@ export const SamlConfigForm = ({
|
||||
>
|
||||
<span className="text-small">
|
||||
{uploadedFile ? (
|
||||
<span className="flex items-center space-x-2">
|
||||
<span className="flex items-center gap-2">
|
||||
<span className="max-w-36 truncate">{uploadedFile.name}</span>
|
||||
</span>
|
||||
) : (
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
"use client";
|
||||
|
||||
import { Card, CardBody, CardHeader } from "@nextui-org/react";
|
||||
import { Card, CardBody, CardHeader } from "@heroui/card";
|
||||
import { CheckIcon, Trash2Icon } from "lucide-react";
|
||||
import { useState } from "react";
|
||||
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
"use client";
|
||||
|
||||
import { Card, CardBody, CardHeader } from "@nextui-org/react";
|
||||
import { Card, CardBody, CardHeader } from "@heroui/card";
|
||||
import { SettingsIcon } from "lucide-react";
|
||||
|
||||
import { AWSSecurityHubIcon } from "@/components/icons/services/IconServices";
|
||||
@@ -19,7 +19,7 @@ export const SecurityHubIntegrationCard = () => {
|
||||
AWS Security Hub
|
||||
</h4>
|
||||
<div className="flex flex-col items-start gap-2 sm:flex-row sm:items-center">
|
||||
<p className="text-nowrap text-xs text-gray-500 dark:text-gray-300">
|
||||
<p className="text-xs text-nowrap text-gray-500 dark:text-gray-300">
|
||||
Send security findings to AWS Security Hub.
|
||||
</p>
|
||||
<CustomLink
|
||||
|
||||
@@ -1,7 +1,9 @@
|
||||
"use client";
|
||||
|
||||
import { Checkbox } from "@heroui/checkbox";
|
||||
import { Divider } from "@heroui/divider";
|
||||
import { Radio, RadioGroup } from "@heroui/radio";
|
||||
import { zodResolver } from "@hookform/resolvers/zod";
|
||||
import { Checkbox, Divider, Radio, RadioGroup } from "@nextui-org/react";
|
||||
import { ArrowLeftIcon, ArrowRightIcon } from "lucide-react";
|
||||
import { useSession } from "next-auth/react";
|
||||
import { useEffect, useMemo, useState } from "react";
|
||||
@@ -250,7 +252,7 @@ export const SecurityHubIntegrationForm = ({
|
||||
if (isEditingCredentials) {
|
||||
// When editing credentials, show the credential type selector first
|
||||
return (
|
||||
<div className="space-y-4">
|
||||
<div className="flex flex-col gap-4">
|
||||
<RadioGroup
|
||||
size="sm"
|
||||
aria-label="Credential type"
|
||||
@@ -319,7 +321,7 @@ export const SecurityHubIntegrationForm = ({
|
||||
<>
|
||||
{!isEditingConfig && (
|
||||
<>
|
||||
<div className="space-y-4">
|
||||
<div className="flex flex-col gap-4">
|
||||
<EnhancedProviderSelector
|
||||
control={form.control}
|
||||
name="provider_id"
|
||||
@@ -473,11 +475,11 @@ export const SecurityHubIntegrationForm = ({
|
||||
? handleNext
|
||||
: form.handleSubmit(onSubmit)
|
||||
}
|
||||
className="flex flex-col space-y-6"
|
||||
className="flex flex-col gap-6"
|
||||
>
|
||||
<div className="flex flex-col space-y-4">
|
||||
<div className="flex flex-col gap-4">
|
||||
<div className="flex flex-col items-start gap-2 sm:flex-row sm:items-center">
|
||||
<p className="flex items-center gap-2 text-sm text-default-500">
|
||||
<p className="text-default-500 flex items-center gap-2 text-sm">
|
||||
Need help configuring your AWS Security Hub integration?
|
||||
</p>
|
||||
<CustomLink
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
"use client";
|
||||
|
||||
import { Card, CardBody, CardHeader, Chip } from "@nextui-org/react";
|
||||
import { Card, CardBody, CardHeader } from "@heroui/card";
|
||||
import { Chip } from "@heroui/chip";
|
||||
import { format } from "date-fns";
|
||||
import { PlusIcon, Trash2Icon } from "lucide-react";
|
||||
import { useState } from "react";
|
||||
@@ -263,7 +264,7 @@ export const SecurityHubIntegrationsManager = ({
|
||||
title="Delete Security Hub Integration"
|
||||
description="This action cannot be undone. This will permanently delete your Security Hub integration."
|
||||
>
|
||||
<div className="flex w-full justify-center space-x-6">
|
||||
<div className="flex w-full justify-center gap-6">
|
||||
<CustomButton
|
||||
type="button"
|
||||
ariaLabel="Cancel"
|
||||
@@ -321,7 +322,7 @@ export const SecurityHubIntegrationsManager = ({
|
||||
/>
|
||||
</CustomAlertModal>
|
||||
|
||||
<div className="space-y-6">
|
||||
<div className="flex flex-col gap-6">
|
||||
<div className="flex items-center justify-between">
|
||||
<div>
|
||||
<h3 className="text-lg font-semibold">
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
"use client";
|
||||
|
||||
import { Chip } from "@nextui-org/react";
|
||||
import { Chip } from "@heroui/chip";
|
||||
import { ExternalLink } from "lucide-react";
|
||||
import { ReactNode } from "react";
|
||||
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
"use client";
|
||||
|
||||
import { Card, CardBody, CardHeader, Skeleton } from "@nextui-org/react";
|
||||
import { Card, CardBody, CardHeader } from "@heroui/card";
|
||||
import { Skeleton } from "@heroui/skeleton";
|
||||
import { ReactNode } from "react";
|
||||
|
||||
interface IntegrationSkeletonProps {
|
||||
@@ -75,7 +76,7 @@ export const IntegrationSkeleton = ({
|
||||
<div className="flex flex-wrap gap-1">
|
||||
<Skeleton className="h-6 w-16 rounded-full" />
|
||||
<Skeleton className="h-6 w-20 rounded-full" />
|
||||
<Skeleton className="w-18 h-6 rounded-full" />
|
||||
<Skeleton className="h-6 w-18 rounded-full" />
|
||||
</div>
|
||||
<div className="flex flex-col gap-3 sm:flex-row sm:items-center sm:justify-between">
|
||||
<Skeleton className="h-3 w-32 rounded" />
|
||||
|
||||
@@ -62,7 +62,7 @@ export const DeleteForm = ({
|
||||
<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">
|
||||
<div className="flex w-full justify-center sm:gap-6">
|
||||
<CustomButton
|
||||
type="button"
|
||||
ariaLabel="Cancel"
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
import { Select, SelectItem } from "@heroui/select";
|
||||
import { zodResolver } from "@hookform/resolvers/zod";
|
||||
import { Select, SelectItem } from "@nextui-org/react";
|
||||
import { MailIcon, ShieldIcon } from "lucide-react";
|
||||
import { Dispatch, SetStateAction } from "react";
|
||||
import { Controller, useForm } from "react-hook-form";
|
||||
@@ -92,17 +92,17 @@ export const EditForm = ({
|
||||
<Form {...form}>
|
||||
<form
|
||||
onSubmit={form.handleSubmit(onSubmitClient)}
|
||||
className="flex flex-col space-y-4"
|
||||
className="flex flex-col gap-4"
|
||||
>
|
||||
<div className="flex flex-row justify-center space-x-4 rounded-lg bg-gray-50 p-3">
|
||||
<div className="flex items-center text-small text-gray-600">
|
||||
<div className="flex flex-row justify-center gap-4 rounded-lg bg-gray-50 p-3">
|
||||
<div className="text-small flex items-center text-gray-600">
|
||||
<MailIcon className="mr-2 h-4 w-4" />
|
||||
<span className="text-gray-500">Email:</span>
|
||||
<span className="ml-2 font-semibold text-gray-900">
|
||||
{invitationEmail}
|
||||
</span>
|
||||
</div>
|
||||
<div className="flex items-center text-small text-gray-600">
|
||||
<div className="text-small flex items-center text-gray-600">
|
||||
<ShieldIcon className="mr-2 h-4 w-4" />
|
||||
<span className="text-gray-500">Role:</span>
|
||||
<span className="ml-2 font-semibold text-gray-900">
|
||||
@@ -119,7 +119,7 @@ export const EditForm = ({
|
||||
label="Email"
|
||||
labelPlacement="outside"
|
||||
placeholder={invitationEmail}
|
||||
variant="bordered"
|
||||
variant="flat"
|
||||
isRequired={false}
|
||||
isInvalid={!!form.formState.errors.invitationEmail}
|
||||
/>
|
||||
@@ -136,7 +136,7 @@ export const EditForm = ({
|
||||
classNames={{
|
||||
selectorIcon: "right-2",
|
||||
}}
|
||||
variant="bordered"
|
||||
variant="flat"
|
||||
selectedKeys={[field.value || ""]}
|
||||
onSelectionChange={(selected) =>
|
||||
field.onChange(selected?.currentKey || "")
|
||||
@@ -157,7 +157,7 @@ export const EditForm = ({
|
||||
</div>
|
||||
<input type="hidden" name="invitationId" value={invitationId} />
|
||||
|
||||
<div className="flex w-full justify-center sm:space-x-6">
|
||||
<div className="flex w-full justify-center sm:gap-6">
|
||||
<CustomButton
|
||||
type="button"
|
||||
ariaLabel="Cancel"
|
||||
|
||||
@@ -1,6 +1,8 @@
|
||||
"use client";
|
||||
|
||||
import { Card, CardBody, Divider, Snippet } from "@nextui-org/react";
|
||||
import { Card, CardBody } from "@heroui/card";
|
||||
import { Divider } from "@heroui/divider";
|
||||
import { Snippet } from "@heroui/snippet";
|
||||
|
||||
import { AddIcon } from "../icons";
|
||||
import { CustomButton } from "../ui/custom";
|
||||
@@ -53,16 +55,16 @@ export const InvitationDetails = ({ attributes }: InvitationDetailsProps) => {
|
||||
<div className="flex flex-col gap-x-4 gap-y-8">
|
||||
<Card
|
||||
isBlurred
|
||||
className="border-none bg-background/60 dark:bg-prowler-blue-800"
|
||||
className="bg-background/60 dark:bg-prowler-blue-800 border-none"
|
||||
shadow="sm"
|
||||
>
|
||||
<CardBody>
|
||||
<h2 className="text-md font-bold text-foreground/90">
|
||||
<h2 className="text-md text-foreground/90 font-bold">
|
||||
Invitation details
|
||||
</h2>
|
||||
<Divider className="my-4" />
|
||||
|
||||
<div className="space-y-3">
|
||||
<div className="flex flex-col gap-3">
|
||||
<InfoField label="Email">{attributes.email}</InfoField>
|
||||
|
||||
<InfoField label="Token">{attributes.token}</InfoField>
|
||||
@@ -87,7 +89,7 @@ export const InvitationDetails = ({ attributes }: InvitationDetailsProps) => {
|
||||
</div>
|
||||
|
||||
<Divider className="my-4" />
|
||||
<h3 className="pb-2 text-small font-bold text-foreground/90">
|
||||
<h3 className="text-small text-foreground/90 pb-2 font-bold">
|
||||
Share this link with the user:
|
||||
</h3>
|
||||
|
||||
@@ -98,9 +100,9 @@ export const InvitationDetails = ({ attributes }: InvitationDetailsProps) => {
|
||||
}}
|
||||
hideSymbol
|
||||
variant="bordered"
|
||||
className="overflow-hidden text-ellipsis whitespace-nowrap bg-gray-50 py-1 dark:bg-slate-800"
|
||||
className="overflow-hidden bg-gray-50 py-1 text-ellipsis whitespace-nowrap dark:bg-slate-800"
|
||||
>
|
||||
<p className="no-scrollbar w-fit overflow-hidden overflow-x-scroll text-ellipsis whitespace-nowrap text-small">
|
||||
<p className="no-scrollbar text-small w-fit overflow-hidden overflow-x-scroll text-ellipsis whitespace-nowrap">
|
||||
{invitationLink}
|
||||
</p>
|
||||
</Snippet>
|
||||
|
||||
@@ -1,18 +1,18 @@
|
||||
"use client";
|
||||
|
||||
import { Button } from "@heroui/button";
|
||||
import {
|
||||
Button,
|
||||
Dropdown,
|
||||
DropdownItem,
|
||||
DropdownMenu,
|
||||
DropdownSection,
|
||||
DropdownTrigger,
|
||||
} from "@nextui-org/react";
|
||||
} from "@heroui/dropdown";
|
||||
import {
|
||||
AddNoteBulkIcon,
|
||||
DeleteDocumentBulkIcon,
|
||||
EditDocumentBulkIcon,
|
||||
} from "@nextui-org/shared-icons";
|
||||
} from "@heroui/shared-icons";
|
||||
import { Row } from "@tanstack/react-table";
|
||||
import clsx from "clsx";
|
||||
import { useRouter } from "next/navigation";
|
||||
@@ -27,8 +27,7 @@ interface DataTableRowActionsProps<InvitationProps> {
|
||||
row: Row<InvitationProps>;
|
||||
roles?: { id: string; name: string }[];
|
||||
}
|
||||
const iconClasses =
|
||||
"text-2xl text-default-500 pointer-events-none flex-shrink-0";
|
||||
const iconClasses = "text-2xl text-default-500 pointer-events-none shrink-0";
|
||||
|
||||
export function DataTableRowActions<InvitationProps>({
|
||||
row,
|
||||
@@ -69,7 +68,7 @@ export function DataTableRowActions<InvitationProps>({
|
||||
|
||||
<div className="relative flex items-center justify-end gap-2">
|
||||
<Dropdown
|
||||
className="shadow-xl dark:bg-prowler-blue-800"
|
||||
className="dark:bg-prowler-blue-800 shadow-xl"
|
||||
placement="bottom"
|
||||
>
|
||||
<DropdownTrigger>
|
||||
|
||||
@@ -1,55 +1,56 @@
|
||||
import { Card, Skeleton } from "@nextui-org/react";
|
||||
import { Card } from "@heroui/card";
|
||||
import { Skeleton } from "@heroui/skeleton";
|
||||
import React from "react";
|
||||
|
||||
export const SkeletonTableInvitation = () => {
|
||||
return (
|
||||
<Card className="h-full w-full space-y-5 p-4" radius="sm">
|
||||
<Card className="flex h-full w-full flex-col gap-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>
|
||||
<div className="bg-default-200 h-8"></div>
|
||||
</Skeleton>
|
||||
<Skeleton className="w-2/12 rounded-lg">
|
||||
<div className="h-8 bg-default-200"></div>
|
||||
<div className="bg-default-200 h-8"></div>
|
||||
</Skeleton>
|
||||
<Skeleton className="w-2/12 rounded-lg">
|
||||
<div className="h-8 bg-default-200"></div>
|
||||
<div className="bg-default-200 h-8"></div>
|
||||
</Skeleton>
|
||||
<Skeleton className="w-2/12 rounded-lg">
|
||||
<div className="h-8 bg-default-200"></div>
|
||||
<div className="bg-default-200 h-8"></div>
|
||||
</Skeleton>
|
||||
<Skeleton className="w-2/12 rounded-lg">
|
||||
<div className="h-8 bg-default-200"></div>
|
||||
<div className="bg-default-200 h-8"></div>
|
||||
</Skeleton>
|
||||
<Skeleton className="w-1/12 rounded-lg">
|
||||
<div className="h-8 bg-default-200"></div>
|
||||
<div className="bg-default-200 h-8"></div>
|
||||
</Skeleton>
|
||||
</div>
|
||||
|
||||
{/* Table body */}
|
||||
<div className="space-y-3">
|
||||
<div className="flex flex-col gap-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"
|
||||
className="flex flex-col items-center justify-between md:flex-row md:gap-4"
|
||||
>
|
||||
<Skeleton className="mb-2 w-full rounded-lg md:mb-0 md:w-2/12">
|
||||
<div className="h-12 bg-default-300"></div>
|
||||
<div className="bg-default-300 h-12"></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>
|
||||
<div className="bg-default-300 h-12"></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>
|
||||
<div className="bg-default-300 h-12"></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>
|
||||
<div className="bg-default-300 h-12"></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>
|
||||
<div className="bg-default-300 h-12"></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>
|
||||
<div className="bg-default-300 h-12"></div>
|
||||
</Skeleton>
|
||||
</div>
|
||||
))}
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
"use client";
|
||||
|
||||
import { Select, SelectItem } from "@heroui/select";
|
||||
import { zodResolver } from "@hookform/resolvers/zod";
|
||||
import { Select, SelectItem } from "@nextui-org/react";
|
||||
import { SaveIcon } from "lucide-react";
|
||||
import { useRouter } from "next/navigation";
|
||||
import { Controller, useForm } from "react-hook-form";
|
||||
@@ -92,7 +92,7 @@ export const SendInvitationForm = ({
|
||||
<Form {...form}>
|
||||
<form
|
||||
onSubmit={form.handleSubmit(onSubmitClient)}
|
||||
className="flex flex-col space-y-4"
|
||||
className="flex flex-col gap-4"
|
||||
>
|
||||
{/* Email Field */}
|
||||
<CustomInput
|
||||
@@ -102,7 +102,7 @@ export const SendInvitationForm = ({
|
||||
label="Email"
|
||||
labelPlacement="inside"
|
||||
placeholder="Enter the email address"
|
||||
variant="bordered"
|
||||
variant="flat"
|
||||
isRequired
|
||||
isInvalid={!!form.formState.errors.email}
|
||||
/>
|
||||
@@ -119,7 +119,7 @@ export const SendInvitationForm = ({
|
||||
classNames={{
|
||||
selectorIcon: "right-2",
|
||||
}}
|
||||
variant="bordered"
|
||||
variant="flat"
|
||||
isDisabled={isSelectorDisabled}
|
||||
selectedKeys={[field.value]}
|
||||
onSelectionChange={(selected) =>
|
||||
@@ -144,7 +144,7 @@ export const SendInvitationForm = ({
|
||||
/>
|
||||
|
||||
{/* Submit Button */}
|
||||
<div className="flex w-full justify-end sm:space-x-6">
|
||||
<div className="flex w-full justify-end sm:gap-6">
|
||||
<CustomButton
|
||||
type="submit"
|
||||
ariaLabel="Send Invitation"
|
||||
|
||||
@@ -1,61 +1,62 @@
|
||||
import { Card, Skeleton } from "@nextui-org/react";
|
||||
import { Card } from "@heroui/card";
|
||||
import { Skeleton } from "@heroui/skeleton";
|
||||
import React from "react";
|
||||
|
||||
export const SkeletonInvitationInfo = () => {
|
||||
return (
|
||||
<Card className="h-full w-full space-y-5 p-4" radius="sm">
|
||||
<Card className="flex h-full w-full flex-col gap-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>
|
||||
<div className="bg-default-200 h-8"></div>
|
||||
</Skeleton>
|
||||
<Skeleton className="w-2/12 rounded-lg">
|
||||
<div className="h-8 bg-default-200"></div>
|
||||
<div className="bg-default-200 h-8"></div>
|
||||
</Skeleton>
|
||||
<Skeleton className="w-2/12 rounded-lg">
|
||||
<div className="h-8 bg-default-200"></div>
|
||||
<div className="bg-default-200 h-8"></div>
|
||||
</Skeleton>
|
||||
<Skeleton className="w-2/12 rounded-lg">
|
||||
<div className="h-8 bg-default-200"></div>
|
||||
<div className="bg-default-200 h-8"></div>
|
||||
</Skeleton>
|
||||
<Skeleton className="w-2/12 rounded-lg">
|
||||
<div className="h-8 bg-default-200"></div>
|
||||
<div className="bg-default-200 h-8"></div>
|
||||
</Skeleton>
|
||||
<Skeleton className="w-1/12 rounded-lg">
|
||||
<div className="h-8 bg-default-200"></div>
|
||||
<div className="bg-default-200 h-8"></div>
|
||||
</Skeleton>
|
||||
<Skeleton className="w-1/12 rounded-lg">
|
||||
<div className="h-8 bg-default-200"></div>
|
||||
<div className="bg-default-200 h-8"></div>
|
||||
</Skeleton>
|
||||
</div>
|
||||
|
||||
{/* Table body */}
|
||||
<div className="space-y-3">
|
||||
<div className="flex flex-col gap-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"
|
||||
className="flex flex-col items-center justify-between md:flex-row md:gap-4"
|
||||
>
|
||||
<Skeleton className="mb-2 w-full rounded-lg md:mb-0 md:w-1/12">
|
||||
<div className="h-12 bg-default-300"></div>
|
||||
<div className="bg-default-300 h-12"></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>
|
||||
<div className="bg-default-300 h-12"></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>
|
||||
<div className="bg-default-300 h-12"></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>
|
||||
<div className="bg-default-300 h-12"></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>
|
||||
<div className="bg-default-300 h-12"></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>
|
||||
<div className="bg-default-300 h-12"></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>
|
||||
<div className="bg-default-300 h-12"></div>
|
||||
</Skeleton>
|
||||
</div>
|
||||
))}
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
"use client";
|
||||
|
||||
import type { ButtonProps } from "@nextui-org/react";
|
||||
import { cn } from "@nextui-org/react";
|
||||
import type { ButtonProps } from "@heroui/button";
|
||||
import { cn } from "@heroui/theme";
|
||||
import { useControlledState } from "@react-stately/utils";
|
||||
import { domAnimation, LazyMotion, m } from "framer-motion";
|
||||
import type { ComponentProps } from "react";
|
||||
@@ -117,38 +117,38 @@ export const VerticalSteps = React.forwardRef<
|
||||
"[--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))]",
|
||||
"[--inactive-border-color:hsl(var(--heroui-default-300))]",
|
||||
"[--inactive-color:hsl(var(--heroui-default-300))]",
|
||||
];
|
||||
|
||||
switch (color) {
|
||||
case "primary":
|
||||
userColor = "[--step-color:hsl(var(--nextui-primary))]";
|
||||
fgColor = "[--step-fg-color:hsl(var(--nextui-primary-foreground))]";
|
||||
userColor = "[--step-color:hsl(var(--heroui-primary))]";
|
||||
fgColor = "[--step-fg-color:hsl(var(--heroui-primary-foreground))]";
|
||||
break;
|
||||
case "secondary":
|
||||
userColor = "[--step-color:hsl(var(--nextui-secondary))]";
|
||||
fgColor = "[--step-fg-color:hsl(var(--nextui-secondary-foreground))]";
|
||||
userColor = "[--step-color:hsl(var(--heroui-secondary))]";
|
||||
fgColor = "[--step-fg-color:hsl(var(--heroui-secondary-foreground))]";
|
||||
break;
|
||||
case "success":
|
||||
userColor = "[--step-color:hsl(var(--nextui-success))]";
|
||||
fgColor = "[--step-fg-color:hsl(var(--nextui-success-foreground))]";
|
||||
userColor = "[--step-color:hsl(var(--heroui-success))]";
|
||||
fgColor = "[--step-fg-color:hsl(var(--heroui-success-foreground))]";
|
||||
break;
|
||||
case "warning":
|
||||
userColor = "[--step-color:hsl(var(--nextui-warning))]";
|
||||
fgColor = "[--step-fg-color:hsl(var(--nextui-warning-foreground))]";
|
||||
userColor = "[--step-color:hsl(var(--heroui-warning))]";
|
||||
fgColor = "[--step-fg-color:hsl(var(--heroui-warning-foreground))]";
|
||||
break;
|
||||
case "danger":
|
||||
userColor = "[--step-color:hsl(var(--nextui-error))]";
|
||||
fgColor = "[--step-fg-color:hsl(var(--nextui-error-foreground))]";
|
||||
userColor = "[--step-color:hsl(var(--heroui-error))]";
|
||||
fgColor = "[--step-fg-color:hsl(var(--heroui-error-foreground))]";
|
||||
break;
|
||||
case "default":
|
||||
userColor = "[--step-color:hsl(var(--nextui-default))]";
|
||||
fgColor = "[--step-fg-color:hsl(var(--nextui-default-foreground))]";
|
||||
userColor = "[--step-color:hsl(var(--heroui-default))]";
|
||||
fgColor = "[--step-fg-color:hsl(var(--heroui-default-foreground))]";
|
||||
break;
|
||||
default:
|
||||
userColor = "[--step-color:hsl(var(--nextui-primary))]";
|
||||
fgColor = "[--step-fg-color:hsl(var(--nextui-primary-foreground))]";
|
||||
userColor = "[--step-color:hsl(var(--heroui-primary))]";
|
||||
fgColor = "[--step-fg-color:hsl(var(--heroui-primary-foreground))]";
|
||||
break;
|
||||
}
|
||||
|
||||
@@ -156,7 +156,7 @@ export const VerticalSteps = React.forwardRef<
|
||||
if (!className?.includes("--step-color")) colorsVars.unshift(userColor);
|
||||
if (!className?.includes("--inactive-bar-color"))
|
||||
colorsVars.push(
|
||||
"[--inactive-bar-color:hsl(var(--nextui-default-300))]",
|
||||
"[--inactive-bar-color:hsl(var(--heroui-default-300))]",
|
||||
);
|
||||
|
||||
return colorsVars;
|
||||
@@ -181,7 +181,7 @@ export const VerticalSteps = React.forwardRef<
|
||||
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",
|
||||
"group rounded-large flex w-full cursor-pointer items-center justify-center gap-4 px-3 py-2.5",
|
||||
stepClassName,
|
||||
)}
|
||||
onClick={() => setCurrentStep(stepIdx)}
|
||||
@@ -193,7 +193,7 @@ export const VerticalSteps = React.forwardRef<
|
||||
<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",
|
||||
"border-medium text-large text-default-foreground relative flex h-[34px] w-[34px] items-center justify-center rounded-full font-semibold",
|
||||
{
|
||||
"shadow-lg": status === "complete",
|
||||
},
|
||||
@@ -221,7 +221,7 @@ export const VerticalSteps = React.forwardRef<
|
||||
>
|
||||
<div className="flex items-center justify-center">
|
||||
{status === "complete" ? (
|
||||
<CheckIcon className="h-6 w-6 text-[var(--active-fg-color)]" />
|
||||
<CheckIcon className="h-6 w-6 text-(--active-fg-color)" />
|
||||
) : (
|
||||
<span>{stepIdx + 1}</span>
|
||||
)}
|
||||
@@ -234,7 +234,7 @@ export const VerticalSteps = React.forwardRef<
|
||||
<div>
|
||||
<div
|
||||
className={cn(
|
||||
"text-medium font-medium text-default-foreground transition-[color,opacity] duration-300 group-active:opacity-70",
|
||||
"text-medium text-default-foreground font-medium transition-[color,opacity] duration-300 group-active:opacity-70",
|
||||
{
|
||||
"text-default-500": status === "inactive",
|
||||
},
|
||||
@@ -244,7 +244,7 @@ export const VerticalSteps = React.forwardRef<
|
||||
</div>
|
||||
<div
|
||||
className={cn(
|
||||
"text-tiny text-default-600 transition-[color,opacity] duration-300 group-active:opacity-70 lg:text-small",
|
||||
"text-tiny text-default-600 lg:text-small transition-[color,opacity] duration-300 group-active:opacity-70",
|
||||
{
|
||||
"text-default-500": status === "inactive",
|
||||
},
|
||||
@@ -260,7 +260,7 @@ export const VerticalSteps = React.forwardRef<
|
||||
<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",
|
||||
"pointer-events-none absolute top-[calc(64px*var(--idx)+1)] left-3 flex h-1/2 -translate-y-1/3 items-center px-4",
|
||||
)}
|
||||
style={{
|
||||
// eslint-disable-next-line @typescript-eslint/ban-ts-comment
|
||||
@@ -270,8 +270,8 @@ export const VerticalSteps = React.forwardRef<
|
||||
>
|
||||
<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-['']",
|
||||
"relative h-full w-0.5 bg-(--inactive-bar-color) transition-colors duration-300",
|
||||
"after:absolute after:block after:h-0 after:w-full after:bg-(--active-border-color) after:transition-[height] after:duration-300 after:content-['']",
|
||||
{
|
||||
"after:h-full": stepIdx < currentStep,
|
||||
},
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
"use client";
|
||||
|
||||
import { Progress, Spacer } from "@nextui-org/react";
|
||||
import { Progress } from "@heroui/progress";
|
||||
import { Spacer } from "@heroui/spacer";
|
||||
import { usePathname } from "next/navigation";
|
||||
import React from "react";
|
||||
|
||||
@@ -31,34 +32,51 @@ export const WorkflowSendInvite = () => {
|
||||
const currentStep = currentStepIndex === -1 ? 0 : currentStepIndex;
|
||||
|
||||
return (
|
||||
<section className="max-w-sm">
|
||||
<h1 className="mb-2 text-xl font-medium" id="getting-started">
|
||||
<section className="w-full max-w-none p-3 sm:max-w-sm sm:p-0">
|
||||
<h1 className="mb-2 text-lg font-medium sm:text-xl" id="getting-started">
|
||||
Send invitation
|
||||
</h1>
|
||||
<p className="mb-5 text-small text-default-500">
|
||||
<p className="sm:text-small text-default-500 mb-3 text-xs sm:mb-5">
|
||||
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",
|
||||
base: "px-0.5 mb-3 sm:mb-5",
|
||||
label: "text-xs sm:text-small",
|
||||
value: "text-xs sm:text-small text-default-400",
|
||||
}}
|
||||
label="Steps"
|
||||
maxValue={steps.length - 1}
|
||||
minValue={0}
|
||||
showValueLabel={true}
|
||||
size="md"
|
||||
size="sm"
|
||||
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} />
|
||||
|
||||
{/* Desktop: Full vertical steps */}
|
||||
<div className="hidden sm:block">
|
||||
<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}
|
||||
/>
|
||||
</div>
|
||||
|
||||
{/* Mobile: Compact current step indicator */}
|
||||
<div className="sm:hidden">
|
||||
<div className="text-default-400 border-l-2 border-blue-500 py-1 pl-3 text-xs">
|
||||
<div className="font-medium">
|
||||
Current: {steps[currentStep]?.title}
|
||||
</div>
|
||||
<div className="text-default-300 mt-1 text-xs">
|
||||
{steps[currentStep]?.description}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<Spacer y={2} />
|
||||
</section>
|
||||
);
|
||||
};
|
||||
@@ -12,7 +12,7 @@ interface BannerConfig {
|
||||
const renderBanner = ({ message, href, gradient }: BannerConfig) => (
|
||||
<Link href={href} className="mb-4 block w-full">
|
||||
<div
|
||||
className={`w-full rounded-lg ${gradient} shadow-lg transition-all duration-200 hover:shadow-xl focus:outline-none focus:ring-2 focus:ring-opacity-50`}
|
||||
className={`w-full rounded-lg ${gradient} focus:ring-opacity-50 shadow-lg transition-all duration-200 hover:shadow-xl focus:ring-2 focus:outline-none`}
|
||||
>
|
||||
<div className="px-4 py-3">
|
||||
<div className="flex items-center gap-4">
|
||||
@@ -35,14 +35,14 @@ export const LighthouseBanner = async () => {
|
||||
message: "Enable Lighthouse to secure your cloud with AI insights",
|
||||
href: "/lighthouse/config",
|
||||
gradient:
|
||||
"bg-gradient-to-r from-green-500 to-blue-500 hover:from-green-600 hover:to-blue-600 focus:ring-green-500/50 dark:from-green-600 dark:to-blue-600 dark:hover:from-green-700 dark:hover:to-blue-700 dark:focus:ring-green-400/50",
|
||||
"bg-linear-to-r from-green-500 to-blue-500 hover:from-green-600 hover:to-blue-600 focus:ring-green-500/50 dark:from-green-600 dark:to-blue-600 dark:hover:from-green-700 dark:hover:to-blue-700 dark:focus:ring-green-400/50",
|
||||
});
|
||||
} else {
|
||||
return renderBanner({
|
||||
message: "Use Lighthouse to review your findings and gain insights",
|
||||
href: "/lighthouse",
|
||||
gradient:
|
||||
"bg-gradient-to-r from-green-500 to-blue-500 hover:from-green-600 hover:to-blue-600 focus:ring-green-500/50 dark:from-green-600 dark:to-blue-600 dark:hover:from-green-700 dark:hover:to-blue-700 dark:focus:ring-green-400/50",
|
||||
"bg-linear-to-r from-green-500 to-blue-500 hover:from-green-600 hover:to-blue-600 focus:ring-green-500/50 dark:from-green-600 dark:to-blue-600 dark:hover:from-green-700 dark:hover:to-blue-700 dark:focus:ring-green-400/50",
|
||||
});
|
||||
}
|
||||
} catch (error) {
|
||||
|
||||
@@ -174,9 +174,9 @@ export const Chat = ({ hasConfig, isActive }: ChatProps) => {
|
||||
const shouldDisableChat = !hasConfig || !isActive;
|
||||
|
||||
return (
|
||||
<div className="relative flex h-[calc(100vh-theme(spacing.16))] min-w-0 flex-col bg-background">
|
||||
<div className="bg-background relative flex h-[calc(100vh-(--spacing(16)))] min-w-0 flex-col">
|
||||
{shouldDisableChat && (
|
||||
<div className="absolute inset-0 z-50 flex items-center justify-center bg-background/80 backdrop-blur-sm">
|
||||
<div className="bg-background/80 absolute inset-0 z-50 flex items-center justify-center backdrop-blur-sm">
|
||||
<div className="bg-card max-w-md rounded-lg p-6 text-center shadow-lg">
|
||||
<h3 className="mb-2 text-lg font-semibold">
|
||||
{!hasConfig
|
||||
@@ -190,7 +190,7 @@ export const Chat = ({ hasConfig, isActive }: ChatProps) => {
|
||||
</p>
|
||||
<CustomLink
|
||||
href="/lighthouse/config"
|
||||
className="inline-flex items-center justify-center rounded-md bg-primary px-4 py-2 text-primary-foreground hover:bg-primary/90"
|
||||
className="bg-primary text-primary-foreground hover:bg-primary/90 inline-flex items-center justify-center rounded-md px-4 py-2"
|
||||
target="_self"
|
||||
size="sm"
|
||||
>
|
||||
@@ -204,7 +204,7 @@ export const Chat = ({ hasConfig, isActive }: ChatProps) => {
|
||||
{(error || errorMessage) && (
|
||||
<div className="mx-4 mt-4 rounded-lg border border-red-200 bg-red-50 p-4 dark:border-red-800 dark:bg-red-900/20">
|
||||
<div className="flex items-start">
|
||||
<div className="flex-shrink-0">
|
||||
<div className="shrink-0">
|
||||
<svg
|
||||
className="h-5 w-5 text-red-400"
|
||||
viewBox="0 0 20 20"
|
||||
@@ -273,7 +273,7 @@ export const Chat = ({ hasConfig, isActive }: ChatProps) => {
|
||||
</div>
|
||||
) : (
|
||||
<div
|
||||
className="flex-1 space-y-4 overflow-y-auto p-4"
|
||||
className="flex flex-1 flex-col gap-4 overflow-y-auto p-4"
|
||||
ref={messagesContainerRef}
|
||||
>
|
||||
{messages.map((message, idx) => {
|
||||
@@ -294,12 +294,12 @@ export const Chat = ({ hasConfig, isActive }: ChatProps) => {
|
||||
<div
|
||||
className={`max-w-[80%] rounded-lg px-4 py-2 ${
|
||||
message.role === "user"
|
||||
? "bg-primary text-primary-foreground dark:!text-black"
|
||||
? "bg-primary text-primary-foreground dark:text-black!"
|
||||
: "bg-muted"
|
||||
}`}
|
||||
>
|
||||
<div
|
||||
className={`prose dark:prose-invert ${message.role === "user" ? "dark:!text-black" : ""}`}
|
||||
className={`prose dark:prose-invert ${message.role === "user" ? "dark:text-black!" : ""}`}
|
||||
>
|
||||
<MemoizedMarkdown
|
||||
id={message.id}
|
||||
@@ -349,7 +349,7 @@ export const Chat = ({ hasConfig, isActive }: ChatProps) => {
|
||||
status === "submitted" ? "Stop generation" : "Send message"
|
||||
}
|
||||
isDisabled={status === "submitted" || !messageValue?.trim()}
|
||||
className="flex h-10 w-10 flex-shrink-0 items-center justify-center rounded-lg bg-primary p-2 text-primary-foreground hover:bg-primary/90 disabled:opacity-50 dark:bg-primary/90"
|
||||
className="bg-primary text-primary-foreground hover:bg-primary/90 dark:bg-primary/90 flex h-10 w-10 shrink-0 items-center justify-center rounded-lg p-2 disabled:opacity-50"
|
||||
>
|
||||
{status === "submitted" ? <span>■</span> : <span>➤</span>}
|
||||
</CustomButton>
|
||||
|
||||
@@ -1,7 +1,8 @@
|
||||
"use client";
|
||||
|
||||
import { Select, SelectItem } from "@heroui/select";
|
||||
import { Spacer } from "@heroui/spacer";
|
||||
import { zodResolver } from "@hookform/resolvers/zod";
|
||||
import { Select, SelectItem, Spacer } from "@nextui-org/react";
|
||||
import { SaveIcon } from "lucide-react";
|
||||
import { useState } from "react";
|
||||
import { Controller, useForm } from "react-hook-form";
|
||||
@@ -98,7 +99,7 @@ export const ChatbotConfig = ({
|
||||
<Form {...form}>
|
||||
<form
|
||||
onSubmit={form.handleSubmit(onSubmit)}
|
||||
className="flex flex-col space-y-6"
|
||||
className="flex flex-col gap-6"
|
||||
>
|
||||
<Controller
|
||||
name="model"
|
||||
@@ -115,24 +116,14 @@ export const ChatbotConfig = ({
|
||||
size="md"
|
||||
isRequired
|
||||
>
|
||||
<SelectItem key="gpt-4o-2024-08-06" value="gpt-4o-2024-08-06">
|
||||
<SelectItem key="gpt-4o-2024-08-06">
|
||||
GPT-4o (Recommended)
|
||||
</SelectItem>
|
||||
<SelectItem
|
||||
key="gpt-4o-mini-2024-07-18"
|
||||
value="gpt-4o-mini-2024-07-18"
|
||||
>
|
||||
<SelectItem key="gpt-4o-mini-2024-07-18">
|
||||
GPT-4o Mini
|
||||
</SelectItem>
|
||||
<SelectItem key="gpt-5-2025-08-07" value="gpt-5-2025-08-07">
|
||||
GPT-5
|
||||
</SelectItem>
|
||||
<SelectItem
|
||||
key="gpt-5-mini-2025-08-07"
|
||||
value="gpt-5-mini-2025-08-07"
|
||||
>
|
||||
GPT-5 Mini
|
||||
</SelectItem>
|
||||
<SelectItem key="gpt-5-2025-08-07">GPT-5</SelectItem>
|
||||
<SelectItem key="gpt-5-mini-2025-08-07">GPT-5 Mini</SelectItem>
|
||||
</Select>
|
||||
)}
|
||||
/>
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
"use client";
|
||||
import { Divider } from "@heroui/divider";
|
||||
import { zodResolver } from "@hookform/resolvers/zod";
|
||||
import { Divider } from "@nextui-org/react";
|
||||
import { SaveIcon } from "lucide-react";
|
||||
import { Controller, useForm } from "react-hook-form";
|
||||
import * as z from "zod";
|
||||
@@ -111,7 +111,7 @@ export const AddGroupForm = ({
|
||||
<Form {...form}>
|
||||
<form
|
||||
onSubmit={form.handleSubmit(onSubmitClient)}
|
||||
className="flex flex-col space-y-4"
|
||||
className="flex flex-col gap-4"
|
||||
>
|
||||
<div className="flex flex-col gap-2">
|
||||
<CustomInput
|
||||
@@ -121,7 +121,7 @@ export const AddGroupForm = ({
|
||||
label="Provider group name"
|
||||
labelPlacement="inside"
|
||||
placeholder="Enter the provider group name"
|
||||
variant="bordered"
|
||||
variant="flat"
|
||||
isRequired
|
||||
isInvalid={!!form.formState.errors.name}
|
||||
/>
|
||||
@@ -177,7 +177,7 @@ export const AddGroupForm = ({
|
||||
)}
|
||||
|
||||
{/* Submit Button */}
|
||||
<div className="flex w-full justify-end sm:space-x-6">
|
||||
<div className="flex w-full justify-end sm:gap-6">
|
||||
<CustomButton
|
||||
type="submit"
|
||||
ariaLabel="Create Group"
|
||||
|
||||
@@ -57,7 +57,7 @@ export const DeleteGroupForm = ({
|
||||
<Form {...form}>
|
||||
<form action={onSubmitClient}>
|
||||
<input type="hidden" name="id" value={groupId} />
|
||||
<div className="flex w-full justify-center sm:space-x-6">
|
||||
<div className="flex w-full justify-center sm:gap-6">
|
||||
<CustomButton
|
||||
type="button"
|
||||
ariaLabel="Cancel"
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
"use client";
|
||||
|
||||
import { Divider } from "@heroui/divider";
|
||||
import { zodResolver } from "@hookform/resolvers/zod";
|
||||
import { Divider } from "@nextui-org/react";
|
||||
import { SaveIcon } from "lucide-react";
|
||||
import { useRouter } from "next/navigation";
|
||||
import { Controller, useForm } from "react-hook-form";
|
||||
@@ -147,7 +147,7 @@ export const EditGroupForm = ({
|
||||
<Form {...form}>
|
||||
<form
|
||||
onSubmit={form.handleSubmit(onSubmitClient)}
|
||||
className="flex flex-col space-y-4"
|
||||
className="flex flex-col gap-4"
|
||||
>
|
||||
{/* Field for the name */}
|
||||
<div className="flex flex-col gap-2">
|
||||
@@ -158,7 +158,7 @@ export const EditGroupForm = ({
|
||||
label="Provider group name"
|
||||
labelPlacement="inside"
|
||||
placeholder="Enter the provider group name"
|
||||
variant="bordered"
|
||||
variant="flat"
|
||||
isRequired
|
||||
isInvalid={!!form.formState.errors.name}
|
||||
/>
|
||||
@@ -241,7 +241,7 @@ export const EditGroupForm = ({
|
||||
</p>
|
||||
)}
|
||||
|
||||
<div className="flex w-full justify-end sm:space-x-6">
|
||||
<div className="flex w-full justify-end sm:gap-6">
|
||||
<CustomButton
|
||||
type="button"
|
||||
ariaLabel="Cancel"
|
||||
|
||||
@@ -1,61 +1,62 @@
|
||||
import { Card, Skeleton } from "@nextui-org/react";
|
||||
import { Card } from "@heroui/card";
|
||||
import { Skeleton } from "@heroui/skeleton";
|
||||
import React from "react";
|
||||
|
||||
export const SkeletonManageGroups = () => {
|
||||
return (
|
||||
<Card className="h-full w-full space-y-5 p-4" radius="sm">
|
||||
<Card className="flex h-full w-full flex-col gap-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>
|
||||
<div className="bg-default-200 h-8"></div>
|
||||
</Skeleton>
|
||||
<Skeleton className="w-2/12 rounded-lg">
|
||||
<div className="h-8 bg-default-200"></div>
|
||||
<div className="bg-default-200 h-8"></div>
|
||||
</Skeleton>
|
||||
<Skeleton className="w-2/12 rounded-lg">
|
||||
<div className="h-8 bg-default-200"></div>
|
||||
<div className="bg-default-200 h-8"></div>
|
||||
</Skeleton>
|
||||
<Skeleton className="w-2/12 rounded-lg">
|
||||
<div className="h-8 bg-default-200"></div>
|
||||
<div className="bg-default-200 h-8"></div>
|
||||
</Skeleton>
|
||||
<Skeleton className="w-2/12 rounded-lg">
|
||||
<div className="h-8 bg-default-200"></div>
|
||||
<div className="bg-default-200 h-8"></div>
|
||||
</Skeleton>
|
||||
<Skeleton className="w-1/12 rounded-lg">
|
||||
<div className="h-8 bg-default-200"></div>
|
||||
<div className="bg-default-200 h-8"></div>
|
||||
</Skeleton>
|
||||
<Skeleton className="w-1/12 rounded-lg">
|
||||
<div className="h-8 bg-default-200"></div>
|
||||
<div className="bg-default-200 h-8"></div>
|
||||
</Skeleton>
|
||||
</div>
|
||||
|
||||
{/* Table body */}
|
||||
<div className="space-y-3">
|
||||
<div className="flex flex-col gap-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"
|
||||
className="flex flex-col items-center justify-between md:flex-row md:gap-4"
|
||||
>
|
||||
<Skeleton className="mb-2 w-full rounded-lg md:mb-0 md:w-1/12">
|
||||
<div className="h-12 bg-default-300"></div>
|
||||
<div className="bg-default-300 h-12"></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>
|
||||
<div className="bg-default-300 h-12"></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>
|
||||
<div className="bg-default-300 h-12"></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>
|
||||
<div className="bg-default-300 h-12"></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>
|
||||
<div className="bg-default-300 h-12"></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>
|
||||
<div className="bg-default-300 h-12"></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>
|
||||
<div className="bg-default-300 h-12"></div>
|
||||
</Skeleton>
|
||||
</div>
|
||||
))}
|
||||
|
||||
@@ -1,17 +1,17 @@
|
||||
"use client";
|
||||
|
||||
import { Button } from "@heroui/button";
|
||||
import {
|
||||
Button,
|
||||
Dropdown,
|
||||
DropdownItem,
|
||||
DropdownMenu,
|
||||
DropdownSection,
|
||||
DropdownTrigger,
|
||||
} from "@nextui-org/react";
|
||||
} from "@heroui/dropdown";
|
||||
import {
|
||||
DeleteDocumentBulkIcon,
|
||||
EditDocumentBulkIcon,
|
||||
} from "@nextui-org/shared-icons";
|
||||
} from "@heroui/shared-icons";
|
||||
import { Row } from "@tanstack/react-table";
|
||||
import clsx from "clsx";
|
||||
import { useRouter } from "next/navigation";
|
||||
@@ -25,8 +25,7 @@ import { DeleteGroupForm } from "../forms";
|
||||
interface DataTableRowActionsProps<ProviderProps> {
|
||||
row: Row<ProviderProps>;
|
||||
}
|
||||
const iconClasses =
|
||||
"text-2xl text-default-500 pointer-events-none flex-shrink-0";
|
||||
const iconClasses = "text-2xl text-default-500 pointer-events-none shrink-0";
|
||||
|
||||
export function DataTableRowActions<ProviderProps>({
|
||||
row,
|
||||
@@ -49,7 +48,7 @@ export function DataTableRowActions<ProviderProps>({
|
||||
|
||||
<div className="relative flex items-center justify-end gap-2">
|
||||
<Dropdown
|
||||
className="shadow-xl dark:bg-prowler-blue-800"
|
||||
className="dark:bg-prowler-blue-800 shadow-xl"
|
||||
placement="bottom"
|
||||
>
|
||||
<DropdownTrigger>
|
||||
|
||||
@@ -1,61 +1,62 @@
|
||||
import { Card, Skeleton } from "@nextui-org/react";
|
||||
import { Card } from "@heroui/card";
|
||||
import { Skeleton } from "@heroui/skeleton";
|
||||
import React from "react";
|
||||
|
||||
export const SkeletonTableGroups = () => {
|
||||
return (
|
||||
<Card className="h-full w-full space-y-5 p-4" radius="sm">
|
||||
<Card className="flex h-full w-full flex-col gap-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>
|
||||
<div className="bg-default-200 h-8"></div>
|
||||
</Skeleton>
|
||||
<Skeleton className="w-2/12 rounded-lg">
|
||||
<div className="h-8 bg-default-200"></div>
|
||||
<div className="bg-default-200 h-8"></div>
|
||||
</Skeleton>
|
||||
<Skeleton className="w-2/12 rounded-lg">
|
||||
<div className="h-8 bg-default-200"></div>
|
||||
<div className="bg-default-200 h-8"></div>
|
||||
</Skeleton>
|
||||
<Skeleton className="w-2/12 rounded-lg">
|
||||
<div className="h-8 bg-default-200"></div>
|
||||
<div className="bg-default-200 h-8"></div>
|
||||
</Skeleton>
|
||||
<Skeleton className="w-2/12 rounded-lg">
|
||||
<div className="h-8 bg-default-200"></div>
|
||||
<div className="bg-default-200 h-8"></div>
|
||||
</Skeleton>
|
||||
<Skeleton className="w-1/12 rounded-lg">
|
||||
<div className="h-8 bg-default-200"></div>
|
||||
<div className="bg-default-200 h-8"></div>
|
||||
</Skeleton>
|
||||
<Skeleton className="w-1/12 rounded-lg">
|
||||
<div className="h-8 bg-default-200"></div>
|
||||
<div className="bg-default-200 h-8"></div>
|
||||
</Skeleton>
|
||||
</div>
|
||||
|
||||
{/* Table body */}
|
||||
<div className="space-y-3">
|
||||
<div className="flex flex-col gap-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"
|
||||
className="flex flex-col items-center justify-between md:flex-row md:gap-4"
|
||||
>
|
||||
<Skeleton className="mb-2 w-full rounded-lg md:mb-0 md:w-1/12">
|
||||
<div className="h-12 bg-default-300"></div>
|
||||
<div className="bg-default-300 h-12"></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>
|
||||
<div className="bg-default-300 h-12"></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>
|
||||
<div className="bg-default-300 h-12"></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>
|
||||
<div className="bg-default-300 h-12"></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>
|
||||
<div className="bg-default-300 h-12"></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>
|
||||
<div className="bg-default-300 h-12"></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>
|
||||
<div className="bg-default-300 h-12"></div>
|
||||
</Skeleton>
|
||||
</div>
|
||||
))}
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
"use client";
|
||||
|
||||
import { Card, CardBody } from "@nextui-org/react";
|
||||
import { Card, CardBody } from "@heroui/card";
|
||||
import { Bar, BarChart, LabelList, XAxis, YAxis } from "recharts";
|
||||
|
||||
import {
|
||||
@@ -70,7 +70,7 @@ export const FindingsBySeverityChart = ({
|
||||
}));
|
||||
|
||||
return (
|
||||
<Card className="h-full dark:bg-prowler-blue-400">
|
||||
<Card className="dark:bg-prowler-blue-400 h-full">
|
||||
<CardBody>
|
||||
<div className="my-auto">
|
||||
<ChartContainer
|
||||
|
||||
+13
-12
@@ -1,11 +1,12 @@
|
||||
import { Card, CardBody, CardHeader, Skeleton } from "@nextui-org/react";
|
||||
import { Card, CardBody, CardHeader } from "@heroui/card";
|
||||
import { Skeleton } from "@heroui/skeleton";
|
||||
|
||||
export const SkeletonFindingsBySeverityChart = () => {
|
||||
return (
|
||||
<Card>
|
||||
<CardHeader>
|
||||
<Skeleton className="h-6 w-1/3 rounded-lg">
|
||||
<div className="h-6 bg-default-200"></div>
|
||||
<div className="bg-default-200 h-6"></div>
|
||||
</Skeleton>
|
||||
</CardHeader>
|
||||
<CardBody>
|
||||
@@ -13,46 +14,46 @@ export const SkeletonFindingsBySeverityChart = () => {
|
||||
{/* Critical */}
|
||||
<div className="flex items-center gap-2">
|
||||
<Skeleton className="h-4 w-1/4 rounded-lg">
|
||||
<div className="h-4 bg-default-200"></div>
|
||||
<div className="bg-default-200 h-4"></div>
|
||||
</Skeleton>
|
||||
<Skeleton className="h-4 w-12 rounded-lg">
|
||||
<div className="h-4 bg-default-200"></div>
|
||||
<div className="bg-default-200 h-4"></div>
|
||||
</Skeleton>
|
||||
</div>
|
||||
{/* High */}
|
||||
<div className="flex items-center gap-2">
|
||||
<Skeleton className="h-4 w-2/4 rounded-lg">
|
||||
<div className="h-4 bg-default-200"></div>
|
||||
<div className="bg-default-200 h-4"></div>
|
||||
</Skeleton>
|
||||
<Skeleton className="h-4 w-12 rounded-lg">
|
||||
<div className="h-4 bg-default-200"></div>
|
||||
<div className="bg-default-200 h-4"></div>
|
||||
</Skeleton>
|
||||
</div>
|
||||
{/* Medium */}
|
||||
<div className="flex items-center gap-2">
|
||||
<Skeleton className="h-4 w-3/4 rounded-lg">
|
||||
<div className="h-4 bg-default-200"></div>
|
||||
<div className="bg-default-200 h-4"></div>
|
||||
</Skeleton>
|
||||
<Skeleton className="h-4 w-12 rounded-lg">
|
||||
<div className="h-4 bg-default-200"></div>
|
||||
<div className="bg-default-200 h-4"></div>
|
||||
</Skeleton>
|
||||
</div>
|
||||
{/* Low */}
|
||||
<div className="flex items-center gap-2">
|
||||
<Skeleton className="h-4 w-1/2 rounded-lg">
|
||||
<div className="h-4 bg-default-200"></div>
|
||||
<div className="bg-default-200 h-4"></div>
|
||||
</Skeleton>
|
||||
<Skeleton className="h-4 w-12 rounded-lg">
|
||||
<div className="h-4 bg-default-200"></div>
|
||||
<div className="bg-default-200 h-4"></div>
|
||||
</Skeleton>
|
||||
</div>
|
||||
{/* Informational */}
|
||||
<div className="flex items-center gap-2">
|
||||
<Skeleton className="h-4 w-1/6 rounded-lg">
|
||||
<div className="h-4 bg-default-200"></div>
|
||||
<div className="bg-default-200 h-4"></div>
|
||||
</Skeleton>
|
||||
<Skeleton className="h-4 w-12 rounded-lg">
|
||||
<div className="h-4 bg-default-200"></div>
|
||||
<div className="bg-default-200 h-4"></div>
|
||||
</Skeleton>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
"use client";
|
||||
|
||||
import { Card, CardBody } from "@nextui-org/react";
|
||||
import { Chip } from "@nextui-org/react";
|
||||
import { Card, CardBody } from "@heroui/card";
|
||||
import { Chip } from "@heroui/chip";
|
||||
import { TrendingUp } from "lucide-react";
|
||||
import Link from "next/link";
|
||||
import { useSearchParams } from "next/navigation";
|
||||
@@ -114,12 +114,12 @@ export const FindingsByStatusChart: React.FC<FindingsByStatusChartProps> = ({
|
||||
{
|
||||
findings: "Empty",
|
||||
number: 1,
|
||||
fill: "hsl(var(--nextui-default-200))",
|
||||
fill: "hsl(var(--heroui-default-200))",
|
||||
},
|
||||
];
|
||||
|
||||
return (
|
||||
<Card className="h-full dark:bg-prowler-blue-400">
|
||||
<Card className="dark:bg-prowler-blue-400 h-full">
|
||||
<CardBody>
|
||||
<div className="flex h-full flex-col items-center justify-around">
|
||||
<ChartContainer
|
||||
@@ -172,10 +172,10 @@ export const FindingsByStatusChart: React.FC<FindingsByStatusChartProps> = ({
|
||||
|
||||
<div className="flex min-h-[156px] flex-col justify-start gap-4">
|
||||
<div className="flex flex-col gap-2">
|
||||
<div className="flex items-center space-x-2">
|
||||
<div className="flex items-center gap-2">
|
||||
<Link
|
||||
href="/findings?filter[status]=PASS"
|
||||
className="flex items-center space-x-2"
|
||||
className="flex items-center gap-2"
|
||||
>
|
||||
<Chip
|
||||
className="h-5"
|
||||
@@ -190,7 +190,7 @@ export const FindingsByStatusChart: React.FC<FindingsByStatusChartProps> = ({
|
||||
<span>{updatedChartData[0].percent}</span>
|
||||
</Link>
|
||||
</div>
|
||||
<div className="text-muted-foreground flex items-center gap-1 text-xs font-medium leading-none">
|
||||
<div className="text-muted-foreground flex items-center gap-1 text-xs leading-none font-medium">
|
||||
{pass_new > 0 ? (
|
||||
<>
|
||||
+{pass_new} pass findings from last day{" "}
|
||||
@@ -208,7 +208,7 @@ export const FindingsByStatusChart: React.FC<FindingsByStatusChartProps> = ({
|
||||
<div className="flex items-center align-middle">
|
||||
<Link
|
||||
href="/findings?filter[status]=FAIL"
|
||||
className="flex items-center space-x-2"
|
||||
className="flex items-center gap-2"
|
||||
>
|
||||
<Chip
|
||||
className="h-5"
|
||||
@@ -223,7 +223,7 @@ export const FindingsByStatusChart: React.FC<FindingsByStatusChartProps> = ({
|
||||
<span>{updatedChartData[1].percent}</span>
|
||||
</Link>
|
||||
</div>
|
||||
<div className="text-muted-foreground flex items-center gap-1 text-xs font-medium leading-none">
|
||||
<div className="text-muted-foreground flex items-center gap-1 text-xs leading-none font-medium">
|
||||
+{fail_new} fail findings from last day{" "}
|
||||
<TrendingUp className="h-4 w-4" />
|
||||
</div>
|
||||
@@ -232,10 +232,10 @@ export const FindingsByStatusChart: React.FC<FindingsByStatusChartProps> = ({
|
||||
<div className="flex min-h-[52px] flex-col gap-2">
|
||||
{shouldShowMuted ? (
|
||||
<>
|
||||
<div className="flex items-center space-x-2">
|
||||
<div className="flex items-center gap-2">
|
||||
<Link
|
||||
href="/findings?filter[muted]=true"
|
||||
className="flex items-center space-x-2"
|
||||
className="flex items-center gap-2"
|
||||
>
|
||||
<Chip
|
||||
className="h-5"
|
||||
@@ -255,7 +255,7 @@ export const FindingsByStatusChart: React.FC<FindingsByStatusChartProps> = ({
|
||||
</span>
|
||||
</Link>
|
||||
</div>
|
||||
<div className="text-muted-foreground flex items-center gap-1 text-xs font-medium leading-none">
|
||||
<div className="text-muted-foreground flex items-center gap-1 text-xs leading-none font-medium">
|
||||
{muted_new > 0 ? (
|
||||
<>
|
||||
+{muted_new} muted findings from last day{" "}
|
||||
|
||||
+12
-11
@@ -1,49 +1,50 @@
|
||||
import { Card, CardBody, CardHeader, Skeleton } from "@nextui-org/react";
|
||||
import { Card, CardBody, CardHeader } from "@heroui/card";
|
||||
import { Skeleton } from "@heroui/skeleton";
|
||||
|
||||
export const SkeletonFindingsByStatusChart = () => {
|
||||
return (
|
||||
<Card>
|
||||
<CardHeader>
|
||||
<Skeleton className="h-6 w-1/4 rounded-lg">
|
||||
<div className="h-6 bg-default-200"></div>
|
||||
<div className="bg-default-200 h-6"></div>
|
||||
</Skeleton>
|
||||
</CardHeader>
|
||||
<CardBody>
|
||||
<div className="flex items-center gap-6">
|
||||
{/* Circle Chart Skeleton */}
|
||||
<Skeleton className="aspect-square h-[150px] w-[150px] rounded-full">
|
||||
<div className="h-[150px] w-[150px] bg-default-200"></div>
|
||||
<div className="bg-default-200 h-[150px] w-[150px]"></div>
|
||||
</Skeleton>
|
||||
|
||||
{/* Text Details Skeleton */}
|
||||
<div className="flex flex-col gap-4">
|
||||
{/* Pass Findings */}
|
||||
<div className="flex flex-col gap-2">
|
||||
<div className="flex items-center space-x-2">
|
||||
<div className="flex items-center gap-2">
|
||||
<Skeleton className="h-5 w-16 rounded-lg">
|
||||
<div className="h-5 bg-default-200"></div>
|
||||
<div className="bg-default-200 h-5"></div>
|
||||
</Skeleton>
|
||||
<Skeleton className="h-5 w-10 rounded-lg">
|
||||
<div className="h-5 bg-default-200"></div>
|
||||
<div className="bg-default-200 h-5"></div>
|
||||
</Skeleton>
|
||||
</div>
|
||||
<Skeleton className="h-4 w-48 rounded-lg">
|
||||
<div className="h-4 bg-default-200"></div>
|
||||
<div className="bg-default-200 h-4"></div>
|
||||
</Skeleton>
|
||||
</div>
|
||||
|
||||
{/* Fail Findings */}
|
||||
<div className="flex flex-col gap-2">
|
||||
<div className="flex items-center space-x-2">
|
||||
<div className="flex items-center gap-2">
|
||||
<Skeleton className="h-5 w-16 rounded-lg">
|
||||
<div className="h-5 bg-default-200"></div>
|
||||
<div className="bg-default-200 h-5"></div>
|
||||
</Skeleton>
|
||||
<Skeleton className="h-5 w-10 rounded-lg">
|
||||
<div className="h-5 bg-default-200"></div>
|
||||
<div className="bg-default-200 h-5"></div>
|
||||
</Skeleton>
|
||||
</div>
|
||||
<Skeleton className="h-4 w-48 rounded-lg">
|
||||
<div className="h-4 bg-default-200"></div>
|
||||
<div className="bg-default-200 h-4"></div>
|
||||
</Skeleton>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@@ -83,18 +83,18 @@ export const ColumnNewFindingsToDate: ColumnDef<FindingProps>[] = [
|
||||
} = getFindingsData(row);
|
||||
const { delta } = row.original.attributes;
|
||||
return (
|
||||
<div className="relative flex max-w-[410px] flex-row items-center gap-2 3xl:max-w-[660px]">
|
||||
<div className="3xl:max-w-[660px] relative flex max-w-[410px] flex-row items-center gap-2">
|
||||
<div className="flex flex-row items-center gap-4">
|
||||
{delta === "new" || delta === "changed" ? (
|
||||
<DeltaIndicator delta={delta} />
|
||||
) : (
|
||||
<div className="w-2" />
|
||||
)}
|
||||
<p className="mr-7 whitespace-normal break-words text-sm">
|
||||
<p className="mr-7 text-sm break-words whitespace-normal">
|
||||
{checktitle}
|
||||
</p>
|
||||
</div>
|
||||
<span className="absolute -right-2 top-1/2 -translate-y-1/2">
|
||||
<span className="absolute top-1/2 -right-2 -translate-y-1/2">
|
||||
<Muted isMuted={muted} mutedReason={muted_reason || ""} />
|
||||
</span>
|
||||
</div>
|
||||
@@ -169,7 +169,7 @@ export const ColumnNewFindingsToDate: ColumnDef<FindingProps>[] = [
|
||||
header: "Service",
|
||||
cell: ({ row }) => {
|
||||
const { servicename } = getFindingsMetadata(row);
|
||||
return <p className="max-w-96 truncate text-small">{servicename}</p>;
|
||||
return <p className="text-small max-w-96 truncate">{servicename}</p>;
|
||||
},
|
||||
},
|
||||
{
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
"use client";
|
||||
|
||||
import { Card, CardBody } from "@nextui-org/react";
|
||||
import { Card, CardBody } from "@heroui/card";
|
||||
|
||||
import { AddIcon } from "@/components/icons/Icons";
|
||||
import {
|
||||
@@ -58,7 +58,7 @@ export const ProvidersOverview = ({
|
||||
|
||||
if (!providersOverview || !Array.isArray(providersOverview.data)) {
|
||||
return (
|
||||
<Card className="h-full dark:bg-prowler-blue-400">
|
||||
<Card className="dark:bg-prowler-blue-400 h-full">
|
||||
<CardBody>
|
||||
<div className="my-auto grid grid-cols-1 gap-3">
|
||||
<div className="grid grid-cols-4 border-b pb-2 text-xs font-semibold">
|
||||
@@ -106,7 +106,7 @@ export const ProvidersOverview = ({
|
||||
}
|
||||
|
||||
return (
|
||||
<Card className="h-full dark:bg-prowler-blue-400">
|
||||
<Card className="dark:bg-prowler-blue-400 h-full">
|
||||
<CardBody>
|
||||
<div className="my-auto grid grid-cols-1 gap-3">
|
||||
<div className="grid grid-cols-4 border-b pb-2 text-xs font-semibold">
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
import { Card, CardBody, CardHeader, Skeleton } from "@nextui-org/react";
|
||||
import { Card, CardBody, CardHeader } from "@heroui/card";
|
||||
import { Skeleton } from "@heroui/skeleton";
|
||||
|
||||
export const SkeletonProvidersOverview = () => {
|
||||
const rows = 4;
|
||||
@@ -7,7 +8,7 @@ export const SkeletonProvidersOverview = () => {
|
||||
<Card>
|
||||
<CardHeader>
|
||||
<Skeleton className="h-6 w-1/3 rounded-lg">
|
||||
<div className="h-6 bg-default-200"></div>
|
||||
<div className="bg-default-200 h-6"></div>
|
||||
</Skeleton>
|
||||
</CardHeader>
|
||||
<CardBody>
|
||||
@@ -15,16 +16,16 @@ export const SkeletonProvidersOverview = () => {
|
||||
{/* 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>
|
||||
<div className="bg-default-200 h-5"></div>
|
||||
</Skeleton>
|
||||
<Skeleton className="h-5 w-full rounded-lg">
|
||||
<div className="h-5 bg-default-200"></div>
|
||||
<div className="bg-default-200 h-5"></div>
|
||||
</Skeleton>
|
||||
<Skeleton className="h-5 w-full rounded-lg">
|
||||
<div className="h-5 bg-default-200"></div>
|
||||
<div className="bg-default-200 h-5"></div>
|
||||
</Skeleton>
|
||||
<Skeleton className="h-5 w-full rounded-lg">
|
||||
<div className="h-5 bg-default-200"></div>
|
||||
<div className="bg-default-200 h-5"></div>
|
||||
</Skeleton>
|
||||
</div>
|
||||
|
||||
@@ -35,25 +36,25 @@ export const SkeletonProvidersOverview = () => {
|
||||
className="grid grid-cols-4 items-center border-b py-2 text-sm"
|
||||
>
|
||||
{/* Provider Name */}
|
||||
<div className="flex items-center space-x-2">
|
||||
<div className="flex items-center gap-2">
|
||||
<Skeleton className="h-5 w-5 rounded-lg">
|
||||
<div className="h-5 w-5 bg-default-200"></div>
|
||||
<div className="bg-default-200 h-5 w-5"></div>
|
||||
</Skeleton>
|
||||
<Skeleton className="h-5 w-1/3 rounded-lg">
|
||||
<div className="h-5 bg-default-200"></div>
|
||||
<div className="bg-default-200 h-5"></div>
|
||||
</Skeleton>
|
||||
</div>
|
||||
{/* Percent Passing */}
|
||||
<Skeleton className="h-5 w-1/4 rounded-lg">
|
||||
<div className="h-5 bg-default-200"></div>
|
||||
<div className="bg-default-200 h-5"></div>
|
||||
</Skeleton>
|
||||
{/* Failing Checks */}
|
||||
<Skeleton className="h-5 w-1/4 rounded-lg">
|
||||
<div className="h-5 bg-default-200"></div>
|
||||
<div className="bg-default-200 h-5"></div>
|
||||
</Skeleton>
|
||||
{/* Total Resources */}
|
||||
<Skeleton className="h-5 w-1/4 rounded-lg">
|
||||
<div className="h-5 bg-default-200"></div>
|
||||
<div className="bg-default-200 h-5"></div>
|
||||
</Skeleton>
|
||||
</div>
|
||||
))}
|
||||
|
||||
@@ -35,7 +35,7 @@ export const title = tv({
|
||||
"pink",
|
||||
"foreground",
|
||||
],
|
||||
class: "bg-clip-text text-transparent bg-gradient-to-b",
|
||||
class: "bg-clip-text text-transparent bg-linear-to-b",
|
||||
},
|
||||
],
|
||||
});
|
||||
@@ -44,7 +44,7 @@ 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",
|
||||
true: "w-full!",
|
||||
},
|
||||
},
|
||||
defaultVariants: {
|
||||
|
||||
@@ -1,6 +1,8 @@
|
||||
"use client";
|
||||
|
||||
import { Button, Input, Select, SelectItem } from "@nextui-org/react";
|
||||
import { Button } from "@heroui/button";
|
||||
import { Input } from "@heroui/input";
|
||||
import { Select, SelectItem } from "@heroui/select";
|
||||
import { CheckSquare, Search, Square } from "lucide-react";
|
||||
import { useMemo, useState } from "react";
|
||||
import { Control } from "react-hook-form";
|
||||
@@ -116,10 +118,10 @@ export const EnhancedProviderSelector = ({
|
||||
return (
|
||||
<>
|
||||
<FormControl>
|
||||
<div className="space-y-2">
|
||||
<div className="flex flex-col gap-2">
|
||||
{isMultiple && filteredProviders.length > 1 && (
|
||||
<div className="flex items-center justify-between">
|
||||
<span className="text-sm font-medium text-default-700">
|
||||
<span className="text-default-700 text-sm font-medium">
|
||||
{label}
|
||||
</span>
|
||||
<Button
|
||||
@@ -158,7 +160,7 @@ export const EnhancedProviderSelector = ({
|
||||
listboxWrapper: "max-h-[300px] dark:bg-gray-800",
|
||||
listbox: "gap-0",
|
||||
label:
|
||||
"tracking-tight font-light !text-default-500 text-xs !z-0",
|
||||
"tracking-tight font-light !text-default-500 text-xs z-0!",
|
||||
value: "text-default-500 text-small dark:text-gray-300",
|
||||
}}
|
||||
renderValue={(items) => {
|
||||
@@ -210,7 +212,7 @@ export const EnhancedProviderSelector = ({
|
||||
}}
|
||||
listboxProps={{
|
||||
topContent: enableSearch ? (
|
||||
<div className="sticky top-0 z-10 bg-content1 py-2 dark:bg-gray-800">
|
||||
<div className="bg-content1 sticky top-0 z-10 py-2 dark:bg-gray-800">
|
||||
<Input
|
||||
isClearable
|
||||
placeholder="Search providers..."
|
||||
@@ -249,20 +251,20 @@ export const EnhancedProviderSelector = ({
|
||||
<div className="flex w-full items-center justify-between">
|
||||
<div className="flex min-w-0 flex-1 items-center gap-3">
|
||||
<div className="min-w-0 flex-1">
|
||||
<div className="truncate text-small font-medium">
|
||||
<div className="text-small truncate font-medium">
|
||||
{displayName}
|
||||
</div>
|
||||
<div className="truncate text-tiny text-default-500">
|
||||
<div className="text-tiny text-default-500 truncate">
|
||||
{typeLabel}
|
||||
{isDisabled && (
|
||||
<span className="ml-2 text-danger">
|
||||
<span className="text-danger ml-2">
|
||||
(Already used)
|
||||
</span>
|
||||
)}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div className="ml-2 flex flex-shrink-0 items-center gap-2">
|
||||
<div className="ml-2 flex shrink-0 items-center gap-2">
|
||||
<div
|
||||
className={`h-2 w-2 rounded-full ${
|
||||
provider.attributes.connection.connected
|
||||
@@ -284,7 +286,7 @@ export const EnhancedProviderSelector = ({
|
||||
</div>
|
||||
</FormControl>
|
||||
{showFormMessage && (
|
||||
<FormMessage className="max-w-full text-xs text-system-error dark:text-system-error" />
|
||||
<FormMessage className="text-system-error dark:text-system-error max-w-full text-xs" />
|
||||
)}
|
||||
</>
|
||||
);
|
||||
|
||||
@@ -59,7 +59,7 @@ export const DeleteForm = ({
|
||||
name={ProviderCredentialFields.PROVIDER_ID}
|
||||
value={providerId}
|
||||
/>
|
||||
<div className="flex w-full justify-center sm:space-x-6">
|
||||
<div className="flex w-full justify-center sm:gap-6">
|
||||
<CustomButton
|
||||
type="button"
|
||||
ariaLabel="Cancel"
|
||||
|
||||
@@ -67,7 +67,7 @@ export const EditForm = ({
|
||||
<Form {...form}>
|
||||
<form
|
||||
onSubmit={form.handleSubmit(onSubmitClient)}
|
||||
className="flex flex-col space-y-4"
|
||||
className="flex flex-col gap-4"
|
||||
>
|
||||
<div className="text-md">
|
||||
Current alias: <span className="font-bold">{providerAlias}</span>
|
||||
@@ -89,7 +89,7 @@ export const EditForm = ({
|
||||
</div>
|
||||
<input type="hidden" name="providerId" value={providerId} />
|
||||
|
||||
<div className="flex w-full justify-center sm:space-x-6">
|
||||
<div className="flex w-full justify-center sm:gap-6">
|
||||
<CustomButton
|
||||
type="button"
|
||||
ariaLabel="Cancel"
|
||||
|
||||
@@ -1,8 +1,13 @@
|
||||
"use client";
|
||||
|
||||
import { Textarea } from "@nextui-org/react";
|
||||
import { Dispatch, SetStateAction, useEffect, useState } from "react";
|
||||
import { useFormState } from "react-dom";
|
||||
import { Textarea } from "@heroui/input";
|
||||
import {
|
||||
Dispatch,
|
||||
SetStateAction,
|
||||
useActionState,
|
||||
useEffect,
|
||||
useState,
|
||||
} from "react";
|
||||
|
||||
import {
|
||||
createMutedFindingsConfig,
|
||||
@@ -45,7 +50,7 @@ export const MutedFindingsConfigForm = ({
|
||||
}>({ isValid: true });
|
||||
const [hasUserStartedTyping, setHasUserStartedTyping] = useState(false);
|
||||
|
||||
const [state, formAction, isPending] = useFormState<
|
||||
const [state, formAction, isPending] = useActionState<
|
||||
MutedFindingsConfigActionState,
|
||||
FormData
|
||||
>(config ? updateMutedFindingsConfig : createMutedFindingsConfig, null);
|
||||
@@ -128,15 +133,15 @@ export const MutedFindingsConfigForm = ({
|
||||
|
||||
if (showDeleteConfirmation) {
|
||||
return (
|
||||
<div className="flex flex-col space-y-4">
|
||||
<h3 className="text-lg font-semibold text-default-700">
|
||||
<div className="flex flex-col gap-4">
|
||||
<h3 className="text-default-700 text-lg font-semibold">
|
||||
Delete Mutelist Configuration
|
||||
</h3>
|
||||
<p className="text-sm text-default-600">
|
||||
<p className="text-default-600 text-sm">
|
||||
Are you sure you want to delete this configuration? This action cannot
|
||||
be undone.
|
||||
</p>
|
||||
<div className="flex w-full justify-center space-x-6">
|
||||
<div className="flex w-full justify-center gap-6">
|
||||
<CustomButton
|
||||
type="button"
|
||||
ariaLabel="Cancel"
|
||||
@@ -167,12 +172,12 @@ export const MutedFindingsConfigForm = ({
|
||||
}
|
||||
|
||||
return (
|
||||
<form action={formAction} className="flex flex-col space-y-4">
|
||||
<form action={formAction} className="flex flex-col gap-4">
|
||||
{config && <input type="hidden" name="id" value={config.id} />}
|
||||
|
||||
<div className="space-y-4">
|
||||
<div className="flex flex-col gap-4">
|
||||
<div>
|
||||
<ul className="mb-4 list-disc pl-5 text-sm text-default-600">
|
||||
<ul className="text-default-600 mb-4 list-disc pl-5 text-sm">
|
||||
<li>
|
||||
<strong>
|
||||
This Mutelist configuration will take effect on the next scan.
|
||||
@@ -196,10 +201,10 @@ export const MutedFindingsConfigForm = ({
|
||||
</ul>
|
||||
</div>
|
||||
|
||||
<div className="space-y-2">
|
||||
<div className="flex flex-col gap-2">
|
||||
<label
|
||||
htmlFor="configuration"
|
||||
className="text-sm font-medium text-default-700"
|
||||
className="text-default-700 text-sm font-medium"
|
||||
>
|
||||
Mutelist Configuration
|
||||
</label>
|
||||
@@ -228,7 +233,7 @@ export const MutedFindingsConfigForm = ({
|
||||
}}
|
||||
/>
|
||||
{yamlValidation.isValid && configText && hasUserStartedTyping && (
|
||||
<div className="my-1 flex items-center px-1 text-tiny text-success">
|
||||
<div className="text-tiny text-success my-1 flex items-center px-1">
|
||||
<span>Valid YAML format</span>
|
||||
</div>
|
||||
)}
|
||||
@@ -236,7 +241,7 @@ export const MutedFindingsConfigForm = ({
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div className="flex flex-col space-y-4">
|
||||
<div className="flex flex-col gap-4">
|
||||
<FormButtons
|
||||
setIsOpen={setIsOpen}
|
||||
onCancel={onCancel}
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import { Tooltip } from "@nextui-org/react";
|
||||
import { Tooltip } from "@heroui/tooltip";
|
||||
import React from "react";
|
||||
|
||||
import { ProviderType } from "@/types";
|
||||
@@ -23,7 +23,7 @@ export const ProviderInfo: React.FC<ProviderInfoProps> = ({
|
||||
case true:
|
||||
return (
|
||||
<Tooltip content="Provider connected" className="text-xs">
|
||||
<div className="flex items-center justify-center rounded-medium border-2 border-system-success bg-system-success-lighter p-1">
|
||||
<div className="rounded-medium border-system-success bg-system-success-lighter flex items-center justify-center border-2 p-1">
|
||||
<ConnectionTrue className="text-system-success" size={24} />
|
||||
</div>
|
||||
</Tooltip>
|
||||
@@ -31,7 +31,7 @@ export const ProviderInfo: React.FC<ProviderInfoProps> = ({
|
||||
case false:
|
||||
return (
|
||||
<Tooltip content="Provider connection failed" className="text-xs">
|
||||
<div className="flex items-center justify-center rounded-medium border-2 border-danger bg-system-error-lighter p-1">
|
||||
<div className="rounded-medium border-danger bg-system-error-lighter flex items-center justify-center border-2 p-1">
|
||||
<ConnectionFalse className="text-danger" size={24} />
|
||||
</div>
|
||||
</Tooltip>
|
||||
@@ -39,7 +39,7 @@ export const ProviderInfo: React.FC<ProviderInfoProps> = ({
|
||||
case null:
|
||||
return (
|
||||
<Tooltip content="Provider not connected" className="text-xs">
|
||||
<div className="bg-info-lighter border-info-lighter flex items-center justify-center rounded-medium border p-1">
|
||||
<div className="bg-info-lighter border-info-lighter rounded-medium flex items-center justify-center border p-1">
|
||||
<ConnectionPending className="text-info" size={24} />
|
||||
</div>
|
||||
</Tooltip>
|
||||
@@ -51,7 +51,7 @@ export const ProviderInfo: React.FC<ProviderInfoProps> = ({
|
||||
|
||||
return (
|
||||
<div className="flex items-center text-sm">
|
||||
<div className="flex items-center space-x-4">
|
||||
<div className="flex items-center gap-4">
|
||||
{getProviderLogo(provider)}
|
||||
{getIcon()}
|
||||
<span className="font-medium">{providerAlias || providerUID}</span>
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
"use client";
|
||||
|
||||
import { RadioGroup } from "@nextui-org/react";
|
||||
import { RadioGroup } from "@heroui/radio";
|
||||
import React from "react";
|
||||
import { Control, Controller } from "react-hook-form";
|
||||
import { z } from "zod";
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
"use client";
|
||||
|
||||
import { Chip } from "@nextui-org/react";
|
||||
import { Chip } from "@heroui/chip";
|
||||
import { ColumnDef } from "@tanstack/react-table";
|
||||
|
||||
import { DateWithTime, SnippetChip } from "@/components/ui/entities";
|
||||
|
||||
@@ -1,18 +1,18 @@
|
||||
"use client";
|
||||
|
||||
import { Button } from "@heroui/button";
|
||||
import {
|
||||
Button,
|
||||
Dropdown,
|
||||
DropdownItem,
|
||||
DropdownMenu,
|
||||
DropdownSection,
|
||||
DropdownTrigger,
|
||||
} from "@nextui-org/react";
|
||||
} from "@heroui/dropdown";
|
||||
import {
|
||||
AddNoteBulkIcon,
|
||||
DeleteDocumentBulkIcon,
|
||||
EditDocumentBulkIcon,
|
||||
} from "@nextui-org/shared-icons";
|
||||
} from "@heroui/shared-icons";
|
||||
import { Row } from "@tanstack/react-table";
|
||||
import clsx from "clsx";
|
||||
import { useRouter } from "next/navigation";
|
||||
@@ -28,8 +28,7 @@ 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";
|
||||
const iconClasses = "text-2xl text-default-500 pointer-events-none shrink-0";
|
||||
|
||||
export function DataTableRowActions<ProviderProps>({
|
||||
row,
|
||||
@@ -54,6 +53,12 @@ export function DataTableRowActions<ProviderProps>({
|
||||
|
||||
const hasSecret = (row.original as any).relationships?.secret?.data;
|
||||
|
||||
// Calculate disabled keys based on conditions
|
||||
const disabledKeys = [];
|
||||
if (!hasSecret || loading) {
|
||||
disabledKeys.push("new");
|
||||
}
|
||||
|
||||
return (
|
||||
<>
|
||||
<CustomAlertModal
|
||||
@@ -78,7 +83,7 @@ export function DataTableRowActions<ProviderProps>({
|
||||
|
||||
<div className="relative flex items-center justify-end gap-2">
|
||||
<Dropdown
|
||||
className="shadow-xl dark:bg-prowler-blue-800"
|
||||
className="dark:bg-prowler-blue-800 shadow-xl"
|
||||
placement="bottom"
|
||||
>
|
||||
<DropdownTrigger>
|
||||
@@ -86,7 +91,13 @@ export function DataTableRowActions<ProviderProps>({
|
||||
<VerticalDotsIcon className="text-default-400" />
|
||||
</Button>
|
||||
</DropdownTrigger>
|
||||
<DropdownMenu aria-label="Actions" color="default" variant="flat">
|
||||
<DropdownMenu
|
||||
aria-label="Actions"
|
||||
color="default"
|
||||
variant="flat"
|
||||
disabledKeys={disabledKeys}
|
||||
closeOnSelect={false}
|
||||
>
|
||||
<DropdownSection title="Actions">
|
||||
<DropdownItem
|
||||
key={hasSecret ? "update" : "add"}
|
||||
@@ -118,7 +129,6 @@ export function DataTableRowActions<ProviderProps>({
|
||||
textValue="Check Connection"
|
||||
startContent={<AddNoteBulkIcon className={iconClasses} />}
|
||||
onPress={handleTestConnection}
|
||||
isDisabled={!hasSecret || loading}
|
||||
closeOnSelect={false}
|
||||
>
|
||||
{loading ? "Testing..." : "Test Connection"}
|
||||
|
||||
@@ -1,61 +1,62 @@
|
||||
import { Card, Skeleton } from "@nextui-org/react";
|
||||
import { Card } from "@heroui/card";
|
||||
import { Skeleton } from "@heroui/skeleton";
|
||||
import React from "react";
|
||||
|
||||
export const SkeletonTableProviders = () => {
|
||||
return (
|
||||
<Card className="h-full w-full space-y-5 p-4" radius="sm">
|
||||
<Card className="flex h-full w-full flex-col gap-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>
|
||||
<div className="bg-default-200 h-8"></div>
|
||||
</Skeleton>
|
||||
<Skeleton className="w-2/12 rounded-lg">
|
||||
<div className="h-8 bg-default-200"></div>
|
||||
<div className="bg-default-200 h-8"></div>
|
||||
</Skeleton>
|
||||
<Skeleton className="w-2/12 rounded-lg">
|
||||
<div className="h-8 bg-default-200"></div>
|
||||
<div className="bg-default-200 h-8"></div>
|
||||
</Skeleton>
|
||||
<Skeleton className="w-2/12 rounded-lg">
|
||||
<div className="h-8 bg-default-200"></div>
|
||||
<div className="bg-default-200 h-8"></div>
|
||||
</Skeleton>
|
||||
<Skeleton className="w-2/12 rounded-lg">
|
||||
<div className="h-8 bg-default-200"></div>
|
||||
<div className="bg-default-200 h-8"></div>
|
||||
</Skeleton>
|
||||
<Skeleton className="w-1/12 rounded-lg">
|
||||
<div className="h-8 bg-default-200"></div>
|
||||
<div className="bg-default-200 h-8"></div>
|
||||
</Skeleton>
|
||||
<Skeleton className="w-1/12 rounded-lg">
|
||||
<div className="h-8 bg-default-200"></div>
|
||||
<div className="bg-default-200 h-8"></div>
|
||||
</Skeleton>
|
||||
</div>
|
||||
|
||||
{/* Table body */}
|
||||
<div className="space-y-3">
|
||||
<div className="flex flex-col gap-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"
|
||||
className="flex flex-col items-center justify-between md:flex-row md:gap-4"
|
||||
>
|
||||
<Skeleton className="mb-2 w-full rounded-lg md:mb-0 md:w-1/12">
|
||||
<div className="h-12 bg-default-300"></div>
|
||||
<div className="bg-default-300 h-12"></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>
|
||||
<div className="bg-default-300 h-12"></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>
|
||||
<div className="bg-default-300 h-12"></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>
|
||||
<div className="bg-default-300 h-12"></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>
|
||||
<div className="bg-default-300 h-12"></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>
|
||||
<div className="bg-default-300 h-12"></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>
|
||||
<div className="bg-default-300 h-12"></div>
|
||||
</Skeleton>
|
||||
</div>
|
||||
))}
|
||||
|
||||
@@ -76,7 +76,7 @@ export const CredentialsRoleHelper = ({
|
||||
</div>
|
||||
|
||||
<div className="flex items-center gap-2">
|
||||
<span className="block text-xs font-medium text-default-500">
|
||||
<span className="text-default-500 block text-xs font-medium">
|
||||
External ID:
|
||||
</span>
|
||||
<SnippetChip value={externalId} icon={<IdIcon size={16} />} />
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
"use client";
|
||||
|
||||
import { Divider } from "@nextui-org/react";
|
||||
import { Divider } from "@heroui/divider";
|
||||
import { ChevronLeftIcon, ChevronRightIcon } from "lucide-react";
|
||||
import { Control } from "react-hook-form";
|
||||
|
||||
@@ -68,7 +68,7 @@ export const BaseCredentialsForm = ({
|
||||
<Form {...form}>
|
||||
<form
|
||||
onSubmit={form.handleSubmit(handleSubmit)}
|
||||
className="flex flex-col space-y-4"
|
||||
className="flex flex-col gap-4"
|
||||
>
|
||||
<input
|
||||
type="hidden"
|
||||
@@ -134,7 +134,7 @@ export const BaseCredentialsForm = ({
|
||||
/>
|
||||
)}
|
||||
|
||||
<div className="flex w-full justify-end sm:space-x-6">
|
||||
<div className="flex w-full justify-end sm:gap-6">
|
||||
{showBackButton && requiresBackButton(searchParamsObj.get("via")) && (
|
||||
<CustomButton
|
||||
type="button"
|
||||
|
||||
@@ -167,7 +167,7 @@ export const ConnectAccountForm = () => {
|
||||
<Form {...form}>
|
||||
<form
|
||||
onSubmit={form.handleSubmit(onSubmitClient)}
|
||||
className="flex flex-col space-y-4"
|
||||
className="flex flex-col gap-4"
|
||||
>
|
||||
{/* Step 1: Provider selection */}
|
||||
{prevStep === 1 && (
|
||||
@@ -206,7 +206,7 @@ export const ConnectAccountForm = () => {
|
||||
</>
|
||||
)}
|
||||
{/* Navigation buttons */}
|
||||
<div className="flex w-full justify-end sm:space-x-6">
|
||||
<div className="flex w-full justify-end sm:gap-6">
|
||||
{/* Show "Back" button only in Step 2 */}
|
||||
{prevStep === 2 && (
|
||||
<CustomButton
|
||||
|
||||
+9
-6
@@ -1,4 +1,7 @@
|
||||
import { Chip, Divider, Select, SelectItem, Switch } from "@nextui-org/react";
|
||||
import { Chip } from "@heroui/chip";
|
||||
import { Divider } from "@heroui/divider";
|
||||
import { Select, SelectItem } from "@heroui/select";
|
||||
import { Switch } from "@heroui/switch";
|
||||
import { useEffect, useState } from "react";
|
||||
import { Control, UseFormSetValue, useWatch } from "react-hook-form";
|
||||
|
||||
@@ -64,13 +67,13 @@ export const AWSRoleCredentialsForm = ({
|
||||
<>
|
||||
<div className="flex flex-col">
|
||||
{type === "providers" && (
|
||||
<div className="text-md font-bold leading-9 text-default-foreground">
|
||||
<div className="text-md text-default-foreground leading-9 font-bold">
|
||||
Connect assuming IAM Role
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
|
||||
<span className="text-xs font-bold text-default-500">
|
||||
<span className="text-default-500 text-xs font-bold">
|
||||
Specify which AWS credentials to use
|
||||
</span>
|
||||
|
||||
@@ -168,10 +171,10 @@ export const AWSRoleCredentialsForm = ({
|
||||
<Divider className="" />
|
||||
|
||||
{type === "providers" ? (
|
||||
<span className="text-xs font-bold text-default-500">Assume Role</span>
|
||||
<span className="text-default-500 text-xs font-bold">Assume Role</span>
|
||||
) : (
|
||||
<div className="flex items-center justify-between">
|
||||
<span className="text-xs font-bold text-default-500">
|
||||
<span className="text-default-500 text-xs font-bold">
|
||||
{isCloudEnv && credentialsType === "aws-sdk-default"
|
||||
? "Adding a role is required"
|
||||
: "Optionally add a role"}
|
||||
@@ -224,7 +227,7 @@ export const AWSRoleCredentialsForm = ({
|
||||
}
|
||||
/>
|
||||
|
||||
<span className="text-xs text-default-500">Optional fields</span>
|
||||
<span className="text-default-500 text-xs">Optional fields</span>
|
||||
<div className="mt-4 grid grid-cols-1 gap-4 md:grid-cols-2">
|
||||
<CustomInput
|
||||
control={control}
|
||||
|
||||
+2
-2
@@ -12,10 +12,10 @@ export const AWSStaticCredentialsForm = ({
|
||||
return (
|
||||
<>
|
||||
<div className="flex flex-col">
|
||||
<div className="text-md font-bold leading-9 text-default-foreground">
|
||||
<div className="text-md text-default-foreground leading-9 font-bold">
|
||||
Connect via Credentials
|
||||
</div>
|
||||
<div className="text-sm text-default-500">
|
||||
<div className="text-default-500 text-sm">
|
||||
Please provide the information for your AWS credentials.
|
||||
</div>
|
||||
</div>
|
||||
|
||||
+3
-3
@@ -1,6 +1,6 @@
|
||||
"use client";
|
||||
|
||||
import { RadioGroup } from "@nextui-org/react";
|
||||
import { RadioGroup } from "@heroui/radio";
|
||||
import React from "react";
|
||||
import { Control, Controller } from "react-hook-form";
|
||||
|
||||
@@ -39,13 +39,13 @@ export const RadioGroupAWSViaCredentialsTypeForm = ({
|
||||
}}
|
||||
>
|
||||
<div className="flex flex-col gap-4">
|
||||
<span className="text-sm text-default-500">Using IAM Role</span>
|
||||
<span className="text-default-500 text-sm">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">
|
||||
<span className="text-default-500 text-sm">
|
||||
Using Credentials
|
||||
</span>
|
||||
<CustomRadio
|
||||
|
||||
+2
-2
@@ -11,10 +11,10 @@ export const GCPDefaultCredentialsForm = ({
|
||||
return (
|
||||
<>
|
||||
<div className="flex flex-col">
|
||||
<div className="text-md font-bold leading-9 text-default-foreground">
|
||||
<div className="text-md text-default-foreground leading-9 font-bold">
|
||||
Connect via Credentials
|
||||
</div>
|
||||
<div className="text-sm text-default-500">
|
||||
<div className="text-default-500 text-sm">
|
||||
Please provide the information for your GCP credentials.
|
||||
</div>
|
||||
</div>
|
||||
|
||||
+2
-2
@@ -11,10 +11,10 @@ export const GCPServiceAccountKeyForm = ({
|
||||
return (
|
||||
<>
|
||||
<div className="flex flex-col">
|
||||
<div className="text-md font-bold leading-9 text-default-foreground">
|
||||
<div className="text-md text-default-foreground leading-9 font-bold">
|
||||
Connect via Service Account Key
|
||||
</div>
|
||||
<div className="text-sm text-default-500">
|
||||
<div className="text-default-500 text-sm">
|
||||
Please provide the service account key for your GCP credentials.
|
||||
</div>
|
||||
</div>
|
||||
|
||||
+3
-3
@@ -1,6 +1,6 @@
|
||||
"use client";
|
||||
|
||||
import { RadioGroup } from "@nextui-org/react";
|
||||
import { RadioGroup } from "@heroui/radio";
|
||||
import React from "react";
|
||||
import { Control, Controller } from "react-hook-form";
|
||||
|
||||
@@ -39,7 +39,7 @@ export const RadioGroupGCPViaCredentialsTypeForm = ({
|
||||
}}
|
||||
>
|
||||
<div className="flex flex-col gap-4">
|
||||
<span className="text-sm text-default-500">
|
||||
<span className="text-default-500 text-sm">
|
||||
Using Service Account
|
||||
</span>
|
||||
<CustomRadio
|
||||
@@ -50,7 +50,7 @@ export const RadioGroupGCPViaCredentialsTypeForm = ({
|
||||
<span className="ml-2">Connect via Service Account Key</span>
|
||||
</div>
|
||||
</CustomRadio>
|
||||
<span className="text-sm text-default-500">
|
||||
<span className="text-default-500 text-sm">
|
||||
Using Application Default Credentials
|
||||
</span>
|
||||
<CustomRadio
|
||||
|
||||
+2
-2
@@ -9,10 +9,10 @@ export const GitHubAppForm = ({ control }: { control: Control<any> }) => {
|
||||
return (
|
||||
<>
|
||||
<div className="flex flex-col">
|
||||
<div className="text-md font-bold leading-9 text-default-foreground">
|
||||
<div className="text-md text-default-foreground leading-9 font-bold">
|
||||
Connect via GitHub App
|
||||
</div>
|
||||
<div className="text-sm text-default-500">
|
||||
<div className="text-default-500 text-sm">
|
||||
Please provide your GitHub App ID and private key.
|
||||
</div>
|
||||
</div>
|
||||
|
||||
+2
-2
@@ -9,10 +9,10 @@ export const GitHubOAuthAppForm = ({ control }: { control: Control<any> }) => {
|
||||
return (
|
||||
<>
|
||||
<div className="flex flex-col">
|
||||
<div className="text-md font-bold leading-9 text-default-foreground">
|
||||
<div className="text-md text-default-foreground leading-9 font-bold">
|
||||
Connect via OAuth App
|
||||
</div>
|
||||
<div className="text-sm text-default-500">
|
||||
<div className="text-default-500 text-sm">
|
||||
Please provide your GitHub OAuth App token.
|
||||
</div>
|
||||
</div>
|
||||
|
||||
+2
-2
@@ -13,10 +13,10 @@ export const GitHubPersonalAccessTokenForm = ({
|
||||
return (
|
||||
<>
|
||||
<div className="flex flex-col">
|
||||
<div className="text-md font-bold leading-9 text-default-foreground">
|
||||
<div className="text-md text-default-foreground leading-9 font-bold">
|
||||
Connect via Personal Access Token
|
||||
</div>
|
||||
<div className="text-sm text-default-500">
|
||||
<div className="text-default-500 text-sm">
|
||||
Please provide your GitHub personal access token.
|
||||
</div>
|
||||
</div>
|
||||
|
||||
+4
-4
@@ -1,6 +1,6 @@
|
||||
"use client";
|
||||
|
||||
import { RadioGroup } from "@nextui-org/react";
|
||||
import { RadioGroup } from "@heroui/radio";
|
||||
import React from "react";
|
||||
import { Control, Controller } from "react-hook-form";
|
||||
|
||||
@@ -39,7 +39,7 @@ export const RadioGroupGitHubViaCredentialsTypeForm = ({
|
||||
}}
|
||||
>
|
||||
<div className="flex flex-col gap-4">
|
||||
<span className="text-sm text-default-500">
|
||||
<span className="text-default-500 text-sm">
|
||||
Personal Access Token
|
||||
</span>
|
||||
<CustomRadio
|
||||
@@ -51,7 +51,7 @@ export const RadioGroupGitHubViaCredentialsTypeForm = ({
|
||||
</div>
|
||||
</CustomRadio>
|
||||
|
||||
<span className="text-sm text-default-500">OAuth App</span>
|
||||
<span className="text-default-500 text-sm">OAuth App</span>
|
||||
<CustomRadio
|
||||
description="Use OAuth App token for authentication"
|
||||
value="oauth_app"
|
||||
@@ -61,7 +61,7 @@ export const RadioGroupGitHubViaCredentialsTypeForm = ({
|
||||
</div>
|
||||
</CustomRadio>
|
||||
|
||||
<span className="text-sm text-default-500">GitHub App</span>
|
||||
<span className="text-default-500 text-sm">GitHub App</span>
|
||||
<CustomRadio
|
||||
description="Use GitHub App ID and private key for authentication"
|
||||
value="github_app"
|
||||
|
||||
@@ -1,8 +1,8 @@
|
||||
"use client";
|
||||
|
||||
import { Checkbox } from "@heroui/checkbox";
|
||||
import { zodResolver } from "@hookform/resolvers/zod";
|
||||
import { Icon } from "@iconify/react";
|
||||
import { Checkbox } from "@nextui-org/react";
|
||||
import { useRouter } from "next/navigation";
|
||||
import { useState } from "react";
|
||||
import { useForm } from "react-hook-form";
|
||||
@@ -201,16 +201,16 @@ export const TestConnectionForm = ({
|
||||
|
||||
if (isRedirecting) {
|
||||
return (
|
||||
<div className="flex flex-col items-center justify-center space-y-6 py-12">
|
||||
<div className="flex flex-col items-center justify-center gap-6 py-12">
|
||||
<div className="relative">
|
||||
<div className="h-24 w-24 animate-pulse rounded-full bg-primary/20" />
|
||||
<div className="absolute inset-0 h-24 w-24 animate-spin rounded-full border-4 border-primary border-t-transparent" />
|
||||
<div className="bg-primary/20 h-24 w-24 animate-pulse rounded-full" />
|
||||
<div className="border-primary absolute inset-0 h-24 w-24 animate-spin rounded-full border-4 border-t-transparent" />
|
||||
</div>
|
||||
<div className="text-center">
|
||||
<p className="text-xl font-medium text-primary">
|
||||
<p className="text-primary text-xl font-medium">
|
||||
Scan initiated successfully
|
||||
</p>
|
||||
<p className="mt-2 text-small font-bold text-gray-500">
|
||||
<p className="text-small mt-2 font-bold text-gray-500">
|
||||
Redirecting to scans job details...
|
||||
</p>
|
||||
</div>
|
||||
@@ -222,7 +222,7 @@ export const TestConnectionForm = ({
|
||||
<Form {...form}>
|
||||
<form
|
||||
onSubmit={form.handleSubmit(onSubmitClient)}
|
||||
className="flex flex-col space-y-4"
|
||||
className="flex flex-col gap-4"
|
||||
>
|
||||
<div className="text-left">
|
||||
<div className="mb-2 text-xl font-medium">
|
||||
@@ -230,7 +230,7 @@ export const TestConnectionForm = ({
|
||||
? "Check connection and launch scan"
|
||||
: "Check connection"}
|
||||
</div>
|
||||
<p className="py-2 text-small text-default-500">
|
||||
<p className="text-small text-default-500 py-2">
|
||||
{!isUpdated
|
||||
? "After a successful connection, a scan will automatically run every 24 hours. To run a single scan instead, select the checkbox below."
|
||||
: "A successful connection will redirect you to the providers page."}
|
||||
@@ -238,7 +238,7 @@ export const TestConnectionForm = ({
|
||||
</div>
|
||||
|
||||
{apiErrorMessage && (
|
||||
<div className="mt-4 rounded-md bg-red-100 p-3 text-danger">
|
||||
<div className="text-danger mt-4 rounded-md bg-red-100 p-3">
|
||||
<p>{`Provider ID ${apiErrorMessage?.toLowerCase()}. Please check and try again.`}</p>
|
||||
</div>
|
||||
)}
|
||||
@@ -249,7 +249,7 @@ export const TestConnectionForm = ({
|
||||
<div className="flex items-center">
|
||||
<Icon
|
||||
icon="heroicons:exclamation-circle"
|
||||
className="h-5 w-5 text-danger"
|
||||
className="text-danger h-5 w-5"
|
||||
/>
|
||||
</div>
|
||||
<div className="flex items-center">
|
||||
@@ -286,19 +286,19 @@ export const TestConnectionForm = ({
|
||||
)}
|
||||
|
||||
{isUpdated && !connectionStatus?.error && (
|
||||
<p className="py-2 text-small text-default-500">
|
||||
<p className="text-small text-default-500 py-2">
|
||||
Check the new credentials and test the connection.
|
||||
</p>
|
||||
)}
|
||||
|
||||
<input type="hidden" name="providerId" value={providerId} />
|
||||
|
||||
<div className="flex w-full justify-end sm:space-x-6">
|
||||
<div className="flex w-full justify-end sm:gap-6">
|
||||
{apiErrorMessage ? (
|
||||
<CustomLink
|
||||
href="/providers"
|
||||
target="_self"
|
||||
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"
|
||||
className="mr-3 flex w-fit items-center justify-center gap-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"
|
||||
|
||||
@@ -11,10 +11,10 @@ export const AzureCredentialsForm = ({
|
||||
return (
|
||||
<>
|
||||
<div className="flex flex-col">
|
||||
<div className="text-md font-bold leading-9 text-default-foreground">
|
||||
<div className="text-md text-default-foreground leading-9 font-bold">
|
||||
Connect via Credentials
|
||||
</div>
|
||||
<div className="text-sm text-default-500">
|
||||
<div className="text-default-500 text-sm">
|
||||
Please provide the information for your Azure credentials.
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@@ -11,10 +11,10 @@ export const KubernetesCredentialsForm = ({
|
||||
return (
|
||||
<>
|
||||
<div className="flex flex-col">
|
||||
<div className="text-md font-bold leading-9 text-default-foreground">
|
||||
<div className="text-md text-default-foreground leading-9 font-bold">
|
||||
Connect via Credentials
|
||||
</div>
|
||||
<div className="text-sm text-default-500">
|
||||
<div className="text-default-500 text-sm">
|
||||
Please provide the kubeconfig content for your Kubernetes credentials.
|
||||
</div>
|
||||
</div>
|
||||
|
||||
Loaded 100 of 261 files, more files were not shown because too many files have changed in this diff.
Show more
Reference in new issue
Block a user