/** * Prompts List Page (Story 19.9) * * Route: /prompts * * Features: * - Table of prompt templates with search and category filter * - "Discovered Prompts" tab for auto-fingerprinted prompts * - Create Template button * - Row click → /prompts/:id */ import React, { useState, useCallback, useMemo } from 'react'; import { useNavigate } from 'react-router-dom'; import { useApi } from '../hooks/useApi'; import { getPrompts, getPromptFingerprints, createPrompt, linkFingerprintToTemplate, } from '../api/prompts'; import type { PromptTemplate, PromptFingerprint, PromptListResponse } from '../api/prompts'; // ─── Constants ────────────────────────────────────────────────── const PAGE_SIZE = 20; const CATEGORIES = ['general', 'system', 'assistant', 'tool', 'safety', 'other']; type TabKey = 'templates' | 'discovered'; // ─── Helpers ──────────────────────────────────────────────────── function formatDate(iso: string): string { try { return new Date(iso).toLocaleDateString(undefined, { year: 'numeric', month: 'short', day: 'numeric', }); } catch { return iso; } } function categoryBadge(category: string): React.ReactElement { const colors: Record = { system: 'bg-blue-100 text-blue-700', safety: 'bg-red-100 text-red-700', tool: 'bg-green-100 text-green-700', assistant: 'bg-purple-100 text-purple-700', general: 'bg-gray-100 text-gray-600', }; const cls = colors[category] || 'bg-gray-100 text-gray-600'; return ( {category} ); } // ─── Create Modal ─────────────────────────────────────────────── function CreatePromptModal({ onClose, onCreated, }: { onClose: () => void; onCreated: () => void; }) { const [name, setName] = useState(''); const [content, setContent] = useState(''); const [description, setDescription] = useState(''); const [category, setCategory] = useState('general'); const [saving, setSaving] = useState(false); const [error, setError] = useState(''); const handleSubmit = async (e: React.FormEvent) => { e.preventDefault(); if (!name.trim() || !content.trim()) return; setSaving(true); setError(''); try { await createPrompt({ name: name.trim(), content, description, category }); onCreated(); onClose(); } catch (err: any) { setError(err?.message || 'Failed to create template'); } finally { setSaving(false); } }; return (
e.stopPropagation()} >

Create Prompt Template

setName(e.target.value)} className="w-full rounded-lg border border-gray-300 px-3 py-2 text-sm focus:ring-2 focus:ring-brand-500 focus:border-brand-500" placeholder="My System Prompt" required />
setDescription(e.target.value)} className="w-full rounded-lg border border-gray-300 px-3 py-2 text-sm" placeholder="Optional description" />