Improve issue and approvals UI: parent chain, project names, approval details
shared: - Add IssueAncestor type and ancestors?: IssueAncestor[] to Issue interface IssueDetail: - Show clickable parent chain breadcrumb above issue title when issue has parents - Ancestors rendered root-first (reversed from API order) with chevron separators IssueProperties: - Project field now shows project name with a link instead of raw UUID - Assignee field now links to agent detail page - Parent field shows immediate parent title (from ancestors[0]) with link - Show request depth when > 0 Approvals: - Pending/All filter tabs with pending count badge - HireAgentPayload renders name, role, title, capabilities, adapter type - CeoStrategyPayload renders plan/description text in a monospace block - Decision note shown when present - Requester agent name shown in header - Approve button uses green styling; empty state with icon Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
@@ -1,6 +1,8 @@
|
||||
import { Link } from "react-router-dom";
|
||||
import type { Issue } from "@paperclip/shared";
|
||||
import { useQuery } from "@tanstack/react-query";
|
||||
import { agentsApi } from "../api/agents";
|
||||
import { projectsApi } from "../api/projects";
|
||||
import { useCompany } from "../context/CompanyContext";
|
||||
import { queryKeys } from "../lib/queryKeys";
|
||||
import { StatusIcon } from "./StatusIcon";
|
||||
@@ -33,18 +35,35 @@ function priorityLabel(priority: string): string {
|
||||
|
||||
export function IssueProperties({ issue, onUpdate }: IssuePropertiesProps) {
|
||||
const { selectedCompanyId } = useCompany();
|
||||
|
||||
const { data: agents } = useQuery({
|
||||
queryKey: queryKeys.agents.list(selectedCompanyId!),
|
||||
queryFn: () => agentsApi.list(selectedCompanyId!),
|
||||
enabled: !!selectedCompanyId,
|
||||
});
|
||||
|
||||
const { data: projects } = useQuery({
|
||||
queryKey: queryKeys.projects.list(selectedCompanyId!),
|
||||
queryFn: () => projectsApi.list(selectedCompanyId!),
|
||||
enabled: !!selectedCompanyId && !!issue.projectId,
|
||||
});
|
||||
|
||||
const agentName = (id: string | null) => {
|
||||
if (!id || !agents) return null;
|
||||
const agent = agents.find((a) => a.id === id);
|
||||
return agent?.name ?? id.slice(0, 8);
|
||||
};
|
||||
|
||||
const projectName = (id: string | null) => {
|
||||
if (!id || !projects) return id?.slice(0, 8) ?? "None";
|
||||
const project = projects.find((p) => p.id === id);
|
||||
return project?.name ?? id.slice(0, 8);
|
||||
};
|
||||
|
||||
const assignee = issue.assigneeAgentId
|
||||
? agents?.find((a) => a.id === issue.assigneeAgentId)
|
||||
: null;
|
||||
|
||||
return (
|
||||
<div className="space-y-4">
|
||||
<div className="space-y-1">
|
||||
@@ -65,16 +84,45 @@ export function IssueProperties({ issue, onUpdate }: IssuePropertiesProps) {
|
||||
</PropertyRow>
|
||||
|
||||
<PropertyRow label="Assignee">
|
||||
<span className="text-sm">
|
||||
{issue.assigneeAgentId ? agentName(issue.assigneeAgentId) : "Unassigned"}
|
||||
</span>
|
||||
{assignee ? (
|
||||
<Link
|
||||
to={`/agents/${assignee.id}`}
|
||||
className="text-sm hover:underline"
|
||||
>
|
||||
{assignee.name}
|
||||
</Link>
|
||||
) : (
|
||||
<span className="text-sm text-muted-foreground">Unassigned</span>
|
||||
)}
|
||||
</PropertyRow>
|
||||
|
||||
<PropertyRow label="Project">
|
||||
<span className="text-sm text-muted-foreground">
|
||||
{issue.projectId ? issue.projectId.slice(0, 8) : "None"}
|
||||
</span>
|
||||
</PropertyRow>
|
||||
{issue.projectId && (
|
||||
<PropertyRow label="Project">
|
||||
<Link
|
||||
to={`/projects/${issue.projectId}`}
|
||||
className="text-sm hover:underline"
|
||||
>
|
||||
{projectName(issue.projectId)}
|
||||
</Link>
|
||||
</PropertyRow>
|
||||
)}
|
||||
|
||||
{issue.parentId && (
|
||||
<PropertyRow label="Parent">
|
||||
<Link
|
||||
to={`/issues/${issue.parentId}`}
|
||||
className="text-sm hover:underline"
|
||||
>
|
||||
{issue.ancestors?.[0]?.title ?? issue.parentId.slice(0, 8)}
|
||||
</Link>
|
||||
</PropertyRow>
|
||||
)}
|
||||
|
||||
{issue.requestDepth > 0 && (
|
||||
<PropertyRow label="Depth">
|
||||
<span className="text-sm font-mono">{issue.requestDepth}</span>
|
||||
</PropertyRow>
|
||||
)}
|
||||
</div>
|
||||
|
||||
<Separator />
|
||||
|
||||
Reference in New Issue
Block a user