diff --git a/ui/AGENTS.md b/ui/AGENTS.md index 38af45860f..c9adca0961 100644 --- a/ui/AGENTS.md +++ b/ui/AGENTS.md @@ -187,7 +187,7 @@ test("action works", { tag: ["@critical", "@feature"] }, async ({ page }) => { Next.js 16.2.3 | React 19.2.5 | Tailwind 4.1.18 | shadcn/ui Zod 4.1.11 | React Hook Form 7.62.0 | Zustand 5.0.8 | NextAuth 5.0.0-beta.30 | Recharts 2.15.4 -> **Note**: HeroUI exists in `components/ui/` as legacy code. Do NOT add new components there. +> **Note**: `components/ui/` only holds temporary re-export shims for the prowler-cloud overlay. Do NOT add new components there. --- @@ -198,7 +198,7 @@ ui/ ├── app/(auth)/ # Auth pages ├── app/(prowler)/ # Main app: compliance, findings, providers, scans ├── components/shadcn/ # shadcn/ui components (USE THIS) -├── components/ui/ # HeroUI (LEGACY - do not add here) +├── components/ui/ # Cloud-overlay re-export shims (do not add here) ├── actions/ # Server actions ├── types/ # Shared types ├── hooks/ # Shared hooks diff --git a/ui/README.md b/ui/README.md index 998dc84a37..31b6ae3057 100644 --- a/ui/README.md +++ b/ui/README.md @@ -114,10 +114,9 @@ pnpm run dev ## Technologies Used -- [Next.js 14](https://nextjs.org/docs/getting-started) -- [NextUI v2](https://nextui.org/) -- [Tailwind CSS](https://tailwindcss.com/) -- [Tailwind Variants](https://tailwind-variants.org) +- [Next.js 16](https://nextjs.org/docs/getting-started) +- [shadcn/ui](https://ui.shadcn.com/) (built on [Radix UI](https://www.radix-ui.com/)) +- [Tailwind CSS 4](https://tailwindcss.com/) - [TypeScript](https://www.typescriptlang.org/) - [Framer Motion](https://www.framer.com/motion/) - [next-themes](https://github.com/pacocoursey/next-themes) diff --git a/ui/app/(auth)/alerts/confirm/page.test.tsx b/ui/app/(auth)/alerts/confirm/page.test.tsx index 8b6203c109..6885db86b3 100644 --- a/ui/app/(auth)/alerts/confirm/page.test.tsx +++ b/ui/app/(auth)/alerts/confirm/page.test.tsx @@ -16,7 +16,8 @@ vi.mock("@/components/auth/oss/auth-layout", () => ({ ), })); -vi.mock("@/components/shadcn", () => ({ +vi.mock("@/components/shadcn", async (importOriginal) => ({ + ...(await importOriginal>()), Button: ({ children }: { children: ReactNode }) =>
{children}
, })); diff --git a/ui/app/(auth)/alerts/unsubscribe/page.test.tsx b/ui/app/(auth)/alerts/unsubscribe/page.test.tsx index 4ffeb548b0..560a5ad010 100644 --- a/ui/app/(auth)/alerts/unsubscribe/page.test.tsx +++ b/ui/app/(auth)/alerts/unsubscribe/page.test.tsx @@ -16,7 +16,8 @@ vi.mock("@/components/auth/oss/auth-layout", () => ({ ), })); -vi.mock("@/components/shadcn", () => ({ +vi.mock("@/components/shadcn", async (importOriginal) => ({ + ...(await importOriginal>()), Button: ({ children }: { children: ReactNode }) =>
{children}
, })); diff --git a/ui/app/(auth)/invitation/accept/accept-invitation-client.tsx b/ui/app/(auth)/invitation/accept/accept-invitation-client.tsx index 0ed6346de7..cec9c8fc55 100644 --- a/ui/app/(auth)/invitation/accept/accept-invitation-client.tsx +++ b/ui/app/(auth)/invitation/accept/accept-invitation-client.tsx @@ -74,11 +74,11 @@ export function AcceptInvitationClient({

Invalid Invitation Link

-

+

No invitation token was provided. Please check the link you received.

@@ -93,11 +93,11 @@ export function AcceptInvitationClient({

Accepting Invitation...

-

+

Please wait while we process your invitation.

@@ -108,13 +108,13 @@ export function AcceptInvitationClient({

Could Not Accept Invitation

-

{state.message}

+

{state.message}

{state.canRetry && }
- +
)} {children} diff --git a/ui/app/(prowler)/lighthouse/config/page.tsx b/ui/app/(prowler)/lighthouse/config/page.tsx index 1cf09496f6..b0c89adf79 100644 --- a/ui/app/(prowler)/lighthouse/config/page.tsx +++ b/ui/app/(prowler)/lighthouse/config/page.tsx @@ -1,7 +1,5 @@ -import { Spacer } from "@heroui/spacer"; - import { LighthouseSettings, LLMProvidersTable } from "@/components/lighthouse"; -import { ContentLayout } from "@/components/ui"; +import { ContentLayout } from "@/components/shadcn/content-layout"; export const dynamic = "force-dynamic"; @@ -9,7 +7,7 @@ export default async function ChatbotConfigPage() { return ( - +
); diff --git a/ui/app/(prowler)/lighthouse/page.tsx b/ui/app/(prowler)/lighthouse/page.tsx index eefca03e6b..78e95a0117 100644 --- a/ui/app/(prowler)/lighthouse/page.tsx +++ b/ui/app/(prowler)/lighthouse/page.tsx @@ -6,7 +6,7 @@ import { } from "@/actions/lighthouse/lighthouse"; import { LighthouseIcon } from "@/components/icons/Icons"; import { Chat } from "@/components/lighthouse"; -import { ContentLayout } from "@/components/ui"; +import { ContentLayout } from "@/components/shadcn/content-layout"; export const dynamic = "force-dynamic"; diff --git a/ui/app/(prowler)/manage-groups/layout.tsx b/ui/app/(prowler)/manage-groups/layout.tsx index 8e8487934e..224c4b4018 100644 --- a/ui/app/(prowler)/manage-groups/layout.tsx +++ b/ui/app/(prowler)/manage-groups/layout.tsx @@ -2,7 +2,7 @@ import "@/styles/globals.css"; import React from "react"; -import { ContentLayout } from "@/components/ui"; +import { ContentLayout } from "@/components/shadcn/content-layout"; interface ProviderLayoutProps { children: React.ReactNode; diff --git a/ui/app/(prowler)/mutelist/_components/advanced-mutelist-form.tsx b/ui/app/(prowler)/mutelist/_components/advanced-mutelist-form.tsx index d6992d6fb5..5d30308ee3 100644 --- a/ui/app/(prowler)/mutelist/_components/advanced-mutelist-form.tsx +++ b/ui/app/(prowler)/mutelist/_components/advanced-mutelist-form.tsx @@ -1,6 +1,5 @@ "use client"; -import { Textarea } from "@heroui/input"; import { Trash2 } from "lucide-react"; import { useActionState, useEffect, useState } from "react"; @@ -10,11 +9,18 @@ import { getMutedFindingsConfig, updateMutedFindingsConfig, } from "@/actions/processors"; -import { Button, Card, Skeleton } from "@/components/shadcn"; +import { + Button, + Card, + FieldError, + Skeleton, + Textarea, +} from "@/components/shadcn"; +import { useToast } from "@/components/shadcn"; +import { CustomLink } from "@/components/shadcn/custom/custom-link"; import { Modal } from "@/components/shadcn/modal"; -import { useToast } from "@/components/ui"; -import { CustomLink } from "@/components/ui/custom/custom-link"; import { fontMono } from "@/config/fonts"; +import { cn } from "@/lib/utils"; import { convertToYaml, defaultMutedFindingsConfig, @@ -132,6 +138,13 @@ export function AdvancedMutelistForm() { } }; + const isConfigInvalid = + (!hasUserStartedTyping && !!state?.errors?.configuration) || + !yamlValidation.isValid; + const configErrorMessage = + (!hasUserStartedTyping && state?.errors?.configuration) || + (!yamlValidation.isValid ? yamlValidation.error : ""); + if (isLoading) { return ( @@ -159,7 +172,7 @@ export function AdvancedMutelistForm() { size="md" >
-

+

Are you sure you want to delete this configuration? This action cannot be undone.

@@ -193,10 +206,10 @@ export function AdvancedMutelistForm() {
-

+

Advanced Mutelist Configuration

-
    +
    • This Mutelist configuration will take effect on the next @@ -227,7 +240,7 @@ export function AdvancedMutelistForm() {
      @@ -236,29 +249,26 @@ export function AdvancedMutelistForm() { id="configuration" name="configuration" placeholder={defaultMutedFindingsConfig} - variant="bordered" value={configText} onChange={(e) => handleConfigChange(e.target.value)} - minRows={20} - maxRows={20} - isInvalid={ - (!hasUserStartedTyping && !!state?.errors?.configuration) || - !yamlValidation.isValid - } - errorMessage={ - (!hasUserStartedTyping && state?.errors?.configuration) || - (!yamlValidation.isValid ? yamlValidation.error : "") - } - classNames={{ - input: fontMono.className + " text-sm", - base: "min-h-[400px]", - errorMessage: "whitespace-pre-wrap", - }} + rows={20} + aria-invalid={isConfigInvalid} + className={cn( + fontMono.className, + "min-h-[400px] text-sm", + isConfigInvalid && + "border-border-error focus:border-border-error focus:ring-border-error", + )} /> + {isConfigInvalid && configErrorMessage && ( + + {configErrorMessage} + + )} {yamlValidation.isValid && configText && hasUserStartedTyping && ( -
      +
      Valid YAML format
      )} diff --git a/ui/app/(prowler)/mutelist/_components/simple/mute-rule-edit-form.test.tsx b/ui/app/(prowler)/mutelist/_components/simple/mute-rule-edit-form.test.tsx index 70b90187b6..1f13aaa09c 100644 --- a/ui/app/(prowler)/mutelist/_components/simple/mute-rule-edit-form.test.tsx +++ b/ui/app/(prowler)/mutelist/_components/simple/mute-rule-edit-form.test.tsx @@ -11,13 +11,7 @@ vi.mock("@/actions/mute-rules", () => ({ updateMuteRule: updateMuteRuleMock, })); -vi.mock("@/components/ui", () => ({ - useToast: () => ({ - toast: toastMock, - }), -})); - -vi.mock("@/components/ui/form", () => ({ +vi.mock("@/components/shadcn/form", () => ({ FormButtons: ({ onCancel, submitText = "Save", @@ -38,7 +32,9 @@ vi.mock("@/components/ui/form", () => ({ ), })); -vi.mock("@/components/shadcn", () => ({ +vi.mock("@/components/shadcn", async (importOriginal) => ({ + ...(await importOriginal>()), + useToast: () => ({ toast: toastMock }), Input: ({ defaultValue, ...props @@ -53,7 +49,7 @@ vi.mock("@/components/shadcn", () => ({ ), })); -vi.mock("@/components/ui/form/Label", () => ({ +vi.mock("@/components/shadcn/form/Label", () => ({ Label: ({ children, ...props diff --git a/ui/app/(prowler)/mutelist/_components/simple/mute-rule-edit-form.tsx b/ui/app/(prowler)/mutelist/_components/simple/mute-rule-edit-form.tsx index 1c90e86b90..96268f72e0 100644 --- a/ui/app/(prowler)/mutelist/_components/simple/mute-rule-edit-form.tsx +++ b/ui/app/(prowler)/mutelist/_components/simple/mute-rule-edit-form.tsx @@ -5,8 +5,8 @@ import { FormEvent, useState } from "react"; import { updateMuteRule } from "@/actions/mute-rules"; import { MuteRuleActionState, MuteRuleData } from "@/actions/mute-rules/types"; import { Input, Textarea } from "@/components/shadcn"; -import { FormButtons } from "@/components/ui/form"; -import { Label } from "@/components/ui/form/Label"; +import { FormButtons } from "@/components/shadcn/form"; +import { Label } from "@/components/shadcn/form/Label"; import { useMuteRuleAction } from "@/hooks/use-mute-rule-action"; import { enforceMuteRuleReasonLimit, diff --git a/ui/app/(prowler)/mutelist/_components/simple/mute-rule-enabled-toggle.tsx b/ui/app/(prowler)/mutelist/_components/simple/mute-rule-enabled-toggle.tsx index ec843e8415..73af798640 100644 --- a/ui/app/(prowler)/mutelist/_components/simple/mute-rule-enabled-toggle.tsx +++ b/ui/app/(prowler)/mutelist/_components/simple/mute-rule-enabled-toggle.tsx @@ -1,11 +1,11 @@ "use client"; -import { Switch } from "@heroui/switch"; import { useState } from "react"; import { toggleMuteRule } from "@/actions/mute-rules"; import { MuteRuleData } from "@/actions/mute-rules/types"; -import { useToast } from "@/components/ui"; +import { Switch } from "@/components/shadcn"; +import { useToast } from "@/components/shadcn"; interface MuteRuleEnabledToggleProps { muteRule: MuteRuleData; @@ -44,10 +44,9 @@ export function MuteRuleEnabledToggle({ return ( ); diff --git a/ui/app/(prowler)/mutelist/_components/simple/mute-rules-columns.test.tsx b/ui/app/(prowler)/mutelist/_components/simple/mute-rules-columns.test.tsx index aeb7747184..89788b7d73 100644 --- a/ui/app/(prowler)/mutelist/_components/simple/mute-rules-columns.test.tsx +++ b/ui/app/(prowler)/mutelist/_components/simple/mute-rules-columns.test.tsx @@ -4,11 +4,11 @@ import { describe, expect, it, vi } from "vitest"; import { createMuteRulesColumns } from "./mute-rules-columns"; -vi.mock("@/components/ui/entities", () => ({ +vi.mock("@/components/shadcn/entities", () => ({ DateWithTime: () => null, })); -vi.mock("@/components/ui/table", () => ({ +vi.mock("@/components/shadcn/table", () => ({ DataTableColumnHeader: ({ title }: { title: string }) => {title}, })); diff --git a/ui/app/(prowler)/mutelist/_components/simple/mute-rules-columns.tsx b/ui/app/(prowler)/mutelist/_components/simple/mute-rules-columns.tsx index 68968bb414..51d136e3fd 100644 --- a/ui/app/(prowler)/mutelist/_components/simple/mute-rules-columns.tsx +++ b/ui/app/(prowler)/mutelist/_components/simple/mute-rules-columns.tsx @@ -5,8 +5,8 @@ import { List } from "lucide-react"; import { MuteRuleData } from "@/actions/mute-rules/types"; import { Button } from "@/components/shadcn"; -import { DateWithTime } from "@/components/ui/entities"; -import { DataTableColumnHeader } from "@/components/ui/table"; +import { DateWithTime } from "@/components/shadcn/entities"; +import { DataTableColumnHeader } from "@/components/shadcn/table"; import { MuteRuleEnabledToggle } from "./mute-rule-enabled-toggle"; import { MuteRuleRowActions } from "./mute-rule-row-actions"; diff --git a/ui/app/(prowler)/mutelist/_components/simple/mute-rules-table-client.test.tsx b/ui/app/(prowler)/mutelist/_components/simple/mute-rules-table-client.test.tsx index 8aa0e8b354..64ac2cee32 100644 --- a/ui/app/(prowler)/mutelist/_components/simple/mute-rules-table-client.test.tsx +++ b/ui/app/(prowler)/mutelist/_components/simple/mute-rules-table-client.test.tsx @@ -19,13 +19,9 @@ vi.mock("@/actions/mute-rules", () => ({ deleteMuteRule: deleteMuteRuleMock, })); -vi.mock("@/components/ui", () => ({ - useToast: () => ({ - toast: toastMock, - }), -})); - -vi.mock("@/components/shadcn", () => ({ +vi.mock("@/components/shadcn", async (importOriginal) => ({ + ...(await importOriginal>()), + useToast: () => ({ toast: toastMock }), Button: ({ children, ...props @@ -52,7 +48,7 @@ vi.mock("@/components/shadcn/modal", () => ({ ) : null, })); -vi.mock("@/components/ui/table", () => ({ +vi.mock("@/components/shadcn/table", () => ({ DataTable: (props: { columns: Array<{ id?: string; diff --git a/ui/app/(prowler)/mutelist/_components/simple/mute-rules-table-client.tsx b/ui/app/(prowler)/mutelist/_components/simple/mute-rules-table-client.tsx index da3a2478a3..17af6dd3c2 100644 --- a/ui/app/(prowler)/mutelist/_components/simple/mute-rules-table-client.tsx +++ b/ui/app/(prowler)/mutelist/_components/simple/mute-rules-table-client.tsx @@ -1,6 +1,5 @@ "use client"; -import { useDisclosure } from "@heroui/use-disclosure"; import { Trash2 } from "lucide-react"; import { useRouter } from "next/navigation"; import { FormEvent, useState } from "react"; @@ -8,9 +7,9 @@ import { FormEvent, useState } from "react"; import { deleteMuteRule } from "@/actions/mute-rules"; import { MuteRuleData } from "@/actions/mute-rules/types"; import { CardTitle } from "@/components/shadcn"; +import { FormButtons } from "@/components/shadcn/form"; import { Modal } from "@/components/shadcn/modal"; -import { FormButtons } from "@/components/ui/form"; -import { DataTable } from "@/components/ui/table"; +import { DataTable } from "@/components/shadcn/table"; import { useMuteRuleAction } from "@/hooks/use-mute-rule-action"; import { MetaDataProps } from "@/types"; @@ -37,27 +36,27 @@ export function MuteRulesTableClient({ const { isPending: isDeleting, runAction: runDeleteAction } = useMuteRuleAction(); - const editModal = useDisclosure(); - const deleteModal = useDisclosure(); - const targetsModal = useDisclosure(); + const [isEditModalOpen, setIsEditModalOpen] = useState(false); + const [isDeleteModalOpen, setIsDeleteModalOpen] = useState(false); + const [isTargetsModalOpen, setIsTargetsModalOpen] = useState(false); const handleEditClick = (muteRule: MuteRuleData) => { setSelectedMuteRule(muteRule); - editModal.onOpen(); + setIsEditModalOpen(true); }; const handleDeleteClick = (muteRule: MuteRuleData) => { setSelectedMuteRule(muteRule); - deleteModal.onOpen(); + setIsDeleteModalOpen(true); }; const handleViewTargets = (muteRule: MuteRuleTableData) => { setSelectedTargetsRule(muteRule); - targetsModal.onOpen(); + setIsTargetsModalOpen(true); }; const handleEditSuccess = () => { - editModal.onClose(); + setIsEditModalOpen(false); router.refresh(); }; @@ -68,7 +67,7 @@ export function MuteRulesTableClient({ runDeleteAction(() => deleteMuteRule(null, formData), { onSuccess: () => { - deleteModal.onClose(); + setIsDeleteModalOpen(false); router.refresh(); }, }); @@ -102,15 +101,15 @@ export function MuteRulesTableClient({ {/* Edit Modal */} {selectedMuteRule && ( setIsEditModalOpen(false)} /> )} @@ -127,8 +126,8 @@ export function MuteRulesTableClient({ {/* Delete Confirmation Modal */} {selectedMuteRule && ( setIsDeleteModalOpen(false)} submitText={isDeleting ? "Deleting..." : "Delete"} isDisabled={isDeleting} submitColor="danger" diff --git a/ui/app/(prowler)/mutelist/_components/simple/mute-rules-table.tsx b/ui/app/(prowler)/mutelist/_components/simple/mute-rules-table.tsx index 2cccb1fe1c..6c6bf5cb11 100644 --- a/ui/app/(prowler)/mutelist/_components/simple/mute-rules-table.tsx +++ b/ui/app/(prowler)/mutelist/_components/simple/mute-rules-table.tsx @@ -94,7 +94,7 @@ export function MuteRulesTableSkeleton() { return (
      {resourcesData?.errors && ( -
      +

      Error:

      {resourcesData.errors[0].detail}

      diff --git a/ui/app/(prowler)/roles/(add-role)/layout.tsx b/ui/app/(prowler)/roles/(add-role)/layout.tsx index 32a1030426..1895ed6892 100644 --- a/ui/app/(prowler)/roles/(add-role)/layout.tsx +++ b/ui/app/(prowler)/roles/(add-role)/layout.tsx @@ -1,10 +1,9 @@ import "@/styles/globals.css"; -import { Spacer } from "@heroui/spacer"; import React from "react"; import { WorkflowAddEditRole } from "@/components/roles/workflow"; -import { NavigationHeader } from "@/components/ui"; +import { NavigationHeader } from "@/components/shadcn"; interface RoleLayoutProps { children: React.ReactNode; @@ -18,7 +17,7 @@ export default function RoleLayout({ children }: RoleLayoutProps) { icon="icon-park-outline:close-small" href="/roles" /> - +
      diff --git a/ui/app/(prowler)/roles/page.tsx b/ui/app/(prowler)/roles/page.tsx index 259776c5a3..e63aa9138f 100644 --- a/ui/app/(prowler)/roles/page.tsx +++ b/ui/app/(prowler)/roles/page.tsx @@ -7,8 +7,8 @@ import { filterRoles } from "@/components/filters/data-filters"; import { AddIcon } from "@/components/icons"; import { ColumnsRoles, SkeletonTableRoles } from "@/components/roles/table"; import { Button } from "@/components/shadcn"; -import { ContentLayout } from "@/components/ui"; -import { DataTable, DataTableFilterCustom } from "@/components/ui/table"; +import { ContentLayout } from "@/components/shadcn/content-layout"; +import { DataTable, DataTableFilterCustom } from "@/components/shadcn/table"; import { SearchParamsProps } from "@/types"; export default async function Roles({ diff --git a/ui/app/(prowler)/scans/page.tsx b/ui/app/(prowler)/scans/page.tsx index 62aba551ae..9ecb439524 100644 --- a/ui/app/(prowler)/scans/page.tsx +++ b/ui/app/(prowler)/scans/page.tsx @@ -12,7 +12,7 @@ import { ScansPageShell } from "@/components/scans/scans-page-shell"; import { ScansProvidersEmptyState } from "@/components/scans/scans-providers-empty-state"; import { SkeletonTableScans } from "@/components/scans/table"; import { ScanJobsTable } from "@/components/scans/table/scan-jobs-table"; -import { ContentLayout } from "@/components/ui"; +import { ContentLayout } from "@/components/shadcn/content-layout"; import { ProviderProps, SCAN_JOBS_TAB, diff --git a/ui/app/(prowler)/services/page.tsx b/ui/app/(prowler)/services/page.tsx index 78e8ddbccc..fc80e6cb4c 100644 --- a/ui/app/(prowler)/services/page.tsx +++ b/ui/app/(prowler)/services/page.tsx @@ -1,7 +1,5 @@ -import { Spacer } from "@heroui/spacer"; - import { FilterControls } from "@/components/filters"; -import { ContentLayout } from "@/components/ui"; +import { ContentLayout } from "@/components/shadcn/content-layout"; export default async function Services() { // const searchParamsKey = JSON.stringify(searchParams || {}); @@ -10,9 +8,9 @@ export default async function Services() { title="Services" icon="material-symbols:linked-services-outline" > - +
      - +
      {/* }> */} diff --git a/ui/app/(prowler)/users/page.tsx b/ui/app/(prowler)/users/page.tsx index fa1e838872..f5d4ab4b36 100644 --- a/ui/app/(prowler)/users/page.tsx +++ b/ui/app/(prowler)/users/page.tsx @@ -7,8 +7,8 @@ import { auth } from "@/auth.config"; import { FilterControls } from "@/components/filters"; import { AddIcon } from "@/components/icons"; import { Button } from "@/components/shadcn"; -import { ContentLayout } from "@/components/ui"; -import { DataTable } from "@/components/ui/table"; +import { ContentLayout } from "@/components/shadcn/content-layout"; +import { DataTable } from "@/components/shadcn/table"; import { ColumnsUser, SkeletonTableUser } from "@/components/users/table"; import { Role, SearchParamsProps, UserProps } from "@/types"; import { TENANT_MEMBERSHIP_ROLE } from "@/types/users"; diff --git a/ui/app/(prowler)/workloads/page.tsx b/ui/app/(prowler)/workloads/page.tsx index 5ffd6a9802..252e35ef6f 100644 --- a/ui/app/(prowler)/workloads/page.tsx +++ b/ui/app/(prowler)/workloads/page.tsx @@ -1,4 +1,4 @@ -import { ContentLayout } from "@/components/ui"; +import { ContentLayout } from "@/components/shadcn/content-layout"; export default async function Workloads() { return ( diff --git a/ui/app/providers.tsx b/ui/app/providers.tsx index 7bda5d45fe..7a40f17739 100644 --- a/ui/app/providers.tsx +++ b/ui/app/providers.tsx @@ -3,26 +3,20 @@ // Import Sentry client-side initialization import "@/app/instrumentation.client"; -import { HeroUIProvider } from "@heroui/system"; -import { useRouter } from "next/navigation"; import { SessionProvider } from "next-auth/react"; import { ThemeProvider as NextThemesProvider } from "next-themes"; import { ThemeProviderProps } from "next-themes/dist/types"; -import * as React from "react"; +import { ReactNode } from "react"; export interface ProvidersProps { - children: React.ReactNode; + children: ReactNode; themeProps?: ThemeProviderProps; } export function Providers({ children, themeProps }: ProvidersProps) { - const router = useRouter(); - return ( - - {children} - + {children} ); } diff --git a/ui/components/ThemeSwitch.tsx b/ui/components/ThemeSwitch.tsx index f9c039db93..4979dec541 100644 --- a/ui/components/ThemeSwitch.tsx +++ b/ui/components/ThemeSwitch.tsx @@ -1,96 +1,57 @@ "use client"; -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"; import { useTheme } from "next-themes"; -import { FC } from "react"; -import React from "react"; +import { ComponentProps, useSyncExternalStore } from "react"; import { Tooltip, TooltipContent, TooltipTrigger, } from "@/components/shadcn/tooltip"; +import { cn } from "@/lib/utils"; import { MoonFilledIcon, SunFilledIcon } from "./icons"; -export interface ThemeSwitchProps { - className?: string; - classNames?: SwitchProps["classNames"]; -} +export type ThemeSwitchProps = ComponentProps<"button">; -export const ThemeSwitch: FC = ({ - className, - classNames, -}) => { +const emptySubscribe = () => () => {}; + +export function ThemeSwitch({ className, ...props }: ThemeSwitchProps) { const { theme, setTheme } = useTheme(); - const isSSR = useIsSSR(); + // Hydration-safe mounted check: false on the server, true after hydration + const isHydrated = useSyncExternalStore( + emptySubscribe, + () => true, + () => false, + ); - const onChange = () => { - theme === "light" ? setTheme("dark") : setTheme("light"); - }; - - const { - Component, - slots, - isSelected, - getBaseProps, - getInputProps, - getWrapperProps, - } = useSwitch({ - isSelected: theme === "light" || isSSR, - "aria-label": `Switch to ${theme === "light" || isSSR ? "dark" : "light"} mode`, - onChange, - }); + const isLightMode = theme === "light" || !isHydrated; return ( - setTheme(isLightMode ? "dark" : "light")} + className={cn( + "text-neutral-tertiary flex cursor-pointer items-center justify-center rounded-lg px-px pt-px transition-opacity hover:opacity-80", + className, + )} > - - - -
      - {!isSelected || isSSR ? ( - - ) : ( - - )} -
      -
      + {isLightMode && isHydrated ? ( + + ) : ( + + )} +
      - {isSelected || isSSR ? "Switch to Dark Mode" : "Switch to Light Mode"} + {isLightMode ? "Switch to Dark Mode" : "Switch to Light Mode"}
      ); -}; +} diff --git a/ui/components/auth/oss/auth-divider.tsx b/ui/components/auth/oss/auth-divider.tsx index 2951a1a01c..2d9fe56b30 100644 --- a/ui/components/auth/oss/auth-divider.tsx +++ b/ui/components/auth/oss/auth-divider.tsx @@ -1,11 +1,11 @@ -import { Divider } from "@heroui/divider"; +import { Separator } from "@/components/shadcn"; export const AuthDivider = () => { return (
      - -

      OR

      - + +

      OR

      +
      ); }; diff --git a/ui/components/auth/oss/auth-footer-link.tsx b/ui/components/auth/oss/auth-footer-link.tsx index 221a48a400..91c6a89c95 100644 --- a/ui/components/auth/oss/auth-footer-link.tsx +++ b/ui/components/auth/oss/auth-footer-link.tsx @@ -1,4 +1,4 @@ -import { CustomLink } from "@/components/ui/custom/custom-link"; +import { CustomLink } from "@/components/shadcn/custom/custom-link"; interface AuthFooterLinkProps { text: string; @@ -12,7 +12,7 @@ export const AuthFooterLink = ({ href, }: AuthFooterLinkProps) => { return ( -

      +

      {text}  {linkText} diff --git a/ui/components/auth/oss/auth-layout.tsx b/ui/components/auth/oss/auth-layout.tsx index 84d47c218c..b33e4d4c32 100644 --- a/ui/components/auth/oss/auth-layout.tsx +++ b/ui/components/auth/oss/auth-layout.tsx @@ -27,7 +27,7 @@ export const AuthLayout = ({ title, children }: AuthLayoutProps) => {

      {/* Auth Form Container */} -
      +
      {/* Header with Title and Theme Toggle */}

      {title}

      diff --git a/ui/components/auth/oss/sign-in-form.tsx b/ui/components/auth/oss/sign-in-form.tsx index 89650f56c4..7a9f53edfb 100644 --- a/ui/components/auth/oss/sign-in-form.tsx +++ b/ui/components/auth/oss/sign-in-form.tsx @@ -13,9 +13,9 @@ import { AuthFooterLink } from "@/components/auth/oss/auth-footer-link"; import { AuthLayout } from "@/components/auth/oss/auth-layout"; import { SocialButtons } from "@/components/auth/oss/social-buttons"; import { Button } from "@/components/shadcn"; -import { useToast } from "@/components/ui"; -import { CustomInput } from "@/components/ui/custom"; -import { Form } from "@/components/ui/form"; +import { useToast } from "@/components/shadcn"; +import { CustomInput } from "@/components/shadcn/custom"; +import { Form } from "@/components/shadcn/form"; import { SignInFormData, signInSchema } from "@/types"; export const SignInForm = ({ @@ -194,7 +194,7 @@ export const SignInForm = ({ > {!isSamlMode && ( diff --git a/ui/components/auth/oss/sign-up-form.tsx b/ui/components/auth/oss/sign-up-form.tsx index e18ded5845..7eb8575e47 100644 --- a/ui/components/auth/oss/sign-up-form.tsx +++ b/ui/components/auth/oss/sign-up-form.tsx @@ -1,6 +1,5 @@ "use client"; -import { Checkbox } from "@heroui/checkbox"; import { zodResolver } from "@hookform/resolvers/zod"; import { useRouter } from "next/navigation"; import { useForm, useWatch } from "react-hook-form"; @@ -16,16 +15,16 @@ import { AuthFooterLink } from "@/components/auth/oss/auth-footer-link"; import { AuthLayout } from "@/components/auth/oss/auth-layout"; import { PasswordRequirementsMessage } from "@/components/auth/oss/password-validator"; import { SocialButtons } from "@/components/auth/oss/social-buttons"; -import { Button } from "@/components/shadcn"; -import { useToast } from "@/components/ui"; -import { CustomInput } from "@/components/ui/custom"; -import { CustomLink } from "@/components/ui/custom/custom-link"; +import { Button, Checkbox } from "@/components/shadcn"; +import { useToast } from "@/components/shadcn"; +import { CustomInput } from "@/components/shadcn/custom"; +import { CustomLink } from "@/components/shadcn/custom/custom-link"; import { Form, FormControl, FormField, FormMessage, -} from "@/components/ui/form"; +} from "@/components/shadcn/form"; import { ApiError, SignUpFormData, signUpSchema } from "@/types"; const AUTH_ERROR_PATHS = { @@ -206,14 +205,18 @@ export const SignUpForm = ({ name="termsAndConditions" render={({ field }) => ( <> - - field.onChange(e.target.checked)} - color="default" +
      + + + + +
      )} diff --git a/ui/components/auth/oss/social-buttons.tsx b/ui/components/auth/oss/social-buttons.tsx index 0dd92c48c0..194578cfc0 100644 --- a/ui/components/auth/oss/social-buttons.tsx +++ b/ui/components/auth/oss/social-buttons.tsx @@ -1,8 +1,12 @@ -import { Tooltip } from "@heroui/tooltip"; import { Icon } from "@iconify/react"; -import { Button } from "@/components/shadcn"; -import { CustomLink } from "@/components/ui/custom/custom-link"; +import { + Button, + Tooltip, + TooltipContent, + TooltipTrigger, +} from "@/components/shadcn"; +import { CustomLink } from "@/components/shadcn/custom/custom-link"; export const SocialButtons = ({ googleAuthUrl, @@ -14,70 +18,78 @@ export const SocialButtons = ({ githubAuthUrl?: string; isGoogleOAuthEnabled?: boolean; isGithubOAuthEnabled?: boolean; -}) => ( - <> - - Social Login with Google is not enabled.{" "} - - Read the docs - -
      - } - placement="top" - shadow="sm" - isDisabled={isGoogleOAuthEnabled} - className="w-96" - > - - - - - - Social Login with Github is not enabled.{" "} - - Read the docs - -
      - } - placement="top" - shadow="sm" - isDisabled={isGithubOAuthEnabled} - className="w-96" - > - - - - - -); +}) => { + const googleButton = ( + + + + ); + + const githubButton = ( + + + + ); + + return ( + <> + {isGoogleOAuthEnabled ? ( + googleButton + ) : ( + + {googleButton} + +
      + Social Login with Google is not enabled.{" "} + + Read the docs + +
      +
      +
      + )} + {isGithubOAuthEnabled ? ( + githubButton + ) : ( + + {githubButton} + +
      + Social Login with Github is not enabled.{" "} + + Read the docs + +
      +
      +
      + )} + + ); +}; diff --git a/ui/components/compliance/compliance-accordion/client-accordion-content.tsx b/ui/components/compliance/compliance-accordion/client-accordion-content.tsx index 4a0ba6b198..3823c30dcd 100644 --- a/ui/components/compliance/compliance-accordion/client-accordion-content.tsx +++ b/ui/components/compliance/compliance-accordion/client-accordion-content.tsx @@ -8,8 +8,8 @@ import { getStandaloneFindingColumns, SkeletonTableFindings, } from "@/components/findings/table"; -import { Accordion } from "@/components/ui/accordion/Accordion"; -import { DataTable } from "@/components/ui/table"; +import { Accordion } from "@/components/shadcn/accordion/Accordion"; +import { DataTable } from "@/components/shadcn/table"; import { createDict, FINDINGS_DEFAULT_SORT, MUTED_FILTER } from "@/lib"; import { getComplianceMapper } from "@/lib/compliance/compliance-mapper"; import { Requirement } from "@/types/compliance"; @@ -162,7 +162,7 @@ export const ClientAccordionContent = ({ key: "checks", title: (
      - {checks.length} + {checks.length} {checks.length > 1 ? Checks : Check}
      ), @@ -207,7 +207,7 @@ export const ClientAccordionContent = ({ items={accordionChecksItems} variant="light" defaultExpandedKeys={[""]} - className="dark:bg-prowler-blue-400 rounded-lg bg-gray-50" + className="dark:bg-bg-neutral-secondary rounded-lg bg-gray-50" />
      )} diff --git a/ui/components/compliance/compliance-accordion/client-accordion-wrapper.tsx b/ui/components/compliance/compliance-accordion/client-accordion-wrapper.tsx index 4682f039e5..08e8658ab9 100644 --- a/ui/components/compliance/compliance-accordion/client-accordion-wrapper.tsx +++ b/ui/components/compliance/compliance-accordion/client-accordion-wrapper.tsx @@ -3,7 +3,7 @@ import { useRef, useState } from "react"; import { Button } from "@/components/shadcn"; -import { Accordion, AccordionItemProps } from "@/components/ui"; +import { Accordion, AccordionItemProps } from "@/components/shadcn"; export const ClientAccordionWrapper = ({ items, @@ -71,7 +71,7 @@ export const ClientAccordionWrapper = ({ lastScrolledKeyRef.current = scrollToKey; // Two nested rAFs: the first lets the accordion children commit to // the DOM, the second lands after the browser has run a layout pass - // so HeroUI's framer-motion expand has settled enough for + // so the Collapsible CSS expand animation has settled enough for // scrollIntoView to read a stable offset. requestAnimationFrame(() => { requestAnimationFrame(() => { diff --git a/ui/components/compliance/compliance-accordion/compliance-accordion-requeriment-title.tsx b/ui/components/compliance/compliance-accordion/compliance-accordion-requeriment-title.tsx index 0c408fb099..9b25319799 100644 --- a/ui/components/compliance/compliance-accordion/compliance-accordion-requeriment-title.tsx +++ b/ui/components/compliance/compliance-accordion/compliance-accordion-requeriment-title.tsx @@ -1,4 +1,4 @@ -import { FindingStatus, StatusFindingBadge } from "@/components/ui/table"; +import { FindingStatus, StatusFindingBadge } from "@/components/shadcn/table"; interface ComplianceAccordionRequirementTitleProps { type: string; @@ -15,7 +15,7 @@ export const ComplianceAccordionRequirementTitle = ({
      {type && ( - + {type} )} diff --git a/ui/components/compliance/compliance-accordion/compliance-accordion-title.tsx b/ui/components/compliance/compliance-accordion/compliance-accordion-title.tsx index 97e700e5a5..0469f93daf 100644 --- a/ui/components/compliance/compliance-accordion/compliance-accordion-title.tsx +++ b/ui/components/compliance/compliance-accordion/compliance-accordion-title.tsx @@ -1,4 +1,4 @@ -import { Tooltip } from "@heroui/tooltip"; +import { Tooltip, TooltipContent, TooltipTrigger } from "@/components/shadcn"; interface ComplianceAccordionTitleProps { label: string; @@ -43,72 +43,63 @@ export const ComplianceAccordionTitle = ({ {total > 0 ? (
      {pass > 0 && ( - + + 0 ? "2px" : "0", + }} + /> + +
      Pass
      -
      +
      {pass} ({passPercentage.toFixed(1)}%)
      - } - size="sm" - placement="top" - delay={0} - closeDelay={0} - > - 0 ? "2px" : "0", - }} - /> + )} {fail > 0 && ( - + + 0 ? "2px" : "0", + }} + /> + +
      Fail
      -
      +
      {fail} ({failPercentage.toFixed(1)}%)
      - } - size="sm" - placement="top" - delay={0} - closeDelay={0} - > - 0 ? "2px" : "0", - }} - /> + )} {manual > 0 && ( - + + + +
      Manual
      -
      +
      {manual} ({manualPercentage.toFixed(1)}%)
      - } - size="sm" - placement="top" - delay={0} - closeDelay={0} - > - + )}
      @@ -117,19 +108,18 @@ export const ComplianceAccordionTitle = ({ )}
      - + + + {total > 0 ? total : "—"} + + +
      Total requirements
      -
      {total}
      +
      {total}
      - } - size="sm" - placement="top" - > - - {total > 0 ? total : "—"} - +
      diff --git a/ui/components/compliance/compliance-card.tsx b/ui/components/compliance/compliance-card.tsx index 98d3949016..03d01dfe19 100644 --- a/ui/components/compliance/compliance-card.tsx +++ b/ui/components/compliance/compliance-card.tsx @@ -135,7 +135,7 @@ export const ComplianceCard: React.FC = ({
      -

      +

      {formatTitle(title)} {version ? ` - ${version}` : ""}

      diff --git a/ui/components/compliance/compliance-charts/heatmap-chart.tsx b/ui/components/compliance/compliance-charts/heatmap-chart.tsx index ff641a73c2..2d7ce547b3 100644 --- a/ui/components/compliance/compliance-charts/heatmap-chart.tsx +++ b/ui/components/compliance/compliance-charts/heatmap-chart.tsx @@ -1,9 +1,9 @@ "use client"; -import { cn } from "@heroui/theme"; import { useTheme } from "next-themes"; import { useState } from "react"; +import { cn } from "@/lib/utils"; import { CategoryData } from "@/types/compliance"; interface HeatmapChartProps { diff --git a/ui/components/compliance/compliance-charts/threatscore-breakdown-card.tsx b/ui/components/compliance/compliance-charts/threatscore-breakdown-card.tsx index e919588169..7b5aab2110 100644 --- a/ui/components/compliance/compliance-charts/threatscore-breakdown-card.tsx +++ b/ui/components/compliance/compliance-charts/threatscore-breakdown-card.tsx @@ -1,12 +1,12 @@ "use client"; -import { Progress } from "@heroui/progress"; - import type { SectionScores } from "@/actions/overview/threat-score"; import { RadialChart } from "@/components/graphs/radial-chart"; import { Card, CardContent, CardHeader, CardTitle } from "@/components/shadcn"; +import { Progress } from "@/components/shadcn/progress"; import { getScoreColor, + getScoreIndicatorClass, getScoreLabel, getScoreLevel, getScoreTextClass, @@ -72,7 +72,7 @@ export function ThreatScoreBreakdownCard({ {/* Pillar Breakdown */}
      - + Score by Pillar
      @@ -80,7 +80,9 @@ export function ThreatScoreBreakdownCard({ {pillars.map(({ name, score, hasData }) => (
      - {name} + + {name} +
      @@ -113,22 +116,22 @@ export function ThreatScoreBreakdownCardSkeleton() { return ( -
      +
      {/* Mobile: vertical, Tablet: horizontal, Desktop: vertical */}
      -
      +
      {Array.from({ length: SKELETON_PILLAR_COUNT }, (_, i) => (
      -
      -
      +
      +
      -
      +
      ))}
      diff --git a/ui/components/compliance/compliance-custom-details/asd-essential-eight-details.test.tsx b/ui/components/compliance/compliance-custom-details/asd-essential-eight-details.test.tsx index 816b62a262..07c36b42de 100644 --- a/ui/components/compliance/compliance-custom-details/asd-essential-eight-details.test.tsx +++ b/ui/components/compliance/compliance-custom-details/asd-essential-eight-details.test.tsx @@ -6,7 +6,7 @@ import { describe, expect, it, vi } from "vitest"; // `next-auth` (server-only). Stub it with a plain anchor — we only need // the `` semantics here so the regex/extraction tests can assert on // `href` and accessible name. -vi.mock("@/components/ui/custom/custom-link", () => ({ +vi.mock("@/components/shadcn/custom/custom-link", () => ({ CustomLink: ({ href, children }: { href: string; children: ReactNode }) => ( {children} ), diff --git a/ui/components/compliance/compliance-custom-details/asd-essential-eight-details.tsx b/ui/components/compliance/compliance-custom-details/asd-essential-eight-details.tsx index 2cb022a174..975e1557cc 100644 --- a/ui/components/compliance/compliance-custom-details/asd-essential-eight-details.tsx +++ b/ui/components/compliance/compliance-custom-details/asd-essential-eight-details.tsx @@ -1,6 +1,6 @@ import ReactMarkdown from "react-markdown"; -import { CustomLink } from "@/components/ui/custom/custom-link"; +import { CustomLink } from "@/components/shadcn/custom/custom-link"; import { isASDAssessmentStatus, isASDCloudApplicability, diff --git a/ui/components/compliance/compliance-custom-details/aws-well-architected-details.tsx b/ui/components/compliance/compliance-custom-details/aws-well-architected-details.tsx index 00aa51e4c5..b9e4baf369 100644 --- a/ui/components/compliance/compliance-custom-details/aws-well-architected-details.tsx +++ b/ui/components/compliance/compliance-custom-details/aws-well-architected-details.tsx @@ -1,5 +1,5 @@ -import { CustomLink } from "@/components/ui/custom/custom-link"; -import { SeverityBadge } from "@/components/ui/table"; +import { CustomLink } from "@/components/shadcn/custom/custom-link"; +import { SeverityBadge } from "@/components/shadcn/table"; import { Requirement } from "@/types/compliance"; import { diff --git a/ui/components/compliance/compliance-custom-details/cis-details.tsx b/ui/components/compliance/compliance-custom-details/cis-details.tsx index 25823038d5..31f32576b0 100644 --- a/ui/components/compliance/compliance-custom-details/cis-details.tsx +++ b/ui/components/compliance/compliance-custom-details/cis-details.tsx @@ -1,6 +1,6 @@ import ReactMarkdown from "react-markdown"; -import { CustomLink } from "@/components/ui/custom/custom-link"; +import { CustomLink } from "@/components/shadcn/custom/custom-link"; import { Requirement } from "@/types/compliance"; import { diff --git a/ui/components/compliance/compliance-custom-details/mitre-details.tsx b/ui/components/compliance/compliance-custom-details/mitre-details.tsx index 53fc583f2c..be53382036 100644 --- a/ui/components/compliance/compliance-custom-details/mitre-details.tsx +++ b/ui/components/compliance/compliance-custom-details/mitre-details.tsx @@ -1,4 +1,4 @@ -import { CustomLink } from "@/components/ui/custom/custom-link"; +import { CustomLink } from "@/components/shadcn/custom/custom-link"; import { Requirement } from "@/types/compliance"; import { diff --git a/ui/components/compliance/compliance-custom-details/okta-idaas-stig-details.tsx b/ui/components/compliance/compliance-custom-details/okta-idaas-stig-details.tsx index 0869b7f390..695b39bdcd 100644 --- a/ui/components/compliance/compliance-custom-details/okta-idaas-stig-details.tsx +++ b/ui/components/compliance/compliance-custom-details/okta-idaas-stig-details.tsx @@ -1,4 +1,4 @@ -import { Severity, SeverityBadge } from "@/components/ui/table"; +import { Severity, SeverityBadge } from "@/components/shadcn/table"; import { Requirement } from "@/types/compliance"; import { diff --git a/ui/components/compliance/compliance-download-container.test.tsx b/ui/components/compliance/compliance-download-container.test.tsx index 70ff11c1c2..66b5d64148 100644 --- a/ui/components/compliance/compliance-download-container.test.tsx +++ b/ui/components/compliance/compliance-download-container.test.tsx @@ -22,7 +22,8 @@ vi.mock("@/lib/helper", () => ({ downloadCompliancePdf: downloadCompliancePdfMock, })); -vi.mock("@/components/ui", () => ({ +vi.mock("@/components/shadcn", async (importOriginal) => ({ + ...(await importOriginal>()), toast: {}, })); diff --git a/ui/components/compliance/compliance-download-container.tsx b/ui/components/compliance/compliance-download-container.tsx index 6e29acc213..a5a00bfad5 100644 --- a/ui/components/compliance/compliance-download-container.tsx +++ b/ui/components/compliance/compliance-download-container.tsx @@ -3,6 +3,7 @@ import { DownloadIcon, FileJsonIcon, FileTextIcon } from "lucide-react"; import { useState } from "react"; +import { toast } from "@/components/shadcn"; import { Button } from "@/components/shadcn/button/button"; import { ActionDropdown, @@ -13,7 +14,6 @@ import { TooltipContent, TooltipTrigger, } from "@/components/shadcn/tooltip"; -import { toast } from "@/components/ui"; import { type ComplianceReportType, isOcsfSupported, diff --git a/ui/components/compliance/compliance-header/compliance-header.tsx b/ui/components/compliance/compliance-header/compliance-header.tsx index c53a5309a5..b5bf70c371 100644 --- a/ui/components/compliance/compliance-header/compliance-header.tsx +++ b/ui/components/compliance/compliance-header/compliance-header.tsx @@ -2,7 +2,7 @@ import Image from "next/image"; -import { DataTableFilterCustom } from "@/components/ui/table/data-table-filter-custom"; +import { DataTableFilterCustom } from "@/components/shadcn/table/data-table-filter-custom"; import { ScanEntity } from "@/types/scans"; import { ComplianceScanInfo } from "./compliance-scan-info"; diff --git a/ui/components/compliance/compliance-header/compliance-scan-info.tsx b/ui/components/compliance/compliance-header/compliance-scan-info.tsx index da1caa5ee9..f596b486e4 100644 --- a/ui/components/compliance/compliance-header/compliance-scan-info.tsx +++ b/ui/components/compliance/compliance-header/compliance-scan-info.tsx @@ -1,7 +1,10 @@ -import { Divider } from "@heroui/divider"; -import { Tooltip } from "@heroui/tooltip"; - -import { DateWithTime, EntityInfo } from "@/components/ui/entities"; +import { + Separator, + Tooltip, + TooltipContent, + TooltipTrigger, +} from "@/components/shadcn"; +import { DateWithTime, EntityInfo } from "@/components/shadcn/entities"; import { ProviderType } from "@/types"; interface ComplianceScanInfoProps { @@ -29,16 +32,17 @@ export const ComplianceScanInfo = ({ scan }: ComplianceScanInfoProps) => { showCopyAction={false} />
      - +
      - -

      + + +

      + {scan.attributes.name || "- -"} +

      + + {scan.attributes.name || "- -"} -

      +
      diff --git a/ui/components/compliance/compliance-overview-grid.tsx b/ui/components/compliance/compliance-overview-grid.tsx index 280465520a..71933587fb 100644 --- a/ui/components/compliance/compliance-overview-grid.tsx +++ b/ui/components/compliance/compliance-overview-grid.tsx @@ -3,7 +3,7 @@ import { useState } from "react"; import { ComplianceCard } from "@/components/compliance/compliance-card"; -import { DataTableSearch } from "@/components/ui/table/data-table-search"; +import { DataTableSearch } from "@/components/shadcn/table/data-table-search"; import type { ComplianceOverviewData } from "@/types/compliance"; import type { ScanEntity } from "@/types/scans"; diff --git a/ui/components/compliance/skeletons/bar-chart-skeleton.tsx b/ui/components/compliance/skeletons/bar-chart-skeleton.tsx index e83813edfe..bcbe3c9198 100644 --- a/ui/components/compliance/skeletons/bar-chart-skeleton.tsx +++ b/ui/components/compliance/skeletons/bar-chart-skeleton.tsx @@ -1,14 +1,12 @@ "use client"; -import { Skeleton } from "@heroui/skeleton"; +import { Skeleton } from "@/components/shadcn"; export const BarChartSkeleton = () => { return (
      {/* Title skeleton */} - -
      - + {/* Chart area skeleton */}
      @@ -28,9 +26,7 @@ export const BarChartSkeleton = () => { ? "w-24" : "w-16" }`} - > -
      - + />
      ))} @@ -38,12 +34,8 @@ export const BarChartSkeleton = () => {
      {Array.from({ length: 3 }).map((_, index) => (
      - -
      - - -
      - + +
      ))}
      diff --git a/ui/components/compliance/skeletons/compliance-accordion-skeleton.tsx b/ui/components/compliance/skeletons/compliance-accordion-skeleton.tsx index 322336bd94..5ea3e56633 100644 --- a/ui/components/compliance/skeletons/compliance-accordion-skeleton.tsx +++ b/ui/components/compliance/skeletons/compliance-accordion-skeleton.tsx @@ -1,5 +1,4 @@ -import { Skeleton } from "@heroui/skeleton"; -import React from "react"; +import { Skeleton } from "@/components/shadcn"; interface SkeletonAccordionProps { itemCount?: number; @@ -19,9 +18,7 @@ export const SkeletonAccordion = ({ 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) => ( - -
      -
      + ))}
      ); diff --git a/ui/components/compliance/skeletons/heatmap-chart-skeleton.tsx b/ui/components/compliance/skeletons/heatmap-chart-skeleton.tsx index dbc8a5e389..beaea5dd93 100644 --- a/ui/components/compliance/skeletons/heatmap-chart-skeleton.tsx +++ b/ui/components/compliance/skeletons/heatmap-chart-skeleton.tsx @@ -1,25 +1,18 @@ "use client"; -import { Skeleton } from "@heroui/skeleton"; +import { Skeleton } from "@/components/shadcn"; export const HeatmapChartSkeleton = () => { return (
      {/* Title skeleton */} - -
      - + {/* Heatmap area skeleton - 3x3 grid like the real component */}
      {Array.from({ length: 9 }).map((_, index) => ( - -
      - + ))}
      diff --git a/ui/components/compliance/skeletons/pie-chart-skeleton.tsx b/ui/components/compliance/skeletons/pie-chart-skeleton.tsx index c819f486ae..6c0035aec6 100644 --- a/ui/components/compliance/skeletons/pie-chart-skeleton.tsx +++ b/ui/components/compliance/skeletons/pie-chart-skeleton.tsx @@ -1,61 +1,41 @@ "use client"; -import { Skeleton } from "@heroui/skeleton"; +import { Skeleton } from "@/components/shadcn"; export const PieChartSkeleton = () => { return (
      {/* Title skeleton */} - -
      - + {/* Pie chart skeleton */}
      {/* Outer circle */} - -
      - + {/* Inner circle (donut hole) */} -
      +
      {/* Center text skeleton */}
      - -
      - - -
      - + +
      {/* Bottom stats skeleton */}
      - -
      - - -
      - + +
      - -
      - - -
      - + +
      - -
      - - -
      - + +
      diff --git a/ui/components/compliance/threatscore-badge.tsx b/ui/components/compliance/threatscore-badge.tsx index 01bf180c9f..f3e526fc3b 100644 --- a/ui/components/compliance/threatscore-badge.tsx +++ b/ui/components/compliance/threatscore-badge.tsx @@ -6,13 +6,13 @@ import { useState } from "react"; import type { SectionScores } from "@/actions/overview/threat-score"; import { ThreatScoreLogo } from "@/components/compliance/threatscore-logo"; +import { toast } from "@/components/shadcn"; import { Card, CardContent } from "@/components/shadcn/card/card"; import { ActionDropdown, ActionDropdownItem, } from "@/components/shadcn/dropdown"; import { Progress } from "@/components/shadcn/progress"; -import { toast } from "@/components/ui"; import { COMPLIANCE_REPORT_TYPES } from "@/lib/compliance/compliance-report-types"; import { getScoreColor, diff --git a/ui/components/filters/apply-filters-button.test.tsx b/ui/components/filters/apply-filters-button.test.tsx index fb6be26b57..81d36690a3 100644 --- a/ui/components/filters/apply-filters-button.test.tsx +++ b/ui/components/filters/apply-filters-button.test.tsx @@ -8,7 +8,8 @@ vi.mock("lucide-react", () => ({ })); // Mock @/components/shadcn to avoid next-auth import chain -vi.mock("@/components/shadcn", () => ({ +vi.mock("@/components/shadcn", async (importOriginal) => ({ + ...(await importOriginal>()), Button: ({ children, disabled, diff --git a/ui/components/filters/custom-search-input.tsx b/ui/components/filters/custom-search-input.tsx index f7b1366f4b..ccf96b0a4b 100644 --- a/ui/components/filters/custom-search-input.tsx +++ b/ui/components/filters/custom-search-input.tsx @@ -1,38 +1,31 @@ -import { Input } from "@heroui/input"; -import { SearchIcon, XCircle } from "lucide-react"; import { useSearchParams } from "next/navigation"; -import React, { useCallback, useEffect, useRef, useState } from "react"; +import { useEffect, useRef, useState } from "react"; +import { SearchInput } from "@/components/shadcn"; import { useUrlFilters } from "@/hooks/use-url-filters"; -export const CustomSearchInput: React.FC = () => { +export const CustomSearchInput = () => { const searchParams = useSearchParams(); const { updateFilter } = useUrlFilters(); const [searchQuery, setSearchQuery] = useState(""); const debounceTimeoutRef = useRef(null); - const applySearch = useCallback( - (query: string) => { - if (query) { - updateFilter("search", query); - } else { - updateFilter("search", null); - } - }, - [updateFilter], - ); + const applySearch = (query: string) => { + if (query) { + updateFilter("search", query); + } else { + updateFilter("search", null); + } + }; - const debouncedChangeHandler = useCallback( - (value: string) => { - if (debounceTimeoutRef.current) { - clearTimeout(debounceTimeoutRef.current); - } - debounceTimeoutRef.current = setTimeout(() => { - applySearch(value); - }, 300); - }, - [applySearch], - ); + const debouncedChangeHandler = (value: string) => { + if (debounceTimeoutRef.current) { + clearTimeout(debounceTimeoutRef.current); + } + debounceTimeoutRef.current = setTimeout(() => { + applySearch(value); + }, 300); + }; const clearIconSearch = () => { setSearchQuery(""); @@ -53,39 +46,16 @@ export const CustomSearchInput: React.FC = () => { }, []); return ( - *]:!rounded-lg", - input: - "text-bg-button-secondary placeholder:text-bg-button-secondary text-sm", - inputWrapper: - "!border-border-input-primary !bg-bg-input-primary dark:!bg-input/30 dark:hover:!bg-input/50 hover:!bg-bg-neutral-secondary !border [&]:!rounded-lg !shadow-xs !transition-[color,box-shadow] focus-within:!border-border-input-primary-press focus-within:!ring-1 focus-within:!ring-border-input-primary-press focus-within:!ring-offset-1 !h-10 !px-4 !py-3 !outline-none", - clearButton: "text-bg-button-secondary", - }} + - } onChange={(e) => { const value = e.target.value; setSearchQuery(value); debouncedChangeHandler(value); }} - endContent={ - searchQuery && ( - - ) - } + onClear={clearIconSearch} /> ); }; diff --git a/ui/components/filters/filter-controls.tsx b/ui/components/filters/filter-controls.tsx index b0403a9a66..94072d8c38 100644 --- a/ui/components/filters/filter-controls.tsx +++ b/ui/components/filters/filter-controls.tsx @@ -1,8 +1,8 @@ "use client"; +import { DataTableFilterCustom } from "@/components/shadcn/table"; import { FilterOption } from "@/types"; -import { DataTableFilterCustom } from "../ui/table"; import { CustomSearchInput } from "./custom-search-input"; export interface FilterControlsProps { diff --git a/ui/components/filters/filter-summary-strip.test.tsx b/ui/components/filters/filter-summary-strip.test.tsx index 57bfca2e14..75d02b7ae3 100644 --- a/ui/components/filters/filter-summary-strip.test.tsx +++ b/ui/components/filters/filter-summary-strip.test.tsx @@ -8,7 +8,8 @@ vi.mock("lucide-react", () => ({ })); // Mock @/components/shadcn to avoid next-auth import chain -vi.mock("@/components/shadcn", () => ({ +vi.mock("@/components/shadcn", async (importOriginal) => ({ + ...(await importOriginal>()), Badge: ({ children, className, diff --git a/ui/components/findings/findings-filters.tsx b/ui/components/findings/findings-filters.tsx index 02a3aec62d..cc4a685a3d 100644 --- a/ui/components/findings/findings-filters.tsx +++ b/ui/components/findings/findings-filters.tsx @@ -15,8 +15,8 @@ import { } from "@/components/filters/filter-summary-strip"; import { ProviderAccountSelectors } from "@/components/filters/provider-account-selectors"; import { Button } from "@/components/shadcn"; -import { ExpandableSection } from "@/components/ui/expandable-section"; -import { DataTableFilterCustom } from "@/components/ui/table/data-table-filter-custom"; +import { ExpandableSection } from "@/components/shadcn/expandable-section"; +import { DataTableFilterCustom } from "@/components/shadcn/table/data-table-filter-custom"; import { useFilterBatch } from "@/hooks/use-filter-batch"; import { getCategoryLabel, getGroupLabel } from "@/lib/categories"; import { FilterType, ScanEntity } from "@/types"; diff --git a/ui/components/findings/mute-findings-modal.test.tsx b/ui/components/findings/mute-findings-modal.test.tsx index 7f323da7cc..d80305c473 100644 --- a/ui/components/findings/mute-findings-modal.test.tsx +++ b/ui/components/findings/mute-findings-modal.test.tsx @@ -12,7 +12,9 @@ vi.mock("@/actions/mute-rules", () => ({ createMuteRule: createMuteRuleMock, })); -vi.mock("@/components/shadcn", () => ({ +vi.mock("@/components/shadcn", async (importOriginal) => ({ + ...(await importOriginal>()), + useToast: () => ({ toast: toastMock }), Button: ({ children, ...props @@ -56,13 +58,7 @@ vi.mock("@/components/shadcn/spinner/spinner", () => ({ ), })); -vi.mock("@/components/ui", () => ({ - useToast: () => ({ - toast: toastMock, - }), -})); - -vi.mock("@/components/ui/form", () => ({ +vi.mock("@/components/shadcn/form", () => ({ FormButtons: ({ onCancel, submitText = "Save", diff --git a/ui/components/findings/mute-findings-modal.tsx b/ui/components/findings/mute-findings-modal.tsx index 999f0dead9..a46a0d8ab2 100644 --- a/ui/components/findings/mute-findings-modal.tsx +++ b/ui/components/findings/mute-findings-modal.tsx @@ -5,10 +5,10 @@ import { Dispatch, SetStateAction, useState } from "react"; import { createMuteRule } from "@/actions/mute-rules"; import { MuteRuleActionState } from "@/actions/mute-rules/types"; import { Button, Input, Textarea } from "@/components/shadcn"; +import { FormButtons } from "@/components/shadcn/form"; +import { Label } from "@/components/shadcn/form/Label"; import { Modal } from "@/components/shadcn/modal"; import { Skeleton } from "@/components/shadcn/skeleton/skeleton"; -import { FormButtons } from "@/components/ui/form"; -import { Label } from "@/components/ui/form/Label"; import { useMuteRuleAction } from "@/hooks/use-mute-rule-action"; import { enforceMuteRuleNameLimit, diff --git a/ui/components/findings/send-to-jira-modal.tsx b/ui/components/findings/send-to-jira-modal.tsx index cee45c9464..aa6774da45 100644 --- a/ui/components/findings/send-to-jira-modal.tsx +++ b/ui/components/findings/send-to-jira-modal.tsx @@ -12,13 +12,13 @@ import { pollJiraDispatchTask, sendFindingToJira, } from "@/actions/integrations/jira-dispatch"; +import { useToast } from "@/components/shadcn"; +import { CustomBanner } from "@/components/shadcn/custom/custom-banner"; +import { Form, FormField, FormMessage } from "@/components/shadcn/form"; +import { FormButtons } from "@/components/shadcn/form/form-buttons"; import { Modal } from "@/components/shadcn/modal"; import { EnhancedMultiSelect } from "@/components/shadcn/select/enhanced-multi-select"; import { Skeleton } from "@/components/shadcn/skeleton/skeleton"; -import { useToast } from "@/components/ui"; -import { CustomBanner } from "@/components/ui/custom/custom-banner"; -import { Form, FormField, FormMessage } from "@/components/ui/form"; -import { FormButtons } from "@/components/ui/form/form-buttons"; import { IntegrationProps } from "@/types/integrations"; interface SendToJiraModalProps { diff --git a/ui/components/findings/table/column-finding-groups.test.tsx b/ui/components/findings/table/column-finding-groups.test.tsx index eefbcb5a45..52e8bde7c7 100644 --- a/ui/components/findings/table/column-finding-groups.test.tsx +++ b/ui/components/findings/table/column-finding-groups.test.tsx @@ -18,7 +18,8 @@ vi.mock("next/navigation", () => ({ useSearchParams: () => new URLSearchParams(), })); -vi.mock("@/components/shadcn", () => ({ +vi.mock("@/components/shadcn", async (importOriginal) => ({ + ...(await importOriginal>()), Checkbox: ({ "aria-label": ariaLabel, onCheckedChange, @@ -37,7 +38,7 @@ vi.mock("@/components/shadcn", () => ({ ), })); -vi.mock("@/components/ui/table", () => ({ +vi.mock("@/components/shadcn/table", () => ({ DataTableColumnHeader: ({ title, }: { diff --git a/ui/components/findings/table/column-finding-groups.tsx b/ui/components/findings/table/column-finding-groups.tsx index 79b584edcc..f200a4ed39 100644 --- a/ui/components/findings/table/column-finding-groups.tsx +++ b/ui/components/findings/table/column-finding-groups.tsx @@ -4,16 +4,16 @@ import { ColumnDef, RowSelectionState } from "@tanstack/react-table"; import { ChevronRight } from "lucide-react"; import { Checkbox } from "@/components/shadcn"; +import { + DataTableColumnHeader, + SeverityBadge, + StatusFindingBadge, +} from "@/components/shadcn/table"; import { Tooltip, TooltipContent, TooltipTrigger, } from "@/components/shadcn/tooltip"; -import { - DataTableColumnHeader, - SeverityBadge, - StatusFindingBadge, -} from "@/components/ui/table"; import { cn } from "@/lib"; import { canDrillDownFindingGroup, diff --git a/ui/components/findings/table/column-finding-resources.test.tsx b/ui/components/findings/table/column-finding-resources.test.tsx index 38a2b4bb20..1352d66272 100644 --- a/ui/components/findings/table/column-finding-resources.test.tsx +++ b/ui/components/findings/table/column-finding-resources.test.tsx @@ -3,7 +3,8 @@ import userEvent from "@testing-library/user-event"; import type { InputHTMLAttributes, ReactNode } from "react"; import { describe, expect, it, vi } from "vitest"; -vi.mock("@/components/shadcn", () => ({ +vi.mock("@/components/shadcn", async (importOriginal) => ({ + ...(await importOriginal>()), Checkbox: ({ "aria-label": ariaLabel, onCheckedChange, @@ -73,11 +74,11 @@ vi.mock("@/components/shadcn/spinner/spinner", () => ({ Spinner: () => null, })); -vi.mock("@/components/ui/entities", () => ({ +vi.mock("@/components/shadcn/entities", () => ({ DateWithTime: () => null, })); -vi.mock("@/components/ui/entities/entity-info", () => ({ +vi.mock("@/components/shadcn/entities/entity-info", () => ({ EntityInfo: ({ entityAlias, entityId, @@ -92,17 +93,17 @@ vi.mock("@/components/ui/entities/entity-info", () => ({ ), })); -vi.mock("@/components/ui/table", () => ({ +vi.mock("@/components/shadcn/table", () => ({ SeverityBadge: ({ severity }: { severity: string }) => ( {severity} ), })); -vi.mock("@/components/ui/table/data-table-column-header", () => ({ +vi.mock("@/components/shadcn/table/data-table-column-header", () => ({ DataTableColumnHeader: ({ title }: { title: string }) => {title}, })); -vi.mock("@/components/ui/table/status-finding-badge", () => ({ +vi.mock("@/components/shadcn/table/status-finding-badge", () => ({ StatusFindingBadge: ({ status }: { status: string }) => {status}, })); diff --git a/ui/components/findings/table/column-finding-resources.tsx b/ui/components/findings/table/column-finding-resources.tsx index 5789b8a96b..8ba590b0f8 100644 --- a/ui/components/findings/table/column-finding-resources.tsx +++ b/ui/components/findings/table/column-finding-resources.tsx @@ -12,16 +12,16 @@ import { ActionDropdown, ActionDropdownItem, } from "@/components/shadcn/dropdown"; +import { DateWithTime } from "@/components/shadcn/entities"; +import { EntityInfo } from "@/components/shadcn/entities/entity-info"; import { InfoField } from "@/components/shadcn/info-field/info-field"; import { Spinner } from "@/components/shadcn/spinner/spinner"; -import { DateWithTime } from "@/components/ui/entities"; -import { EntityInfo } from "@/components/ui/entities/entity-info"; -import { SeverityBadge } from "@/components/ui/table"; -import { DataTableColumnHeader } from "@/components/ui/table/data-table-column-header"; +import { SeverityBadge } from "@/components/shadcn/table"; +import { DataTableColumnHeader } from "@/components/shadcn/table/data-table-column-header"; import { type FindingStatus, StatusFindingBadge, -} from "@/components/ui/table/status-finding-badge"; +} from "@/components/shadcn/table/status-finding-badge"; import { getFailingForLabel } from "@/lib/date-utils"; import { FindingResourceRow } from "@/types"; diff --git a/ui/components/findings/table/column-standalone-findings.tsx b/ui/components/findings/table/column-standalone-findings.tsx index 0f457140f1..4bd5638a54 100644 --- a/ui/components/findings/table/column-standalone-findings.tsx +++ b/ui/components/findings/table/column-standalone-findings.tsx @@ -3,12 +3,12 @@ import { ColumnDef } from "@tanstack/react-table"; import { Container } from "lucide-react"; -import { DateWithTime, EntityInfo } from "@/components/ui/entities"; +import { DateWithTime, EntityInfo } from "@/components/shadcn/entities"; import { DataTableColumnHeader, SeverityBadge, StatusFindingBadge, -} from "@/components/ui/table"; +} from "@/components/shadcn/table"; import { getRegionFlag } from "@/lib/region-flags"; import { FindingProps, ProviderType } from "@/types"; diff --git a/ui/components/findings/table/delta-indicator.tsx b/ui/components/findings/table/delta-indicator.tsx index 7f79d1ede2..9bd2392210 100644 --- a/ui/components/findings/table/delta-indicator.tsx +++ b/ui/components/findings/table/delta-indicator.tsx @@ -19,9 +19,9 @@ export const DeltaIndicator = ({ delta }: DeltaIndicatorProps) => { className={cn( "h-2 w-2 min-w-2 cursor-pointer rounded-full", delta === "new" - ? "bg-system-severity-high" + ? "bg-bg-data-high" : delta === "changed" - ? "bg-system-severity-low" + ? "bg-bg-data-low" : "bg-text-neutral-tertiary", )} /> diff --git a/ui/components/findings/table/findings-group-drill-down.tsx b/ui/components/findings/table/findings-group-drill-down.tsx index 2bee7d5667..8eb8d8ac90 100644 --- a/ui/components/findings/table/findings-group-drill-down.tsx +++ b/ui/components/findings/table/findings-group-drill-down.tsx @@ -16,8 +16,8 @@ import { TableHead, TableHeader, TableRow, -} from "@/components/ui/table"; -import { SeverityBadge, StatusFindingBadge } from "@/components/ui/table"; +} from "@/components/shadcn/table"; +import { SeverityBadge, StatusFindingBadge } from "@/components/shadcn/table"; import { useFindingGroupResourceState } from "@/hooks/use-finding-group-resource-state"; import { cn, hasHistoricalFindingFilter } from "@/lib"; import { @@ -116,7 +116,7 @@ export function FindingsGroupDrillDown({ >
      diff --git a/ui/components/findings/table/findings-group-table.test.tsx b/ui/components/findings/table/findings-group-table.test.tsx index 38887bf1fb..2b5bc52176 100644 --- a/ui/components/findings/table/findings-group-table.test.tsx +++ b/ui/components/findings/table/findings-group-table.test.tsx @@ -11,7 +11,7 @@ vi.mock("next/navigation", () => ({ useSearchParams: () => new URLSearchParams(), })); -vi.mock("@/components/ui/table", () => ({ +vi.mock("@/components/shadcn/table", () => ({ DataTable: ({ toolbarRightContent }: { toolbarRightContent?: ReactNode }) => (
      {toolbarRightContent}
      diff --git a/ui/components/findings/table/findings-group-table.tsx b/ui/components/findings/table/findings-group-table.tsx index 8c5e9def0d..a029a67c39 100644 --- a/ui/components/findings/table/findings-group-table.tsx +++ b/ui/components/findings/table/findings-group-table.tsx @@ -6,7 +6,7 @@ import { useRef, useState } from "react"; import { resolveFindingIdsByVisibleGroupResources } from "@/actions/findings/findings-by-resource"; import { CustomCheckboxMutedFindings } from "@/components/filters/custom-checkbox-muted-findings"; -import { DataTable } from "@/components/ui/table"; +import { DataTable } from "@/components/shadcn/table"; import { canDrillDownFindingGroup } from "@/lib/findings-groups"; import { FindingGroupRow, MetaDataProps } from "@/types"; diff --git a/ui/components/findings/table/inline-resource-container.tsx b/ui/components/findings/table/inline-resource-container.tsx index 22ccb027e1..6960008d64 100644 --- a/ui/components/findings/table/inline-resource-container.tsx +++ b/ui/components/findings/table/inline-resource-container.tsx @@ -11,7 +11,7 @@ import { useImperativeHandle, useRef } from "react"; import { Skeleton } from "@/components/shadcn/skeleton/skeleton"; import { LoadingState } from "@/components/shadcn/spinner/loading-state"; -import { TableCell, TableRow } from "@/components/ui/table"; +import { TableCell, TableRow } from "@/components/shadcn/table"; import { useFindingGroupResourceState } from "@/hooks/use-finding-group-resource-state"; import { useScrollHint } from "@/hooks/use-scroll-hint"; import { FindingGroupRow } from "@/types"; diff --git a/ui/components/findings/table/notification-indicator.test.tsx b/ui/components/findings/table/notification-indicator.test.tsx index 093db2f3c6..9c35e3a22f 100644 --- a/ui/components/findings/table/notification-indicator.test.tsx +++ b/ui/components/findings/table/notification-indicator.test.tsx @@ -23,7 +23,8 @@ vi.mock("@/components/icons", () => ({ ), })); -vi.mock("@/components/shadcn", () => ({ +vi.mock("@/components/shadcn", async (importOriginal) => ({ + ...(await importOriginal>()), Button: ({ children, asChild, diff --git a/ui/components/findings/table/notification-indicator.tsx b/ui/components/findings/table/notification-indicator.tsx index 1691694816..d5b212a3bd 100644 --- a/ui/components/findings/table/notification-indicator.tsx +++ b/ui/components/findings/table/notification-indicator.tsx @@ -101,9 +101,7 @@ function DeltaIndicator({
      diff --git a/ui/components/findings/table/resource-detail-drawer/resource-detail-drawer-content.test.tsx b/ui/components/findings/table/resource-detail-drawer/resource-detail-drawer-content.test.tsx index 368a6b7dc3..1dcb0e440b 100644 --- a/ui/components/findings/table/resource-detail-drawer/resource-detail-drawer-content.test.tsx +++ b/ui/components/findings/table/resource-detail-drawer/resource-detail-drawer-content.test.tsx @@ -60,11 +60,12 @@ vi.mock("next/link", () => ({ })); // Mock the entire shadcn barrel to avoid auth import chain -vi.mock("@/components/shadcn", () => { +vi.mock("@/components/shadcn", async (importOriginal) => { const Passthrough = ({ children }: { children?: ReactNode }) => ( <>{children} ); return { + ...(await importOriginal>()), Badge: ({ children, className, @@ -125,7 +126,8 @@ vi.mock("@/components/shadcn", () => { }; }); -vi.mock("@/components/shadcn/card/card", () => ({ +vi.mock("@/components/shadcn/card/card", async (importOriginal) => ({ + ...(await importOriginal>()), Card: ({ children, variant }: { children: ReactNode; variant?: string }) => (
      {children} @@ -263,7 +265,7 @@ vi.mock("@/components/icons/services/IconServices", () => ({ JiraIcon: () => null, })); -vi.mock("@/components/ui/code-snippet/code-snippet", () => ({ +vi.mock("@/components/shadcn/code-snippet/code-snippet", () => ({ CodeSnippet: ({ value, formatter, @@ -282,11 +284,11 @@ vi.mock("@/components/ui/code-snippet/code-snippet", () => ({ ), })); -vi.mock("@/components/ui/entities/date-with-time", () => ({ +vi.mock("@/components/shadcn/entities/date-with-time", () => ({ DateWithTime: ({ dateTime }: { dateTime: string }) => {dateTime}, })); -vi.mock("@/components/ui/entities/entity-info", () => ({ +vi.mock("@/components/shadcn/entities/entity-info", () => ({ EntityInfo: ({ nameAction, idAction, @@ -304,7 +306,7 @@ vi.mock("@/components/ui/entities/entity-info", () => ({ ) : null, })); -vi.mock("@/components/ui/table", () => ({ +vi.mock("@/components/shadcn/table", () => ({ Table: ({ children }: { children: ReactNode }) => {children}
      , TableBody: ({ children }: { children: ReactNode }) => ( {children} @@ -319,13 +321,13 @@ vi.mock("@/components/ui/table", () => ({ ), })); -vi.mock("@/components/ui/table/severity-badge", () => ({ +vi.mock("@/components/shadcn/table/severity-badge", () => ({ SeverityBadge: ({ severity }: { severity: string }) => ( {severity} ), })); -vi.mock("@/components/ui/table/status-finding-badge", () => ({ +vi.mock("@/components/shadcn/table/status-finding-badge", () => ({ FindingStatus: {}, StatusFindingBadge: ({ status }: { status: string }) => {status}, })); diff --git a/ui/components/findings/table/resource-detail-drawer/resource-detail-drawer-content.tsx b/ui/components/findings/table/resource-detail-drawer/resource-detail-drawer-content.tsx index 096b4f030c..8e0aade727 100644 --- a/ui/components/findings/table/resource-detail-drawer/resource-detail-drawer-content.tsx +++ b/ui/components/findings/table/resource-detail-drawer/resource-detail-drawer-content.tsx @@ -32,12 +32,28 @@ import { TabsTrigger, } from "@/components/shadcn"; import { Card } from "@/components/shadcn/card/card"; +import { CodeSnippet } from "@/components/shadcn/code-snippet/code-snippet"; import { ActionDropdown, ActionDropdownItem, } from "@/components/shadcn/dropdown"; +import { DateWithTime } from "@/components/shadcn/entities/date-with-time"; +import { EntityInfo } from "@/components/shadcn/entities/entity-info"; import { Skeleton } from "@/components/shadcn/skeleton/skeleton"; import { LoadingState } from "@/components/shadcn/spinner/loading-state"; +import { + Table, + TableBody, + TableCell, + TableHead, + TableHeader, + TableRow, +} from "@/components/shadcn/table"; +import { SeverityBadge } from "@/components/shadcn/table/severity-badge"; +import { + type FindingStatus, + StatusFindingBadge, +} from "@/components/shadcn/table/status-finding-badge"; import { Tooltip, TooltipContent, @@ -51,22 +67,6 @@ import { type QueryEditorLanguage, } from "@/components/shared/query-code-editor"; import { ResourceMetadataPanel } from "@/components/shared/resource-metadata-panel"; -import { CodeSnippet } from "@/components/ui/code-snippet/code-snippet"; -import { DateWithTime } from "@/components/ui/entities/date-with-time"; -import { EntityInfo } from "@/components/ui/entities/entity-info"; -import { - Table, - TableBody, - TableCell, - TableHead, - TableHeader, - TableRow, -} from "@/components/ui/table"; -import { SeverityBadge } from "@/components/ui/table/severity-badge"; -import { - type FindingStatus, - StatusFindingBadge, -} from "@/components/ui/table/status-finding-badge"; import { getFailingForLabel } from "@/lib/date-utils"; import { formatDuration } from "@/lib/date-utils"; import { getRegionFlag } from "@/lib/region-flags"; diff --git a/ui/components/findings/table/skeleton-table-findings.tsx b/ui/components/findings/table/skeleton-table-findings.tsx index 79654d554c..98fd17ee65 100644 --- a/ui/components/findings/table/skeleton-table-findings.tsx +++ b/ui/components/findings/table/skeleton-table-findings.tsx @@ -58,7 +58,7 @@ export const SkeletonTableFindings = () => { const rows = 10; return ( -
      +
      {/* Toolbar: Search + Total entries */}
      {/* Search icon button */} diff --git a/ui/components/graphs/donut-chart.tsx b/ui/components/graphs/donut-chart.tsx index 796e2d9bc2..0111a2936c 100644 --- a/ui/components/graphs/donut-chart.tsx +++ b/ui/components/graphs/donut-chart.tsx @@ -11,7 +11,7 @@ import { Tooltip, } from "recharts"; -import { ChartConfig, ChartContainer } from "@/components/ui/chart/Chart"; +import { ChartConfig, ChartContainer } from "@/components/shadcn/chart/Chart"; import { ChartLegend } from "./shared/chart-legend"; import { DonutDataPoint } from "./types"; diff --git a/ui/components/graphs/line-chart.tsx b/ui/components/graphs/line-chart.tsx index 9b9b676f18..eab0551bb6 100644 --- a/ui/components/graphs/line-chart.tsx +++ b/ui/components/graphs/line-chart.tsx @@ -15,7 +15,7 @@ import { ChartConfig, ChartContainer, ChartTooltip, -} from "@/components/ui/chart/Chart"; +} from "@/components/shadcn/chart/Chart"; import { AlertPill } from "./shared/alert-pill"; import { ChartLegend } from "./shared/chart-legend"; diff --git a/ui/components/graphs/map-region-filter.tsx b/ui/components/graphs/map-region-filter.tsx index 3b483d1c62..3b779454a8 100644 --- a/ui/components/graphs/map-region-filter.tsx +++ b/ui/components/graphs/map-region-filter.tsx @@ -6,7 +6,7 @@ import { SelectItem, SelectTrigger, SelectValue, -} from "../ui/select/Select"; +} from "@/components/shadcn/select/select"; interface MapRegionFilterProps { regions: string[]; diff --git a/ui/components/graphs/radar-chart.tsx b/ui/components/graphs/radar-chart.tsx index 6acd773e39..4fe807b6fd 100644 --- a/ui/components/graphs/radar-chart.tsx +++ b/ui/components/graphs/radar-chart.tsx @@ -12,7 +12,7 @@ import { ChartConfig, ChartContainer, ChartTooltip, -} from "@/components/ui/chart/Chart"; +} from "@/components/shadcn/chart/Chart"; import { AlertPill } from "./shared/alert-pill"; import { RadarDataPoint } from "./types"; diff --git a/ui/components/graphs/sankey-chart.tsx b/ui/components/graphs/sankey-chart.tsx index 0a41d0e4e7..32176ffb7b 100644 --- a/ui/components/graphs/sankey-chart.tsx +++ b/ui/components/graphs/sankey-chart.tsx @@ -613,7 +613,7 @@ export function SankeyChart({
      )} {zeroDataProviders.length > 0 && ( -
      +

      Providers with no failed findings

      diff --git a/ui/components/icons/providers-badge/provider-type-icon.test.tsx b/ui/components/icons/providers-badge/provider-type-icon.test.tsx index 96b4f5f4d4..f50a71ae46 100644 --- a/ui/components/icons/providers-badge/provider-type-icon.test.tsx +++ b/ui/components/icons/providers-badge/provider-type-icon.test.tsx @@ -29,7 +29,8 @@ vi.mock("@/components/icons/providers-badge", () => ({ })); // Render the tooltip pieces inline so the hover content is queryable in jsdom. -vi.mock("@/components/shadcn", () => ({ +vi.mock("@/components/shadcn", async (importOriginal) => ({ + ...(await importOriginal>()), Badge: ({ children }: { children: React.ReactNode }) => ( {children} ), diff --git a/ui/components/icons/prowler/ProwlerIcons.tsx b/ui/components/icons/prowler/ProwlerIcons.tsx index 4a616553a4..1beb80ae25 100644 --- a/ui/components/icons/prowler/ProwlerIcons.tsx +++ b/ui/components/icons/prowler/ProwlerIcons.tsx @@ -10,7 +10,7 @@ export const ProwlerExtended: React.FC = ({ }) => { return ( = ({ ...props }) => (
      -

      +

      Need help configuring your Jira integration?

      - + {/* S3 Configuration */}
      @@ -421,7 +421,7 @@ export const S3IntegrationForm = ({ >
      -

      +

      Need help configuring your Amazon S3 integration?

      { size="md" >
      -

      +

      Are you sure you want to remove the SAML SSO configuration? Users will no longer be able to sign in using SAML.

      diff --git a/ui/components/integrations/security-hub/security-hub-integration-card.tsx b/ui/components/integrations/security-hub/security-hub-integration-card.tsx index bce91812f4..4003f8c286 100644 --- a/ui/components/integrations/security-hub/security-hub-integration-card.tsx +++ b/ui/components/integrations/security-hub/security-hub-integration-card.tsx @@ -5,7 +5,7 @@ import Link from "next/link"; import { AWSSecurityHubIcon } from "@/components/icons/services/IconServices"; import { Button } from "@/components/shadcn"; -import { CustomLink } from "@/components/ui/custom/custom-link"; +import { CustomLink } from "@/components/shadcn/custom/custom-link"; import { Card, CardContent, CardHeader } from "../../shadcn"; diff --git a/ui/components/integrations/security-hub/security-hub-integration-form.tsx b/ui/components/integrations/security-hub/security-hub-integration-form.tsx index 1c3b436832..b7fac10706 100644 --- a/ui/components/integrations/security-hub/security-hub-integration-form.tsx +++ b/ui/components/integrations/security-hub/security-hub-integration-form.tsx @@ -1,8 +1,5 @@ "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 { ArrowLeftIcon, ArrowRightIcon } from "lucide-react"; import { useSession } from "next-auth/react"; @@ -15,16 +12,21 @@ import { ProviderTypeIcon, } from "@/components/icons/providers-badge/provider-type-icon"; import { AWSRoleCredentialsForm } from "@/components/providers/workflow/forms/select-credentials-type/aws/credentials-type/aws-role-credentials-form"; -import { EnhancedMultiSelect } from "@/components/shadcn/select/enhanced-multi-select"; -import { useToast } from "@/components/ui"; -import { CustomLink } from "@/components/ui/custom/custom-link"; +import { Checkbox, Separator } from "@/components/shadcn"; +import { useToast } from "@/components/shadcn"; +import { CustomLink } from "@/components/shadcn/custom/custom-link"; import { Form, FormControl, FormField, FormMessage, -} from "@/components/ui/form"; -import { FormButtons } from "@/components/ui/form/form-buttons"; +} from "@/components/shadcn/form"; +import { FormButtons } from "@/components/shadcn/form/form-buttons"; +import { + RadioGroup, + RadioGroupItem, +} from "@/components/shadcn/radio-group/radio-group"; +import { EnhancedMultiSelect } from "@/components/shadcn/select/enhanced-multi-select"; import { getAWSCredentialsTemplateLinks } from "@/lib"; import { AWSCredentialsRole } from "@/types"; import { @@ -289,8 +291,8 @@ export const SecurityHubIntegrationForm = ({ return (
      { form.setValue("use_custom_credentials", value === "custom", { @@ -299,17 +301,29 @@ export const SecurityHubIntegrationForm = ({ }); }} > - - Use provider credentials - - - Use custom credentials - +
      + + +
      +
      + + +
      {useCustomCredentials && ( <> - + } setValue={form.setValue as any} @@ -382,7 +396,7 @@ export const SecurityHubIntegrationForm = ({ )} />
      - + )} @@ -392,16 +406,20 @@ export const SecurityHubIntegrationForm = ({ name="send_only_fails" render={({ field }) => ( - - +
      + + + +
      )} /> @@ -411,14 +429,20 @@ export const SecurityHubIntegrationForm = ({ name="archive_previous_findings" render={({ field }) => ( - - Archive previous findings - +
      + + +
      )} /> @@ -429,17 +453,21 @@ export const SecurityHubIntegrationForm = ({ name="use_custom_credentials" render={({ field }) => ( - - +
      + + + +
      )} /> @@ -529,7 +557,7 @@ export const SecurityHubIntegrationForm = ({ >
      -

      +

      Need help configuring your AWS Security Hub integration?

      {connectionStatus.label || diff --git a/ui/components/integrations/shared/integration-skeleton.tsx b/ui/components/integrations/shared/integration-skeleton.tsx index 245085ca70..469dbb6f22 100644 --- a/ui/components/integrations/shared/integration-skeleton.tsx +++ b/ui/components/integrations/shared/integration-skeleton.tsx @@ -1,9 +1,9 @@ "use client"; -import { Card, CardBody, CardHeader } from "@heroui/card"; -import { Skeleton } from "@heroui/skeleton"; import { ReactNode } from "react"; +import { Card, CardContent, CardHeader, Skeleton } from "@/components/shadcn"; + interface IntegrationSkeletonProps { variant?: "main" | "manager"; count?: number; @@ -21,8 +21,8 @@ export const IntegrationSkeleton = ({ }: IntegrationSkeletonProps) => { if (variant === "main") { return ( - - + +
      {icon} @@ -39,12 +39,12 @@ export const IntegrationSkeleton = ({
      - +
      -
      +
      ); } @@ -53,8 +53,8 @@ export const IntegrationSkeleton = ({ return (
      {Array.from({ length: count }).map((_, index) => ( - - + +
      {icon} @@ -70,7 +70,7 @@ export const IntegrationSkeleton = ({
      - +
      {/* Region chips skeleton */}
      @@ -89,7 +89,7 @@ export const IntegrationSkeleton = ({
      - +
      ))}
      diff --git a/ui/components/integrations/shared/link-card.tsx b/ui/components/integrations/shared/link-card.tsx index 5721f3a3b5..ceb74d6a1b 100644 --- a/ui/components/integrations/shared/link-card.tsx +++ b/ui/components/integrations/shared/link-card.tsx @@ -4,7 +4,7 @@ import { ExternalLinkIcon, LucideIcon } from "lucide-react"; import Link from "next/link"; import { Button } from "@/components/shadcn"; -import { CustomLink } from "@/components/ui/custom/custom-link"; +import { CustomLink } from "@/components/shadcn/custom/custom-link"; import { Card, CardContent, CardHeader } from "../../shadcn"; @@ -34,7 +34,7 @@ export const LinkCard = ({
      -
      +
      diff --git a/ui/components/invitations/forms/delete-form.tsx b/ui/components/invitations/forms/delete-form.tsx index 097ad9620d..58618b9dc6 100644 --- a/ui/components/invitations/forms/delete-form.tsx +++ b/ui/components/invitations/forms/delete-form.tsx @@ -8,8 +8,8 @@ import * as z from "zod"; import { revokeInvite } from "@/actions/invitations/invitation"; import { DeleteIcon } from "@/components/icons"; import { Button } from "@/components/shadcn"; -import { useToast } from "@/components/ui"; -import { Form } from "@/components/ui/form"; +import { useToast } from "@/components/shadcn"; +import { Form } from "@/components/shadcn/form"; const formSchema = z.object({ invitationId: z.string(), diff --git a/ui/components/invitations/forms/edit-form.tsx b/ui/components/invitations/forms/edit-form.tsx index 57f0717313..b8bfaf6f70 100644 --- a/ui/components/invitations/forms/edit-form.tsx +++ b/ui/components/invitations/forms/edit-form.tsx @@ -5,6 +5,9 @@ import { Controller, useForm } from "react-hook-form"; import * as z from "zod"; import { updateInvite } from "@/actions/invitations/invitation"; +import { useToast } from "@/components/shadcn"; +import { CustomInput } from "@/components/shadcn/custom"; +import { Form, FormButtons } from "@/components/shadcn/form"; import { Select, SelectContent, @@ -12,9 +15,6 @@ import { SelectTrigger, SelectValue, } from "@/components/shadcn/select/select"; -import { useToast } from "@/components/ui"; -import { CustomInput } from "@/components/ui/custom"; -import { Form, FormButtons } from "@/components/ui/form"; import { editInviteFormSchema } from "@/types"; import { Card, CardContent } from "../../shadcn"; @@ -103,14 +103,14 @@ export const EditForm = ({ > -
      +
      Email: {invitationEmail}
      -
      +
      Role: diff --git a/ui/components/invitations/invitation-details.tsx b/ui/components/invitations/invitation-details.tsx index 0cc8e2b919..259a1de0a4 100644 --- a/ui/components/invitations/invitation-details.tsx +++ b/ui/components/invitations/invitation-details.tsx @@ -2,11 +2,12 @@ import Link from "next/link"; +import { CodeSnippet } from "@/components/shadcn/code-snippet/code-snippet"; +import { DateWithTime } from "@/components/shadcn/entities"; + import { AddIcon } from "../icons"; import { Button, Card, CardContent, CardHeader } from "../shadcn"; import { Separator } from "../shadcn/separator/separator"; -import { CodeSnippet } from "../ui/code-snippet/code-snippet"; -import { DateWithTime } from "../ui/entities"; interface InvitationDetailsProps { attributes: { @@ -39,7 +40,7 @@ const InfoField = ({ {label}
      - + {children}
      diff --git a/ui/components/invitations/table/column-invitations.tsx b/ui/components/invitations/table/column-invitations.tsx index 2af64ef6fd..628f0c2788 100644 --- a/ui/components/invitations/table/column-invitations.tsx +++ b/ui/components/invitations/table/column-invitations.tsx @@ -2,8 +2,8 @@ import { ColumnDef } from "@tanstack/react-table"; -import { DateWithTime } from "@/components/ui/entities"; -import { DataTableColumnHeader } from "@/components/ui/table"; +import { DateWithTime } from "@/components/shadcn/entities"; +import { DataTableColumnHeader } from "@/components/shadcn/table"; import { InvitationProps } from "@/types"; import { DataTableRowActions } from "./data-table-row-actions"; diff --git a/ui/components/invitations/workflow/forms/send-invitation-form.tsx b/ui/components/invitations/workflow/forms/send-invitation-form.tsx index 729dc89d28..67e6938d4a 100644 --- a/ui/components/invitations/workflow/forms/send-invitation-form.tsx +++ b/ui/components/invitations/workflow/forms/send-invitation-form.tsx @@ -8,6 +8,9 @@ import * as z from "zod"; import { sendInvite } from "@/actions/invitations/invitation"; import { Button } from "@/components/shadcn"; +import { useToast } from "@/components/shadcn"; +import { CustomInput } from "@/components/shadcn/custom"; +import { Form } from "@/components/shadcn/form"; import { Select, SelectContent, @@ -15,9 +18,6 @@ import { SelectTrigger, SelectValue, } from "@/components/shadcn/select/select"; -import { useToast } from "@/components/ui"; -import { CustomInput } from "@/components/ui/custom"; -import { Form } from "@/components/ui/form"; import { ApiError } from "@/types"; const sendInvitationFormSchema = z.object({ diff --git a/ui/components/invitations/workflow/skeleton-invitation-info.tsx b/ui/components/invitations/workflow/skeleton-invitation-info.tsx index b83568d054..4ab48ddcfc 100644 --- a/ui/components/invitations/workflow/skeleton-invitation-info.tsx +++ b/ui/components/invitations/workflow/skeleton-invitation-info.tsx @@ -1,33 +1,17 @@ -import { Card } from "@heroui/card"; -import { Skeleton } from "@heroui/skeleton"; -import React from "react"; +import { Card, Skeleton } from "@/components/shadcn"; export const SkeletonInvitationInfo = () => { return ( - + {/* Table headers */}
      - -
      -
      - -
      -
      - -
      -
      - -
      -
      - -
      -
      - -
      -
      - -
      -
      + + + + + + +
      {/* Table body */} @@ -37,27 +21,13 @@ export const SkeletonInvitationInfo = () => { key={index} className="flex flex-col items-center justify-between md:flex-row md:gap-4" > - -
      -
      - -
      -
      - -
      -
      - -
      -
      - -
      -
      - -
      -
      - -
      -
      + + + + + + +
      ))}
      diff --git a/ui/components/invitations/workflow/vertical-steps.tsx b/ui/components/invitations/workflow/vertical-steps.tsx index 16dd7c9647..17abec63d2 100644 --- a/ui/components/invitations/workflow/vertical-steps.tsx +++ b/ui/components/invitations/workflow/vertical-steps.tsx @@ -1,11 +1,12 @@ "use client"; -import { cn } from "@heroui/theme"; import { useControlledState } from "@react-stately/utils"; import { domAnimation, LazyMotion, m } from "framer-motion"; import type { ComponentProps } from "react"; import React from "react"; +import { cn } from "@/lib/utils"; + export type VerticalStepProps = { className?: string; description?: React.ReactNode; @@ -122,38 +123,37 @@ 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(--heroui-default-300))]", - "[--inactive-color:hsl(var(--heroui-default-300))]", + "[--inactive-border-color:var(--border-neutral-tertiary)]", + "[--inactive-color:var(--border-neutral-tertiary)]", ]; switch (color) { - case "primary": - userColor = "[--step-color:var(--bg-button-primary)]"; - fgColor = "[--step-fg-color:hsl(var(--heroui-primary-foreground))]"; - break; case "secondary": - userColor = "[--step-color:hsl(var(--heroui-secondary))]"; - fgColor = "[--step-fg-color:hsl(var(--heroui-secondary-foreground))]"; + userColor = + "[--step-color:var(--color-violet-600)] dark:[--step-color:var(--color-violet-400)]"; + fgColor = "[--step-fg-color:var(--color-white)]"; break; case "success": - userColor = "[--step-color:hsl(var(--heroui-success))]"; - fgColor = "[--step-fg-color:hsl(var(--heroui-success-foreground))]"; + userColor = "[--step-color:var(--bg-pass-primary)]"; + fgColor = "[--step-fg-color:var(--color-black)]"; break; case "warning": - userColor = "[--step-color:hsl(var(--heroui-warning))]"; - fgColor = "[--step-fg-color:hsl(var(--heroui-warning-foreground))]"; + userColor = "[--step-color:var(--bg-warning-primary)]"; + fgColor = "[--step-fg-color:var(--color-black)]"; break; case "danger": - userColor = "[--step-color:hsl(var(--heroui-error))]"; - fgColor = "[--step-fg-color:hsl(var(--heroui-error-foreground))]"; + userColor = "[--step-color:var(--bg-fail-primary)]"; + fgColor = "[--step-fg-color:var(--color-white)]"; break; case "default": - userColor = "[--step-color:hsl(var(--heroui-default))]"; - fgColor = "[--step-fg-color:hsl(var(--heroui-default-foreground))]"; + userColor = + "[--step-color:var(--color-zinc-300)] dark:[--step-color:var(--color-zinc-600)]"; + fgColor = "[--step-fg-color:var(--text-neutral-primary)]"; break; + case "primary": default: - userColor = "[--step-color:hsl(var(--heroui-primary))]"; - fgColor = "[--step-fg-color:hsl(var(--heroui-primary-foreground))]"; + userColor = "[--step-color:var(--bg-button-primary)]"; + fgColor = "[--step-fg-color:var(--color-black)]"; break; } @@ -161,7 +161,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(--heroui-default-300))]", + "[--inactive-bar-color:var(--border-neutral-tertiary)]", ); return colorsVars; @@ -186,7 +186,7 @@ export const VerticalSteps = React.forwardRef< ref={ref} aria-current={status === "active" ? "step" : undefined} className={cn( - "group rounded-large flex w-full cursor-pointer items-center justify-center gap-4 px-3 py-2.5", + "group flex w-full cursor-pointer items-center justify-center gap-4 rounded-[14px] px-3 py-2.5", stepClassName, )} onClick={() => setCurrentStep(stepIdx)} @@ -197,12 +197,9 @@ export const VerticalSteps = React.forwardRef<
      {step.title}
      {step.description}
      diff --git a/ui/components/invitations/workflow/workflow-send-invite.tsx b/ui/components/invitations/workflow/workflow-send-invite.tsx index 9183c27a8d..879a96b83f 100644 --- a/ui/components/invitations/workflow/workflow-send-invite.tsx +++ b/ui/components/invitations/workflow/workflow-send-invite.tsx @@ -1,10 +1,10 @@ "use client"; -import { Progress } from "@heroui/progress"; -import { Spacer } from "@heroui/spacer"; import { usePathname } from "next/navigation"; import React from "react"; +import { Progress } from "@/components/shadcn/progress"; + import { VerticalSteps } from "./vertical-steps"; const steps = [ @@ -36,24 +36,23 @@ export const WorkflowSendInvite = () => {

      Send invitation

      -

      +

      Follow the steps to send an invitation to the users.

      - +
      +
      + Steps + + {`${currentStep + 1} of ${steps.length}`} + +
      + +
      {/* Desktop: Full vertical steps */}
      @@ -71,13 +70,13 @@ export const WorkflowSendInvite = () => {
      Current: {steps[currentStep]?.title}
      -
      +
      {steps[currentStep]?.description}
      - +
      ); }; diff --git a/ui/components/layout/index.ts b/ui/components/layout/index.ts new file mode 100644 index 0000000000..33b087bb29 --- /dev/null +++ b/ui/components/layout/index.ts @@ -0,0 +1,4 @@ +export * from "./main-layout"; +export * from "./nav-bar"; +export * from "./sidebar"; +export * from "./user-nav"; diff --git a/ui/components/layout/main-layout/index.ts b/ui/components/layout/main-layout/index.ts new file mode 100644 index 0000000000..b816f0d4ee --- /dev/null +++ b/ui/components/layout/main-layout/index.ts @@ -0,0 +1 @@ +export * from "./main-layout"; diff --git a/ui/components/ui/main-layout/main-layout.test.tsx b/ui/components/layout/main-layout/main-layout.test.tsx similarity index 100% rename from ui/components/ui/main-layout/main-layout.test.tsx rename to ui/components/layout/main-layout/main-layout.test.tsx diff --git a/ui/components/ui/main-layout/main-layout.tsx b/ui/components/layout/main-layout/main-layout.tsx similarity index 100% rename from ui/components/ui/main-layout/main-layout.tsx rename to ui/components/layout/main-layout/main-layout.tsx diff --git a/ui/components/layout/nav-bar/index.ts b/ui/components/layout/nav-bar/index.ts new file mode 100644 index 0000000000..0f6da2a562 --- /dev/null +++ b/ui/components/layout/nav-bar/index.ts @@ -0,0 +1,2 @@ +export * from "./navbar"; +export * from "./navbar-client"; diff --git a/ui/components/ui/nav-bar/navbar-client.tsx b/ui/components/layout/nav-bar/navbar-client.tsx similarity index 96% rename from ui/components/ui/nav-bar/navbar-client.tsx rename to ui/components/layout/nav-bar/navbar-client.tsx index fa48c9c103..f897da7565 100644 --- a/ui/components/ui/nav-bar/navbar-client.tsx +++ b/ui/components/layout/nav-bar/navbar-client.tsx @@ -4,8 +4,8 @@ import { BellRing } from "lucide-react"; import { ReactNode } from "react"; import { Button } from "@/components/shadcn"; +import { BreadcrumbNavigation } from "@/components/shadcn"; import { ThemeSwitch } from "@/components/ThemeSwitch"; -import { BreadcrumbNavigation } from "@/components/ui"; import { useSidebar } from "@/hooks/use-sidebar"; import { SheetMenu } from "../sidebar/sheet-menu"; diff --git a/ui/components/ui/nav-bar/navbar.tsx b/ui/components/layout/nav-bar/navbar.tsx similarity index 100% rename from ui/components/ui/nav-bar/navbar.tsx rename to ui/components/layout/nav-bar/navbar.tsx diff --git a/ui/components/ui/sidebar/collapsible-menu.tsx b/ui/components/layout/sidebar/collapsible-menu.tsx similarity index 96% rename from ui/components/ui/sidebar/collapsible-menu.tsx rename to ui/components/layout/sidebar/collapsible-menu.tsx index 7937bf940d..27d62a5a3f 100644 --- a/ui/components/ui/sidebar/collapsible-menu.tsx +++ b/ui/components/layout/sidebar/collapsible-menu.tsx @@ -4,18 +4,18 @@ import { ChevronDown } from "lucide-react"; import { usePathname } from "next/navigation"; import { useEffect, useState } from "react"; +import { SubmenuItem } from "@/components/layout/sidebar/submenu-item"; import { Button } from "@/components/shadcn/button/button"; +import { + Collapsible, + CollapsibleContent, + CollapsibleTrigger, +} from "@/components/shadcn/collapsible"; import { Tooltip, TooltipContent, TooltipTrigger, } from "@/components/shadcn/tooltip"; -import { - Collapsible, - CollapsibleContent, - CollapsibleTrigger, -} from "@/components/ui/collapsible/collapsible"; -import { SubmenuItem } from "@/components/ui/sidebar/submenu-item"; import { cn } from "@/lib/utils"; import { IconComponent, SubmenuProps } from "@/types"; diff --git a/ui/components/layout/sidebar/index.ts b/ui/components/layout/sidebar/index.ts new file mode 100644 index 0000000000..6fe9b4c4e2 --- /dev/null +++ b/ui/components/layout/sidebar/index.ts @@ -0,0 +1,7 @@ +export * from "./collapsible-menu"; +export * from "./menu"; +export * from "./menu-item"; +export * from "./sheet-menu"; +export * from "./sidebar"; +export * from "./sidebar-toggle"; +export * from "./submenu-item"; diff --git a/ui/components/ui/sidebar/menu-item.tsx b/ui/components/layout/sidebar/menu-item.tsx similarity index 100% rename from ui/components/ui/sidebar/menu-item.tsx rename to ui/components/layout/sidebar/menu-item.tsx diff --git a/ui/components/ui/sidebar/menu.test.tsx b/ui/components/layout/sidebar/menu.test.tsx similarity index 100% rename from ui/components/ui/sidebar/menu.test.tsx rename to ui/components/layout/sidebar/menu.test.tsx diff --git a/ui/components/ui/sidebar/menu.tsx b/ui/components/layout/sidebar/menu.tsx similarity index 95% rename from ui/components/ui/sidebar/menu.tsx rename to ui/components/layout/sidebar/menu.tsx index a36da25934..21903a2a55 100644 --- a/ui/components/ui/sidebar/menu.tsx +++ b/ui/components/layout/sidebar/menu.tsx @@ -1,19 +1,19 @@ "use client"; -import { Divider } from "@heroui/divider"; import Link from "next/link"; import { usePathname } from "next/navigation"; import { InfoIcon, ProwlerShort } from "@/components/icons"; +import { CollapsibleMenu } from "@/components/layout/sidebar/collapsible-menu"; +import { MenuItem } from "@/components/layout/sidebar/menu-item"; +import { Separator } from "@/components/shadcn"; import { Button } from "@/components/shadcn/button/button"; +import { ScrollArea } from "@/components/shadcn/scroll-area/scroll-area"; import { Tooltip, TooltipContent, TooltipTrigger, } from "@/components/shadcn/tooltip"; -import { ScrollArea } from "@/components/ui/scroll-area/scroll-area"; -import { CollapsibleMenu } from "@/components/ui/sidebar/collapsible-menu"; -import { MenuItem } from "@/components/ui/sidebar/menu-item"; import { useAuth } from "@/hooks"; import { getMenuList } from "@/lib/menu-list"; import { LAUNCH_SCAN_HREF } from "@/lib/scans-navigation"; @@ -151,7 +151,7 @@ export const Menu = ({ isOpen }: { isOpen: boolean }) => { {process.env.NEXT_PUBLIC_PROWLER_RELEASE_VERSION} {process.env.NEXT_PUBLIC_IS_CLOUD_ENV === "true" && ( <> - + void; diff --git a/ui/components/ui/sidebar/sidebar.tsx b/ui/components/layout/sidebar/sidebar.tsx similarity index 97% rename from ui/components/ui/sidebar/sidebar.tsx rename to ui/components/layout/sidebar/sidebar.tsx index cf1baea4b4..16815eb6c3 100644 --- a/ui/components/ui/sidebar/sidebar.tsx +++ b/ui/components/layout/sidebar/sidebar.tsx @@ -5,11 +5,11 @@ import Link from "next/link"; import { ProwlerShort } from "@/components/icons"; import { ProwlerExtended } from "@/components/icons"; +import { Button } from "@/components/shadcn/button/button"; import { useSidebar } from "@/hooks/use-sidebar"; import { useStore } from "@/hooks/use-store"; import { cn } from "@/lib/utils"; -import { Button } from "../button/button"; import { Menu } from "./menu"; export function Sidebar() { diff --git a/ui/components/ui/sidebar/submenu-item.test.tsx b/ui/components/layout/sidebar/submenu-item.test.tsx similarity index 100% rename from ui/components/ui/sidebar/submenu-item.test.tsx rename to ui/components/layout/sidebar/submenu-item.test.tsx diff --git a/ui/components/ui/sidebar/submenu-item.tsx b/ui/components/layout/sidebar/submenu-item.tsx similarity index 100% rename from ui/components/ui/sidebar/submenu-item.tsx rename to ui/components/layout/sidebar/submenu-item.tsx diff --git a/ui/components/layout/user-nav/index.ts b/ui/components/layout/user-nav/index.ts new file mode 100644 index 0000000000..2e600a84a1 --- /dev/null +++ b/ui/components/layout/user-nav/index.ts @@ -0,0 +1 @@ +export * from "./user-nav"; diff --git a/ui/components/ui/user-nav/user-nav.tsx b/ui/components/layout/user-nav/user-nav.tsx similarity index 94% rename from ui/components/ui/user-nav/user-nav.tsx rename to ui/components/layout/user-nav/user-nav.tsx index dd2c2d8247..20c5baf2a3 100644 --- a/ui/components/ui/user-nav/user-nav.tsx +++ b/ui/components/layout/user-nav/user-nav.tsx @@ -4,18 +4,18 @@ import { LogOut } from "lucide-react"; import { useSession } from "next-auth/react"; import { logOut } from "@/actions/auth"; +import { + Avatar, + AvatarFallback, + AvatarImage, +} from "@/components/shadcn/avatar/avatar"; import { Button } from "@/components/shadcn/button/button"; +import { CustomLink } from "@/components/shadcn/custom/custom-link"; import { Tooltip, TooltipContent, TooltipTrigger, } from "@/components/shadcn/tooltip"; -import { - Avatar, - AvatarFallback, - AvatarImage, -} from "@/components/ui/avatar/avatar"; -import { CustomLink } from "@/components/ui/custom/custom-link"; export const UserNav = () => { const { data: session } = useSession(); diff --git a/ui/components/lighthouse/ai-elements/actions.tsx b/ui/components/lighthouse/ai-elements/actions.tsx index 900f7409c6..537957a74b 100644 --- a/ui/components/lighthouse/ai-elements/actions.tsx +++ b/ui/components/lighthouse/ai-elements/actions.tsx @@ -37,7 +37,7 @@ export const Action = ({ const button = ( ), diff --git a/ui/components/providers/organizations/org-launch-scan.tsx b/ui/components/providers/organizations/org-launch-scan.tsx index 535d4186ba..f1f70a49ad 100644 --- a/ui/components/providers/organizations/org-launch-scan.tsx +++ b/ui/components/providers/organizations/org-launch-scan.tsx @@ -10,6 +10,7 @@ import { WIZARD_FOOTER_ACTION_TYPE, WizardFooterConfig, } from "@/components/providers/wizard/steps/footer-controls"; +import { ToastAction, useToast } from "@/components/shadcn"; import { Select, SelectContent, @@ -19,7 +20,6 @@ import { } from "@/components/shadcn/select/select"; import { Spinner } from "@/components/shadcn/spinner/spinner"; import { TreeStatusIcon } from "@/components/shadcn/tree-view/tree-status-icon"; -import { ToastAction, useToast } from "@/components/ui"; import { useOrgSetupStore } from "@/store/organizations/store"; import { TREE_ITEM_STATUS } from "@/types/tree"; diff --git a/ui/components/providers/organizations/org-setup-form.tsx b/ui/components/providers/organizations/org-setup-form.tsx index fe6d086d9f..a9852fa202 100644 --- a/ui/components/providers/organizations/org-setup-form.tsx +++ b/ui/components/providers/organizations/org-setup-form.tsx @@ -1,10 +1,9 @@ "use client"; -import { useClipboard } from "@heroui/use-clipboard"; import { zodResolver } from "@hookform/resolvers/zod"; import { Check, Copy, ExternalLink } from "lucide-react"; import { useSession } from "next-auth/react"; -import { FormEvent, useEffect, useState } from "react"; +import { FormEvent, useEffect, useRef, useState } from "react"; import { Controller, useForm } from "react-hook-form"; import { z } from "zod"; @@ -19,12 +18,12 @@ import { OrgWizardIntent, } from "@/components/providers/wizard/types"; import { WizardInputField } from "@/components/providers/workflow/forms/fields"; +import { useToast } from "@/components/shadcn"; import { Alert, AlertDescription } from "@/components/shadcn/alert"; import { Button } from "@/components/shadcn/button/button"; import { Checkbox } from "@/components/shadcn/checkbox/checkbox"; +import { Form } from "@/components/shadcn/form"; import { Spinner } from "@/components/shadcn/spinner/spinner"; -import { useToast } from "@/components/ui"; -import { Form } from "@/components/ui/form"; import { getAWSCredentialsTemplateLinks, PROWLER_CF_TEMPLATE_URL, @@ -90,12 +89,29 @@ export function OrgSetupForm({ const stackSetExternalId = session?.tenantId ?? ""; const { organizationId } = useOrgSetupStore(); const { toast } = useToast(); - const { copied: isExternalIdCopied, copy: copyExternalId } = useClipboard({ - timeout: 1500, - }); - const { copied: isTemplateUrlCopied, copy: copyTemplateUrl } = useClipboard({ - timeout: 1500, - }); + const COPY_RESET_TIMEOUT = 1500; + const [isExternalIdCopied, setIsExternalIdCopied] = useState(false); + const [isTemplateUrlCopied, setIsTemplateUrlCopied] = useState(false); + const externalIdCopyTimer = useRef>(undefined); + const templateUrlCopyTimer = useRef>(undefined); + + // Copies text and flips the copied flag back after the timeout, without effects + const copyWithFeedback = ( + text: string, + setCopied: (copied: boolean) => void, + timerRef: { current: ReturnType | undefined }, + ) => { + navigator.clipboard.writeText(text).then(() => { + setCopied(true); + clearTimeout(timerRef.current); + timerRef.current = setTimeout(() => setCopied(false), COPY_RESET_TIMEOUT); + }); + }; + + const copyExternalId = (text: string) => + copyWithFeedback(text, setIsExternalIdCopied, externalIdCopyTimer); + const copyTemplateUrl = (text: string) => + copyWithFeedback(text, setIsTemplateUrlCopied, templateUrlCopyTimer); const [setupPhase, setSetupPhase] = useState(initialPhase); const [isSaving, setIsSaving] = useState(false); const formId = "org-wizard-setup-form"; diff --git a/ui/components/providers/providers-accounts-table.tsx b/ui/components/providers/providers-accounts-table.tsx index 0c25b609d9..572f2e12f0 100644 --- a/ui/components/providers/providers-accounts-table.tsx +++ b/ui/components/providers/providers-accounts-table.tsx @@ -7,7 +7,7 @@ import type { OrgWizardInitialData, ProviderWizardInitialData, } from "@/components/providers/wizard/types"; -import { DataTable } from "@/components/ui/table"; +import { DataTable } from "@/components/shadcn/table"; import { MetaDataProps } from "@/types"; import { isProvidersOrganizationRow, diff --git a/ui/components/providers/providers-filters.test.tsx b/ui/components/providers/providers-filters.test.tsx index b6e6655247..9dee9a90a7 100644 --- a/ui/components/providers/providers-filters.test.tsx +++ b/ui/components/providers/providers-filters.test.tsx @@ -20,7 +20,7 @@ vi.mock("@/components/filters/clear-filters-button", () => ({ ClearFiltersButton: () => , })); -vi.mock("@/components/ui/entities/entity-info", () => ({ +vi.mock("@/components/shadcn/entities/entity-info", () => ({ EntityInfo: () => null, })); diff --git a/ui/components/providers/providers-filters.tsx b/ui/components/providers/providers-filters.tsx index 285bae4c1e..f217328a3b 100644 --- a/ui/components/providers/providers-filters.tsx +++ b/ui/components/providers/providers-filters.tsx @@ -5,6 +5,7 @@ import type { ReactNode } from "react"; import { ProviderTypeSelector } from "@/app/(prowler)/_overview/_components/provider-type-selector"; import { ClearFiltersButton } from "@/components/filters/clear-filters-button"; +import { EntityInfo } from "@/components/shadcn/entities/entity-info"; import { MultiSelect, MultiSelectContent, @@ -14,7 +15,6 @@ import { MultiSelectTrigger, MultiSelectValue, } from "@/components/shadcn/select/multiselect"; -import { EntityInfo } from "@/components/ui/entities/entity-info"; import { useUrlFilters } from "@/hooks/use-url-filters"; import { isConnectionStatus, isGroupFilterEntity } from "@/lib/helper-filters"; import { FilterEntity, FilterOption, ProviderEntity } from "@/types"; diff --git a/ui/components/providers/radio-card.tsx b/ui/components/providers/radio-card.tsx index f4b5e13aca..2a15fa6b19 100644 --- a/ui/components/providers/radio-card.tsx +++ b/ui/components/providers/radio-card.tsx @@ -30,15 +30,15 @@ export function RadioCard({ disabled ? "border-border-neutral-primary bg-bg-neutral-tertiary cursor-not-allowed" : selected - ? "border-primary bg-bg-neutral-tertiary cursor-pointer" - : "hover:border-primary border-border-neutral-primary bg-bg-neutral-tertiary cursor-pointer", + ? "border-button-primary bg-bg-neutral-tertiary cursor-pointer" + : "hover:border-button-primary border-border-neutral-primary bg-bg-neutral-tertiary cursor-pointer", )} >
      @@ -53,7 +53,9 @@ export function RadioCard({ {title} diff --git a/ui/components/providers/radio-group-provider.tsx b/ui/components/providers/radio-group-provider.tsx index 6c9930fd83..de8d941f3a 100644 --- a/ui/components/providers/radio-group-provider.tsx +++ b/ui/components/providers/radio-group-provider.tsx @@ -5,6 +5,7 @@ import { Control, Controller } from "react-hook-form"; import { z } from "zod"; import { SearchInput } from "@/components/shadcn"; +import { FormMessage } from "@/components/shadcn/form"; import { cn } from "@/lib/utils"; import { addProviderFormSchema } from "@/types"; @@ -26,7 +27,6 @@ import { OracleCloudProviderBadge, VercelProviderBadge, } from "../icons/providers-badge"; -import { FormMessage } from "../ui/form"; const PROVIDERS = [ { @@ -169,22 +169,22 @@ export const RadioGroupProvider: FC = ({ onClick={() => field.onChange(provider.value)} className={cn( "flex min-h-[72px] w-full items-center gap-4 rounded-lg border px-3 py-2.5 text-left transition-colors", - "focus-visible:border-primary focus-visible:outline-none", + "focus-visible:border-button-primary focus-visible:outline-none", isSelected - ? "border-primary bg-bg-neutral-tertiary" - : "border-border-neutral-primary bg-bg-neutral-tertiary hover:border-primary", + ? "border-button-primary bg-bg-neutral-tertiary" + : "border-border-neutral-primary bg-bg-neutral-tertiary hover:border-button-primary", isInvalid && "border-bg-fail", )} >
      {isSelected && ( -
      +
      )}
      - + {provider.label}
      diff --git a/ui/components/providers/table/column-providers.tsx b/ui/components/providers/table/column-providers.tsx index ec5766f491..d759936e15 100644 --- a/ui/components/providers/table/column-providers.tsx +++ b/ui/components/providers/table/column-providers.tsx @@ -14,11 +14,11 @@ import type { ProviderWizardInitialData, } from "@/components/providers/wizard/types"; import { Checkbox } from "@/components/shadcn/checkbox/checkbox"; -import { CodeSnippet } from "@/components/ui/code-snippet/code-snippet"; -import { DateWithTime, EntityInfo } from "@/components/ui/entities"; -import { DataTableColumnHeader } from "@/components/ui/table"; -import { DataTableExpandAllToggle } from "@/components/ui/table/data-table-expand-all-toggle"; -import { DataTableExpandableCell } from "@/components/ui/table/data-table-expandable-cell"; +import { CodeSnippet } from "@/components/shadcn/code-snippet/code-snippet"; +import { DateWithTime, EntityInfo } from "@/components/shadcn/entities"; +import { DataTableColumnHeader } from "@/components/shadcn/table"; +import { DataTableExpandAllToggle } from "@/components/shadcn/table/data-table-expand-all-toggle"; +import { DataTableExpandableCell } from "@/components/shadcn/table/data-table-expandable-cell"; import { isProvidersOrganizationRow, PROVIDERS_GROUP_KIND, @@ -47,7 +47,7 @@ const OrganizationIcon = ({ groupKind }: { groupKind: string }) => { const ProviderStatusCell = ({ connected }: { connected: boolean | null }) => { if (connected === true) { return ( -
      +
      Connected
      diff --git a/ui/components/providers/table/data-table-row-actions.test.tsx b/ui/components/providers/table/data-table-row-actions.test.tsx index d72874af31..08d74376ea 100644 --- a/ui/components/providers/table/data-table-row-actions.test.tsx +++ b/ui/components/providers/table/data-table-row-actions.test.tsx @@ -32,7 +32,8 @@ vi.mock("../forms/edit-name-form", () => ({ EditNameForm: () => null, })); -vi.mock("@/components/ui", () => ({ +vi.mock("@/components/shadcn", async (importOriginal) => ({ + ...(await importOriginal>()), useToast: () => ({ toast: vi.fn() }), })); diff --git a/ui/components/providers/table/data-table-row-actions.tsx b/ui/components/providers/table/data-table-row-actions.tsx index 9b531f272a..969f1a63e9 100644 --- a/ui/components/providers/table/data-table-row-actions.tsx +++ b/ui/components/providers/table/data-table-row-actions.tsx @@ -11,13 +11,13 @@ import { OrgWizardInitialData, ProviderWizardInitialData, } from "@/components/providers/wizard/types"; +import { useToast } from "@/components/shadcn"; import { ActionDropdown, ActionDropdownDangerZone, ActionDropdownItem, } from "@/components/shadcn/dropdown"; import { Modal } from "@/components/shadcn/modal"; -import { useToast } from "@/components/ui"; import { runWithConcurrencyLimit } from "@/lib/concurrency"; import { testProviderConnection } from "@/lib/provider-helpers"; import { ORG_SETUP_PHASE, ORG_WIZARD_STEP } from "@/types/organizations"; diff --git a/ui/components/providers/table/skeleton-table-provider.tsx b/ui/components/providers/table/skeleton-table-provider.tsx index 1fe557b808..ac99be94bd 100644 --- a/ui/components/providers/table/skeleton-table-provider.tsx +++ b/ui/components/providers/table/skeleton-table-provider.tsx @@ -57,7 +57,7 @@ export const SkeletonTableProviders = () => { const rows = 10; return ( -
      +
      {/* Toolbar: Search + Total entries */}
      diff --git a/ui/components/providers/wizard/steps/launch-step.test.tsx b/ui/components/providers/wizard/steps/launch-step.test.tsx index 1f33955849..ec6bbfe697 100644 --- a/ui/components/providers/wizard/steps/launch-step.test.tsx +++ b/ui/components/providers/wizard/steps/launch-step.test.tsx @@ -18,7 +18,8 @@ vi.mock("@/actions/scans", () => ({ scanOnDemand: scanOnDemandMock, })); -vi.mock("@/components/ui", () => ({ +vi.mock("@/components/shadcn", async (importOriginal) => ({ + ...(await importOriginal>()), ToastAction: ({ children, ...props }: ComponentProps<"button">) => ( ), diff --git a/ui/components/providers/wizard/steps/launch-step.tsx b/ui/components/providers/wizard/steps/launch-step.tsx index 1e63f6700d..064d281b22 100644 --- a/ui/components/providers/wizard/steps/launch-step.tsx +++ b/ui/components/providers/wizard/steps/launch-step.tsx @@ -4,6 +4,7 @@ import Link from "next/link"; import { useEffect, useRef, useState } from "react"; import { scanOnDemand, scheduleDaily } from "@/actions/scans"; +import { ToastAction, useToast } from "@/components/shadcn"; import { Select, SelectContent, @@ -13,7 +14,6 @@ import { } from "@/components/shadcn/select/select"; import { Spinner } from "@/components/shadcn/spinner/spinner"; import { TreeStatusIcon } from "@/components/shadcn/tree-view/tree-status-icon"; -import { ToastAction, useToast } from "@/components/ui"; import { useProviderWizardStore } from "@/store/provider-wizard/store"; import { SCAN_JOBS_TAB } from "@/types"; import { TREE_ITEM_STATUS } from "@/types/tree"; diff --git a/ui/components/providers/workflow/credentials-role-helper.tsx b/ui/components/providers/workflow/credentials-role-helper.tsx index 0ded59beee..12e0bd3502 100644 --- a/ui/components/providers/workflow/credentials-role-helper.tsx +++ b/ui/components/providers/workflow/credentials-role-helper.tsx @@ -2,7 +2,7 @@ import { IdIcon } from "@/components/icons"; import { Button } from "@/components/shadcn"; -import { CodeSnippet } from "@/components/ui/code-snippet/code-snippet"; +import { CodeSnippet } from "@/components/shadcn/code-snippet/code-snippet"; import { IntegrationType } from "@/types/integrations"; interface CredentialsRoleHelperProps { @@ -92,7 +92,7 @@ export const CredentialsRoleHelper = ({
      - + External ID: } /> diff --git a/ui/components/providers/workflow/forms/base-credentials-form.tsx b/ui/components/providers/workflow/forms/base-credentials-form.tsx index 227a2eada6..8bedaa2514 100644 --- a/ui/components/providers/workflow/forms/base-credentials-form.tsx +++ b/ui/components/providers/workflow/forms/base-credentials-form.tsx @@ -5,8 +5,8 @@ import { useEffect } from "react"; import { Control, UseFormSetValue } from "react-hook-form"; import { Button } from "@/components/shadcn"; +import { Form } from "@/components/shadcn/form"; import { Separator } from "@/components/shadcn/separator/separator"; -import { Form } from "@/components/ui/form"; import { useCredentialsForm } from "@/hooks/use-credentials-form"; import { getAWSCredentialsTemplateLinks } from "@/lib"; import { ProviderCredentialFields } from "@/lib/provider-credentials/provider-credential-fields"; diff --git a/ui/components/providers/workflow/forms/connect-account-form.tsx b/ui/components/providers/workflow/forms/connect-account-form.tsx index c4a242a5c3..da4cae4638 100644 --- a/ui/components/providers/workflow/forms/connect-account-form.tsx +++ b/ui/components/providers/workflow/forms/connect-account-form.tsx @@ -12,8 +12,8 @@ import { AwsMethodSelector } from "@/components/providers/organizations/aws-meth import { WizardInputField } from "@/components/providers/workflow/forms/fields"; import { ProviderTitleDocs } from "@/components/providers/workflow/provider-title-docs"; import { Button } from "@/components/shadcn"; -import { useToast } from "@/components/ui"; -import { Form } from "@/components/ui/form"; +import { useToast } from "@/components/shadcn"; +import { Form } from "@/components/shadcn/form"; import { addProviderFormSchema, ApiError, ProviderType } from "@/types"; import { RadioGroupProvider } from "../../radio-group-provider"; diff --git a/ui/components/providers/workflow/forms/fields/wizard-input-field.tsx b/ui/components/providers/workflow/forms/fields/wizard-input-field.tsx index b769bd1461..bcfd945807 100644 --- a/ui/components/providers/workflow/forms/fields/wizard-input-field.tsx +++ b/ui/components/providers/workflow/forms/fields/wizard-input-field.tsx @@ -4,8 +4,8 @@ import { Icon } from "@iconify/react"; import { InputHTMLAttributes, useState } from "react"; import { Control, FieldPath, FieldValues } from "react-hook-form"; +import { FormControl, FormField, FormMessage } from "@/components/shadcn/form"; import { Input } from "@/components/shadcn/input/input"; -import { FormControl, FormField, FormMessage } from "@/components/ui/form"; import { cn } from "@/lib/utils"; interface WizardInputFieldProps { @@ -142,7 +142,7 @@ export const WizardInputField = ({ ), @@ -46,7 +46,7 @@ vi.mock("@/components/shadcn/modal", () => ({ ) : null, })); -vi.mock("@/components/ui/entities", () => ({ +vi.mock("@/components/shadcn/entities", () => ({ EntityInfo: ({ entityAlias, entityId, diff --git a/ui/components/scans/launch-scan-modal.tsx b/ui/components/scans/launch-scan-modal.tsx index dd4b049c87..f39d0dabe5 100644 --- a/ui/components/scans/launch-scan-modal.tsx +++ b/ui/components/scans/launch-scan-modal.tsx @@ -10,9 +10,9 @@ import { z } from "zod"; import { scanOnDemand } from "@/actions/scans"; import { AccountsSelector } from "@/app/(prowler)/_overview/_components/accounts-selector"; import { Field, FieldError, FieldLabel, Input } from "@/components/shadcn"; +import { FormButtons } from "@/components/shadcn/form"; import { Modal } from "@/components/shadcn/modal"; -import { FormButtons } from "@/components/ui/form"; -import { toast, ToastAction } from "@/components/ui/toast"; +import { toast, ToastAction } from "@/components/shadcn/toast"; import { SCAN_JOBS_TAB } from "@/types"; import type { ProviderProps } from "@/types/providers"; diff --git a/ui/components/scans/scan-error-details-modal.test.tsx b/ui/components/scans/scan-error-details-modal.test.tsx index 1474e7eea1..f7993fc632 100644 --- a/ui/components/scans/scan-error-details-modal.test.tsx +++ b/ui/components/scans/scan-error-details-modal.test.tsx @@ -6,7 +6,7 @@ import { type ScanErrorDetailsState, } from "./scan-error-details-modal"; -vi.mock("@/components/ui/code-snippet/code-snippet", () => ({ +vi.mock("@/components/shadcn/code-snippet/code-snippet", () => ({ CodeSnippet: ({ value, formatter, diff --git a/ui/components/scans/scan-error-details-view.test.tsx b/ui/components/scans/scan-error-details-view.test.tsx index 145f84d529..30fe5ed83e 100644 --- a/ui/components/scans/scan-error-details-view.test.tsx +++ b/ui/components/scans/scan-error-details-view.test.tsx @@ -5,7 +5,7 @@ import type { ScanErrorDetails } from "@/actions/task/task.adapter"; import { ScanErrorDetailsView } from "./scan-error-details-view"; -vi.mock("@/components/ui/code-snippet/code-snippet", () => ({ +vi.mock("@/components/shadcn/code-snippet/code-snippet", () => ({ CodeSnippet: ({ value, formatter, diff --git a/ui/components/scans/scan-error-details-view.tsx b/ui/components/scans/scan-error-details-view.tsx index 8670e20ba4..b6e9b641e9 100644 --- a/ui/components/scans/scan-error-details-view.tsx +++ b/ui/components/scans/scan-error-details-view.tsx @@ -2,7 +2,7 @@ import type { ScanErrorDetails } from "@/actions/task/task.adapter"; import { Field, FieldLabel, LabeledField } from "@/components/shadcn"; -import { CodeSnippet } from "@/components/ui/code-snippet/code-snippet"; +import { CodeSnippet } from "@/components/shadcn/code-snippet/code-snippet"; interface ScanErrorDetailsViewProps { details: ScanErrorDetails; diff --git a/ui/components/scans/scans-filter-bar.test.tsx b/ui/components/scans/scans-filter-bar.test.tsx index f629e0291b..bf82ca4d84 100644 --- a/ui/components/scans/scans-filter-bar.test.tsx +++ b/ui/components/scans/scans-filter-bar.test.tsx @@ -9,7 +9,8 @@ vi.mock("@/components/filters/provider-account-selectors", () => ({ ProviderAccountSelectors: () =>
      Provider account selectors
      , })); -vi.mock("@/components/shadcn", () => ({ +vi.mock("@/components/shadcn", async (importOriginal) => ({ + ...(await importOriginal>()), Select: ({ children }: { children: React.ReactNode }) => (
      {children}
      ), diff --git a/ui/components/scans/table/cells/account-cell.tsx b/ui/components/scans/table/cells/account-cell.tsx index ecc7bcc987..104e94610e 100644 --- a/ui/components/scans/table/cells/account-cell.tsx +++ b/ui/components/scans/table/cells/account-cell.tsx @@ -1,6 +1,6 @@ "use client"; -import { EntityInfo } from "@/components/ui/entities"; +import { EntityInfo } from "@/components/shadcn/entities"; import type { ProviderType, ScanProps } from "@/types"; export function AccountCell({ scan }: { scan: ScanProps }) { diff --git a/ui/components/scans/table/cells/scan-info-cell.tsx b/ui/components/scans/table/cells/scan-info-cell.tsx index aa61a118d0..9fa92f11ef 100644 --- a/ui/components/scans/table/cells/scan-info-cell.tsx +++ b/ui/components/scans/table/cells/scan-info-cell.tsx @@ -1,7 +1,7 @@ "use client"; import { getScanAlias } from "@/components/scans/scans.utils"; -import { EntityInfo } from "@/components/ui/entities"; +import { EntityInfo } from "@/components/shadcn/entities"; import type { ScanProps } from "@/types"; export function ScanInfoCell({ scan }: { scan: ScanProps }) { diff --git a/ui/components/scans/table/cells/schedule-cell.tsx b/ui/components/scans/table/cells/schedule-cell.tsx index 7e70dde52d..c24f6b6a56 100644 --- a/ui/components/scans/table/cells/schedule-cell.tsx +++ b/ui/components/scans/table/cells/schedule-cell.tsx @@ -1,7 +1,7 @@ "use client"; import { getScanScheduleLabel } from "@/components/scans/scans.utils"; -import { DateWithTime } from "@/components/ui/entities"; +import { DateWithTime } from "@/components/shadcn/entities"; import type { ScanProps } from "@/types"; export function ScheduleCell({ scan }: { scan: ScanProps }) { diff --git a/ui/components/scans/table/scan-jobs-columns.test.tsx b/ui/components/scans/table/scan-jobs-columns.test.tsx index 03f22cecc0..8b369de54d 100644 --- a/ui/components/scans/table/scan-jobs-columns.test.tsx +++ b/ui/components/scans/table/scan-jobs-columns.test.tsx @@ -4,14 +4,15 @@ import { describe, expect, it, vi } from "vitest"; import type { ScanProps } from "@/types"; -vi.mock("@/components/shadcn", () => ({ +vi.mock("@/components/shadcn", async (importOriginal) => ({ + ...(await importOriginal>()), Badge: ({ children }: { children: React.ReactNode }) => ( {children} ), Progress: () =>
      , })); -vi.mock("@/components/ui/entities", () => ({ +vi.mock("@/components/shadcn/entities", () => ({ DateWithTime: () =>