# Component Library - ColaFlow Enterprise Features ## Document Overview This document catalogs all reusable React components for ColaFlow's enterprise features, including props, usage examples, and design guidelines. **UI Framework**: shadcn/ui + Tailwind CSS 4 + Radix UI --- ## Table of Contents 1. [Authentication Components](#authentication-components) 2. [Settings Components](#settings-components) 3. [MCP Token Components](#mcp-token-components) 4. [Form Components](#form-components) 5. [Utility Components](#utility-components) 6. [Design Tokens](#design-tokens) --- ## Authentication Components ### 1. SsoButton **Purpose**: Displays SSO provider button with logo and loading state. **File**: `components/auth/SsoButton.tsx` **Props**: ```typescript interface SsoButtonProps { provider: 'AzureAD' | 'Google' | 'Okta' | 'SAML'; onClick: () => void; loading?: boolean; disabled?: boolean; fullWidth?: boolean; size?: 'sm' | 'md' | 'lg'; } ``` **Implementation**: ```tsx import { Button } from '@/components/ui/button'; import Image from 'next/image'; export function SsoButton({ provider, onClick, loading = false, disabled = false, fullWidth = true, size = 'md', }: SsoButtonProps) { const providerConfig = { AzureAD: { label: 'Continue with Microsoft', logo: '/logos/microsoft.svg', bgColor: 'bg-[#2F2F2F]', hoverColor: 'hover:bg-[#1F1F1F]', textColor: 'text-white', }, Google: { label: 'Continue with Google', logo: '/logos/google.svg', bgColor: 'bg-white', hoverColor: 'hover:bg-gray-50', textColor: 'text-gray-700', border: 'border border-gray-300', }, Okta: { label: 'Continue with Okta', logo: '/logos/okta.svg', bgColor: 'bg-[#007DC1]', hoverColor: 'hover:bg-[#0062A3]', textColor: 'text-white', }, SAML: { label: 'Continue with SSO', logo: '/logos/saml.svg', bgColor: 'bg-indigo-600', hoverColor: 'hover:bg-indigo-700', textColor: 'text-white', }, }; const config = providerConfig[provider]; const sizeClasses = { sm: 'h-9 px-3 text-sm', md: 'h-11 px-4 text-base', lg: 'h-13 px-6 text-lg', }; return ( ); } ``` **Usage**: ```tsx loginWithSso('AzureAD')} loading={isLoading} /> ``` --- ### 2. TenantSlugInput **Purpose**: Input field with real-time slug validation (available/taken). **File**: `components/auth/TenantSlugInput.tsx` **Props**: ```typescript interface TenantSlugInputProps { value: string; onChange: (value: string) => void; error?: string; disabled?: boolean; } ``` **Implementation**: ```tsx import { Input } from '@/components/ui/input'; import { useCheckSlug } from '@/hooks/tenants/useCheckSlug'; import { CheckCircle2, XCircle, Loader2 } from 'lucide-react'; export function TenantSlugInput({ value, onChange, error, disabled = false, }: TenantSlugInputProps) { const { data, isLoading } = useCheckSlug(value, value.length >= 3); const showValidation = value.length >= 3 && !error; return (
{ // Only allow lowercase letters, numbers, and hyphens const cleaned = e.target.value.toLowerCase().replace(/[^a-z0-9-]/g, ''); onChange(cleaned); }} placeholder="your-company" disabled={disabled} className={` pr-10 ${error ? 'border-red-500 focus-visible:ring-red-500' : ''} ${showValidation && data?.available ? 'border-green-500' : ''} ${showValidation && data?.available === false ? 'border-red-500' : ''} `} /> {/* Validation Icon */}
{isLoading && ( )} {showValidation && !isLoading && data?.available === true && ( )} {showValidation && !isLoading && data?.available === false && ( )}
{/* Validation Message */} {showValidation && !isLoading && (

{data?.available ? '✓ This slug is available' : '✗ This slug is already taken'}

)} {/* Error Message */} {error &&

{error}

} {/* Helper Text */}

Your organization URL: {value || 'your-company'}.colaflow.com

); } ``` **Usage**: ```tsx ``` --- ### 3. PasswordStrengthIndicator **Purpose**: Visual password strength meter using zxcvbn. **File**: `components/auth/PasswordStrengthIndicator.tsx` **Props**: ```typescript interface PasswordStrengthIndicatorProps { password: string; show?: boolean; } ``` **Implementation**: ```tsx import { useMemo } from 'react'; import zxcvbn from 'zxcvbn'; export function PasswordStrengthIndicator({ password, show = true, }: PasswordStrengthIndicatorProps) { const result = useMemo(() => { if (!password) return null; return zxcvbn(password); }, [password]); if (!show || !result) return null; const score = result.score; // 0-4 const strength = ['Very Weak', 'Weak', 'Fair', 'Good', 'Strong'][score]; const color = ['red', 'orange', 'yellow', 'lime', 'green'][score]; const barWidth = `${(score + 1) * 20}%`; return (
{/* Strength Bar */}
{/* Strength Label */}
Password strength: {strength} {score < 3 && ( {result.feedback.warning || 'Try a longer password'} )}
{/* Suggestions */} {result.feedback.suggestions.length > 0 && score < 3 && (
    {result.feedback.suggestions.map((suggestion, index) => (
  • • {suggestion}
  • ))}
)}
); } ``` **Usage**: ```tsx setPassword(e.target.value)} /> ``` --- ## Settings Components ### 4. SsoConfigForm **Purpose**: Dynamic SSO configuration form (OIDC/SAML). **File**: `components/settings/SsoConfigForm.tsx` **Props**: ```typescript interface SsoConfigFormProps { initialValues?: SsoConfig; onSubmit: (values: SsoConfig) => Promise; isLoading?: boolean; } ``` **Implementation**: ```tsx import { useState } from 'react'; import { useForm } from 'react-hook-form'; import { zodResolver } from '@hookform/resolvers/zod'; import { z } from 'zod'; import { Select, SelectContent, SelectItem, SelectTrigger, SelectValue } from '@/components/ui/select'; import { Input } from '@/components/ui/input'; import { Textarea } from '@/components/ui/textarea'; import { Button } from '@/components/ui/button'; import { Switch } from '@/components/ui/switch'; import { Form, FormField, FormItem, FormLabel, FormControl, FormMessage } from '@/components/ui/form'; // Validation schema const ssoConfigSchema = z.object({ provider: z.enum(['AzureAD', 'Google', 'Okta', 'GenericSaml']), authority: z.string().url().optional(), clientId: z.string().optional(), clientSecret: z.string().optional(), metadataUrl: z.string().url().optional(), entityId: z.string().optional(), signOnUrl: z.string().url().optional(), certificate: z.string().optional(), autoProvisionUsers: z.boolean().default(true), allowedDomains: z.string().optional(), }); export function SsoConfigForm({ initialValues, onSubmit, isLoading = false, }: SsoConfigFormProps) { const [provider, setProvider] = useState(initialValues?.provider || 'AzureAD'); const form = useForm({ resolver: zodResolver(ssoConfigSchema), defaultValues: initialValues || { provider: 'AzureAD', autoProvisionUsers: true, }, }); const isSaml = provider === 'GenericSaml'; return (
{/* Provider Selection */} ( SSO Provider )} /> {/* OIDC Fields */} {!isSaml && ( <> ( Authority / Issuer URL * )} /> ( Client ID * )} /> ( Client Secret * )} /> ( Metadata URL (Optional) )} /> )} {/* SAML Fields */} {isSaml && ( <> ( Entity ID * )} /> ( Sign-On URL * )} /> ( X.509 Certificate *