@burdenoff/microfe-admin 2026.610.1 → 2026.625.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (81) hide show
  1. package/dist/admin/components/AccessDenied.js +2 -2
  2. package/dist/admin/components/AccessDenied.js.map +1 -1
  3. package/dist/admin/components/ActivityFeed.js +4 -4
  4. package/dist/admin/components/ActivityFeed.js.map +1 -1
  5. package/dist/admin/components/Charts.js +4 -4
  6. package/dist/admin/components/Charts.js.map +1 -1
  7. package/dist/admin/components/ConfirmDialog.js +6 -6
  8. package/dist/admin/components/ConfirmDialog.js.map +1 -1
  9. package/dist/admin/components/DataTable.js +8 -8
  10. package/dist/admin/components/DataTable.js.map +1 -1
  11. package/dist/admin/components/FormSheet.js +7 -7
  12. package/dist/admin/components/FormSheet.js.map +1 -1
  13. package/dist/admin/components/MetricCard.js +43 -40
  14. package/dist/admin/components/MetricCard.js.map +1 -1
  15. package/dist/admin/components/PageLayout.js +28 -22
  16. package/dist/admin/components/PageLayout.js.map +1 -1
  17. package/dist/admin/components/PermissionGuard.js +1 -1
  18. package/dist/admin/components/PermissionGuard.js.map +1 -1
  19. package/dist/admin/components/RowActions.js +2 -2
  20. package/dist/admin/components/RowActions.js.map +1 -1
  21. package/dist/admin/components/TenantMembersPanel.js +15 -15
  22. package/dist/admin/components/TenantMembersPanel.js.map +1 -1
  23. package/dist/admin/components/TenantSsoPanel.js +14 -14
  24. package/dist/admin/components/TenantSsoPanel.js.map +1 -1
  25. package/dist/admin/components/Toast.js +9 -9
  26. package/dist/admin/components/Toast.js.map +1 -1
  27. package/dist/admin/components/forms/SubscriptionForm.js +10 -10
  28. package/dist/admin/components/forms/SubscriptionForm.js.map +1 -1
  29. package/dist/admin/components/forms/TenantForm.js +8 -8
  30. package/dist/admin/components/forms/TenantForm.js.map +1 -1
  31. package/dist/admin/components/forms/TicketForm.js +2 -2
  32. package/dist/admin/components/forms/TicketForm.js.map +1 -1
  33. package/dist/admin/components/forms/UserForm.js +8 -8
  34. package/dist/admin/components/forms/UserForm.js.map +1 -1
  35. package/dist/admin/components/ui.js +58 -51
  36. package/dist/admin/components/ui.js.map +1 -1
  37. package/dist/admin/constants/index.js +8 -8
  38. package/dist/admin/constants/index.js.map +1 -1
  39. package/dist/admin/pages/AuditLogsPage.js +10 -8
  40. package/dist/admin/pages/AuditLogsPage.js.map +1 -1
  41. package/dist/admin/pages/BillingPage.js +51 -43
  42. package/dist/admin/pages/BillingPage.js.map +1 -1
  43. package/dist/admin/pages/CommunicationsPage.js +5 -2
  44. package/dist/admin/pages/CommunicationsPage.js.map +1 -1
  45. package/dist/admin/pages/ContentPagesPage.js +2 -0
  46. package/dist/admin/pages/ContentPagesPage.js.map +1 -1
  47. package/dist/admin/pages/DashboardPage.js +7 -4
  48. package/dist/admin/pages/DashboardPage.js.map +1 -1
  49. package/dist/admin/pages/FeatureFlagsPage.js +6 -4
  50. package/dist/admin/pages/FeatureFlagsPage.js.map +1 -1
  51. package/dist/admin/pages/OrganizationsListPage.js +8 -6
  52. package/dist/admin/pages/OrganizationsListPage.js.map +1 -1
  53. package/dist/admin/pages/ProductsPage.js +10 -7
  54. package/dist/admin/pages/ProductsPage.js.map +1 -1
  55. package/dist/admin/pages/ReferralsPage.js +27 -23
  56. package/dist/admin/pages/ReferralsPage.js.map +1 -1
  57. package/dist/admin/pages/RolesPermissionsPage.js +11 -8
  58. package/dist/admin/pages/RolesPermissionsPage.js.map +1 -1
  59. package/dist/admin/pages/SREPage.js +12 -8
  60. package/dist/admin/pages/SREPage.js.map +1 -1
  61. package/dist/admin/pages/SandboxSettingsPage.js +21 -20
  62. package/dist/admin/pages/SandboxSettingsPage.js.map +1 -1
  63. package/dist/admin/pages/SettingsPage.js +154 -142
  64. package/dist/admin/pages/SettingsPage.js.map +1 -1
  65. package/dist/admin/pages/SyncFailuresPage.js +14 -11
  66. package/dist/admin/pages/SyncFailuresPage.js.map +1 -1
  67. package/dist/admin/pages/TenantDetailPage.js +22 -22
  68. package/dist/admin/pages/TenantDetailPage.js.map +1 -1
  69. package/dist/admin/pages/TenantFormRoutePage.js +2 -2
  70. package/dist/admin/pages/TenantFormRoutePage.js.map +1 -1
  71. package/dist/admin/pages/TenantsListPage.js +7 -5
  72. package/dist/admin/pages/TenantsListPage.js.map +1 -1
  73. package/dist/admin/pages/UsersListPage.js +8 -6
  74. package/dist/admin/pages/UsersListPage.js.map +1 -1
  75. package/dist/admin/pages/WaitlistPage.js +9 -7
  76. package/dist/admin/pages/WaitlistPage.js.map +1 -1
  77. package/dist/admin/pages/WorkflowsPage.js +6 -3
  78. package/dist/admin/pages/WorkflowsPage.js.map +1 -1
  79. package/dist/admin/pages/WorkspacesListPage.js +9 -8
  80. package/dist/admin/pages/WorkspacesListPage.js.map +1 -1
  81. package/package.json +2 -2
