feat(ui): migrate from HeroUI to shadcn/ui (#11532)

This commit is contained in:
Alejandro Bailo
2026-07-08 16:57:02 +02:00
committed by GitHub
parent c665005790
commit 52875b5c7c
519 changed files with 4814 additions and 7013 deletions
@@ -13,11 +13,11 @@ import { z } from "zod";
import { createSamlConfig, updateSamlConfig } from "@/actions/integrations";
import { AddIcon } from "@/components/icons";
import { Button, Card, CardContent, CardHeader } from "@/components/shadcn";
import { useToast } from "@/components/ui";
import { CodeSnippet } from "@/components/ui/code-snippet/code-snippet";
import { CustomServerInput } from "@/components/ui/custom";
import { CustomLink } from "@/components/ui/custom/custom-link";
import { FormButtons } from "@/components/ui/form";
import { useToast } from "@/components/shadcn";
import { CodeSnippet } from "@/components/shadcn/code-snippet/code-snippet";
import { CustomServerInput } from "@/components/shadcn/custom";
import { CustomLink } from "@/components/shadcn/custom/custom-link";
import { FormButtons } from "@/components/shadcn/form";
import { useRuntimeConfig } from "@/hooks/use-runtime-config";
const validateXMLContent = (
@@ -0,0 +1,53 @@
import { render, screen, within } from "@testing-library/react";
import { describe, expect, it, vi } from "vitest";
import { SamlIntegrationCard } from "./saml-integration-card";
vi.mock("@/actions/integrations", () => ({
deleteSamlConfig: vi.fn(),
}));
vi.mock("./saml-config-form", () => ({
SamlConfigForm: () => <div>SAML form</div>,
}));
vi.mock("@/components/shadcn", async (importOriginal) => ({
...(await importOriginal<Record<string, unknown>>()),
useToast: () => ({ toast: vi.fn() }),
}));
describe("SamlIntegrationCard", () => {
it("shows the disabled status as a header badge without a status label", () => {
// When
render(<SamlIntegrationCard />);
// Then
const title = screen.getByRole("heading", {
name: "SAML SSO Integration",
});
const header = title.closest('[data-slot="card-header"]');
expect(header).toBeInTheDocument();
expect(header).not.toHaveTextContent("Status:");
expect(within(header as HTMLElement).getByText("Disabled")).toHaveAttribute(
"data-slot",
"badge",
);
});
it("shows the enabled status as a success header badge", () => {
// When
render(<SamlIntegrationCard samlConfig={{ id: "saml-1" }} />);
// Then
const title = screen.getByRole("heading", {
name: "SAML SSO Integration",
});
const header = title.closest('[data-slot="card-header"]');
const badge = within(header as HTMLElement).getByText("Enabled");
expect(header).not.toHaveTextContent("Status:");
expect(badge).toHaveAttribute("data-slot", "badge");
expect(badge).toHaveClass("bg-bg-pass-secondary");
});
});
@@ -1,15 +1,21 @@
"use client";
import { CheckIcon, Trash2Icon } from "lucide-react";
import { Trash2Icon } from "lucide-react";
import { useState } from "react";
import { deleteSamlConfig } from "@/actions/integrations";
import { Button } from "@/components/shadcn";
import {
Badge,
Button,
Card,
CardAction,
CardContent,
CardHeader,
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 { Card, CardContent, CardHeader } from "../../shadcn";
import { SamlConfigForm } from "./saml-config-form";
export const SamlIntegrationCard = ({ samlConfig }: { samlConfig?: any }) => {
@@ -18,6 +24,7 @@ export const SamlIntegrationCard = ({ samlConfig }: { samlConfig?: any }) => {
const [isDeleting, setIsDeleting] = useState(false);
const { toast } = useToast();
const id = samlConfig?.id;
const statusLabel = id ? "Enabled" : "Disabled";
const handleRemoveSaml = async () => {
if (!id) return;
@@ -72,7 +79,7 @@ export const SamlIntegrationCard = ({ samlConfig }: { samlConfig?: any }) => {
size="md"
>
<div className="flex flex-col gap-4">
<p className="text-default-600 text-sm">
<p className="text-text-neutral-secondary text-sm">
Are you sure you want to remove the SAML SSO configuration? Users
will no longer be able to sign in using SAML.
</p>
@@ -100,13 +107,10 @@ export const SamlIntegrationCard = ({ samlConfig }: { samlConfig?: any }) => {
</div>
</Modal>
<Card variant="base" padding="lg">
<Card variant="inner" padding="none" className="gap-4 p-4 md:p-5">
<CardHeader>
<div className="flex flex-col gap-1">
<div className="flex items-center gap-2">
<h4 className="text-lg font-bold">SAML SSO Integration</h4>
{id && <CheckIcon className="text-button-primary" size={20} />}
</div>
<h4 className="text-lg font-bold">SAML SSO Integration</h4>
<p className="text-xs text-gray-500">
{id ? (
"SAML Single Sign-On is enabled for this organization"
@@ -120,30 +124,25 @@ export const SamlIntegrationCard = ({ samlConfig }: { samlConfig?: any }) => {
)}
</p>
</div>
<CardAction className="pt-2">
<Badge variant={id ? "success" : "outline"}>{statusLabel}</Badge>
</CardAction>
</CardHeader>
<CardContent>
<div className="flex items-center justify-between">
<div className="text-sm">
<span className="font-medium">Status: </span>
<span className={id ? "text-button-primary" : "text-gray-500"}>
{id ? "Enabled" : "Disabled"}
</span>
</div>
<div className="flex gap-2">
<Button size="sm" onClick={() => setIsSamlModalOpen(true)}>
{id ? "Update" : "Enable"}
<div className="flex justify-end gap-2">
<Button size="sm" onClick={() => setIsSamlModalOpen(true)}>
{id ? "Update" : "Enable"}
</Button>
{id && (
<Button
size="sm"
variant="destructive"
onClick={() => setIsDeleteModalOpen(true)}
>
<Trash2Icon size={16} />
Remove
</Button>
{id && (
<Button
size="sm"
variant="destructive"
onClick={() => setIsDeleteModalOpen(true)}
>
<Trash2Icon size={16} />
Remove
</Button>
)}
</div>
)}
</div>
</CardContent>
</Card>