Skip to content

Admin UI Components API ​

This document describes the reusable UI components available for building admin interfaces in Veriprompt.

Components Overview ​

ComponentImport PathPurpose
Breadcrumbs@/components/ui/breadcrumbsNavigation breadcrumbs
ExportButton@/components/ui/export-buttonData export functionality
CloneButton@/components/ui/clone-buttonItem duplication

Utilities ​

UtilityImport PathPurpose
cross-links@/lib/cross-linksRelated page navigation

Displays hierarchical navigation showing the user's current location.

Import ​

tsx
import { Breadcrumbs } from '@/components/ui/breadcrumbs';

Props ​

PropTypeDefaultDescription
itemsBreadcrumbItem[][]Array of breadcrumb items
showHomebooleantrueShow home icon as first item
homeHrefstring/dashboardURL for home link
separatorReactNode<ChevronRight />Custom separator element
classNamestring-Additional CSS classes
autoGeneratebooleanfalseAuto-generate from URL path
typescript
interface BreadcrumbItem {
  label: string;      // Display text
  href?: string;      // Link URL (optional for last item)
  icon?: ReactNode;   // Optional icon
}

Usage Examples ​

Manual Items:

tsx
<Breadcrumbs
  items={[
    { label: 'Admin', href: '/admin' },
    { label: 'Settings', href: '/admin/settings' },
    { label: 'API Keys' }  // Current page (no href)
  ]}
/>

Auto-Generated:

tsx
<Breadcrumbs autoGenerate />
// URL: /admin/routing-policies
// Output: Home > Admin > Routing Policies

Custom Separator:

tsx
<Breadcrumbs
  items={items}
  separator={<span className="mx-2">/</span>}
/>

Path Labels ​

The component includes predefined labels for common paths:

Path SegmentLabel
adminAdmin
routing-policiesRouting Policies
dynamic-rankingDynamic Ranking
throttlingThrottling
api-consoleAPI Console
ai-providersAI Providers
analyticsAnalytics

ExportButton Component ​

Button component for exporting data to files.

Import ​

tsx
import { ExportButton } from '@/components/ui/export-button';

Props ​

PropTypeDefaultDescription
dataunknownRequiredData to export
filenamestring'export'Filename without extension
format'json' | 'csv' | 'txt''json'Export format
onExport(data, format) => void-Custom export handler
onExportSuccess() => void-Success callback
onExportError(error) => void-Error callback
showIconbooleantrueShow format icon
labelstring'Export {FORMAT}'Button label
successLabelstring'Exported!'Success state label
loadingLabelstring'Exporting...'Loading state label

Inherits all ButtonProps except onClick and onError.

Usage Examples ​

Basic JSON Export:

tsx
<ExportButton
  data={apiResponse}
  filename="routing-policies"
  format="json"
/>

CSV Export with Callbacks:

tsx
<ExportButton
  data={analyticsData}
  filename="monthly-report"
  format="csv"
  onExportSuccess={() => toast.success('Report exported!')}
  onExportError={(err) => toast.error(err.message)}
/>

Custom Export Handler:

tsx
<ExportButton
  data={encryptedData}
  format="json"
  onExport={(data, format) => {
    const decrypted = decrypt(data);
    downloadFile(decrypted, format);
  }}
/>

Format Handling ​

FormatMIME TypeConversion
jsonapplication/jsonJSON.stringify(data, null, 2)
csvtext/csvConverts array of objects to CSV
txttext/plainString or JSON stringified

CloneButton Component ​

Button component for duplicating items.

Import ​

tsx
import { CloneButton } from '@/components/ui/clone-button';

Props ​

PropTypeDefaultDescription
onClone() => Promise<void> | voidRequiredClone handler function
labelstring'Clone'Button label
successLabelstring'Cloned!'Success state label
loadingLabelstring'Cloning...'Loading state label
showIconbooleantrueShow copy icon
confirmMessagestring'Are you sure...'Confirmation dialog text
requireConfirmbooleanfalseShow confirmation dialog

Inherits all ButtonProps except onClick.

Usage Examples ​

Simple Clone:

tsx
<CloneButton
  onClone={async () => {
    await api.clonePolicy(policyId);
    refreshList();
  }}
/>

With Confirmation:

tsx
<CloneButton
  onClone={handleClone}
  requireConfirm={true}
  confirmMessage="Clone this routing policy? A new policy will be created."
/>

Custom Labels:

tsx
<CloneButton
  onClone={handleDuplicate}
  label="Duplicate"
  successLabel="Duplicated!"
  loadingLabel="Duplicating..."
