Add detail pages, property panels, and restyle list pages
New pages: AgentDetail, GoalDetail, IssueDetail, ProjectDetail, Inbox, MyIssues. New feature components: AgentProperties, GoalProperties, IssueProperties, ProjectProperties, GoalTree, NewIssueDialog. Add heartbeats API client. Restyle all list pages (Agents, Issues, Goals, Projects, Dashboard, Costs, Activity, Org) with EntityRow, FilterBar, and improved layouts. Add routing for detail views. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
77
ui/src/components/IssueProperties.tsx
Normal file
77
ui/src/components/IssueProperties.tsx
Normal file
@@ -0,0 +1,77 @@
|
||||
import type { Issue } from "@paperclip/shared";
|
||||
import { StatusIcon } from "./StatusIcon";
|
||||
import { PriorityIcon } from "./PriorityIcon";
|
||||
import { formatDate } from "../lib/utils";
|
||||
import { Separator } from "@/components/ui/separator";
|
||||
|
||||
interface IssuePropertiesProps {
|
||||
issue: Issue;
|
||||
onUpdate: (data: Record<string, unknown>) => void;
|
||||
}
|
||||
|
||||
function PropertyRow({ label, children }: { label: string; children: React.ReactNode }) {
|
||||
return (
|
||||
<div className="flex items-center justify-between py-1.5">
|
||||
<span className="text-xs text-muted-foreground">{label}</span>
|
||||
<div className="flex items-center gap-1.5">{children}</div>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
function statusLabel(status: string): string {
|
||||
return status.replace(/_/g, " ").replace(/\b\w/g, (c) => c.toUpperCase());
|
||||
}
|
||||
|
||||
function priorityLabel(priority: string): string {
|
||||
return priority.charAt(0).toUpperCase() + priority.slice(1);
|
||||
}
|
||||
|
||||
export function IssueProperties({ issue, onUpdate }: IssuePropertiesProps) {
|
||||
return (
|
||||
<div className="space-y-4">
|
||||
<div className="space-y-1">
|
||||
<PropertyRow label="Status">
|
||||
<StatusIcon
|
||||
status={issue.status}
|
||||
onChange={(status) => onUpdate({ status })}
|
||||
/>
|
||||
<span className="text-sm">{statusLabel(issue.status)}</span>
|
||||
</PropertyRow>
|
||||
|
||||
<PropertyRow label="Priority">
|
||||
<PriorityIcon
|
||||
priority={issue.priority}
|
||||
onChange={(priority) => onUpdate({ priority })}
|
||||
/>
|
||||
<span className="text-sm">{priorityLabel(issue.priority)}</span>
|
||||
</PropertyRow>
|
||||
|
||||
{issue.assigneeAgentId && (
|
||||
<PropertyRow label="Assignee">
|
||||
<span className="text-sm font-mono">{issue.assigneeAgentId.slice(0, 8)}</span>
|
||||
</PropertyRow>
|
||||
)}
|
||||
|
||||
{issue.projectId && (
|
||||
<PropertyRow label="Project">
|
||||
<span className="text-sm font-mono">{issue.projectId.slice(0, 8)}</span>
|
||||
</PropertyRow>
|
||||
)}
|
||||
</div>
|
||||
|
||||
<Separator />
|
||||
|
||||
<div className="space-y-1">
|
||||
<PropertyRow label="ID">
|
||||
<span className="text-sm font-mono">{issue.id.slice(0, 8)}</span>
|
||||
</PropertyRow>
|
||||
<PropertyRow label="Created">
|
||||
<span className="text-sm">{formatDate(issue.createdAt)}</span>
|
||||
</PropertyRow>
|
||||
<PropertyRow label="Updated">
|
||||
<span className="text-sm">{formatDate(issue.updatedAt)}</span>
|
||||
</PropertyRow>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
Reference in New Issue
Block a user