Files
projectbrain-Public/src/features/memory/pages/MemoryRules.tsx
T

117 lines
5.3 KiB
TypeScript

"use client";
import { useState } from "react";
import { Link, useParams } from "react-router-dom";
import { Card, CardContent } from "@/components/ui/card";
import { Badge } from "@/components/ui/badge";
import {
Search,
ShieldAlert,
Code2,
Palette,
Workflow,
CheckCircle2,
AlertTriangle,
} from "lucide-react";
import { Input } from "@/components/ui/input";
import { cn } from "@/shared/lib/utils";
import { useProject } from "@/shared/contexts/ProjectContext";
import { PageHeader } from "@/components/ui/PageHeader";
const MemoryRules = () => {
const { projectId } = useParams();
const { projects, contextPacks } = useProject();
const project = projects.find(p => p.id === projectId);
const rules = project?.memoryRules ?? [];
const [search, setSearch] = useState("");
const visibleRules = rules.filter((rule) => `${rule.title} ${rule.description} ${rule.category}`.toLowerCase().includes(search.trim().toLowerCase()));
const activePack = project?.activeContextPackId
? contextPacks.find((pack) => pack.id === project.activeContextPackId)
: undefined;
return (
<div className="space-y-8">
<PageHeader
title="Memory Rules"
subtitle="Define the constraints and rules that guide your project's development."
/>
<div className="flex items-center gap-4">
<div className="relative flex-1">
<Search className="absolute left-3 top-1/2 -translate-y-1/2 text-muted-foreground" size={16} />
<Input value={search} onChange={(event) => setSearch(event.target.value)} placeholder="Search rules..." className="pl-10" aria-label="Search memory rules" />
</div>
</div>
<div className="grid grid-cols-1 gap-4">
{visibleRules.map((rule) => (
<Card key={rule.id} className="hover:shadow-sm transition-shadow animate-fade-in">
<CardContent className="p-6 flex items-start gap-4">
<div className="p-2 rounded-lg bg-primary/10 text-primary">
{rule.category === "UX" && <Palette size={24} />}
{rule.category === "Technical" && <Code2 size={24} />}
{rule.category === "Architecture" && <Workflow size={24} />}
{rule.category === "Do Not Break" && <ShieldAlert size={24} />}
</div>
<div className="flex-1">
<div className="flex items-center gap-2 mb-1">
<span className="text-xs font-semibold uppercase tracking-wider text-muted-foreground">
{rule.category}
</span>
<Badge variant={rule.scope === "global" ? "default" : rule.scope === "project" ? "secondary" : "outline"}>
{rule.scope ?? "project"}
</Badge>
<Badge variant="outline" className={cn(
"text-[10px]",
rule.priority === "Critical" ? "text-destructive border-destructive/20 bg-destructive/5" : ""
)}>
{rule.priority}
</Badge>
<Badge variant="secondary" className="text-[10px]">{rule.impact}</Badge>
{rule.scope === "feature" && <Badge variant="outline">feature-scoped</Badge>}
{rule.category === "Do Not Break" && (
<Badge variant="destructive" className="text-[10px]">Do Not Break</Badge>
)}
</div>
<div className="flex items-center gap-2">
<h3 className="text-lg font-semibold">{rule.title}</h3>
{rule.status === "Verified" ? (
<CheckCircle2 size={14} className="text-green-500" />
) : (
<AlertTriangle size={14} className="text-yellow-500" />
)}
</div>
<p className="text-sm text-muted-foreground mt-1">{rule.description}</p>
<p className="text-xs text-muted-foreground mt-2">
Severity: {rule.severity ?? rule.priority} • {rule.linkedFeatureIds?.length ? "linked features" : "no linked features"}
</p>
<p className="text-xs text-muted-foreground mt-1">
Include in active context pack:{" "}
{(rule.includeInContextPacks ?? []).includes(activePack?.id ?? "") ? "yes" : "no"}
{activePack ? (
<Link
to={`/projects/${projectId}/context-packs`}
className="ml-2 underline underline-offset-4"
>
open context packs
</Link>
) : null}
</p>
</div>
</CardContent>
</Card>
))}
{visibleRules.length === 0 && (
<div className="text-center py-20 border-2 border-dashed rounded-xl bg-muted/10">
<ShieldAlert size={48} className="mx-auto text-muted-foreground mb-4" />
<h3 className="text-lg font-semibold mb-2">{rules.length ? "No matching memory rules" : "No memory rules defined"}</h3>
<p className="text-muted-foreground">{rules.length ? "Try a broader search." : "Create rules through the database-backed Memory API or Review Queue conversion flow."}</p>
</div>
)}
</div>
</div>
);
};
export default MemoryRules;