@@ -1 +1 @@
1
- {"version":3,"file":"TicketForm.js","names":[],"sources":["../../../../src/admin/components/forms/TicketForm.tsx"],"sourcesContent":["import * as React from 'react';\nimport { useForm } from 'react-hook-form';\nimport { zodResolver } from '@hookform/resolvers/zod';\nimport { z } from 'zod';\nimport { FormSheet, FormSheetFooter, FormSection, FormRow } from '../FormSheet';\nimport { Input } from '../ui';\nimport { cn } from '../../utils/cn';\nimport type { SupportTicket } from '../../types';\n\n/**\n * Form field wrapper with label and error\n */\ninterface FormFieldProps {\n label: string;\n error?: string;\n required?: boolean;\n children: React.ReactNode;\n description?: string;\n}\n\nfunction FormField({ label, error, required, children, description }: FormFieldProps) {\n return (\n <div className=\"space-y-1.5\">\n <label className=\"text-sm font-medium text-foreground\">\n {label}\n {required && <span className=\"text-destructive ml-0.5\">*</span>}\n </label>\n {children}\n {description && !error && <p className=\"text-xs text-muted-foreground\">{description}</p>}\n {error && <p className=\"text-xs text-destructive\">{error}</p>}\n </div>\n );\n}\n\n/**\n * Select wrapper styled like Input\n */\ninterface SelectFieldProps extends React.SelectHTMLAttributes<HTMLSelectElement> {\n options: { value: string; label: string }[];\n placeholder?: string;\n}\n\nconst SelectField = React.forwardRef<HTMLSelectElement, SelectFieldProps>(\n ({ className, options, placeholder, ...props }, ref) => (\n <select\n ref={ref}\n className={cn(\n 'flex h-9 w-full rounded-md border border-input bg-transparent px-3 py-1 text-sm shadow-sm transition-colors',\n 'focus-visible:outline-none focus-visible:ring-1 focus-visible:ring-ring',\n 'disabled:cursor-not-allowed disabled:opacity-50',\n className\n )}\n {...props}\n >\n {placeholder && <option value=\"\">{placeholder}</option>}\n {options.map((opt) => (\n <option key={opt.value} value={opt.value}>\n {opt.label}\n </option>\n ))}\n </select>\n )\n);\nSelectField.displayName = 'SelectField';\n\n/**\n * Textarea wrapper styled like Input\n */\ntype TextareaFieldProps = React.TextareaHTMLAttributes<HTMLTextAreaElement>;\n\nconst TextareaField = React.forwardRef<HTMLTextAreaElement, TextareaFieldProps>(\n ({ className, ...props }, ref) => (\n <textarea\n ref={ref}\n className={cn(\n 'flex min-h-[120px] w-full rounded-md border border-input bg-transparent px-3 py-2 text-sm shadow-sm transition-colors',\n 'placeholder:text-muted-foreground',\n 'focus-visible:outline-none focus-visible:ring-1 focus-visible:ring-ring',\n 'disabled:cursor-not-allowed disabled:opacity-50',\n 'resize-none',\n className\n )}\n {...props}\n />\n )\n);\nTextareaField.displayName = 'TextareaField';\n\n// Unified form schema\nconst ticketFormSchema = z.object({\n subject: z\n .string()\n .min(5, 'Subject must be at least 5 characters')\n .max(200, 'Subject must be less than 200 characters'),\n description: z\n .string()\n .min(10, 'Description must be at least 10 characters')\n .max(5000, 'Description must be less than 5000 characters'),\n category: z.enum(['billing', 'technical', 'account', 'feature_request', 'other']),\n priority: z.enum(['low', 'medium', 'high', 'urgent']),\n status: z.enum(['open', 'in_progress', 'waiting', 'resolved', 'closed']).optional(),\n tenantId: z.string().optional(),\n userId: z.string().optional(),\n assigneeId: z.string().optional(),\n});\n\ntype TicketFormData = z.infer<typeof ticketFormSchema>;\n\n/**\n * TicketForm props\n */\nexport interface TicketFormProps {\n /** Whether the form is open */\n open: boolean;\n /** Callback when the form should close */\n onClose: () => void;\n /** Existing ticket data for editing (undefined for create) */\n ticket?: SupportTicket;\n /** Pre-selected tenant ID */\n tenantId?: string;\n /** Pre-selected user ID */\n userId?: string;\n /** List of available tenants for selection */\n tenants?: { id: string; name: string }[];\n /** List of available assignees */\n assignees?: { id: string; name: string }[];\n /** Callback on successful save */\n onSave: (data: TicketFormData & { id?: string }) => Promise<void>;\n}\n\nconst categoryOptions = [\n { value: 'billing', label: 'Billing' },\n { value: 'technical', label: 'Technical' },\n { value: 'account', label: 'Account' },\n { value: 'feature_request', label: 'Feature Request' },\n { value: 'other', label: 'Other' },\n];\n\nconst priorityOptions = [\n { value: 'low', label: 'Low' },\n { value: 'medium', label: 'Medium' },\n { value: 'high', label: 'High' },\n { value: 'urgent', label: 'Urgent' },\n];\n\nconst statusOptions = [\n { value: 'open', label: 'Open' },\n { value: 'in_progress', label: 'In Progress' },\n { value: 'waiting', label: 'Waiting on Customer' },\n { value: 'resolved', label: 'Resolved' },\n { value: 'closed', label: 'Closed' },\n];\n\n/**\n * TicketForm - Create/Edit support ticket form in a slide-over panel\n */\nexport function TicketForm({\n open,\n onClose,\n ticket,\n tenantId,\n userId,\n tenants = [],\n assignees = [],\n onSave,\n}: TicketFormProps) {\n const isEditing = !!ticket;\n const formId = 'ticket-form';\n\n const defaultValues: TicketFormData = {\n subject: ticket?.subject ?? '',\n description: ticket?.description ?? '',\n category: (ticket?.category ?? 'other') as TicketFormData['category'],\n priority: (ticket?.priority ?? 'medium') as TicketFormData['priority'],\n status: ticket?.status as TicketFormData['status'],\n tenantId: ticket?.tenantId ?? tenantId ?? '',\n userId: ticket?.userId ?? userId ?? '',\n assigneeId: ticket?.assigneeId ?? '',\n };\n\n const {\n register,\n handleSubmit,\n formState: { errors, isSubmitting },\n reset,\n } = useForm<TicketFormData>({\n resolver: zodResolver(ticketFormSchema),\n defaultValues,\n });\n\n // Reset form when ticket changes\n React.useEffect(() => {\n if (open) {\n reset(defaultValues);\n }\n }, [open, ticket?.id, tenantId, userId]);\n\n const onSubmit = async (data: TicketFormData) => {\n try {\n await onSave({ ...data, id: ticket?.id });\n onClose();\n } catch (error) {\n console.error('Failed to save ticket:', error);\n }\n };\n\n return (\n <FormSheet\n open={open}\n onClose={onClose}\n title={isEditing ? 'Edit Ticket' : 'Create Support Ticket'}\n description={\n isEditing ? `Editing ticket #${ticket.id.slice(0, 8)}` : 'Create a new support ticket'\n }\n width=\"lg\"\n footer={\n <FormSheetFooter\n formId={formId}\n submitLabel={isEditing ? 'Save Changes' : 'Create Ticket'}\n onCancel={onClose}\n isSubmitting={isSubmitting}\n />\n }\n >\n <form id={formId} onSubmit={handleSubmit(onSubmit)} className=\"space-y-6\">\n {/* Subject */}\n <FormSection>\n <FormField\n label=\"Subject\"\n required\n error={errors.subject?.message}\n description=\"Brief summary of the issue\"\n >\n <Input\n {...register('subject')}\n placeholder=\"e.g., Unable to access billing page\"\n aria-invalid={!!errors.subject}\n />\n </FormField>\n </FormSection>\n\n {/* Category & Priority */}\n <FormSection title=\"Classification\">\n <FormRow>\n <FormField label=\"Category\" required>\n <SelectField {...register('category')} options={categoryOptions} />\n </FormField>\n\n <FormField label=\"Priority\" required>\n <SelectField {...register('priority')} options={priorityOptions} />\n </FormField>\n </FormRow>\n\n {isEditing && (\n <FormRow>\n <FormField label=\"Status\">\n <SelectField {...register('status')} options={statusOptions} />\n </FormField>\n\n {assignees.length > 0 && (\n <FormField label=\"Assignee\">\n <SelectField\n {...register('assigneeId')}\n options={assignees.map((a) => ({ value: a.id, label: a.name }))}\n placeholder=\"Unassigned\"\n />\n </FormField>\n )}\n </FormRow>\n )}\n </FormSection>\n\n {/* Description */}\n <FormSection title=\"Details\">\n <FormField\n label=\"Description\"\n required\n error={errors.description?.message}\n description=\"Provide as much detail as possible\"\n >\n <TextareaField\n {...register('description')}\n placeholder=\"Describe the issue in detail. Include steps to reproduce if applicable...\"\n aria-invalid={!!errors.description}\n rows={6}\n />\n </FormField>\n </FormSection>\n\n {/* Context (Tenant/User) */}\n {tenants.length > 0 && (\n <FormSection title=\"Context\">\n <FormField\n label=\"Related Tenant\"\n description=\"Associate this ticket with a specific tenant\"\n >\n <SelectField\n {...register('tenantId')}\n options={tenants.map((t) => ({ value: t.id, label: t.name }))}\n placeholder=\"Select a tenant (optional)\"\n />\n </FormField>\n </FormSection>\n )}\n </form>\n </FormSheet>\n );\n}\n"],"mappings":";;;;;;;AA0CA,IAAM,IAAc,EAAM,YACvB,EAAE,cAAW,YAAS,gBAAa,GAAG,KAAS,MAC9C,kBAAC,UAAD;CACO;CACL,WAAW,EACT,+GACA,2EACA,mDACA,EACD;CACD,GAAI;WARN,CAUG,KAAe,kBAAC,UAAD;EAAQ,OAAM;YAAI;EAAqB,CAAA,EACtD,EAAQ,KAAK,MACZ,kBAAC,UAAD;EAAwB,OAAO,EAAI;YAChC,EAAI;EACE,EAFI,EAAI,MAER,CACT,CACK;GAEZ;AACD,EAAY,cAAc;AAO1B,IAAM,IAAgB,EAAM,YACzB,EAAE,cAAW,GAAG,KAAS,MACxB,kBAAC,YAAD;CACO;CACL,WAAW,EACT,yHACA,qCACA,2EACA,mDACA,eACA,EACD;CACD,GAAI;CACJ,CAAA,CAEL;AACD,EAAc,cAAc,iBAGH,EAAS;CAChC,SAAS,GACE,CACR,IAAI,GAAG,wCAAwC,CAC/C,IAAI,KAAK,2CAA2C;CACvD,aAAa,GACF,CACR,IAAI,IAAI,6CAA6C,CACrD,IAAI,KAAM,gDAAgD;CAC7D,UAAU,EAAO;EAAC;EAAW;EAAa;EAAW;EAAmB;EAAQ,CAAC;CACjF,UAAU,EAAO;EAAC;EAAO;EAAU;EAAQ;EAAS,CAAC;CACrD,QAAQ,EAAO;EAAC;EAAQ;EAAe;EAAW;EAAY;EAAS,CAAC,CAAC,UAAU;CACnF,UAAU,GAAU,CAAC,UAAU;CAC/B,QAAQ,GAAU,CAAC,UAAU;CAC7B,YAAY,GAAU,CAAC,UAAU;CAClC,CAAC"}
1
+ {"version":3,"file":"TicketForm.js","names":[],"sources":["../../../../src/admin/components/forms/TicketForm.tsx"],"sourcesContent":["import * as React from 'react';\nimport { useForm } from 'react-hook-form';\nimport { zodResolver } from '@hookform/resolvers/zod';\nimport { z } from 'zod';\nimport { FormSheet, FormSheetFooter, FormSection, FormRow } from '../FormSheet';\nimport { Input } from '../ui';\nimport { cn } from '../../utils/cn';\nimport type { SupportTicket } from '../../types';\n\n/**\n * Form field wrapper with label and error\n */\ninterface FormFieldProps {\n label: string;\n error?: string;\n required?: boolean;\n children: React.ReactNode;\n description?: string;\n}\n\nfunction FormField({ label, error, required, children, description }: FormFieldProps) {\n return (\n <div className=\"space-y-1.5\">\n <label className=\"text-sm font-medium text-text-primary\">\n {label}\n {required && <span className=\"text-status-error-text ml-0.5\">*</span>}\n </label>\n {children}\n {description && !error && <p className=\"text-xs text-text-secondary\">{description}</p>}\n {error && <p className=\"text-xs text-status-error-text\">{error}</p>}\n </div>\n );\n}\n\n/**\n * Select wrapper styled like Input\n */\ninterface SelectFieldProps extends React.SelectHTMLAttributes<HTMLSelectElement> {\n options: { value: string; label: string }[];\n placeholder?: string;\n}\n\nconst SelectField = React.forwardRef<HTMLSelectElement, SelectFieldProps>(\n ({ className, options, placeholder, ...props }, ref) => (\n <select\n ref={ref}\n className={cn(\n 'flex h-9 w-full rounded-md border border-border-default bg-transparent px-3 py-1 text-sm shadow-sm transition-colors',\n 'focus-visible:outline-none focus-visible:ring-1 focus-visible:ring-[var(--color-focus-ring)]',\n 'disabled:cursor-not-allowed disabled:opacity-50',\n className\n )}\n {...props}\n >\n {placeholder && <option value=\"\">{placeholder}</option>}\n {options.map((opt) => (\n <option key={opt.value} value={opt.value}>\n {opt.label}\n </option>\n ))}\n </select>\n )\n);\nSelectField.displayName = 'SelectField';\n\n/**\n * Textarea wrapper styled like Input\n */\ntype TextareaFieldProps = React.TextareaHTMLAttributes<HTMLTextAreaElement>;\n\nconst TextareaField = React.forwardRef<HTMLTextAreaElement, TextareaFieldProps>(\n ({ className, ...props }, ref) => (\n <textarea\n ref={ref}\n className={cn(\n 'flex min-h-[120px] w-full rounded-md border border-border-default bg-transparent px-3 py-2 text-sm shadow-sm transition-colors',\n 'placeholder:text-text-secondary',\n 'focus-visible:outline-none focus-visible:ring-1 focus-visible:ring-[var(--color-focus-ring)]',\n 'disabled:cursor-not-allowed disabled:opacity-50',\n 'resize-none',\n className\n )}\n {...props}\n />\n )\n);\nTextareaField.displayName = 'TextareaField';\n\n// Unified form schema\nconst ticketFormSchema = z.object({\n subject: z\n .string()\n .min(5, 'Subject must be at least 5 characters')\n .max(200, 'Subject must be less than 200 characters'),\n description: z\n .string()\n .min(10, 'Description must be at least 10 characters')\n .max(5000, 'Description must be less than 5000 characters'),\n category: z.enum(['billing', 'technical', 'account', 'feature_request', 'other']),\n priority: z.enum(['low', 'medium', 'high', 'urgent']),\n status: z.enum(['open', 'in_progress', 'waiting', 'resolved', 'closed']).optional(),\n tenantId: z.string().optional(),\n userId: z.string().optional(),\n assigneeId: z.string().optional(),\n});\n\ntype TicketFormData = z.infer<typeof ticketFormSchema>;\n\n/**\n * TicketForm props\n */\nexport interface TicketFormProps {\n /** Whether the form is open */\n open: boolean;\n /** Callback when the form should close */\n onClose: () => void;\n /** Existing ticket data for editing (undefined for create) */\n ticket?: SupportTicket;\n /** Pre-selected tenant ID */\n tenantId?: string;\n /** Pre-selected user ID */\n userId?: string;\n /** List of available tenants for selection */\n tenants?: { id: string; name: string }[];\n /** List of available assignees */\n assignees?: { id: string; name: string }[];\n /** Callback on successful save */\n onSave: (data: TicketFormData & { id?: string }) => Promise<void>;\n}\n\nconst categoryOptions = [\n { value: 'billing', label: 'Billing' },\n { value: 'technical', label: 'Technical' },\n { value: 'account', label: 'Account' },\n { value: 'feature_request', label: 'Feature Request' },\n { value: 'other', label: 'Other' },\n];\n\nconst priorityOptions = [\n { value: 'low', label: 'Low' },\n { value: 'medium', label: 'Medium' },\n { value: 'high', label: 'High' },\n { value: 'urgent', label: 'Urgent' },\n];\n\nconst statusOptions = [\n { value: 'open', label: 'Open' },\n { value: 'in_progress', label: 'In Progress' },\n { value: 'waiting', label: 'Waiting on Customer' },\n { value: 'resolved', label: 'Resolved' },\n { value: 'closed', label: 'Closed' },\n];\n\n/**\n * TicketForm - Create/Edit support ticket form in a slide-over panel\n */\nexport function TicketForm({\n open,\n onClose,\n ticket,\n tenantId,\n userId,\n tenants = [],\n assignees = [],\n onSave,\n}: TicketFormProps) {\n const isEditing = !!ticket;\n const formId = 'ticket-form';\n\n const defaultValues: TicketFormData = {\n subject: ticket?.subject ?? '',\n description: ticket?.description ?? '',\n category: (ticket?.category ?? 'other') as TicketFormData['category'],\n priority: (ticket?.priority ?? 'medium') as TicketFormData['priority'],\n status: ticket?.status as TicketFormData['status'],\n tenantId: ticket?.tenantId ?? tenantId ?? '',\n userId: ticket?.userId ?? userId ?? '',\n assigneeId: ticket?.assigneeId ?? '',\n };\n\n const {\n register,\n handleSubmit,\n formState: { errors, isSubmitting },\n reset,\n } = useForm<TicketFormData>({\n resolver: zodResolver(ticketFormSchema),\n defaultValues,\n });\n\n // Reset form when ticket changes\n React.useEffect(() => {\n if (open) {\n reset(defaultValues);\n }\n }, [open, ticket?.id, tenantId, userId]);\n\n const onSubmit = async (data: TicketFormData) => {\n try {\n await onSave({ ...data, id: ticket?.id });\n onClose();\n } catch (error) {\n console.error('Failed to save ticket:', error);\n }\n };\n\n return (\n <FormSheet\n open={open}\n onClose={onClose}\n title={isEditing ? 'Edit Ticket' : 'Create Support Ticket'}\n description={\n isEditing ? `Editing ticket #${ticket.id.slice(0, 8)}` : 'Create a new support ticket'\n }\n width=\"lg\"\n footer={\n <FormSheetFooter\n formId={formId}\n submitLabel={isEditing ? 'Save Changes' : 'Create Ticket'}\n onCancel={onClose}\n isSubmitting={isSubmitting}\n />\n }\n >\n <form id={formId} onSubmit={handleSubmit(onSubmit)} className=\"space-y-6\">\n {/* Subject */}\n <FormSection>\n <FormField\n label=\"Subject\"\n required\n error={errors.subject?.message}\n description=\"Brief summary of the issue\"\n >\n <Input\n {...register('subject')}\n placeholder=\"e.g., Unable to access billing page\"\n aria-invalid={!!errors.subject}\n />\n </FormField>\n </FormSection>\n\n {/* Category & Priority */}\n <FormSection title=\"Classification\">\n <FormRow>\n <FormField label=\"Category\" required>\n <SelectField {...register('category')} options={categoryOptions} />\n </FormField>\n\n <FormField label=\"Priority\" required>\n <SelectField {...register('priority')} options={priorityOptions} />\n </FormField>\n </FormRow>\n\n {isEditing && (\n <FormRow>\n <FormField label=\"Status\">\n <SelectField {...register('status')} options={statusOptions} />\n </FormField>\n\n {assignees.length > 0 && (\n <FormField label=\"Assignee\">\n <SelectField\n {...register('assigneeId')}\n options={assignees.map((a) => ({ value: a.id, label: a.name }))}\n placeholder=\"Unassigned\"\n />\n </FormField>\n )}\n </FormRow>\n )}\n </FormSection>\n\n {/* Description */}\n <FormSection title=\"Details\">\n <FormField\n label=\"Description\"\n required\n error={errors.description?.message}\n description=\"Provide as much detail as possible\"\n >\n <TextareaField\n {...register('description')}\n placeholder=\"Describe the issue in detail. Include steps to reproduce if applicable...\"\n aria-invalid={!!errors.description}\n rows={6}\n />\n </FormField>\n </FormSection>\n\n {/* Context (Tenant/User) */}\n {tenants.length > 0 && (\n <FormSection title=\"Context\">\n <FormField\n label=\"Related Tenant\"\n description=\"Associate this ticket with a specific tenant\"\n >\n <SelectField\n {...register('tenantId')}\n options={tenants.map((t) => ({ value: t.id, label: t.name }))}\n placeholder=\"Select a tenant (optional)\"\n />\n </FormField>\n </FormSection>\n )}\n </form>\n </FormSheet>\n );\n}\n"],"mappings":";;;;;;;AA0CA,IAAM,IAAc,EAAM,YACvB,EAAE,cAAW,YAAS,gBAAa,GAAG,KAAS,MAC9C,kBAAC,UAAD;CACO;CACL,WAAW,EACT,wHACA,gGACA,mDACA,EACD;CACD,GAAI;WARN,CAUG,KAAe,kBAAC,UAAD;EAAQ,OAAM;YAAI;EAAqB,CAAA,EACtD,EAAQ,KAAK,MACZ,kBAAC,UAAD;EAAwB,OAAO,EAAI;YAChC,EAAI;EACE,EAFI,EAAI,MAER,CACT,CACK;GAEZ;AACD,EAAY,cAAc;AAO1B,IAAM,IAAgB,EAAM,YACzB,EAAE,cAAW,GAAG,KAAS,MACxB,kBAAC,YAAD;CACO;CACL,WAAW,EACT,kIACA,mCACA,gGACA,mDACA,eACA,EACD;CACD,GAAI;CACJ,CAAA,CAEL;AACD,EAAc,cAAc,iBAGH,EAAS;CAChC,SAAS,GACE,CACR,IAAI,GAAG,wCAAwC,CAC/C,IAAI,KAAK,2CAA2C;CACvD,aAAa,GACF,CACR,IAAI,IAAI,6CAA6C,CACrD,IAAI,KAAM,gDAAgD;CAC7D,UAAU,EAAO;EAAC;EAAW;EAAa;EAAW;EAAmB;EAAQ,CAAC;CACjF,UAAU,EAAO;EAAC;EAAO;EAAU;EAAQ;EAAS,CAAC;CACrD,QAAQ,EAAO;EAAC;EAAQ;EAAe;EAAW;EAAY;EAAS,CAAC,CAAC,UAAU;CACnF,UAAU,GAAU,CAAC,UAAU;CAC/B,QAAQ,GAAU,CAAC,UAAU;CAC7B,YAAY,GAAU,CAAC,UAAU;CAClC,CAAC"}
@@ -12,19 +12,19 @@ function g({ label: e, error: t, required: n, children: r, description: i }) {
12
12
  className: "space-y-1.5",
13
13
  children: [
14
14
  /* @__PURE__ */ h("label", {
15
- className: "text-sm font-medium text-foreground",
15
+ className: "text-sm font-medium text-text-primary",
16
16
  children: [e, n && /* @__PURE__ */ m("span", {
17
- className: "text-destructive ml-0.5",
17
+ className: "text-status-error-text ml-0.5",
18
18
  children: "*"
19
19
  })]
20
20
  }),
21
21
  r,
22
22
  i && !t && /* @__PURE__ */ m("p", {
23
- className: "text-xs text-muted-foreground",
23
+ className: "text-xs text-text-secondary",
24
24
  children: i
25
25
  }),
26
26
  t && /* @__PURE__ */ m("p", {
27
- className: "text-xs text-destructive",
27
+ className: "text-xs text-status-error-text",
28
28
  children: t
29
29
  })
30
30
  ]
@@ -32,7 +32,7 @@ function g({ label: e, error: t, required: n, children: r, description: i }) {
32
32
  }
33
33
  var _ = p.forwardRef(({ className: t, options: n, placeholder: r, ...i }, a) => /* @__PURE__ */ h("select", {
34
34
  ref: a,
35
- className: e("flex h-9 w-full rounded-md border border-input bg-transparent px-3 py-1 text-sm shadow-sm transition-colors", "focus-visible:outline-none focus-visible:ring-1 focus-visible:ring-ring", "disabled:cursor-not-allowed disabled:opacity-50", t),
35
+ className: e("flex h-9 w-full rounded-md border border-border-default bg-transparent px-3 py-1 text-sm shadow-sm transition-colors", "focus-visible:outline-none focus-visible:ring-1 focus-visible:ring-[var(--color-focus-ring)]", "disabled:cursor-not-allowed disabled:opacity-50", t),
36
36
  ...i,
37
37
  children: [r && /* @__PURE__ */ m("option", {
38
38
  value: "",
@@ -52,14 +52,14 @@ function v({ label: t, checked: n, onChange: r, description: i, disabled: a }) {
52
52
  checked: n,
53
53
  onChange: (e) => r(e.target.checked),
54
54
  disabled: a,
55
- className: e("mt-0.5 h-4 w-4 rounded border border-input shadow-sm", "focus-visible:outline-none focus-visible:ring-1 focus-visible:ring-ring", "disabled:cursor-not-allowed disabled:opacity-50", "checked:bg-primary checked:border-primary")
55
+ className: e("mt-0.5 h-4 w-4 rounded border border-border-default shadow-sm", "focus-visible:outline-none focus-visible:ring-1 focus-visible:ring-[var(--color-focus-ring)]", "disabled:cursor-not-allowed disabled:opacity-50", "checked:bg-action-primary-bg checked:border-primary")
56
56
  }), /* @__PURE__ */ h("div", {
57
57
  className: "space-y-0.5",
58
58
  children: [/* @__PURE__ */ m("span", {
59
- className: "text-sm font-medium text-foreground",
59
+ className: "text-sm font-medium text-text-primary",
60
60
  children: t
61
61
  }), i && /* @__PURE__ */ m("p", {
62
- className: "text-xs text-muted-foreground",
62
+ className: "text-xs text-text-secondary",
63
63
  children: i
64
64
  })]
65
65
  })]
@@ -1 +1 @@
1
- {"version":3,"file":"UserForm.js","names":[],"sources":["../../../../src/admin/components/forms/UserForm.tsx"],"sourcesContent":["import * as React from 'react';\nimport { useForm, Controller, type ControllerRenderProps } from 'react-hook-form';\nimport { zodResolver } from '@hookform/resolvers/zod';\nimport { z } from 'zod';\nimport { FormSheet, FormSheetFooter, FormSection, FormRow } from '../FormSheet';\nimport { Input } from '../ui';\nimport { cn } from '../../utils/cn';\nimport type { User } from '../../types';\n\n/**\n * Form field wrapper with label and error\n */\ninterface FormFieldProps {\n label: string;\n error?: string;\n required?: boolean;\n children: React.ReactNode;\n description?: string;\n}\n\nfunction FormField({ label, error, required, children, description }: FormFieldProps) {\n return (\n <div className=\"space-y-1.5\">\n <label className=\"text-sm font-medium text-foreground\">\n {label}\n {required && <span className=\"text-destructive ml-0.5\">*</span>}\n </label>\n {children}\n {description && !error && <p className=\"text-xs text-muted-foreground\">{description}</p>}\n {error && <p className=\"text-xs text-destructive\">{error}</p>}\n </div>\n );\n}\n\n/**\n * Select wrapper styled like Input\n */\ninterface SelectFieldProps extends React.SelectHTMLAttributes<HTMLSelectElement> {\n options: { value: string; label: string }[];\n placeholder?: string;\n}\n\nconst SelectField = React.forwardRef<HTMLSelectElement, SelectFieldProps>(\n ({ className, options, placeholder, ...props }, ref) => (\n <select\n ref={ref}\n className={cn(\n 'flex h-9 w-full rounded-md border border-input bg-transparent px-3 py-1 text-sm shadow-sm transition-colors',\n 'focus-visible:outline-none focus-visible:ring-1 focus-visible:ring-ring',\n 'disabled:cursor-not-allowed disabled:opacity-50',\n className\n )}\n {...props}\n >\n {placeholder && (\n <option value=\"\" disabled>\n {placeholder}\n </option>\n )}\n {options.map((opt) => (\n <option key={opt.value} value={opt.value}>\n {opt.label}\n </option>\n ))}\n </select>\n )\n);\nSelectField.displayName = 'SelectField';\n\n/**\n * Checkbox with label\n */\ninterface CheckboxFieldProps {\n label: string;\n checked: boolean;\n onChange: (checked: boolean) => void;\n description?: string;\n disabled?: boolean;\n}\n\nfunction CheckboxField({ label, checked, onChange, description, disabled }: CheckboxFieldProps) {\n return (\n <label className=\"flex items-start gap-3 cursor-pointer\">\n <input\n type=\"checkbox\"\n checked={checked}\n onChange={(e) => onChange(e.target.checked)}\n disabled={disabled}\n className={cn(\n 'mt-0.5 h-4 w-4 rounded border border-input shadow-sm',\n 'focus-visible:outline-none focus-visible:ring-1 focus-visible:ring-ring',\n 'disabled:cursor-not-allowed disabled:opacity-50',\n 'checked:bg-primary checked:border-primary'\n )}\n />\n <div className=\"space-y-0.5\">\n <span className=\"text-sm font-medium text-foreground\">{label}</span>\n {description && <p className=\"text-xs text-muted-foreground\">{description}</p>}\n </div>\n </label>\n );\n}\n\n// Unified form schema (handles both create and edit)\nconst userFormSchema = z.object({\n email: z.string().email('Invalid email address'),\n firstName: z\n .string()\n .min(1, 'First name is required')\n .max(50, 'First name must be less than 50 characters'),\n lastName: z\n .string()\n .min(1, 'Last name is required')\n .max(50, 'Last name must be less than 50 characters'),\n role: z.enum(['admin', 'member', 'viewer', 'owner']),\n status: z.enum(['active', 'inactive', 'pending', 'suspended']).optional(),\n tenantId: z.string().optional(),\n sendInvite: z.boolean(),\n});\n\ntype UserFormData = z.infer<typeof userFormSchema>;\n\n/**\n * UserForm props\n */\nexport interface UserFormProps {\n /** Whether the form is open */\n open: boolean;\n /** Callback when the form should close */\n onClose: () => void;\n /** Existing user data for editing (undefined for create) */\n user?: User;\n /** Pre-selected tenant ID */\n tenantId?: string;\n /** List of available tenants for selection */\n tenants?: { id: string; name: string }[];\n /** Callback on successful save */\n onSave: (data: UserFormData & { id?: string }) => Promise<void>;\n}\n\nconst roleOptions = [\n { value: 'viewer', label: 'Viewer' },\n { value: 'member', label: 'Member' },\n { value: 'admin', label: 'Admin' },\n { value: 'owner', label: 'Owner' },\n];\n\nconst statusOptions = [\n { value: 'active', label: 'Active' },\n { value: 'inactive', label: 'Inactive' },\n { value: 'pending', label: 'Pending' },\n { value: 'suspended', label: 'Suspended' },\n];\n\n/**\n * UserForm - Create/Edit user form in a slide-over panel\n */\nexport function UserForm({ open, onClose, user, tenantId, tenants = [], onSave }: UserFormProps) {\n const isEditing = !!user;\n const formId = 'user-form';\n\n // Extract first/last name from user.name if available\n const nameParts =\n user?.firstName && user?.lastName\n ? { firstName: user.firstName, lastName: user.lastName }\n : user?.email\n ? { firstName: '', lastName: '' }\n : { firstName: '', lastName: '' };\n\n const defaultValues: UserFormData = {\n email: user?.email ?? '',\n firstName: nameParts.firstName,\n lastName: nameParts.lastName,\n role: (user?.role?.toLowerCase() ?? 'member') as UserFormData['role'],\n status: user?.status as UserFormData['status'],\n tenantId: user?.tenantId ?? tenantId ?? '',\n sendInvite: !isEditing,\n };\n\n const {\n register,\n handleSubmit,\n control,\n formState: { errors, isSubmitting },\n reset,\n } = useForm<UserFormData>({\n resolver: zodResolver(userFormSchema),\n defaultValues,\n });\n\n // Reset form when user or tenantId changes\n React.useEffect(() => {\n if (open) {\n reset(defaultValues);\n }\n }, [open, user?.id, tenantId]);\n\n const onSubmit = async (data: UserFormData) => {\n try {\n await onSave({ ...data, id: user?.id });\n onClose();\n } catch (error) {\n console.error('Failed to save user:', error);\n }\n };\n\n return (\n <FormSheet\n open={open}\n onClose={onClose}\n title={isEditing ? 'Edit User' : 'Invite User'}\n description={isEditing ? `Editing ${user.email}` : 'Add a new user and send them an invite'}\n width=\"md\"\n footer={\n <FormSheetFooter\n formId={formId}\n submitLabel={isEditing ? 'Save Changes' : 'Send Invite'}\n onCancel={onClose}\n isSubmitting={isSubmitting}\n />\n }\n >\n <form id={formId} onSubmit={handleSubmit(onSubmit)} className=\"space-y-6\">\n {/* Basic Information */}\n <FormSection title=\"Basic Information\">\n <FormField label=\"Email\" required error={errors.email?.message}>\n <Input\n type=\"email\"\n {...register('email')}\n placeholder=\"user@example.com\"\n aria-invalid={!!errors.email}\n disabled={isEditing} // Can't change email after creation\n />\n </FormField>\n\n <FormRow>\n <FormField label=\"First Name\" required error={errors.firstName?.message}>\n <Input\n {...register('firstName')}\n placeholder=\"John\"\n aria-invalid={!!errors.firstName}\n />\n </FormField>\n\n <FormField label=\"Last Name\" required error={errors.lastName?.message}>\n <Input {...register('lastName')} placeholder=\"Doe\" aria-invalid={!!errors.lastName} />\n </FormField>\n </FormRow>\n </FormSection>\n\n {/* Role & Access */}\n <FormSection title=\"Role & Access\">\n <FormRow>\n <FormField label=\"Role\" required>\n <SelectField {...register('role')} options={roleOptions} />\n </FormField>\n\n {isEditing && (\n <FormField label=\"Status\">\n <SelectField {...register('status')} options={statusOptions} />\n </FormField>\n )}\n </FormRow>\n\n {tenants.length > 0 && (\n <FormField label=\"Tenant\" description=\"Assign user to a specific tenant\">\n <SelectField\n {...register('tenantId')}\n options={tenants.map((t) => ({ value: t.id, label: t.name }))}\n placeholder=\"Select a tenant...\"\n />\n </FormField>\n )}\n </FormSection>\n\n {/* Invite Options (only for new users) */}\n {!isEditing && (\n <FormSection title=\"Invite Options\">\n <Controller\n name=\"sendInvite\"\n control={control}\n render={({ field }: { field: ControllerRenderProps<UserFormData, 'sendInvite'> }) => (\n <CheckboxField\n label=\"Send Invite Email\"\n checked={field.value ?? true}\n onChange={field.onChange}\n description=\"Send an invitation email to the user with login instructions\"\n />\n )}\n />\n </FormSection>\n )}\n </form>\n </FormSheet>\n );\n}\n"],"mappings":"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"}
1
+ {"version":3,"file":"UserForm.js","names":[],"sources":["../../../../src/admin/components/forms/UserForm.tsx"],"sourcesContent":["import * as React from 'react';\nimport { useForm, Controller, type ControllerRenderProps } from 'react-hook-form';\nimport { zodResolver } from '@hookform/resolvers/zod';\nimport { z } from 'zod';\nimport { FormSheet, FormSheetFooter, FormSection, FormRow } from '../FormSheet';\nimport { Input } from '../ui';\nimport { cn } from '../../utils/cn';\nimport type { User } from '../../types';\n\n/**\n * Form field wrapper with label and error\n */\ninterface FormFieldProps {\n label: string;\n error?: string;\n required?: boolean;\n children: React.ReactNode;\n description?: string;\n}\n\nfunction FormField({ label, error, required, children, description }: FormFieldProps) {\n return (\n <div className=\"space-y-1.5\">\n <label className=\"text-sm font-medium text-text-primary\">\n {label}\n {required && <span className=\"text-status-error-text ml-0.5\">*</span>}\n </label>\n {children}\n {description && !error && <p className=\"text-xs text-text-secondary\">{description}</p>}\n {error && <p className=\"text-xs text-status-error-text\">{error}</p>}\n </div>\n );\n}\n\n/**\n * Select wrapper styled like Input\n */\ninterface SelectFieldProps extends React.SelectHTMLAttributes<HTMLSelectElement> {\n options: { value: string; label: string }[];\n placeholder?: string;\n}\n\nconst SelectField = React.forwardRef<HTMLSelectElement, SelectFieldProps>(\n ({ className, options, placeholder, ...props }, ref) => (\n <select\n ref={ref}\n className={cn(\n 'flex h-9 w-full rounded-md border border-border-default bg-transparent px-3 py-1 text-sm shadow-sm transition-colors',\n 'focus-visible:outline-none focus-visible:ring-1 focus-visible:ring-[var(--color-focus-ring)]',\n 'disabled:cursor-not-allowed disabled:opacity-50',\n className\n )}\n {...props}\n >\n {placeholder && (\n <option value=\"\" disabled>\n {placeholder}\n </option>\n )}\n {options.map((opt) => (\n <option key={opt.value} value={opt.value}>\n {opt.label}\n </option>\n ))}\n </select>\n )\n);\nSelectField.displayName = 'SelectField';\n\n/**\n * Checkbox with label\n */\ninterface CheckboxFieldProps {\n label: string;\n checked: boolean;\n onChange: (checked: boolean) => void;\n description?: string;\n disabled?: boolean;\n}\n\nfunction CheckboxField({ label, checked, onChange, description, disabled }: CheckboxFieldProps) {\n return (\n <label className=\"flex items-start gap-3 cursor-pointer\">\n <input\n type=\"checkbox\"\n checked={checked}\n onChange={(e) => onChange(e.target.checked)}\n disabled={disabled}\n className={cn(\n 'mt-0.5 h-4 w-4 rounded border border-border-default shadow-sm',\n 'focus-visible:outline-none focus-visible:ring-1 focus-visible:ring-[var(--color-focus-ring)]',\n 'disabled:cursor-not-allowed disabled:opacity-50',\n 'checked:bg-action-primary-bg checked:border-primary'\n )}\n />\n <div className=\"space-y-0.5\">\n <span className=\"text-sm font-medium text-text-primary\">{label}</span>\n {description && <p className=\"text-xs text-text-secondary\">{description}</p>}\n </div>\n </label>\n );\n}\n\n// Unified form schema (handles both create and edit)\nconst userFormSchema = z.object({\n email: z.string().email('Invalid email address'),\n firstName: z\n .string()\n .min(1, 'First name is required')\n .max(50, 'First name must be less than 50 characters'),\n lastName: z\n .string()\n .min(1, 'Last name is required')\n .max(50, 'Last name must be less than 50 characters'),\n role: z.enum(['admin', 'member', 'viewer', 'owner']),\n status: z.enum(['active', 'inactive', 'pending', 'suspended']).optional(),\n tenantId: z.string().optional(),\n sendInvite: z.boolean(),\n});\n\ntype UserFormData = z.infer<typeof userFormSchema>;\n\n/**\n * UserForm props\n */\nexport interface UserFormProps {\n /** Whether the form is open */\n open: boolean;\n /** Callback when the form should close */\n onClose: () => void;\n /** Existing user data for editing (undefined for create) */\n user?: User;\n /** Pre-selected tenant ID */\n tenantId?: string;\n /** List of available tenants for selection */\n tenants?: { id: string; name: string }[];\n /** Callback on successful save */\n onSave: (data: UserFormData & { id?: string }) => Promise<void>;\n}\n\nconst roleOptions = [\n { value: 'viewer', label: 'Viewer' },\n { value: 'member', label: 'Member' },\n { value: 'admin', label: 'Admin' },\n { value: 'owner', label: 'Owner' },\n];\n\nconst statusOptions = [\n { value: 'active', label: 'Active' },\n { value: 'inactive', label: 'Inactive' },\n { value: 'pending', label: 'Pending' },\n { value: 'suspended', label: 'Suspended' },\n];\n\n/**\n * UserForm - Create/Edit user form in a slide-over panel\n */\nexport function UserForm({ open, onClose, user, tenantId, tenants = [], onSave }: UserFormProps) {\n const isEditing = !!user;\n const formId = 'user-form';\n\n // Extract first/last name from user.name if available\n const nameParts =\n user?.firstName && user?.lastName\n ? { firstName: user.firstName, lastName: user.lastName }\n : user?.email\n ? { firstName: '', lastName: '' }\n : { firstName: '', lastName: '' };\n\n const defaultValues: UserFormData = {\n email: user?.email ?? '',\n firstName: nameParts.firstName,\n lastName: nameParts.lastName,\n role: (user?.role?.toLowerCase() ?? 'member') as UserFormData['role'],\n status: user?.status as UserFormData['status'],\n tenantId: user?.tenantId ?? tenantId ?? '',\n sendInvite: !isEditing,\n };\n\n const {\n register,\n handleSubmit,\n control,\n formState: { errors, isSubmitting },\n reset,\n } = useForm<UserFormData>({\n resolver: zodResolver(userFormSchema),\n defaultValues,\n });\n\n // Reset form when user or tenantId changes\n React.useEffect(() => {\n if (open) {\n reset(defaultValues);\n }\n }, [open, user?.id, tenantId]);\n\n const onSubmit = async (data: UserFormData) => {\n try {\n await onSave({ ...data, id: user?.id });\n onClose();\n } catch (error) {\n console.error('Failed to save user:', error);\n }\n };\n\n return (\n <FormSheet\n open={open}\n onClose={onClose}\n title={isEditing ? 'Edit User' : 'Invite User'}\n description={isEditing ? `Editing ${user.email}` : 'Add a new user and send them an invite'}\n width=\"md\"\n footer={\n <FormSheetFooter\n formId={formId}\n submitLabel={isEditing ? 'Save Changes' : 'Send Invite'}\n onCancel={onClose}\n isSubmitting={isSubmitting}\n />\n }\n >\n <form id={formId} onSubmit={handleSubmit(onSubmit)} className=\"space-y-6\">\n {/* Basic Information */}\n <FormSection title=\"Basic Information\">\n <FormField label=\"Email\" required error={errors.email?.message}>\n <Input\n type=\"email\"\n {...register('email')}\n placeholder=\"user@example.com\"\n aria-invalid={!!errors.email}\n disabled={isEditing} // Can't change email after creation\n />\n </FormField>\n\n <FormRow>\n <FormField label=\"First Name\" required error={errors.firstName?.message}>\n <Input\n {...register('firstName')}\n placeholder=\"John\"\n aria-invalid={!!errors.firstName}\n />\n </FormField>\n\n <FormField label=\"Last Name\" required error={errors.lastName?.message}>\n <Input {...register('lastName')} placeholder=\"Doe\" aria-invalid={!!errors.lastName} />\n </FormField>\n </FormRow>\n </FormSection>\n\n {/* Role & Access */}\n <FormSection title=\"Role & Access\">\n <FormRow>\n <FormField label=\"Role\" required>\n <SelectField {...register('role')} options={roleOptions} />\n </FormField>\n\n {isEditing && (\n <FormField label=\"Status\">\n <SelectField {...register('status')} options={statusOptions} />\n </FormField>\n )}\n </FormRow>\n\n {tenants.length > 0 && (\n <FormField label=\"Tenant\" description=\"Assign user to a specific tenant\">\n <SelectField\n {...register('tenantId')}\n options={tenants.map((t) => ({ value: t.id, label: t.name }))}\n placeholder=\"Select a tenant...\"\n />\n </FormField>\n )}\n </FormSection>\n\n {/* Invite Options (only for new users) */}\n {!isEditing && (\n <FormSection title=\"Invite Options\">\n <Controller\n name=\"sendInvite\"\n control={control}\n render={({ field }: { field: ControllerRenderProps<UserFormData, 'sendInvite'> }) => (\n <CheckboxField\n label=\"Send Invite Email\"\n checked={field.value ?? true}\n onChange={field.onChange}\n description=\"Send an invitation email to the user with login instructions\"\n />\n )}\n />\n </FormSection>\n )}\n </form>\n </FormSheet>\n );\n}\n"],"mappings":"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"}
@@ -1,140 +1,147 @@
1
1
  import { cn as e } from "../utils/cn.js";
2
2
  import { forwardRef as t } from "react";
3
3
  import { jsx as n, jsxs as r } from "react/jsx-runtime";
4
+ import { IllustratedEmptyState as i } from "@burdenoff/fe-libs/ui";
4
5
  //#region src/admin/components/ui.tsx
5
- var i = t(({ className: t, children: r, ...i }, a) => /* @__PURE__ */ n("div", {
6
+ var a = t(({ className: t, children: r, ...i }, a) => /* @__PURE__ */ n("div", {
6
7
  ref: a,
7
- className: e("rounded-lg border border-border bg-card text-card-foreground shadow-sm", t),
8
+ className: e("rounded-card border border-border-seam bg-bg-surface text-text-primary shadow-elevation-1 transition-[box-shadow,border-color] duration-200 hover:border-border-strong", t),
8
9
  ...i,
9
10
  children: r
10
11
  }));
11
- i.displayName = "Card";
12
- var a = t(({ className: t, children: r, ...i }, a) => /* @__PURE__ */ n("div", {
12
+ a.displayName = "Card";
13
+ var o = t(({ className: t, children: r, ...i }, a) => /* @__PURE__ */ n("div", {
13
14
  ref: a,
14
15
  className: e("flex flex-col space-y-1.5 p-6", t),
15
16
  ...i,
16
17
  children: r
17
18
  }));
18
- a.displayName = "CardHeader";
19
- var o = t(({ className: t, children: r, ...i }, a) => /* @__PURE__ */ n("h3", {
19
+ o.displayName = "CardHeader";
20
+ var s = t(({ className: t, children: r, ...i }, a) => /* @__PURE__ */ n("h3", {
20
21
  ref: a,
21
22
  className: e("text-2xl font-semibold leading-none tracking-tight", t),
22
23
  ...i,
23
24
  children: r
24
25
  }));
25
- o.displayName = "CardTitle";
26
- var s = t(({ className: t, children: r, ...i }, a) => /* @__PURE__ */ n("p", {
26
+ s.displayName = "CardTitle";
27
+ var c = t(({ className: t, children: r, ...i }, a) => /* @__PURE__ */ n("p", {
27
28
  ref: a,
28
- className: e("text-sm text-muted-foreground", t),
29
+ className: e("text-sm text-text-secondary", t),
29
30
  ...i,
30
31
  children: r
31
32
  }));
32
- s.displayName = "CardDescription";
33
- var c = t(({ className: t, children: r, ...i }, a) => /* @__PURE__ */ n("div", {
33
+ c.displayName = "CardDescription";
34
+ var l = t(({ className: t, children: r, ...i }, a) => /* @__PURE__ */ n("div", {
34
35
  ref: a,
35
36
  className: e("p-6 pt-0", t),
36
37
  ...i,
37
38
  children: r
38
39
  }));
39
- c.displayName = "CardContent";
40
- var l = t(({ className: t, children: r, ...i }, a) => /* @__PURE__ */ n("div", {
40
+ l.displayName = "CardContent";
41
+ var u = t(({ className: t, children: r, ...i }, a) => /* @__PURE__ */ n("div", {
41
42
  ref: a,
42
43
  className: e("flex items-center p-6 pt-0", t),
43
44
  ...i,
44
45
  children: r
45
46
  }));
46
- l.displayName = "CardFooter";
47
- var u = {
48
- default: "bg-primary text-primary-foreground",
47
+ u.displayName = "CardFooter";
48
+ var d = {
49
+ default: "bg-action-primary-bg text-action-primary-text",
49
50
  secondary: "bg-secondary text-secondary-foreground",
50
51
  success: "bg-success/10 text-success border-success/20",
51
52
  warning: "bg-warning/10 text-warning border-warning/20",
52
- destructive: "bg-destructive/10 text-destructive border-destructive/20",
53
- outline: "border-border bg-transparent text-foreground"
54
- }, d = t(({ className: t, variant: r = "default", children: i, ...a }, o) => /* @__PURE__ */ n("span", {
53
+ destructive: "bg-status-error-bg/10 text-status-error-text border-status-error-border/20",
54
+ outline: "border-border-subtle bg-transparent text-text-primary"
55
+ }, f = t(({ className: t, variant: r = "default", children: i, ...a }, o) => /* @__PURE__ */ n("span", {
55
56
  ref: o,
56
- className: e("inline-flex items-center rounded-full border px-2.5 py-0.5 text-xs font-semibold transition-colors", u[r], t),
57
+ className: e("inline-flex items-center rounded-full border px-2.5 py-0.5 text-xs font-semibold transition-colors", d[r], t),
57
58
  ...a,
58
59
  children: i
59
60
  }));
60
- d.displayName = "Badge";
61
- var f = {
62
- default: "bg-primary text-primary-foreground hover:bg-primary/90",
61
+ f.displayName = "Badge";
62
+ var p = {
63
+ default: "bg-action-primary-bg text-action-primary-text hover:bg-action-primary-bg/90",
63
64
  secondary: "bg-secondary text-secondary-foreground hover:bg-secondary/80",
64
- outline: "border border-input bg-background hover:bg-accent hover:text-accent-foreground",
65
- ghost: "hover:bg-accent hover:text-accent-foreground",
66
- destructive: "bg-destructive text-destructive-foreground hover:bg-destructive/90",
65
+ outline: "border border-border-default bg-bg-surface hover:bg-accent hover:text-text-primary",
66
+ ghost: "hover:bg-accent hover:text-text-primary",
67
+ destructive: "bg-status-error-bg text-status-error-text hover:bg-status-error-bg/90",
67
68
  link: "text-primary underline-offset-4 hover:underline"
68
- }, p = {
69
+ }, m = {
69
70
  default: "h-10 px-4 py-2",
70
71
  sm: "h-9 rounded-md px-3",
71
72
  lg: "h-11 rounded-md px-8",
72
73
  icon: "h-10 w-10"
73
- }, m = t(({ className: t, variant: r = "default", size: i = "default", children: a, ...o }, s) => /* @__PURE__ */ n("button", {
74
+ }, h = t(({ className: t, variant: r = "default", size: i = "default", children: a, ...o }, s) => /* @__PURE__ */ n("button", {
74
75
  ref: s,
75
- className: e("inline-flex items-center justify-center whitespace-nowrap rounded-md text-sm font-medium ring-offset-background transition-colors", "focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2", "disabled:pointer-events-none disabled:opacity-50", f[r], p[i], t),
76
+ className: e("inline-flex items-center justify-center whitespace-nowrap rounded-md text-sm font-medium ring-offset-background transition-colors", "focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-[var(--color-focus-ring)] focus-visible:ring-offset-2", "disabled:pointer-events-none disabled:opacity-50", p[r], m[i], t),
76
77
  ...o,
77
78
  children: a
78
79
  }));
79
- m.displayName = "Button";
80
- var h = t(({ className: t, type: r, ...i }, a) => /* @__PURE__ */ n("input", {
80
+ h.displayName = "Button";
81
+ var g = t(({ className: t, type: r, ...i }, a) => /* @__PURE__ */ n("input", {
81
82
  type: r,
82
- className: e("flex h-10 w-full rounded-md border border-input bg-background px-3 py-2 text-sm ring-offset-background", "file:border-0 file:bg-transparent file:text-sm file:font-medium file:text-foreground", "placeholder:text-muted-foreground", "focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2", "disabled:cursor-not-allowed disabled:opacity-50", t),
83
+ className: e("flex h-10 w-full rounded-md border border-border-default bg-bg-surface px-3 py-2 text-sm ring-offset-background", "file:border-0 file:bg-transparent file:text-sm file:font-medium file:text-text-primary", "placeholder:text-text-secondary", "focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-[var(--color-focus-ring)] focus-visible:ring-offset-2", "disabled:cursor-not-allowed disabled:opacity-50", t),
83
84
  ref: a,
84
85
  ...i
85
86
  }));
86
- h.displayName = "Input";
87
- var g = t(({ className: t, ...r }, i) => /* @__PURE__ */ n("div", {
87
+ g.displayName = "Input";
88
+ var _ = t(({ className: t, ...r }, i) => /* @__PURE__ */ n("div", {
88
89
  ref: i,
89
- className: e("animate-pulse rounded-md bg-muted", t),
90
+ className: e("animate-pulse rounded-md bg-bg-sunken", t),
90
91
  ...r
91
92
  }));
92
- g.displayName = "Skeleton";
93
- var _ = t(({ className: t, orientation: r = "horizontal", ...i }, a) => /* @__PURE__ */ n("div", {
93
+ _.displayName = "Skeleton";
94
+ var v = t(({ className: t, orientation: r = "horizontal", ...i }, a) => /* @__PURE__ */ n("div", {
94
95
  ref: a,
95
96
  className: e("shrink-0 bg-border", r === "horizontal" ? "h-[1px] w-full" : "h-full w-[1px]", t),
96
97
  ...i
97
98
  }));
98
- _.displayName = "Separator";
99
- var v = {
99
+ v.displayName = "Separator";
100
+ var y = {
100
101
  sm: "h-8 w-8 text-xs",
101
102
  default: "h-10 w-10 text-sm",
102
103
  lg: "h-12 w-12 text-base"
103
- }, y = t(({ className: t, src: r, alt: i, fallback: a, size: o = "default", ...s }, c) => /* @__PURE__ */ n("div", {
104
+ }, b = t(({ className: t, src: r, alt: i, fallback: a, size: o = "default", ...s }, c) => /* @__PURE__ */ n("div", {
104
105
  ref: c,
105
- className: e("relative flex shrink-0 overflow-hidden rounded-full bg-muted", v[o], t),
106
+ className: e("relative flex shrink-0 overflow-hidden rounded-full bg-bg-sunken", y[o], t),
106
107
  ...s,
107
108
  children: r ? /* @__PURE__ */ n("img", {
108
109
  src: r,
109
110
  alt: i,
110
111
  className: "aspect-square h-full w-full object-cover"
111
112
  }) : /* @__PURE__ */ n("span", {
112
- className: "flex h-full w-full items-center justify-center font-medium text-muted-foreground",
113
+ className: "flex h-full w-full items-center justify-center font-medium text-text-secondary",
113
114
  children: a
114
115
  })
115
116
  }));
116
- y.displayName = "Avatar";
117
- function b({ icon: e, title: t, description: i, action: a }) {
118
- return /* @__PURE__ */ r("div", {
117
+ b.displayName = "Avatar";
118
+ function x({ icon: e, title: t, description: a, action: o, illustration: s }) {
119
+ return s ? /* @__PURE__ */ n(i, {
120
+ illustration: s,
121
+ title: t,
122
+ description: a,
123
+ action: o,
124
+ className: "py-12"
125
+ }) : /* @__PURE__ */ r("div", {
119
126
  className: "flex flex-col items-center justify-center py-12 text-center",
120
127
  children: [
121
128
  e && /* @__PURE__ */ n("div", {
122
- className: "mb-4 rounded-full bg-muted p-4 text-muted-foreground",
129
+ className: "mb-4 rounded-full bg-bg-sunken p-4 text-text-secondary",
123
130
  children: e
124
131
  }),
125
132
  /* @__PURE__ */ n("h3", {
126
133
  className: "mb-2 text-lg font-semibold",
127
134
  children: t
128
135
  }),
129
- i && /* @__PURE__ */ n("p", {
130
- className: "mb-4 max-w-sm text-sm text-muted-foreground",
131
- children: i
136
+ a && /* @__PURE__ */ n("p", {
137
+ className: "mb-4 max-w-sm text-sm text-text-secondary",
138
+ children: a
132
139
  }),
133
- a
140
+ o
134
141
  ]
135
142
  });
136
143
  }
137
144
  //#endregion
138
- export { y as Avatar, d as Badge, m as Button, i as Card, c as CardContent, s as CardDescription, l as CardFooter, a as CardHeader, o as CardTitle, b as EmptyState, h as Input, _ as Separator, g as Skeleton };
145
+ export { b as Avatar, f as Badge, h as Button, a as Card, l as CardContent, c as CardDescription, u as CardFooter, o as CardHeader, s as CardTitle, x as EmptyState, g as Input, v as Separator, _ as Skeleton };
139
146
 
140
147
  //# sourceMappingURL=ui.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"ui.js","names":[],"sources":["../../../src/admin/components/ui.tsx"],"sourcesContent":["/**\n * Shared UI Components for Admin Console\n * Using semantic tokens for consistent theming\n */\n\nimport type { ReactNode, HTMLAttributes, ButtonHTMLAttributes } from 'react';\nimport { forwardRef } from 'react';\nimport { cn } from '../utils/cn';\n\n// ============================================================================\n// Card Components\n// ============================================================================\n\ninterface CardProps extends HTMLAttributes<HTMLDivElement> {\n children: ReactNode;\n}\n\nexport const Card = forwardRef<HTMLDivElement, CardProps>(\n ({ className, children, ...props }, ref) => (\n <div\n ref={ref}\n className={cn(\n 'rounded-lg border border-border bg-card text-card-foreground shadow-sm',\n className\n )}\n {...props}\n >\n {children}\n </div>\n )\n);\nCard.displayName = 'Card';\n\nexport const CardHeader = forwardRef<HTMLDivElement, CardProps>(\n ({ className, children, ...props }, ref) => (\n <div ref={ref} className={cn('flex flex-col space-y-1.5 p-6', className)} {...props}>\n {children}\n </div>\n )\n);\nCardHeader.displayName = 'CardHeader';\n\nexport const CardTitle = forwardRef<HTMLHeadingElement, HTMLAttributes<HTMLHeadingElement>>(\n ({ className, children, ...props }, ref) => (\n <h3\n ref={ref}\n className={cn('text-2xl font-semibold leading-none tracking-tight', className)}\n {...props}\n >\n {children}\n </h3>\n )\n);\nCardTitle.displayName = 'CardTitle';\n\nexport const CardDescription = forwardRef<\n HTMLParagraphElement,\n HTMLAttributes<HTMLParagraphElement>\n>(({ className, children, ...props }, ref) => (\n <p ref={ref} className={cn('text-sm text-muted-foreground', className)} {...props}>\n {children}\n </p>\n));\nCardDescription.displayName = 'CardDescription';\n\nexport const CardContent = forwardRef<HTMLDivElement, CardProps>(\n ({ className, children, ...props }, ref) => (\n <div ref={ref} className={cn('p-6 pt-0', className)} {...props}>\n {children}\n </div>\n )\n);\nCardContent.displayName = 'CardContent';\n\nexport const CardFooter = forwardRef<HTMLDivElement, CardProps>(\n ({ className, children, ...props }, ref) => (\n <div ref={ref} className={cn('flex items-center p-6 pt-0', className)} {...props}>\n {children}\n </div>\n )\n);\nCardFooter.displayName = 'CardFooter';\n\n// ============================================================================\n// Badge Component\n// ============================================================================\n\ninterface BadgeProps extends HTMLAttributes<HTMLSpanElement> {\n variant?: 'default' | 'secondary' | 'success' | 'warning' | 'destructive' | 'outline';\n}\n\nconst badgeVariants = {\n default: 'bg-primary text-primary-foreground',\n secondary: 'bg-secondary text-secondary-foreground',\n success: 'bg-success/10 text-success border-success/20',\n warning: 'bg-warning/10 text-warning border-warning/20',\n destructive: 'bg-destructive/10 text-destructive border-destructive/20',\n outline: 'border-border bg-transparent text-foreground',\n};\n\nexport const Badge = forwardRef<HTMLSpanElement, BadgeProps>(\n ({ className, variant = 'default', children, ...props }, ref) => (\n <span\n ref={ref}\n className={cn(\n 'inline-flex items-center rounded-full border px-2.5 py-0.5 text-xs font-semibold transition-colors',\n badgeVariants[variant],\n className\n )}\n {...props}\n >\n {children}\n </span>\n )\n);\nBadge.displayName = 'Badge';\n\n// ============================================================================\n// Button Component\n// ============================================================================\n\ninterface ButtonProps extends ButtonHTMLAttributes<HTMLButtonElement> {\n variant?: 'default' | 'secondary' | 'outline' | 'ghost' | 'destructive' | 'link';\n size?: 'default' | 'sm' | 'lg' | 'icon';\n}\n\nconst buttonVariants = {\n default: 'bg-primary text-primary-foreground hover:bg-primary/90',\n secondary: 'bg-secondary text-secondary-foreground hover:bg-secondary/80',\n outline: 'border border-input bg-background hover:bg-accent hover:text-accent-foreground',\n ghost: 'hover:bg-accent hover:text-accent-foreground',\n destructive: 'bg-destructive text-destructive-foreground hover:bg-destructive/90',\n link: 'text-primary underline-offset-4 hover:underline',\n};\n\nconst buttonSizes = {\n default: 'h-10 px-4 py-2',\n sm: 'h-9 rounded-md px-3',\n lg: 'h-11 rounded-md px-8',\n icon: 'h-10 w-10',\n};\n\nexport const Button = forwardRef<HTMLButtonElement, ButtonProps>(\n ({ className, variant = 'default', size = 'default', children, ...props }, ref) => (\n <button\n ref={ref}\n className={cn(\n 'inline-flex items-center justify-center whitespace-nowrap rounded-md text-sm font-medium ring-offset-background transition-colors',\n 'focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2',\n 'disabled:pointer-events-none disabled:opacity-50',\n buttonVariants[variant],\n buttonSizes[size],\n className\n )}\n {...props}\n >\n {children}\n </button>\n )\n);\nButton.displayName = 'Button';\n\n// ============================================================================\n// Input Component\n// ============================================================================\n\ntype InputProps = React.InputHTMLAttributes<HTMLInputElement>;\n\nexport const Input = forwardRef<HTMLInputElement, InputProps>(\n ({ className, type, ...props }, ref) => (\n <input\n type={type}\n className={cn(\n 'flex h-10 w-full rounded-md border border-input bg-background px-3 py-2 text-sm ring-offset-background',\n 'file:border-0 file:bg-transparent file:text-sm file:font-medium file:text-foreground',\n 'placeholder:text-muted-foreground',\n 'focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2',\n 'disabled:cursor-not-allowed disabled:opacity-50',\n className\n )}\n ref={ref}\n {...props}\n />\n )\n);\nInput.displayName = 'Input';\n\n// ============================================================================\n// Skeleton Component\n// ============================================================================\n\ntype SkeletonProps = HTMLAttributes<HTMLDivElement>;\n\nexport const Skeleton = forwardRef<HTMLDivElement, SkeletonProps>(\n ({ className, ...props }, ref) => (\n <div ref={ref} className={cn('animate-pulse rounded-md bg-muted', className)} {...props} />\n )\n);\nSkeleton.displayName = 'Skeleton';\n\n// ============================================================================\n// Separator Component\n// ============================================================================\n\ninterface SeparatorProps extends HTMLAttributes<HTMLDivElement> {\n orientation?: 'horizontal' | 'vertical';\n}\n\nexport const Separator = forwardRef<HTMLDivElement, SeparatorProps>(\n ({ className, orientation = 'horizontal', ...props }, ref) => (\n <div\n ref={ref}\n className={cn(\n 'shrink-0 bg-border',\n orientation === 'horizontal' ? 'h-[1px] w-full' : 'h-full w-[1px]',\n className\n )}\n {...props}\n />\n )\n);\nSeparator.displayName = 'Separator';\n\n// ============================================================================\n// Avatar Component\n// ============================================================================\n\ninterface AvatarProps extends HTMLAttributes<HTMLDivElement> {\n src?: string;\n alt?: string;\n fallback: string;\n size?: 'sm' | 'default' | 'lg';\n}\n\nconst avatarSizes = {\n sm: 'h-8 w-8 text-xs',\n default: 'h-10 w-10 text-sm',\n lg: 'h-12 w-12 text-base',\n};\n\nexport const Avatar = forwardRef<HTMLDivElement, AvatarProps>(\n ({ className, src, alt, fallback, size = 'default', ...props }, ref) => (\n <div\n ref={ref}\n className={cn(\n 'relative flex shrink-0 overflow-hidden rounded-full bg-muted',\n avatarSizes[size],\n className\n )}\n {...props}\n >\n {src ? (\n <img src={src} alt={alt} className=\"aspect-square h-full w-full object-cover\" />\n ) : (\n <span className=\"flex h-full w-full items-center justify-center font-medium text-muted-foreground\">\n {fallback}\n </span>\n )}\n </div>\n )\n);\nAvatar.displayName = 'Avatar';\n\n// ============================================================================\n// Empty State Component\n// ============================================================================\n\ninterface EmptyStateProps {\n icon?: ReactNode;\n title: string;\n description?: string;\n action?: ReactNode;\n}\n\nexport function EmptyState({ icon, title, description, action }: EmptyStateProps) {\n return (\n <div className=\"flex flex-col items-center justify-center py-12 text-center\">\n {icon && <div className=\"mb-4 rounded-full bg-muted p-4 text-muted-foreground\">{icon}</div>}\n <h3 className=\"mb-2 text-lg font-semibold\">{title}</h3>\n {description && <p className=\"mb-4 max-w-sm text-sm text-muted-foreground\">{description}</p>}\n {action}\n </div>\n );\n}\n\n// ============================================================================\n// Loading Spinner Component\n// ============================================================================\n\ninterface SpinnerProps extends HTMLAttributes<HTMLDivElement> {\n size?: 'sm' | 'default' | 'lg';\n}\n\nconst spinnerSizes = {\n sm: 'h-4 w-4',\n default: 'h-6 w-6',\n lg: 'h-8 w-8',\n};\n\nexport function Spinner({ className, size = 'default', ...props }: SpinnerProps) {\n return (\n <div\n className={cn(\n 'animate-spin rounded-full border-2 border-current border-t-transparent text-primary',\n spinnerSizes[size],\n className\n )}\n {...props}\n />\n );\n}\n\n// ============================================================================\n// Page Loading Fallback\n// ============================================================================\n\ninterface PageLoadingFallbackProps {\n message?: string;\n}\n\nexport function PageLoadingFallback({ message = 'Loading...' }: PageLoadingFallbackProps) {\n return (\n <div className=\"flex h-full min-h-[400px] flex-col items-center justify-center gap-4\">\n <Spinner size=\"lg\" />\n <p className=\"text-sm text-muted-foreground\">{message}</p>\n </div>\n );\n}\n"],"mappings":"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"}
1
+ {"version":3,"file":"ui.js","names":[],"sources":["../../../src/admin/components/ui.tsx"],"sourcesContent":["/**\n * Shared UI Components for Admin Console\n * Using semantic tokens for consistent theming\n */\n\nimport type { ReactNode, HTMLAttributes, ButtonHTMLAttributes } from 'react';\nimport { forwardRef } from 'react';\nimport { IllustratedEmptyState } from '@burdenoff/fe-libs/ui';\nimport { cn } from '../utils/cn';\n\n// ============================================================================\n// Card Components\n// ============================================================================\n\ninterface CardProps extends HTMLAttributes<HTMLDivElement> {\n children: ReactNode;\n}\n\nexport const Card = forwardRef<HTMLDivElement, CardProps>(\n ({ className, children, ...props }, ref) => (\n <div\n ref={ref}\n className={cn(\n 'rounded-card border border-border-seam bg-bg-surface text-text-primary shadow-elevation-1 transition-[box-shadow,border-color] duration-200 hover:border-border-strong',\n className\n )}\n {...props}\n >\n {children}\n </div>\n )\n);\nCard.displayName = 'Card';\n\nexport const CardHeader = forwardRef<HTMLDivElement, CardProps>(\n ({ className, children, ...props }, ref) => (\n <div ref={ref} className={cn('flex flex-col space-y-1.5 p-6', className)} {...props}>\n {children}\n </div>\n )\n);\nCardHeader.displayName = 'CardHeader';\n\nexport const CardTitle = forwardRef<HTMLHeadingElement, HTMLAttributes<HTMLHeadingElement>>(\n ({ className, children, ...props }, ref) => (\n <h3\n ref={ref}\n className={cn('text-2xl font-semibold leading-none tracking-tight', className)}\n {...props}\n >\n {children}\n </h3>\n )\n);\nCardTitle.displayName = 'CardTitle';\n\nexport const CardDescription = forwardRef<\n HTMLParagraphElement,\n HTMLAttributes<HTMLParagraphElement>\n>(({ className, children, ...props }, ref) => (\n <p ref={ref} className={cn('text-sm text-text-secondary', className)} {...props}>\n {children}\n </p>\n));\nCardDescription.displayName = 'CardDescription';\n\nexport const CardContent = forwardRef<HTMLDivElement, CardProps>(\n ({ className, children, ...props }, ref) => (\n <div ref={ref} className={cn('p-6 pt-0', className)} {...props}>\n {children}\n </div>\n )\n);\nCardContent.displayName = 'CardContent';\n\nexport const CardFooter = forwardRef<HTMLDivElement, CardProps>(\n ({ className, children, ...props }, ref) => (\n <div ref={ref} className={cn('flex items-center p-6 pt-0', className)} {...props}>\n {children}\n </div>\n )\n);\nCardFooter.displayName = 'CardFooter';\n\n// ============================================================================\n// Badge Component\n// ============================================================================\n\ninterface BadgeProps extends HTMLAttributes<HTMLSpanElement> {\n variant?: 'default' | 'secondary' | 'success' | 'warning' | 'destructive' | 'outline';\n}\n\nconst badgeVariants = {\n default: 'bg-action-primary-bg text-action-primary-text',\n secondary: 'bg-secondary text-secondary-foreground',\n success: 'bg-success/10 text-success border-success/20',\n warning: 'bg-warning/10 text-warning border-warning/20',\n destructive: 'bg-status-error-bg/10 text-status-error-text border-status-error-border/20',\n outline: 'border-border-subtle bg-transparent text-text-primary',\n};\n\nexport const Badge = forwardRef<HTMLSpanElement, BadgeProps>(\n ({ className, variant = 'default', children, ...props }, ref) => (\n <span\n ref={ref}\n className={cn(\n 'inline-flex items-center rounded-full border px-2.5 py-0.5 text-xs font-semibold transition-colors',\n badgeVariants[variant],\n className\n )}\n {...props}\n >\n {children}\n </span>\n )\n);\nBadge.displayName = 'Badge';\n\n// ============================================================================\n// Button Component\n// ============================================================================\n\ninterface ButtonProps extends ButtonHTMLAttributes<HTMLButtonElement> {\n variant?: 'default' | 'secondary' | 'outline' | 'ghost' | 'destructive' | 'link';\n size?: 'default' | 'sm' | 'lg' | 'icon';\n}\n\nconst buttonVariants = {\n default: 'bg-action-primary-bg text-action-primary-text hover:bg-action-primary-bg/90',\n secondary: 'bg-secondary text-secondary-foreground hover:bg-secondary/80',\n outline: 'border border-border-default bg-bg-surface hover:bg-accent hover:text-text-primary',\n ghost: 'hover:bg-accent hover:text-text-primary',\n destructive: 'bg-status-error-bg text-status-error-text hover:bg-status-error-bg/90',\n link: 'text-primary underline-offset-4 hover:underline',\n};\n\nconst buttonSizes = {\n default: 'h-10 px-4 py-2',\n sm: 'h-9 rounded-md px-3',\n lg: 'h-11 rounded-md px-8',\n icon: 'h-10 w-10',\n};\n\nexport const Button = forwardRef<HTMLButtonElement, ButtonProps>(\n ({ className, variant = 'default', size = 'default', children, ...props }, ref) => (\n <button\n ref={ref}\n className={cn(\n 'inline-flex items-center justify-center whitespace-nowrap rounded-md text-sm font-medium ring-offset-background transition-colors',\n 'focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-[var(--color-focus-ring)] focus-visible:ring-offset-2',\n 'disabled:pointer-events-none disabled:opacity-50',\n buttonVariants[variant],\n buttonSizes[size],\n className\n )}\n {...props}\n >\n {children}\n </button>\n )\n);\nButton.displayName = 'Button';\n\n// ============================================================================\n// Input Component\n// ============================================================================\n\ntype InputProps = React.InputHTMLAttributes<HTMLInputElement>;\n\nexport const Input = forwardRef<HTMLInputElement, InputProps>(\n ({ className, type, ...props }, ref) => (\n <input\n type={type}\n className={cn(\n 'flex h-10 w-full rounded-md border border-border-default bg-bg-surface px-3 py-2 text-sm ring-offset-background',\n 'file:border-0 file:bg-transparent file:text-sm file:font-medium file:text-text-primary',\n 'placeholder:text-text-secondary',\n 'focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-[var(--color-focus-ring)] focus-visible:ring-offset-2',\n 'disabled:cursor-not-allowed disabled:opacity-50',\n className\n )}\n ref={ref}\n {...props}\n />\n )\n);\nInput.displayName = 'Input';\n\n// ============================================================================\n// Skeleton Component\n// ============================================================================\n\ntype SkeletonProps = HTMLAttributes<HTMLDivElement>;\n\nexport const Skeleton = forwardRef<HTMLDivElement, SkeletonProps>(\n ({ className, ...props }, ref) => (\n <div ref={ref} className={cn('animate-pulse rounded-md bg-bg-sunken', className)} {...props} />\n )\n);\nSkeleton.displayName = 'Skeleton';\n\n// ============================================================================\n// Separator Component\n// ============================================================================\n\ninterface SeparatorProps extends HTMLAttributes<HTMLDivElement> {\n orientation?: 'horizontal' | 'vertical';\n}\n\nexport const Separator = forwardRef<HTMLDivElement, SeparatorProps>(\n ({ className, orientation = 'horizontal', ...props }, ref) => (\n <div\n ref={ref}\n className={cn(\n 'shrink-0 bg-border',\n orientation === 'horizontal' ? 'h-[1px] w-full' : 'h-full w-[1px]',\n className\n )}\n {...props}\n />\n )\n);\nSeparator.displayName = 'Separator';\n\n// ============================================================================\n// Avatar Component\n// ============================================================================\n\ninterface AvatarProps extends HTMLAttributes<HTMLDivElement> {\n src?: string;\n alt?: string;\n fallback: string;\n size?: 'sm' | 'default' | 'lg';\n}\n\nconst avatarSizes = {\n sm: 'h-8 w-8 text-xs',\n default: 'h-10 w-10 text-sm',\n lg: 'h-12 w-12 text-base',\n};\n\nexport const Avatar = forwardRef<HTMLDivElement, AvatarProps>(\n ({ className, src, alt, fallback, size = 'default', ...props }, ref) => (\n <div\n ref={ref}\n className={cn(\n 'relative flex shrink-0 overflow-hidden rounded-full bg-bg-sunken',\n avatarSizes[size],\n className\n )}\n {...props}\n >\n {src ? (\n <img src={src} alt={alt} className=\"aspect-square h-full w-full object-cover\" />\n ) : (\n <span className=\"flex h-full w-full items-center justify-center font-medium text-text-secondary\">\n {fallback}\n </span>\n )}\n </div>\n )\n);\nAvatar.displayName = 'Avatar';\n\n// ============================================================================\n// Empty State Component\n// ============================================================================\n\ninterface EmptyStateProps {\n icon?: ReactNode;\n title: string;\n description?: string;\n action?: ReactNode;\n /**\n * On-brand illustration name (Boff UI 2.0). When provided, renders the\n * IllustratedEmptyState (host serves /illustrations/<name>.webp). Standard\n * names: empty-data, empty-search, empty-files, empty-people,\n * empty-notifications, onboarding, empty-generic. Falls back to the icon\n * variant when omitted.\n */\n illustration?: string;\n}\n\nexport function EmptyState({ icon, title, description, action, illustration }: EmptyStateProps) {\n if (illustration) {\n return (\n <IllustratedEmptyState\n illustration={illustration}\n title={title}\n description={description}\n action={action}\n className=\"py-12\"\n />\n );\n }\n return (\n <div className=\"flex flex-col items-center justify-center py-12 text-center\">\n {icon && <div className=\"mb-4 rounded-full bg-bg-sunken p-4 text-text-secondary\">{icon}</div>}\n <h3 className=\"mb-2 text-lg font-semibold\">{title}</h3>\n {description && <p className=\"mb-4 max-w-sm text-sm text-text-secondary\">{description}</p>}\n {action}\n </div>\n );\n}\n\n// ============================================================================\n// Loading Spinner Component\n// ============================================================================\n\ninterface SpinnerProps extends HTMLAttributes<HTMLDivElement> {\n size?: 'sm' | 'default' | 'lg';\n}\n\nconst spinnerSizes = {\n sm: 'h-4 w-4',\n default: 'h-6 w-6',\n lg: 'h-8 w-8',\n};\n\nexport function Spinner({ className, size = 'default', ...props }: SpinnerProps) {\n return (\n <div\n className={cn(\n 'animate-spin rounded-full border-2 border-current border-t-transparent text-primary',\n spinnerSizes[size],\n className\n )}\n {...props}\n />\n );\n}\n\n// ============================================================================\n// Page Loading Fallback\n// ============================================================================\n\ninterface PageLoadingFallbackProps {\n message?: string;\n}\n\nexport function PageLoadingFallback({ message = 'Loading...' }: PageLoadingFallbackProps) {\n return (\n <div className=\"flex h-full min-h-[400px] flex-col items-center justify-center gap-4\">\n <Spinner size=\"lg\" />\n <p className=\"text-sm text-text-secondary\">{message}</p>\n </div>\n );\n}\n"],"mappings":"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"}
@@ -6,7 +6,7 @@ var e = {
6
6
  },
7
7
  suspended: {
8
8
  label: "Suspended",
9
- color: "bg-destructive/10 text-destructive border-destructive/20"
9
+ color: "bg-status-error-bg/10 text-status-error-text border-status-error-border/20"
10
10
  },
11
11
  trial: {
12
12
  label: "Trial",
@@ -14,7 +14,7 @@ var e = {
14
14
  },
15
15
  deleted: {
16
16
  label: "Deleted",
17
- color: "bg-muted text-muted-foreground border-muted"
17
+ color: "bg-bg-sunken text-text-secondary border-muted"
18
18
  },
19
19
  pending: {
20
20
  label: "Pending",
@@ -31,11 +31,11 @@ var e = {
31
31
  },
32
32
  inactive: {
33
33
  label: "Inactive",
34
- color: "bg-muted text-muted-foreground border-muted"
34
+ color: "bg-bg-sunken text-text-secondary border-muted"
35
35
  },
36
36
  blocked: {
37
37
  label: "Blocked",
38
- color: "bg-destructive/10 text-destructive border-destructive/20"
38
+ color: "bg-status-error-bg/10 text-status-error-text border-status-error-border/20"
39
39
  },
40
40
  pending: {
41
41
  label: "Pending",
@@ -52,16 +52,16 @@ var e = {
52
52
  },
53
53
  down: {
54
54
  label: "Down",
55
- color: "bg-destructive/10 text-destructive border-destructive/20"
55
+ color: "bg-status-error-bg/10 text-status-error-text border-status-error-border/20"
56
56
  },
57
57
  unknown: {
58
58
  label: "Unknown",
59
- color: "bg-muted text-muted-foreground border-muted"
59
+ color: "bg-bg-sunken text-text-secondary border-muted"
60
60
  }
61
61
  }, r = {
62
62
  pending: {
63
63
  label: "Pending",
64
- color: "bg-muted text-muted-foreground border-muted"
64
+ color: "bg-bg-sunken text-text-secondary border-muted"
65
65
  },
66
66
  running: {
67
67
  label: "Running",
@@ -77,7 +77,7 @@ var e = {
77
77
  },
78
78
  failed: {
79
79
  label: "Failed",
80
- color: "bg-destructive/10 text-destructive border-destructive/20"
80
+ color: "bg-status-error-bg/10 text-status-error-text border-status-error-border/20"
81
81
  },
82
82
  rolled_back: {
83
83
  label: "Rolled Back",
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","names":[],"sources":["../../../src/admin/constants/index.ts"],"sourcesContent":["import type {\n TenantStatus,\n UserStatus,\n SubscriptionStatus,\n TicketStatus,\n TicketPriority,\n HealthStatus,\n DeploymentStatus,\n CloudProvider,\n} from '../types';\n\n/**\n * Tenant status labels and colors\n */\nexport const TENANT_STATUS_CONFIG: Record<TenantStatus, { label: string; color: string }> = {\n active: { label: 'Active', color: 'bg-success/10 text-success border-success/20' },\n suspended: {\n label: 'Suspended',\n color: 'bg-destructive/10 text-destructive border-destructive/20',\n },\n trial: { label: 'Trial', color: 'bg-warning/10 text-warning border-warning/20' },\n deleted: { label: 'Deleted', color: 'bg-muted text-muted-foreground border-muted' },\n pending: { label: 'Pending', color: 'bg-info/10 text-info border-info/20' },\n provisioning: { label: 'Provisioning', color: 'bg-amber-100 text-amber-700 border-amber-200' },\n};\n\n/**\n * User status labels and colors\n */\nexport const USER_STATUS_CONFIG: Record<UserStatus, { label: string; color: string }> = {\n active: { label: 'Active', color: 'bg-success/10 text-success border-success/20' },\n inactive: { label: 'Inactive', color: 'bg-muted text-muted-foreground border-muted' },\n blocked: { label: 'Blocked', color: 'bg-destructive/10 text-destructive border-destructive/20' },\n pending: { label: 'Pending', color: 'bg-warning/10 text-warning border-warning/20' },\n};\n\n/**\n * Subscription status labels and colors\n */\nexport const SUBSCRIPTION_STATUS_CONFIG: Record<\n SubscriptionStatus,\n { label: string; color: string }\n> = {\n active: { label: 'Active', color: 'bg-success/10 text-success border-success/20' },\n canceled: { label: 'Canceled', color: 'bg-muted text-muted-foreground border-muted' },\n past_due: {\n label: 'Past Due',\n color: 'bg-destructive/10 text-destructive border-destructive/20',\n },\n trialing: { label: 'Trialing', color: 'bg-info/10 text-info border-info/20' },\n paused: { label: 'Paused', color: 'bg-warning/10 text-warning border-warning/20' },\n};\n\n/**\n * Ticket status labels and colors\n */\nexport const TICKET_STATUS_CONFIG: Record<TicketStatus, { label: string; color: string }> = {\n open: { label: 'Open', color: 'bg-info/10 text-info border-info/20' },\n in_progress: { label: 'In Progress', color: 'bg-warning/10 text-warning border-warning/20' },\n resolved: { label: 'Resolved', color: 'bg-success/10 text-success border-success/20' },\n closed: { label: 'Closed', color: 'bg-muted text-muted-foreground border-muted' },\n};\n\n/**\n * Ticket priority labels and colors\n */\nexport const TICKET_PRIORITY_CONFIG: Record<TicketPriority, { label: string; color: string }> = {\n low: { label: 'Low', color: 'bg-muted text-muted-foreground border-muted' },\n medium: { label: 'Medium', color: 'bg-info/10 text-info border-info/20' },\n high: { label: 'High', color: 'bg-warning/10 text-warning border-warning/20' },\n critical: {\n label: 'Critical',\n color: 'bg-destructive/10 text-destructive border-destructive/20',\n },\n};\n\n/**\n * Health status labels and colors\n */\nexport const HEALTH_STATUS_CONFIG: Record<HealthStatus, { label: string; color: string }> = {\n healthy: { label: 'Healthy', color: 'bg-success/10 text-success border-success/20' },\n degraded: { label: 'Degraded', color: 'bg-warning/10 text-warning border-warning/20' },\n down: { label: 'Down', color: 'bg-destructive/10 text-destructive border-destructive/20' },\n unknown: { label: 'Unknown', color: 'bg-muted text-muted-foreground border-muted' },\n};\n\n/**\n * Deployment status labels and colors\n */\nexport const DEPLOYMENT_STATUS_CONFIG: Record<DeploymentStatus, { label: string; color: string }> =\n {\n pending: { label: 'Pending', color: 'bg-muted text-muted-foreground border-muted' },\n running: { label: 'Running', color: 'bg-info/10 text-info border-info/20' },\n in_progress: { label: 'In Progress', color: 'bg-info/10 text-info border-info/20' },\n success: { label: 'Success', color: 'bg-success/10 text-success border-success/20' },\n failed: { label: 'Failed', color: 'bg-destructive/10 text-destructive border-destructive/20' },\n rolled_back: { label: 'Rolled Back', color: 'bg-warning/10 text-warning border-warning/20' },\n };\n\n/**\n * Cloud provider labels and colors\n */\nexport const CLOUD_PROVIDER_CONFIG: Record<\n CloudProvider,\n { label: string; color: string; icon: string }\n> = {\n aws: {\n label: 'AWS',\n color: 'bg-orange-500/10 text-orange-500 border-orange-500/20',\n icon: 'aws',\n },\n azure: {\n label: 'Azure',\n color: 'bg-blue-500/10 text-blue-500 border-blue-500/20',\n icon: 'azure',\n },\n gcp: { label: 'GCP', color: 'bg-red-500/10 text-red-500 border-red-500/20', icon: 'gcp' },\n digitalocean: {\n label: 'DigitalOcean',\n color: 'bg-cyan-500/10 text-cyan-500 border-cyan-500/20',\n icon: 'do',\n },\n};\n\n/**\n * Chart colors using semantic tokens\n */\nexport const CHART_COLORS = {\n primary: 'hsl(var(--chart-1))',\n secondary: 'hsl(var(--chart-2))',\n tertiary: 'hsl(var(--chart-3))',\n quaternary: 'hsl(var(--chart-4))',\n quinary: 'hsl(var(--chart-5))',\n};\n\n/**\n * Default pagination\n */\nexport const DEFAULT_PAGE_SIZE = 20;\nexport const PAGE_SIZE_OPTIONS = [10, 20, 50, 100];\n"],"mappings":";AAcA,IAAa,IAA+E;CAC1F,QAAQ;EAAE,OAAO;EAAU,OAAO;EAAgD;CAClF,WAAW;EACT,OAAO;EACP,OAAO;EACR;CACD,OAAO;EAAE,OAAO;EAAS,OAAO;EAAgD;CAChF,SAAS;EAAE,OAAO;EAAW,OAAO;EAA+C;CACnF,SAAS;EAAE,OAAO;EAAW,OAAO;EAAuC;CAC3E,cAAc;EAAE,OAAO;EAAgB,OAAO;EAAgD;CAC/F,EAKY,IAA2E;CACtF,QAAQ;EAAE,OAAO;EAAU,OAAO;EAAgD;CAClF,UAAU;EAAE,OAAO;EAAY,OAAO;EAA+C;CACrF,SAAS;EAAE,OAAO;EAAW,OAAO;EAA4D;CAChG,SAAS;EAAE,OAAO;EAAW,OAAO;EAAgD;CACrF,EA6CY,IAA+E;CAC1F,SAAS;EAAE,OAAO;EAAW,OAAO;EAAgD;CACpF,UAAU;EAAE,OAAO;EAAY,OAAO;EAAgD;CACtF,MAAM;EAAE,OAAO;EAAQ,OAAO;EAA4D;CAC1F,SAAS;EAAE,OAAO;EAAW,OAAO;EAA+C;CACpF,EAKY,IACX;CACE,SAAS;EAAE,OAAO;EAAW,OAAO;EAA+C;CACnF,SAAS;EAAE,OAAO;EAAW,OAAO;EAAuC;CAC3E,aAAa;EAAE,OAAO;EAAe,OAAO;EAAuC;CACnF,SAAS;EAAE,OAAO;EAAW,OAAO;EAAgD;CACpF,QAAQ;EAAE,OAAO;EAAU,OAAO;EAA4D;CAC9F,aAAa;EAAE,OAAO;EAAe,OAAO;EAAgD;CAC7F"}
1
+ {"version":3,"file":"index.js","names":[],"sources":["../../../src/admin/constants/index.ts"],"sourcesContent":["import type {\n TenantStatus,\n UserStatus,\n SubscriptionStatus,\n TicketStatus,\n TicketPriority,\n HealthStatus,\n DeploymentStatus,\n CloudProvider,\n} from '../types';\n\n/**\n * Tenant status labels and colors\n */\nexport const TENANT_STATUS_CONFIG: Record<TenantStatus, { label: string; color: string }> = {\n active: { label: 'Active', color: 'bg-success/10 text-success border-success/20' },\n suspended: {\n label: 'Suspended',\n color: 'bg-status-error-bg/10 text-status-error-text border-status-error-border/20',\n },\n trial: { label: 'Trial', color: 'bg-warning/10 text-warning border-warning/20' },\n deleted: { label: 'Deleted', color: 'bg-bg-sunken text-text-secondary border-muted' },\n pending: { label: 'Pending', color: 'bg-info/10 text-info border-info/20' },\n provisioning: { label: 'Provisioning', color: 'bg-amber-100 text-amber-700 border-amber-200' },\n};\n\n/**\n * User status labels and colors\n */\nexport const USER_STATUS_CONFIG: Record<UserStatus, { label: string; color: string }> = {\n active: { label: 'Active', color: 'bg-success/10 text-success border-success/20' },\n inactive: { label: 'Inactive', color: 'bg-bg-sunken text-text-secondary border-muted' },\n blocked: { label: 'Blocked', color: 'bg-status-error-bg/10 text-status-error-text border-status-error-border/20' },\n pending: { label: 'Pending', color: 'bg-warning/10 text-warning border-warning/20' },\n};\n\n/**\n * Subscription status labels and colors\n */\nexport const SUBSCRIPTION_STATUS_CONFIG: Record<\n SubscriptionStatus,\n { label: string; color: string }\n> = {\n active: { label: 'Active', color: 'bg-success/10 text-success border-success/20' },\n canceled: { label: 'Canceled', color: 'bg-bg-sunken text-text-secondary border-muted' },\n past_due: {\n label: 'Past Due',\n color: 'bg-status-error-bg/10 text-status-error-text border-status-error-border/20',\n },\n trialing: { label: 'Trialing', color: 'bg-info/10 text-info border-info/20' },\n paused: { label: 'Paused', color: 'bg-warning/10 text-warning border-warning/20' },\n};\n\n/**\n * Ticket status labels and colors\n */\nexport const TICKET_STATUS_CONFIG: Record<TicketStatus, { label: string; color: string }> = {\n open: { label: 'Open', color: 'bg-info/10 text-info border-info/20' },\n in_progress: { label: 'In Progress', color: 'bg-warning/10 text-warning border-warning/20' },\n resolved: { label: 'Resolved', color: 'bg-success/10 text-success border-success/20' },\n closed: { label: 'Closed', color: 'bg-bg-sunken text-text-secondary border-muted' },\n};\n\n/**\n * Ticket priority labels and colors\n */\nexport const TICKET_PRIORITY_CONFIG: Record<TicketPriority, { label: string; color: string }> = {\n low: { label: 'Low', color: 'bg-bg-sunken text-text-secondary border-muted' },\n medium: { label: 'Medium', color: 'bg-info/10 text-info border-info/20' },\n high: { label: 'High', color: 'bg-warning/10 text-warning border-warning/20' },\n critical: {\n label: 'Critical',\n color: 'bg-status-error-bg/10 text-status-error-text border-status-error-border/20',\n },\n};\n\n/**\n * Health status labels and colors\n */\nexport const HEALTH_STATUS_CONFIG: Record<HealthStatus, { label: string; color: string }> = {\n healthy: { label: 'Healthy', color: 'bg-success/10 text-success border-success/20' },\n degraded: { label: 'Degraded', color: 'bg-warning/10 text-warning border-warning/20' },\n down: { label: 'Down', color: 'bg-status-error-bg/10 text-status-error-text border-status-error-border/20' },\n unknown: { label: 'Unknown', color: 'bg-bg-sunken text-text-secondary border-muted' },\n};\n\n/**\n * Deployment status labels and colors\n */\nexport const DEPLOYMENT_STATUS_CONFIG: Record<DeploymentStatus, { label: string; color: string }> =\n {\n pending: { label: 'Pending', color: 'bg-bg-sunken text-text-secondary border-muted' },\n running: { label: 'Running', color: 'bg-info/10 text-info border-info/20' },\n in_progress: { label: 'In Progress', color: 'bg-info/10 text-info border-info/20' },\n success: { label: 'Success', color: 'bg-success/10 text-success border-success/20' },\n failed: { label: 'Failed', color: 'bg-status-error-bg/10 text-status-error-text border-status-error-border/20' },\n rolled_back: { label: 'Rolled Back', color: 'bg-warning/10 text-warning border-warning/20' },\n };\n\n/**\n * Cloud provider labels and colors\n */\nexport const CLOUD_PROVIDER_CONFIG: Record<\n CloudProvider,\n { label: string; color: string; icon: string }\n> = {\n aws: {\n label: 'AWS',\n color: 'bg-orange-500/10 text-orange-500 border-orange-500/20',\n icon: 'aws',\n },\n azure: {\n label: 'Azure',\n color: 'bg-blue-500/10 text-blue-500 border-blue-500/20',\n icon: 'azure',\n },\n gcp: { label: 'GCP', color: 'bg-red-500/10 text-red-500 border-red-500/20', icon: 'gcp' },\n digitalocean: {\n label: 'DigitalOcean',\n color: 'bg-cyan-500/10 text-cyan-500 border-cyan-500/20',\n icon: 'do',\n },\n};\n\n/**\n * Chart colors using semantic tokens\n */\nexport const CHART_COLORS = {\n primary: 'hsl(var(--chart-1))',\n secondary: 'hsl(var(--chart-2))',\n tertiary: 'hsl(var(--chart-3))',\n quaternary: 'hsl(var(--chart-4))',\n quinary: 'hsl(var(--chart-5))',\n};\n\n/**\n * Default pagination\n */\nexport const DEFAULT_PAGE_SIZE = 20;\nexport const PAGE_SIZE_OPTIONS = [10, 20, 50, 100];\n"],"mappings":";AAcA,IAAa,IAA+E;CAC1F,QAAQ;EAAE,OAAO;EAAU,OAAO;EAAgD;CAClF,WAAW;EACT,OAAO;EACP,OAAO;EACR;CACD,OAAO;EAAE,OAAO;EAAS,OAAO;EAAgD;CAChF,SAAS;EAAE,OAAO;EAAW,OAAO;EAAiD;CACrF,SAAS;EAAE,OAAO;EAAW,OAAO;EAAuC;CAC3E,cAAc;EAAE,OAAO;EAAgB,OAAO;EAAgD;CAC/F,EAKY,IAA2E;CACtF,QAAQ;EAAE,OAAO;EAAU,OAAO;EAAgD;CAClF,UAAU;EAAE,OAAO;EAAY,OAAO;EAAiD;CACvF,SAAS;EAAE,OAAO;EAAW,OAAO;EAA8E;CAClH,SAAS;EAAE,OAAO;EAAW,OAAO;EAAgD;CACrF,EA6CY,IAA+E;CAC1F,SAAS;EAAE,OAAO;EAAW,OAAO;EAAgD;CACpF,UAAU;EAAE,OAAO;EAAY,OAAO;EAAgD;CACtF,MAAM;EAAE,OAAO;EAAQ,OAAO;EAA8E;CAC5G,SAAS;EAAE,OAAO;EAAW,OAAO;EAAiD;CACtF,EAKY,IACX;CACE,SAAS;EAAE,OAAO;EAAW,OAAO;EAAiD;CACrF,SAAS;EAAE,OAAO;EAAW,OAAO;EAAuC;CAC3E,aAAa;EAAE,OAAO;EAAe,OAAO;EAAuC;CACnF,SAAS;EAAE,OAAO;EAAW,OAAO;EAAgD;CACpF,QAAQ;EAAE,OAAO;EAAU,OAAO;EAA8E;CAChH,aAAa;EAAE,OAAO;EAAe,OAAO;EAAgD;CAC7F"}