/>

Utility functions for managing page relationships and navigation.

Import ​

typescript
import {
  getRelatedPages,
  getAllCrossLinks,
  buildCrossLink,
  getPageMetadata,
  isValidCrossLink
} from '@/lib/cross-links';

Functions ​

getRelatedPages ​

Returns related pages for the current path.

typescript
function getRelatedPages(currentPath: string): CrossLinkDefinition[]

Example:

typescript
const related = getRelatedPages('/admin/routing-policies');
// Returns:
// [
//   { label: 'Dynamic Ranking', href: '/admin/dynamic-ranking', ... },
//   { label: 'AI Providers', href: '/admin/ai-providers', ... },
//   { label: 'Throttling', href: '/admin/throttling', ... }
// ]

Returns all cross-links grouped by category.

typescript
function getAllCrossLinks(): CrossLinkGroup[]

Example:

typescript
const groups = getAllCrossLinks();
// Returns:
// [
//   { title: 'Routing & Optimization', links: [...] },
//   { title: 'Provider Management', links: [...] },
//   { title: 'Testing & Development', links: [...] },
//   { title: 'Monitoring & Analytics', links: [...] }
// ]

Builds a URL with optional query parameters.

typescript
function buildCrossLink(
  basePath: string,
  params?: Record<string, string | number | boolean | undefined>
): string

Example:

typescript
const url = buildCrossLink('/admin/analytics', {
  startDate: '2024-01-01',
  provider: 'openai'
});
// Returns: '/admin/analytics?startDate=2024-01-01&provider=openai'

getPageMetadata ​

Returns metadata for a page path.

typescript
function getPageMetadata(path: string): {
  label: string;
  description: string;
  icon?: string;
} | null

Checks if a path is a valid cross-link destination.

typescript
function isValidCrossLink(path: string): boolean

Interfaces ​

typescript
interface CrossLinkDefinition {
  label: string;
  href: string;
  description?: string;
  icon?: string;
}

interface CrossLinkGroup {
  title: string;
  links: CrossLinkDefinition[];
}

Usage in Components ​

tsx
import { getRelatedPages } from '@/lib/cross-links';
import { usePathname } from 'next/navigation';
import Link from 'next/link';

export function RelatedPages() {
  const pathname = usePathname();
  const relatedPages = getRelatedPages(pathname);

  if (relatedPages.length === 0) return null;

  return (
    <div className="flex gap-2">
      <span>Related:</span>
      {relatedPages.map(page => (
        <Link key={page.href} href={page.href}>
          {page.label}
        </Link>
      ))}
    </div>
  );
}

Complete Example ​

Here's a complete example combining all components:

tsx
'use client';

import { useState } from 'react';
import { Breadcrumbs } from '@/components/ui/breadcrumbs';
import { ExportButton } from '@/components/ui/export-button';
import { CloneButton } from '@/components/ui/clone-button';
import { getRelatedPages } from '@/lib/cross-links';
import Link from 'next/link';

interface Policy {
  id: string;
  name: string;
  weights: Record<string, number>;
}

export default function PoliciesPage() {
  const [policies, setPolicies] = useState<Policy[]>([]);
  const relatedPages = getRelatedPages('/admin/routing-policies');

  const handleClone = async (policy: Policy) => {
    const cloned = { ...policy, id: crypto.randomUUID(), name: `${policy.name} (Copy)` };
    setPolicies([...policies, cloned]);
  };

  return (
    <div>
      {/* Breadcrumbs */}
      <Breadcrumbs
        items={[
          { label: 'Admin', href: '/admin' },
          { label: 'Routing Policies' }
        ]}
      />

      {/* Related Pages */}
      <div className="flex gap-2 text-sm">
        <span>Related:</span>
        {relatedPages.map(page => (
          <Link key={page.href} href={page.href} className="text-blue-600">
            {page.label}
          </Link>
        ))}
      </div>

      {/* Export All */}
      <ExportButton
        data={policies}
        filename="routing-policies"
        format="json"
      />

      {/* Policy List */}
      {policies.map(policy => (
        <div key={policy.id} className="flex items-center gap-2">
          <span>{policy.name}</span>
          <CloneButton
            onClone={() => handleClone(policy)}
            label="Clone"
            size="sm"
          />
          <ExportButton
            data={policy}
            filename={`policy-${policy.id}`}
            format="json"
            size="sm"
          />
        </div>
      ))}
    </div>
  );
}