"use client"
import { useState } from "react"
import {
BookOpen,
InboxIcon,
LoaderCircle,
RefreshCw,
Zap,
Clock,
Tag,
FileText,
Lightbulb,
Repeat2,
StickyNote,
ArrowRightLeft,
CalendarClock,
ListTodo,
} from "lucide-react"
import { Badge } from "@/components/ui/badge"
import { Button } from "@/components/ui/button"
import type {
KnowledgeData,
KnowledgeEntry,
CapturesData,
CaptureEntry,
Classification,
} from "@/lib/knowledge-captures-types"
import { cn } from "@/lib/utils"
import {
useGSDWorkspaceActions,
useGSDWorkspaceState,
} from "@/lib/gsd-workspace-store"
// ═══════════════════════════════════════════════════════════════════════
// SHARED HELPERS
// ═══════════════════════════════════════════════════════════════════════
function PanelHeader({
title,
subtitle,
status,
onRefresh,
refreshing,
}: {
title: string
subtitle?: string | null
status?: React.ReactNode
onRefresh: () => void
refreshing: boolean
}) {
return (
{title}
{status}
{subtitle && {subtitle}}
)
}
function PanelError({ message }: { message: string }) {
return (
{message}
)
}
function PanelLoading({ label }: { label: string }) {
return (
{label}
)
}
function PanelEmpty({ message }: { message: string }) {
return (
{message}
)
}
function StatPill({ label, value, variant }: { label: string; value: number | string; variant?: "default" | "error" | "warning" | "info" }) {
return (
{label}
{value}
)
}
// ═══════════════════════════════════════════════════════════════════════
// KNOWLEDGE TYPE STYLING
// ═══════════════════════════════════════════════════════════════════════
function knowledgeTypeBadge(type: KnowledgeEntry["type"]) {
switch (type) {
case "rule":
return { label: "Rule", className: "border-violet-500/30 bg-violet-500/10 text-violet-400" }
case "pattern":
return { label: "Pattern", className: "border-info/30 bg-info/10 text-info" }
case "lesson":
return { label: "Lesson", className: "border-warning/30 bg-warning/10 text-warning" }
case "freeform":
return { label: "Freeform", className: "border-success/30 bg-success/10 text-success" }
}
}
function KnowledgeTypeIcon({ type, className }: { type: KnowledgeEntry["type"]; className?: string }) {
const base = cn("h-3.5 w-3.5 shrink-0", className)
switch (type) {
case "rule":
return
case "pattern":
return
case "lesson":
return
case "freeform":
return
}
}
// ═══════════════════════════════════════════════════════════════════════
// CAPTURE STATUS STYLING
// ═══════════════════════════════════════════════════════════════════════
function captureStatusStyle(status: CaptureEntry["status"]) {
switch (status) {
case "pending":
return { label: "Pending", className: "border-warning/30 bg-warning/10 text-warning" }
case "triaged":
return { label: "Triaged", className: "border-info/30 bg-info/10 text-info" }
case "resolved":
return { label: "Resolved", className: "border-success/30 bg-success/10 text-success" }
}
}
function classificationLabel(c: Classification): string {
switch (c) {
case "quick-task": return "Quick Task"
case "inject": return "Inject"
case "defer": return "Defer"
case "replan": return "Replan"
case "note": return "Note"
}
}
function ClassificationIcon({ classification, className }: { classification: Classification; className?: string }) {
const base = cn("h-3 w-3 shrink-0", className)
switch (classification) {
case "quick-task": return
case "inject": return
case "defer": return
case "replan": return
case "note": return
}
}
const CLASSIFICATION_OPTIONS: Classification[] = ["quick-task", "inject", "defer", "replan", "note"]
// ═══════════════════════════════════════════════════════════════════════
// KNOWLEDGE TAB CONTENT
// ═══════════════════════════════════════════════════════════════════════
function KnowledgeEntryRow({ entry }: { entry: KnowledgeEntry }) {
const badge = knowledgeTypeBadge(entry.type)
return (
{entry.title}
{badge.label}
{entry.content && (
{entry.content}
)}
)
}
function KnowledgeTabContent({
data,
phase,
error,
onRefresh,
}: {
data: KnowledgeData | null
phase: string
error: string | null
onRefresh: () => void
}) {
if (phase === "loading") return
if (phase === "error" && error) return
if (!data || data.entries.length === 0) return
return (
{data.entries.map((entry) => (
))}
{data.lastModified && (
Last modified: {new Date(data.lastModified).toLocaleString()}
)}
)
}
// ═══════════════════════════════════════════════════════════════════════
// CAPTURES TAB CONTENT
// ═══════════════════════════════════════════════════════════════════════
function CaptureEntryRow({
entry,
onResolve,
resolvePending,
}: {
entry: CaptureEntry
onResolve: (captureId: string, classification: Classification) => void
resolvePending: boolean
}) {
const status = captureStatusStyle(entry.status)
return (
{entry.text}
{status.label}
{entry.classification && (
{classificationLabel(entry.classification)}
)}
{entry.timestamp && (
{entry.timestamp}
)}
{entry.resolution && (
{entry.resolution}
)}
{entry.status === "pending" && (
{CLASSIFICATION_OPTIONS.map((c) => (
))}
)}
)
}
function CapturesTabContent({
data,
phase,
error,
resolvePending,
resolveError,
onRefresh,
onResolve,
}: {
data: CapturesData | null
phase: string
error: string | null
resolvePending: boolean
resolveError: string | null
onRefresh: () => void
onResolve: (captureId: string, classification: Classification) => void
}) {
if (phase === "loading") return
if (phase === "error" && error) return
if (!data || data.entries.length === 0) return
return (
0 ? "warning" : "default"} />
0 ? "info" : "default"} />
}
onRefresh={onRefresh}
refreshing={phase === "loading"}
/>
{resolveError && (
Resolve error: {resolveError}
)}
{data.entries.map((entry) => (
))}
)
}
// ═══════════════════════════════════════════════════════════════════════
// MAIN PANEL COMPONENT
// ═══════════════════════════════════════════════════════════════════════
interface KnowledgeCapturesPanelProps {
initialTab: "knowledge" | "captures"
}
export function KnowledgeCapturesPanel({ initialTab }: KnowledgeCapturesPanelProps) {
const [activeTab, setActiveTab] = useState<"knowledge" | "captures">(initialTab)
const workspace = useGSDWorkspaceState()
const { loadKnowledgeData, loadCapturesData, resolveCaptureAction } = useGSDWorkspaceActions()
const knowledgeCaptures = workspace.commandSurface.knowledgeCaptures
const knowledgeState = knowledgeCaptures.knowledge
const capturesState = knowledgeCaptures.captures
const resolveState = knowledgeCaptures.resolveRequest
const capturesData = capturesState.data as CapturesData | null
const pendingCount = capturesData?.pendingCount ?? 0
const handleResolve = (captureId: string, classification: Classification) => {
void resolveCaptureAction({
captureId,
classification,
resolution: "Manual browser triage",
rationale: "Triaged via web UI",
})
}
return (
{/* Tab bar */}
{/* Tab content */}
{activeTab === "knowledge" ? (
void loadKnowledgeData()}
/>
) : (
void loadCapturesData()}
onResolve={handleResolve}
/>
)}
)
}