Add credentials settings page, audit log page, CRUD dialog components (create, view, edit, rotate), credential card, dialog UI component, and API client for the M7-CredentialSecurity feature. Refs #346 Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
129 lines
3.6 KiB
TypeScript
129 lines
3.6 KiB
TypeScript
import * as React from "react";
|
|
import { X } from "lucide-react";
|
|
|
|
export interface DialogProps {
|
|
open?: boolean;
|
|
onOpenChange?: (open: boolean) => void;
|
|
children?: React.ReactNode;
|
|
}
|
|
|
|
export interface DialogTriggerProps {
|
|
children?: React.ReactNode;
|
|
asChild?: boolean;
|
|
}
|
|
|
|
export interface DialogContentProps {
|
|
children?: React.ReactNode;
|
|
className?: string;
|
|
}
|
|
|
|
export interface DialogHeaderProps {
|
|
children?: React.ReactNode;
|
|
className?: string;
|
|
}
|
|
|
|
export interface DialogFooterProps {
|
|
children?: React.ReactNode;
|
|
className?: string;
|
|
}
|
|
|
|
export interface DialogTitleProps {
|
|
children?: React.ReactNode;
|
|
className?: string;
|
|
}
|
|
|
|
export interface DialogDescriptionProps {
|
|
children?: React.ReactNode;
|
|
className?: string;
|
|
}
|
|
|
|
const DialogContext = React.createContext<{
|
|
open?: boolean;
|
|
onOpenChange?: (open: boolean) => void;
|
|
}>({});
|
|
|
|
export function Dialog({ open, onOpenChange, children }: DialogProps): React.JSX.Element {
|
|
const contextValue: { open?: boolean; onOpenChange?: (open: boolean) => void } = {};
|
|
if (open !== undefined) {
|
|
contextValue.open = open;
|
|
}
|
|
if (onOpenChange !== undefined) {
|
|
contextValue.onOpenChange = onOpenChange;
|
|
}
|
|
|
|
return <DialogContext.Provider value={contextValue}>{children}</DialogContext.Provider>;
|
|
}
|
|
|
|
export function DialogTrigger({ children, asChild }: DialogTriggerProps): React.JSX.Element {
|
|
const { onOpenChange } = React.useContext(DialogContext);
|
|
|
|
if (asChild && React.isValidElement(children)) {
|
|
return React.cloneElement(children, {
|
|
onClick: () => onOpenChange?.(true),
|
|
} as React.HTMLAttributes<HTMLElement>);
|
|
}
|
|
|
|
return <div onClick={() => onOpenChange?.(true)}>{children}</div>;
|
|
}
|
|
|
|
export function DialogContent({
|
|
children,
|
|
className = "",
|
|
}: DialogContentProps): React.JSX.Element | null {
|
|
const { open, onOpenChange } = React.useContext(DialogContext);
|
|
|
|
if (!open) return null;
|
|
|
|
return (
|
|
<div className="fixed inset-0 z-50 flex items-center justify-center">
|
|
{/* Overlay */}
|
|
<div className="fixed inset-0 bg-black/50" onClick={() => onOpenChange?.(false)} />
|
|
|
|
{/* Dialog Content */}
|
|
<div
|
|
className={`relative z-50 w-full max-w-lg rounded-lg bg-white p-6 shadow-lg ${className}`}
|
|
>
|
|
{/* Close Button */}
|
|
<button
|
|
onClick={() => onOpenChange?.(false)}
|
|
className="absolute right-4 top-4 rounded-sm opacity-70 hover:opacity-100 transition-opacity"
|
|
>
|
|
<X className="h-4 w-4" />
|
|
<span className="sr-only">Close</span>
|
|
</button>
|
|
|
|
{children}
|
|
</div>
|
|
</div>
|
|
);
|
|
}
|
|
|
|
export function DialogHeader({ children, className = "" }: DialogHeaderProps): React.JSX.Element {
|
|
return <div className={`mb-4 ${className}`}>{children}</div>;
|
|
}
|
|
|
|
export function DialogFooter({ children, className = "" }: DialogFooterProps): React.JSX.Element {
|
|
return <div className={`mt-4 flex justify-end gap-2 ${className}`}>{children}</div>;
|
|
}
|
|
|
|
export function DialogTitle({ children, className = "" }: DialogTitleProps): React.JSX.Element {
|
|
return <h2 className={`text-lg font-semibold ${className}`}>{children}</h2>;
|
|
}
|
|
|
|
export function DialogDescription({
|
|
children,
|
|
className = "",
|
|
}: DialogDescriptionProps): React.JSX.Element {
|
|
return <p className={`text-sm text-gray-600 ${className}`}>{children}</p>;
|
|
}
|
|
|
|
export const DialogPortal = ({ children }: { children: React.ReactNode }): React.JSX.Element => (
|
|
<>{children}</>
|
|
);
|
|
export const DialogOverlay = ({ children }: { children: React.ReactNode }): React.JSX.Element => (
|
|
<>{children}</>
|
|
);
|
|
export const DialogClose = ({ children }: { children: React.ReactNode }): React.JSX.Element => (
|
|
<>{children}</>
|
|
);
|