2026-03-13 21:30:48 -05:00
|
|
|
import { useEffect, useMemo, useRef, useState, type ChangeEvent, type DragEvent } from "react";
|
2026-03-10 20:59:55 -05:00
|
|
|
import { Link, useLocation, useNavigate, useParams } from "@/lib/router";
|
2026-02-17 12:24:48 -06:00
|
|
|
import { useQuery, useMutation, useQueryClient } from "@tanstack/react-query";
|
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>
2026-02-17 09:57:06 -06:00
|
|
|
import { issuesApi } from "../api/issues";
|
UI: Identity component, LiveRunWidget, issue identifiers, and UX improvements
Add Identity component (avatar + name) used across agent/issue displays. Add
LiveRunWidget for real-time streaming of active heartbeat runs on issue detail
pages via WebSocket. Display issue identifiers (PAP-42) instead of UUID
fragments throughout Issues, Inbox, CommandPalette, and detail pages.
Enhance CommentThread with re-open checkbox, Cmd+Enter submit, sorted display,
and run linking. Improve Activity page with richer formatting and filtering.
Update Dashboard with live metrics. Add reports-to agent link in AgentProperties.
Various small fixes: StatusIcon centering, CopyText ref init, agent detail
run-issue cross-links.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-19 09:10:07 -06:00
|
|
|
import { activityApi } from "../api/activity";
|
2026-02-25 17:40:13 -06:00
|
|
|
import { heartbeatsApi } from "../api/heartbeats";
|
UI: Identity component, LiveRunWidget, issue identifiers, and UX improvements
Add Identity component (avatar + name) used across agent/issue displays. Add
LiveRunWidget for real-time streaming of active heartbeat runs on issue detail
pages via WebSocket. Display issue identifiers (PAP-42) instead of UUID
fragments throughout Issues, Inbox, CommandPalette, and detail pages.
Enhance CommentThread with re-open checkbox, Cmd+Enter submit, sorted display,
and run linking. Improve Activity page with richer formatting and filtering.
Update Dashboard with live metrics. Add reports-to agent link in AgentProperties.
Various small fixes: StatusIcon centering, CopyText ref init, agent detail
run-issue cross-links.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-19 09:10:07 -06:00
|
|
|
import { agentsApi } from "../api/agents";
|
2026-02-26 16:33:48 -06:00
|
|
|
import { authApi } from "../api/auth";
|
2026-02-20 09:01:28 -06:00
|
|
|
import { projectsApi } from "../api/projects";
|
2026-02-17 12:24:48 -06:00
|
|
|
import { useCompany } from "../context/CompanyContext";
|
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>
2026-02-17 09:57:06 -06:00
|
|
|
import { usePanel } from "../context/PanelContext";
|
|
|
|
|
import { useBreadcrumbs } from "../context/BreadcrumbContext";
|
2026-02-17 12:24:48 -06:00
|
|
|
import { queryKeys } from "../lib/queryKeys";
|
2026-03-10 20:59:55 -05:00
|
|
|
import { readIssueDetailBreadcrumb } from "../lib/issueDetailBreadcrumb";
|
2026-03-02 14:20:49 -06:00
|
|
|
import { useProjectOrder } from "../hooks/useProjectOrder";
|
2026-02-20 10:32:32 -06:00
|
|
|
import { relativeTime, cn, formatTokens } from "../lib/utils";
|
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>
2026-02-17 09:57:06 -06:00
|
|
|
import { InlineEditor } from "../components/InlineEditor";
|
|
|
|
|
import { CommentThread } from "../components/CommentThread";
|
2026-03-13 21:30:48 -05:00
|
|
|
import { IssueDocumentsSection } from "../components/IssueDocumentsSection";
|
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>
2026-02-17 09:57:06 -06:00
|
|
|
import { IssueProperties } from "../components/IssueProperties";
|
UI: Identity component, LiveRunWidget, issue identifiers, and UX improvements
Add Identity component (avatar + name) used across agent/issue displays. Add
LiveRunWidget for real-time streaming of active heartbeat runs on issue detail
pages via WebSocket. Display issue identifiers (PAP-42) instead of UUID
fragments throughout Issues, Inbox, CommandPalette, and detail pages.
Enhance CommentThread with re-open checkbox, Cmd+Enter submit, sorted display,
and run linking. Improve Activity page with richer formatting and filtering.
Update Dashboard with live metrics. Add reports-to agent link in AgentProperties.
Various small fixes: StatusIcon centering, CopyText ref init, agent detail
run-issue cross-links.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-19 09:10:07 -06:00
|
|
|
import { LiveRunWidget } from "../components/LiveRunWidget";
|
2026-03-02 13:31:58 -06:00
|
|
|
import type { MentionOption } from "../components/MarkdownEditor";
|
2026-03-07 20:07:39 -06:00
|
|
|
import { ScrollToBottom } from "../components/ScrollToBottom";
|
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>
2026-02-17 09:57:06 -06:00
|
|
|
import { StatusIcon } from "../components/StatusIcon";
|
|
|
|
|
import { PriorityIcon } from "../components/PriorityIcon";
|
UI: Identity component, LiveRunWidget, issue identifiers, and UX improvements
Add Identity component (avatar + name) used across agent/issue displays. Add
LiveRunWidget for real-time streaming of active heartbeat runs on issue detail
pages via WebSocket. Display issue identifiers (PAP-42) instead of UUID
fragments throughout Issues, Inbox, CommandPalette, and detail pages.
Enhance CommentThread with re-open checkbox, Cmd+Enter submit, sorted display,
and run linking. Improve Activity page with richer formatting and filtering.
Update Dashboard with live metrics. Add reports-to agent link in AgentProperties.
Various small fixes: StatusIcon centering, CopyText ref init, agent detail
run-issue cross-links.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-19 09:10:07 -06:00
|
|
|
import { StatusBadge } from "../components/StatusBadge";
|
|
|
|
|
import { Identity } from "../components/Identity";
|
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>
2026-02-17 09:57:06 -06:00
|
|
|
import { Separator } from "@/components/ui/separator";
|
2026-02-19 15:44:05 -06:00
|
|
|
import { Popover, PopoverTrigger, PopoverContent } from "@/components/ui/popover";
|
|
|
|
|
import { Button } from "@/components/ui/button";
|
2026-02-25 08:39:31 -06:00
|
|
|
import { Collapsible, CollapsibleContent, CollapsibleTrigger } from "@/components/ui/collapsible";
|
2026-02-23 19:49:43 -06:00
|
|
|
import { Sheet, SheetContent, SheetHeader, SheetTitle } from "@/components/ui/sheet";
|
|
|
|
|
import { ScrollArea } from "@/components/ui/scroll-area";
|
2026-02-25 08:39:31 -06:00
|
|
|
import { Tabs, TabsContent, TabsList, TabsTrigger } from "@/components/ui/tabs";
|
|
|
|
|
import {
|
|
|
|
|
Activity as ActivityIcon,
|
|
|
|
|
ChevronDown,
|
|
|
|
|
ChevronRight,
|
|
|
|
|
EyeOff,
|
|
|
|
|
Hexagon,
|
|
|
|
|
ListTree,
|
|
|
|
|
MessageSquare,
|
|
|
|
|
MoreHorizontal,
|
|
|
|
|
Paperclip,
|
|
|
|
|
SlidersHorizontal,
|
|
|
|
|
Trash2,
|
|
|
|
|
} from "lucide-react";
|
2026-03-03 08:45:26 -06:00
|
|
|
import type { ActivityEvent } from "@paperclipai/shared";
|
|
|
|
|
import type { Agent, IssueAttachment } from "@paperclipai/shared";
|
UI: Identity component, LiveRunWidget, issue identifiers, and UX improvements
Add Identity component (avatar + name) used across agent/issue displays. Add
LiveRunWidget for real-time streaming of active heartbeat runs on issue detail
pages via WebSocket. Display issue identifiers (PAP-42) instead of UUID
fragments throughout Issues, Inbox, CommandPalette, and detail pages.
Enhance CommentThread with re-open checkbox, Cmd+Enter submit, sorted display,
and run linking. Improve Activity page with richer formatting and filtering.
Update Dashboard with live metrics. Add reports-to agent link in AgentProperties.
Various small fixes: StatusIcon centering, CopyText ref init, agent detail
run-issue cross-links.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-19 09:10:07 -06:00
|
|
|
|
2026-02-26 16:33:48 -06:00
|
|
|
type CommentReassignment = {
|
|
|
|
|
assigneeAgentId: string | null;
|
|
|
|
|
assigneeUserId: string | null;
|
|
|
|
|
};
|
|
|
|
|
|
UI: Identity component, LiveRunWidget, issue identifiers, and UX improvements
Add Identity component (avatar + name) used across agent/issue displays. Add
LiveRunWidget for real-time streaming of active heartbeat runs on issue detail
pages via WebSocket. Display issue identifiers (PAP-42) instead of UUID
fragments throughout Issues, Inbox, CommandPalette, and detail pages.
Enhance CommentThread with re-open checkbox, Cmd+Enter submit, sorted display,
and run linking. Improve Activity page with richer formatting and filtering.
Update Dashboard with live metrics. Add reports-to agent link in AgentProperties.
Various small fixes: StatusIcon centering, CopyText ref init, agent detail
run-issue cross-links.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-19 09:10:07 -06:00
|
|
|
const ACTION_LABELS: Record<string, string> = {
|
|
|
|
|
"issue.created": "created the issue",
|
|
|
|
|
"issue.updated": "updated the issue",
|
|
|
|
|
"issue.checked_out": "checked out the issue",
|
|
|
|
|
"issue.released": "released the issue",
|
|
|
|
|
"issue.comment_added": "added a comment",
|
2026-02-20 11:29:13 -06:00
|
|
|
"issue.attachment_added": "added an attachment",
|
|
|
|
|
"issue.attachment_removed": "removed an attachment",
|
2026-03-13 21:30:48 -05:00
|
|
|
"issue.document_created": "created a document",
|
|
|
|
|
"issue.document_updated": "updated a document",
|
|
|
|
|
"issue.document_deleted": "deleted a document",
|
UI: Identity component, LiveRunWidget, issue identifiers, and UX improvements
Add Identity component (avatar + name) used across agent/issue displays. Add
LiveRunWidget for real-time streaming of active heartbeat runs on issue detail
pages via WebSocket. Display issue identifiers (PAP-42) instead of UUID
fragments throughout Issues, Inbox, CommandPalette, and detail pages.
Enhance CommentThread with re-open checkbox, Cmd+Enter submit, sorted display,
and run linking. Improve Activity page with richer formatting and filtering.
Update Dashboard with live metrics. Add reports-to agent link in AgentProperties.
Various small fixes: StatusIcon centering, CopyText ref init, agent detail
run-issue cross-links.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-19 09:10:07 -06:00
|
|
|
"issue.deleted": "deleted the issue",
|
|
|
|
|
"agent.created": "created an agent",
|
|
|
|
|
"agent.updated": "updated the agent",
|
|
|
|
|
"agent.paused": "paused the agent",
|
|
|
|
|
"agent.resumed": "resumed the agent",
|
|
|
|
|
"agent.terminated": "terminated the agent",
|
|
|
|
|
"heartbeat.invoked": "invoked a heartbeat",
|
|
|
|
|
"heartbeat.cancelled": "cancelled a heartbeat",
|
|
|
|
|
"approval.created": "requested approval",
|
|
|
|
|
"approval.approved": "approved",
|
|
|
|
|
"approval.rejected": "rejected",
|
|
|
|
|
};
|
|
|
|
|
|
UI: approval detail page, agent hiring UX, costs breakdown, sidebar badges, and dashboard improvements
Add ApprovalDetail page with comment thread, revision request/resubmit flow,
and ApprovalPayload component for structured payload display. Extend AgentDetail
with permissions management, config revision history, and duplicate action.
Add agent hire dialog with permission-gated access. Rework Costs page with
per-agent breakdown table and period filtering. Add sidebar badge counts for
pending approvals and inbox items. Enhance Dashboard with live metrics and
sparkline trends. Extend Agents list with pending_approval status and bulk
actions. Update IssueDetail with approval linking. Various component improvements
to MetricCard, InlineEditor, CommentThread, and StatusBadge.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-19 13:03:08 -06:00
|
|
|
function humanizeValue(value: unknown): string {
|
|
|
|
|
if (typeof value !== "string") return String(value ?? "none");
|
|
|
|
|
return value.replace(/_/g, " ");
|
|
|
|
|
}
|
|
|
|
|
|
2026-02-20 10:32:32 -06:00
|
|
|
function asRecord(value: unknown): Record<string, unknown> | null {
|
|
|
|
|
if (typeof value !== "object" || value === null || Array.isArray(value)) return null;
|
|
|
|
|
return value as Record<string, unknown>;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
function usageNumber(usage: Record<string, unknown> | null, ...keys: string[]) {
|
|
|
|
|
if (!usage) return 0;
|
|
|
|
|
for (const key of keys) {
|
|
|
|
|
const value = usage[key];
|
|
|
|
|
if (typeof value === "number" && Number.isFinite(value)) return value;
|
|
|
|
|
}
|
|
|
|
|
return 0;
|
|
|
|
|
}
|
|
|
|
|
|
2026-02-20 15:48:42 -06:00
|
|
|
function truncate(text: string, max: number): string {
|
|
|
|
|
if (text.length <= max) return text;
|
|
|
|
|
return text.slice(0, max - 1) + "\u2026";
|
|
|
|
|
}
|
|
|
|
|
|
2026-03-13 21:30:48 -05:00
|
|
|
function isMarkdownFile(file: File) {
|
|
|
|
|
const name = file.name.toLowerCase();
|
|
|
|
|
return (
|
|
|
|
|
name.endsWith(".md") ||
|
|
|
|
|
name.endsWith(".markdown") ||
|
|
|
|
|
file.type === "text/markdown"
|
|
|
|
|
);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
function fileBaseName(filename: string) {
|
|
|
|
|
return filename.replace(/\.[^.]+$/, "");
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
function slugifyDocumentKey(input: string) {
|
|
|
|
|
const slug = input
|
|
|
|
|
.trim()
|
|
|
|
|
.toLowerCase()
|
|
|
|
|
.replace(/[^a-z0-9]+/g, "-")
|
|
|
|
|
.replace(/^-+|-+$/g, "");
|
|
|
|
|
return slug || "document";
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
function titleizeFilename(input: string) {
|
|
|
|
|
return input
|
|
|
|
|
.split(/[-_ ]+/g)
|
|
|
|
|
.filter(Boolean)
|
|
|
|
|
.map((part) => part.charAt(0).toUpperCase() + part.slice(1))
|
|
|
|
|
.join(" ");
|
|
|
|
|
}
|
|
|
|
|
|
UI: approval detail page, agent hiring UX, costs breakdown, sidebar badges, and dashboard improvements
Add ApprovalDetail page with comment thread, revision request/resubmit flow,
and ApprovalPayload component for structured payload display. Extend AgentDetail
with permissions management, config revision history, and duplicate action.
Add agent hire dialog with permission-gated access. Rework Costs page with
per-agent breakdown table and period filtering. Add sidebar badge counts for
pending approvals and inbox items. Enhance Dashboard with live metrics and
sparkline trends. Extend Agents list with pending_approval status and bulk
actions. Update IssueDetail with approval linking. Various component improvements
to MetricCard, InlineEditor, CommentThread, and StatusBadge.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-19 13:03:08 -06:00
|
|
|
function formatAction(action: string, details?: Record<string, unknown> | null): string {
|
|
|
|
|
if (action === "issue.updated" && details) {
|
|
|
|
|
const previous = (details._previous ?? {}) as Record<string, unknown>;
|
|
|
|
|
const parts: string[] = [];
|
|
|
|
|
|
|
|
|
|
if (details.status !== undefined) {
|
|
|
|
|
const from = previous.status;
|
|
|
|
|
parts.push(
|
|
|
|
|
from
|
|
|
|
|
? `changed the status from ${humanizeValue(from)} to ${humanizeValue(details.status)}`
|
|
|
|
|
: `changed the status to ${humanizeValue(details.status)}`
|
|
|
|
|
);
|
|
|
|
|
}
|
|
|
|
|
if (details.priority !== undefined) {
|
|
|
|
|
const from = previous.priority;
|
|
|
|
|
parts.push(
|
|
|
|
|
from
|
|
|
|
|
? `changed the priority from ${humanizeValue(from)} to ${humanizeValue(details.priority)}`
|
|
|
|
|
: `changed the priority to ${humanizeValue(details.priority)}`
|
|
|
|
|
);
|
|
|
|
|
}
|
2026-02-26 16:33:48 -06:00
|
|
|
if (details.assigneeAgentId !== undefined || details.assigneeUserId !== undefined) {
|
|
|
|
|
parts.push(
|
|
|
|
|
details.assigneeAgentId || details.assigneeUserId
|
|
|
|
|
? "assigned the issue"
|
|
|
|
|
: "unassigned the issue",
|
|
|
|
|
);
|
UI: approval detail page, agent hiring UX, costs breakdown, sidebar badges, and dashboard improvements
Add ApprovalDetail page with comment thread, revision request/resubmit flow,
and ApprovalPayload component for structured payload display. Extend AgentDetail
with permissions management, config revision history, and duplicate action.
Add agent hire dialog with permission-gated access. Rework Costs page with
per-agent breakdown table and period filtering. Add sidebar badge counts for
pending approvals and inbox items. Enhance Dashboard with live metrics and
sparkline trends. Extend Agents list with pending_approval status and bulk
actions. Update IssueDetail with approval linking. Various component improvements
to MetricCard, InlineEditor, CommentThread, and StatusBadge.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-19 13:03:08 -06:00
|
|
|
}
|
|
|
|
|
if (details.title !== undefined) parts.push("updated the title");
|
|
|
|
|
if (details.description !== undefined) parts.push("updated the description");
|
|
|
|
|
|
|
|
|
|
if (parts.length > 0) return parts.join(", ");
|
|
|
|
|
}
|
2026-03-13 21:30:48 -05:00
|
|
|
if (
|
|
|
|
|
(action === "issue.document_created" || action === "issue.document_updated" || action === "issue.document_deleted") &&
|
|
|
|
|
details
|
|
|
|
|
) {
|
|
|
|
|
const key = typeof details.key === "string" ? details.key : "document";
|
|
|
|
|
const title = typeof details.title === "string" && details.title ? ` (${details.title})` : "";
|
|
|
|
|
return `${ACTION_LABELS[action] ?? action} ${key}${title}`;
|
|
|
|
|
}
|
UI: Identity component, LiveRunWidget, issue identifiers, and UX improvements
Add Identity component (avatar + name) used across agent/issue displays. Add
LiveRunWidget for real-time streaming of active heartbeat runs on issue detail
pages via WebSocket. Display issue identifiers (PAP-42) instead of UUID
fragments throughout Issues, Inbox, CommandPalette, and detail pages.
Enhance CommentThread with re-open checkbox, Cmd+Enter submit, sorted display,
and run linking. Improve Activity page with richer formatting and filtering.
Update Dashboard with live metrics. Add reports-to agent link in AgentProperties.
Various small fixes: StatusIcon centering, CopyText ref init, agent detail
run-issue cross-links.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-19 09:10:07 -06:00
|
|
|
return ACTION_LABELS[action] ?? action.replace(/[._]/g, " ");
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
function ActorIdentity({ evt, agentMap }: { evt: ActivityEvent; agentMap: Map<string, Agent> }) {
|
|
|
|
|
const id = evt.actorId;
|
|
|
|
|
if (evt.actorType === "agent") {
|
|
|
|
|
const agent = agentMap.get(id);
|
|
|
|
|
return <Identity name={agent?.name ?? id.slice(0, 8)} size="sm" />;
|
|
|
|
|
}
|
|
|
|
|
if (evt.actorType === "system") return <Identity name="System" size="sm" />;
|
2026-02-23 19:44:02 -06:00
|
|
|
if (evt.actorType === "user") return <Identity name="Board" size="sm" />;
|
|
|
|
|
return <Identity name={id || "Unknown"} size="sm" />;
|
UI: Identity component, LiveRunWidget, issue identifiers, and UX improvements
Add Identity component (avatar + name) used across agent/issue displays. Add
LiveRunWidget for real-time streaming of active heartbeat runs on issue detail
pages via WebSocket. Display issue identifiers (PAP-42) instead of UUID
fragments throughout Issues, Inbox, CommandPalette, and detail pages.
Enhance CommentThread with re-open checkbox, Cmd+Enter submit, sorted display,
and run linking. Improve Activity page with richer formatting and filtering.
Update Dashboard with live metrics. Add reports-to agent link in AgentProperties.
Various small fixes: StatusIcon centering, CopyText ref init, agent detail
run-issue cross-links.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-19 09:10:07 -06:00
|
|
|
}
|
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>
2026-02-17 09:57:06 -06:00
|
|
|
|
|
|
|
|
export function IssueDetail() {
|
|
|
|
|
const { issueId } = useParams<{ issueId: string }>();
|
2026-02-17 12:24:48 -06:00
|
|
|
const { selectedCompanyId } = useCompany();
|
2026-03-03 14:56:32 -06:00
|
|
|
const { openPanel, closePanel, panelVisible, setPanelVisible } = usePanel();
|
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>
2026-02-17 09:57:06 -06:00
|
|
|
const { setBreadcrumbs } = useBreadcrumbs();
|
2026-02-17 12:24:48 -06:00
|
|
|
const queryClient = useQueryClient();
|
2026-02-19 15:44:05 -06:00
|
|
|
const navigate = useNavigate();
|
2026-03-10 20:59:55 -05:00
|
|
|
const location = useLocation();
|
2026-02-19 15:44:05 -06:00
|
|
|
const [moreOpen, setMoreOpen] = useState(false);
|
2026-02-23 19:49:43 -06:00
|
|
|
const [mobilePropsOpen, setMobilePropsOpen] = useState(false);
|
2026-02-25 08:39:31 -06:00
|
|
|
const [detailTab, setDetailTab] = useState("comments");
|
|
|
|
|
const [secondaryOpen, setSecondaryOpen] = useState({
|
|
|
|
|
approvals: false,
|
|
|
|
|
cost: false,
|
|
|
|
|
});
|
2026-02-20 10:32:32 -06:00
|
|
|
const [attachmentError, setAttachmentError] = useState<string | null>(null);
|
2026-03-13 21:30:48 -05:00
|
|
|
const [attachmentDragActive, setAttachmentDragActive] = useState(false);
|
2026-02-20 10:32:32 -06:00
|
|
|
const fileInputRef = useRef<HTMLInputElement | null>(null);
|
2026-03-06 08:34:19 -06:00
|
|
|
const lastMarkedReadIssueIdRef = useRef<string | null>(null);
|
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>
2026-02-17 09:57:06 -06:00
|
|
|
|
2026-02-17 12:24:48 -06:00
|
|
|
const { data: issue, isLoading, error } = useQuery({
|
|
|
|
|
queryKey: queryKeys.issues.detail(issueId!),
|
|
|
|
|
queryFn: () => issuesApi.get(issueId!),
|
|
|
|
|
enabled: !!issueId,
|
|
|
|
|
});
|
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>
2026-02-17 09:57:06 -06:00
|
|
|
|
2026-02-17 12:24:48 -06:00
|
|
|
const { data: comments } = useQuery({
|
|
|
|
|
queryKey: queryKeys.issues.comments(issueId!),
|
|
|
|
|
queryFn: () => issuesApi.listComments(issueId!),
|
|
|
|
|
enabled: !!issueId,
|
|
|
|
|
});
|
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>
2026-02-17 09:57:06 -06:00
|
|
|
|
UI: Identity component, LiveRunWidget, issue identifiers, and UX improvements
Add Identity component (avatar + name) used across agent/issue displays. Add
LiveRunWidget for real-time streaming of active heartbeat runs on issue detail
pages via WebSocket. Display issue identifiers (PAP-42) instead of UUID
fragments throughout Issues, Inbox, CommandPalette, and detail pages.
Enhance CommentThread with re-open checkbox, Cmd+Enter submit, sorted display,
and run linking. Improve Activity page with richer formatting and filtering.
Update Dashboard with live metrics. Add reports-to agent link in AgentProperties.
Various small fixes: StatusIcon centering, CopyText ref init, agent detail
run-issue cross-links.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-19 09:10:07 -06:00
|
|
|
const { data: activity } = useQuery({
|
|
|
|
|
queryKey: queryKeys.issues.activity(issueId!),
|
|
|
|
|
queryFn: () => activityApi.forIssue(issueId!),
|
|
|
|
|
enabled: !!issueId,
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
const { data: linkedRuns } = useQuery({
|
|
|
|
|
queryKey: queryKeys.issues.runs(issueId!),
|
|
|
|
|
queryFn: () => activityApi.runsForIssue(issueId!),
|
|
|
|
|
enabled: !!issueId,
|
|
|
|
|
refetchInterval: 5000,
|
|
|
|
|
});
|
|
|
|
|
|
UI: approval detail page, agent hiring UX, costs breakdown, sidebar badges, and dashboard improvements
Add ApprovalDetail page with comment thread, revision request/resubmit flow,
and ApprovalPayload component for structured payload display. Extend AgentDetail
with permissions management, config revision history, and duplicate action.
Add agent hire dialog with permission-gated access. Rework Costs page with
per-agent breakdown table and period filtering. Add sidebar badge counts for
pending approvals and inbox items. Enhance Dashboard with live metrics and
sparkline trends. Extend Agents list with pending_approval status and bulk
actions. Update IssueDetail with approval linking. Various component improvements
to MetricCard, InlineEditor, CommentThread, and StatusBadge.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-19 13:03:08 -06:00
|
|
|
const { data: linkedApprovals } = useQuery({
|
|
|
|
|
queryKey: queryKeys.issues.approvals(issueId!),
|
|
|
|
|
queryFn: () => issuesApi.listApprovals(issueId!),
|
|
|
|
|
enabled: !!issueId,
|
|
|
|
|
});
|
|
|
|
|
|
2026-02-20 10:32:32 -06:00
|
|
|
const { data: attachments } = useQuery({
|
|
|
|
|
queryKey: queryKeys.issues.attachments(issueId!),
|
|
|
|
|
queryFn: () => issuesApi.listAttachments(issueId!),
|
|
|
|
|
enabled: !!issueId,
|
|
|
|
|
});
|
|
|
|
|
|
2026-02-25 17:40:13 -06:00
|
|
|
const { data: liveRuns } = useQuery({
|
|
|
|
|
queryKey: queryKeys.issues.liveRuns(issueId!),
|
|
|
|
|
queryFn: () => heartbeatsApi.liveRunsForIssue(issueId!),
|
2026-03-03 11:06:41 -06:00
|
|
|
enabled: !!issueId,
|
|
|
|
|
refetchInterval: 3000,
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
const { data: activeRun } = useQuery({
|
|
|
|
|
queryKey: queryKeys.issues.activeRun(issueId!),
|
|
|
|
|
queryFn: () => heartbeatsApi.activeRunForIssue(issueId!),
|
|
|
|
|
enabled: !!issueId,
|
2026-02-25 17:40:13 -06:00
|
|
|
refetchInterval: 3000,
|
|
|
|
|
});
|
|
|
|
|
|
2026-03-03 11:06:41 -06:00
|
|
|
const hasLiveRuns = (liveRuns ?? []).length > 0 || !!activeRun;
|
2026-03-10 20:59:55 -05:00
|
|
|
const sourceBreadcrumb = useMemo(
|
|
|
|
|
() => readIssueDetailBreadcrumb(location.state) ?? { label: "Issues", href: "/issues" },
|
|
|
|
|
[location.state],
|
|
|
|
|
);
|
2026-02-25 17:40:13 -06:00
|
|
|
|
2026-03-03 12:19:26 -06:00
|
|
|
// Filter out runs already shown by the live widget to avoid duplication
|
|
|
|
|
const timelineRuns = useMemo(() => {
|
|
|
|
|
const liveIds = new Set<string>();
|
|
|
|
|
for (const r of liveRuns ?? []) liveIds.add(r.id);
|
|
|
|
|
if (activeRun) liveIds.add(activeRun.id);
|
|
|
|
|
if (liveIds.size === 0) return linkedRuns ?? [];
|
|
|
|
|
return (linkedRuns ?? []).filter((r) => !liveIds.has(r.runId));
|
|
|
|
|
}, [linkedRuns, liveRuns, activeRun]);
|
|
|
|
|
|
2026-02-20 14:48:30 -06:00
|
|
|
const { data: allIssues } = useQuery({
|
|
|
|
|
queryKey: queryKeys.issues.list(selectedCompanyId!),
|
|
|
|
|
queryFn: () => issuesApi.list(selectedCompanyId!),
|
|
|
|
|
enabled: !!selectedCompanyId,
|
|
|
|
|
});
|
|
|
|
|
|
UI: Identity component, LiveRunWidget, issue identifiers, and UX improvements
Add Identity component (avatar + name) used across agent/issue displays. Add
LiveRunWidget for real-time streaming of active heartbeat runs on issue detail
pages via WebSocket. Display issue identifiers (PAP-42) instead of UUID
fragments throughout Issues, Inbox, CommandPalette, and detail pages.
Enhance CommentThread with re-open checkbox, Cmd+Enter submit, sorted display,
and run linking. Improve Activity page with richer formatting and filtering.
Update Dashboard with live metrics. Add reports-to agent link in AgentProperties.
Various small fixes: StatusIcon centering, CopyText ref init, agent detail
run-issue cross-links.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-19 09:10:07 -06:00
|
|
|
const { data: agents } = useQuery({
|
|
|
|
|
queryKey: queryKeys.agents.list(selectedCompanyId!),
|
|
|
|
|
queryFn: () => agentsApi.list(selectedCompanyId!),
|
|
|
|
|
enabled: !!selectedCompanyId,
|
|
|
|
|
});
|
|
|
|
|
|
2026-02-26 16:33:48 -06:00
|
|
|
const { data: session } = useQuery({
|
|
|
|
|
queryKey: queryKeys.auth.session,
|
|
|
|
|
queryFn: () => authApi.getSession(),
|
|
|
|
|
});
|
|
|
|
|
|
2026-02-20 09:01:28 -06:00
|
|
|
const { data: projects } = useQuery({
|
|
|
|
|
queryKey: queryKeys.projects.list(selectedCompanyId!),
|
|
|
|
|
queryFn: () => projectsApi.list(selectedCompanyId!),
|
|
|
|
|
enabled: !!selectedCompanyId,
|
|
|
|
|
});
|
2026-03-02 14:20:49 -06:00
|
|
|
const currentUserId = session?.user?.id ?? session?.session?.userId ?? null;
|
|
|
|
|
const { orderedProjects } = useProjectOrder({
|
|
|
|
|
projects: projects ?? [],
|
|
|
|
|
companyId: selectedCompanyId,
|
|
|
|
|
userId: currentUserId,
|
|
|
|
|
});
|
2026-02-20 09:01:28 -06:00
|
|
|
|
UI: Identity component, LiveRunWidget, issue identifiers, and UX improvements
Add Identity component (avatar + name) used across agent/issue displays. Add
LiveRunWidget for real-time streaming of active heartbeat runs on issue detail
pages via WebSocket. Display issue identifiers (PAP-42) instead of UUID
fragments throughout Issues, Inbox, CommandPalette, and detail pages.
Enhance CommentThread with re-open checkbox, Cmd+Enter submit, sorted display,
and run linking. Improve Activity page with richer formatting and filtering.
Update Dashboard with live metrics. Add reports-to agent link in AgentProperties.
Various small fixes: StatusIcon centering, CopyText ref init, agent detail
run-issue cross-links.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-19 09:10:07 -06:00
|
|
|
const agentMap = useMemo(() => {
|
|
|
|
|
const map = new Map<string, Agent>();
|
|
|
|
|
for (const a of agents ?? []) map.set(a.id, a);
|
|
|
|
|
return map;
|
|
|
|
|
}, [agents]);
|
|
|
|
|
|
2026-03-02 13:31:58 -06:00
|
|
|
const mentionOptions = useMemo<MentionOption[]>(() => {
|
|
|
|
|
const options: MentionOption[] = [];
|
|
|
|
|
const activeAgents = [...(agents ?? [])]
|
|
|
|
|
.filter((agent) => agent.status !== "terminated")
|
|
|
|
|
.sort((a, b) => a.name.localeCompare(b.name));
|
|
|
|
|
for (const agent of activeAgents) {
|
|
|
|
|
options.push({
|
|
|
|
|
id: `agent:${agent.id}`,
|
|
|
|
|
name: agent.name,
|
|
|
|
|
kind: "agent",
|
|
|
|
|
});
|
|
|
|
|
}
|
2026-03-02 14:20:49 -06:00
|
|
|
for (const project of orderedProjects) {
|
2026-03-02 13:31:58 -06:00
|
|
|
options.push({
|
|
|
|
|
id: `project:${project.id}`,
|
|
|
|
|
name: project.name,
|
|
|
|
|
kind: "project",
|
|
|
|
|
projectId: project.id,
|
|
|
|
|
projectColor: project.color,
|
|
|
|
|
});
|
|
|
|
|
}
|
|
|
|
|
return options;
|
2026-03-02 14:20:49 -06:00
|
|
|
}, [agents, orderedProjects]);
|
2026-03-02 13:31:58 -06:00
|
|
|
|
2026-02-20 14:48:30 -06:00
|
|
|
const childIssues = useMemo(() => {
|
2026-02-20 16:04:05 -06:00
|
|
|
if (!allIssues || !issue) return [];
|
2026-02-20 14:48:30 -06:00
|
|
|
return allIssues
|
2026-02-20 16:04:05 -06:00
|
|
|
.filter((i) => i.parentId === issue.id)
|
2026-02-20 14:48:30 -06:00
|
|
|
.sort((a, b) => new Date(a.createdAt).getTime() - new Date(b.createdAt).getTime());
|
2026-02-20 16:04:05 -06:00
|
|
|
}, [allIssues, issue]);
|
2026-02-20 14:48:30 -06:00
|
|
|
|
2026-02-26 16:33:48 -06:00
|
|
|
const commentReassignOptions = useMemo(() => {
|
2026-03-02 16:56:05 -06:00
|
|
|
const options: Array<{ id: string; label: string; searchText?: string }> = [];
|
2026-02-26 16:33:48 -06:00
|
|
|
const activeAgents = [...(agents ?? [])]
|
|
|
|
|
.filter((agent) => agent.status !== "terminated")
|
|
|
|
|
.sort((a, b) => a.name.localeCompare(b.name));
|
|
|
|
|
for (const agent of activeAgents) {
|
2026-03-02 16:56:05 -06:00
|
|
|
options.push({ id: `agent:${agent.id}`, label: agent.name });
|
2026-02-26 16:33:48 -06:00
|
|
|
}
|
2026-03-02 16:56:05 -06:00
|
|
|
if (currentUserId) {
|
2026-03-12 16:12:38 -05:00
|
|
|
options.push({ id: `user:${currentUserId}`, label: "Me" });
|
2026-02-26 16:33:48 -06:00
|
|
|
}
|
|
|
|
|
return options;
|
2026-03-02 16:56:05 -06:00
|
|
|
}, [agents, currentUserId]);
|
|
|
|
|
|
|
|
|
|
const currentAssigneeValue = useMemo(() => {
|
|
|
|
|
if (issue?.assigneeAgentId) return `agent:${issue.assigneeAgentId}`;
|
|
|
|
|
if (issue?.assigneeUserId) return `user:${issue.assigneeUserId}`;
|
|
|
|
|
return "";
|
|
|
|
|
}, [issue?.assigneeAgentId, issue?.assigneeUserId]);
|
2026-02-26 16:33:48 -06:00
|
|
|
|
UI: Identity component, LiveRunWidget, issue identifiers, and UX improvements
Add Identity component (avatar + name) used across agent/issue displays. Add
LiveRunWidget for real-time streaming of active heartbeat runs on issue detail
pages via WebSocket. Display issue identifiers (PAP-42) instead of UUID
fragments throughout Issues, Inbox, CommandPalette, and detail pages.
Enhance CommentThread with re-open checkbox, Cmd+Enter submit, sorted display,
and run linking. Improve Activity page with richer formatting and filtering.
Update Dashboard with live metrics. Add reports-to agent link in AgentProperties.
Various small fixes: StatusIcon centering, CopyText ref init, agent detail
run-issue cross-links.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-19 09:10:07 -06:00
|
|
|
const commentsWithRunMeta = useMemo(() => {
|
|
|
|
|
const runMetaByCommentId = new Map<string, { runId: string; runAgentId: string | null }>();
|
|
|
|
|
const agentIdByRunId = new Map<string, string>();
|
|
|
|
|
for (const run of linkedRuns ?? []) {
|
|
|
|
|
agentIdByRunId.set(run.runId, run.agentId);
|
|
|
|
|
}
|
|
|
|
|
for (const evt of activity ?? []) {
|
|
|
|
|
if (evt.action !== "issue.comment_added" || !evt.runId) continue;
|
|
|
|
|
const details = evt.details ?? {};
|
|
|
|
|
const commentId = typeof details["commentId"] === "string" ? details["commentId"] : null;
|
|
|
|
|
if (!commentId || runMetaByCommentId.has(commentId)) continue;
|
|
|
|
|
runMetaByCommentId.set(commentId, {
|
|
|
|
|
runId: evt.runId,
|
|
|
|
|
runAgentId: evt.agentId ?? agentIdByRunId.get(evt.runId) ?? null,
|
|
|
|
|
});
|
|
|
|
|
}
|
|
|
|
|
return (comments ?? []).map((comment) => {
|
|
|
|
|
const meta = runMetaByCommentId.get(comment.id);
|
|
|
|
|
return meta ? { ...comment, ...meta } : comment;
|
|
|
|
|
});
|
|
|
|
|
}, [activity, comments, linkedRuns]);
|
|
|
|
|
|
2026-02-20 10:32:32 -06:00
|
|
|
const issueCostSummary = useMemo(() => {
|
|
|
|
|
let input = 0;
|
|
|
|
|
let output = 0;
|
|
|
|
|
let cached = 0;
|
|
|
|
|
let cost = 0;
|
|
|
|
|
let hasCost = false;
|
|
|
|
|
let hasTokens = false;
|
|
|
|
|
|
|
|
|
|
for (const run of linkedRuns ?? []) {
|
|
|
|
|
const usage = asRecord(run.usageJson);
|
|
|
|
|
const result = asRecord(run.resultJson);
|
|
|
|
|
const runInput = usageNumber(usage, "inputTokens", "input_tokens");
|
|
|
|
|
const runOutput = usageNumber(usage, "outputTokens", "output_tokens");
|
|
|
|
|
const runCached = usageNumber(
|
|
|
|
|
usage,
|
|
|
|
|
"cachedInputTokens",
|
|
|
|
|
"cached_input_tokens",
|
|
|
|
|
"cache_read_input_tokens",
|
|
|
|
|
);
|
|
|
|
|
const runCost =
|
|
|
|
|
usageNumber(usage, "costUsd", "cost_usd", "total_cost_usd") ||
|
|
|
|
|
usageNumber(result, "total_cost_usd", "cost_usd", "costUsd");
|
|
|
|
|
if (runCost > 0) hasCost = true;
|
|
|
|
|
if (runInput + runOutput + runCached > 0) hasTokens = true;
|
|
|
|
|
input += runInput;
|
|
|
|
|
output += runOutput;
|
|
|
|
|
cached += runCached;
|
|
|
|
|
cost += runCost;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return {
|
|
|
|
|
input,
|
|
|
|
|
output,
|
|
|
|
|
cached,
|
|
|
|
|
cost,
|
|
|
|
|
totalTokens: input + output,
|
|
|
|
|
hasCost,
|
|
|
|
|
hasTokens,
|
|
|
|
|
};
|
|
|
|
|
}, [linkedRuns]);
|
|
|
|
|
|
UI: Identity component, LiveRunWidget, issue identifiers, and UX improvements
Add Identity component (avatar + name) used across agent/issue displays. Add
LiveRunWidget for real-time streaming of active heartbeat runs on issue detail
pages via WebSocket. Display issue identifiers (PAP-42) instead of UUID
fragments throughout Issues, Inbox, CommandPalette, and detail pages.
Enhance CommentThread with re-open checkbox, Cmd+Enter submit, sorted display,
and run linking. Improve Activity page with richer formatting and filtering.
Update Dashboard with live metrics. Add reports-to agent link in AgentProperties.
Various small fixes: StatusIcon centering, CopyText ref init, agent detail
run-issue cross-links.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-19 09:10:07 -06:00
|
|
|
const invalidateIssue = () => {
|
|
|
|
|
queryClient.invalidateQueries({ queryKey: queryKeys.issues.detail(issueId!) });
|
|
|
|
|
queryClient.invalidateQueries({ queryKey: queryKeys.issues.activity(issueId!) });
|
|
|
|
|
queryClient.invalidateQueries({ queryKey: queryKeys.issues.runs(issueId!) });
|
UI: approval detail page, agent hiring UX, costs breakdown, sidebar badges, and dashboard improvements
Add ApprovalDetail page with comment thread, revision request/resubmit flow,
and ApprovalPayload component for structured payload display. Extend AgentDetail
with permissions management, config revision history, and duplicate action.
Add agent hire dialog with permission-gated access. Rework Costs page with
per-agent breakdown table and period filtering. Add sidebar badge counts for
pending approvals and inbox items. Enhance Dashboard with live metrics and
sparkline trends. Extend Agents list with pending_approval status and bulk
actions. Update IssueDetail with approval linking. Various component improvements
to MetricCard, InlineEditor, CommentThread, and StatusBadge.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-19 13:03:08 -06:00
|
|
|
queryClient.invalidateQueries({ queryKey: queryKeys.issues.approvals(issueId!) });
|
2026-02-20 10:32:32 -06:00
|
|
|
queryClient.invalidateQueries({ queryKey: queryKeys.issues.attachments(issueId!) });
|
2026-03-13 21:30:48 -05:00
|
|
|
queryClient.invalidateQueries({ queryKey: queryKeys.issues.documents(issueId!) });
|
UI: Identity component, LiveRunWidget, issue identifiers, and UX improvements
Add Identity component (avatar + name) used across agent/issue displays. Add
LiveRunWidget for real-time streaming of active heartbeat runs on issue detail
pages via WebSocket. Display issue identifiers (PAP-42) instead of UUID
fragments throughout Issues, Inbox, CommandPalette, and detail pages.
Enhance CommentThread with re-open checkbox, Cmd+Enter submit, sorted display,
and run linking. Improve Activity page with richer formatting and filtering.
Update Dashboard with live metrics. Add reports-to agent link in AgentProperties.
Various small fixes: StatusIcon centering, CopyText ref init, agent detail
run-issue cross-links.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-19 09:10:07 -06:00
|
|
|
queryClient.invalidateQueries({ queryKey: queryKeys.issues.liveRuns(issueId!) });
|
|
|
|
|
queryClient.invalidateQueries({ queryKey: queryKeys.issues.activeRun(issueId!) });
|
|
|
|
|
if (selectedCompanyId) {
|
|
|
|
|
queryClient.invalidateQueries({ queryKey: queryKeys.issues.list(selectedCompanyId) });
|
2026-03-06 08:34:19 -06:00
|
|
|
queryClient.invalidateQueries({ queryKey: queryKeys.issues.listTouchedByMe(selectedCompanyId) });
|
|
|
|
|
queryClient.invalidateQueries({ queryKey: queryKeys.issues.listUnreadTouchedByMe(selectedCompanyId) });
|
|
|
|
|
queryClient.invalidateQueries({ queryKey: queryKeys.sidebarBadges(selectedCompanyId) });
|
UI: Identity component, LiveRunWidget, issue identifiers, and UX improvements
Add Identity component (avatar + name) used across agent/issue displays. Add
LiveRunWidget for real-time streaming of active heartbeat runs on issue detail
pages via WebSocket. Display issue identifiers (PAP-42) instead of UUID
fragments throughout Issues, Inbox, CommandPalette, and detail pages.
Enhance CommentThread with re-open checkbox, Cmd+Enter submit, sorted display,
and run linking. Improve Activity page with richer formatting and filtering.
Update Dashboard with live metrics. Add reports-to agent link in AgentProperties.
Various small fixes: StatusIcon centering, CopyText ref init, agent detail
run-issue cross-links.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-19 09:10:07 -06:00
|
|
|
}
|
|
|
|
|
};
|
|
|
|
|
|
2026-03-06 08:34:19 -06:00
|
|
|
const markIssueRead = useMutation({
|
|
|
|
|
mutationFn: (id: string) => issuesApi.markRead(id),
|
|
|
|
|
onSuccess: () => {
|
|
|
|
|
if (selectedCompanyId) {
|
|
|
|
|
queryClient.invalidateQueries({ queryKey: queryKeys.issues.listTouchedByMe(selectedCompanyId) });
|
|
|
|
|
queryClient.invalidateQueries({ queryKey: queryKeys.issues.listUnreadTouchedByMe(selectedCompanyId) });
|
|
|
|
|
queryClient.invalidateQueries({ queryKey: queryKeys.sidebarBadges(selectedCompanyId) });
|
|
|
|
|
}
|
|
|
|
|
},
|
|
|
|
|
});
|
|
|
|
|
|
2026-02-17 12:24:48 -06:00
|
|
|
const updateIssue = useMutation({
|
|
|
|
|
mutationFn: (data: Record<string, unknown>) => issuesApi.update(issueId!, data),
|
2026-03-07 08:42:58 -06:00
|
|
|
onSuccess: () => {
|
2026-02-20 13:47:13 -06:00
|
|
|
invalidateIssue();
|
|
|
|
|
},
|
2026-02-17 12:24:48 -06:00
|
|
|
});
|
|
|
|
|
|
|
|
|
|
const addComment = useMutation({
|
UI: Identity component, LiveRunWidget, issue identifiers, and UX improvements
Add Identity component (avatar + name) used across agent/issue displays. Add
LiveRunWidget for real-time streaming of active heartbeat runs on issue detail
pages via WebSocket. Display issue identifiers (PAP-42) instead of UUID
fragments throughout Issues, Inbox, CommandPalette, and detail pages.
Enhance CommentThread with re-open checkbox, Cmd+Enter submit, sorted display,
and run linking. Improve Activity page with richer formatting and filtering.
Update Dashboard with live metrics. Add reports-to agent link in AgentProperties.
Various small fixes: StatusIcon centering, CopyText ref init, agent detail
run-issue cross-links.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-19 09:10:07 -06:00
|
|
|
mutationFn: ({ body, reopen }: { body: string; reopen?: boolean }) =>
|
|
|
|
|
issuesApi.addComment(issueId!, body, reopen),
|
2026-03-07 08:31:59 -06:00
|
|
|
onSuccess: () => {
|
UI: Identity component, LiveRunWidget, issue identifiers, and UX improvements
Add Identity component (avatar + name) used across agent/issue displays. Add
LiveRunWidget for real-time streaming of active heartbeat runs on issue detail
pages via WebSocket. Display issue identifiers (PAP-42) instead of UUID
fragments throughout Issues, Inbox, CommandPalette, and detail pages.
Enhance CommentThread with re-open checkbox, Cmd+Enter submit, sorted display,
and run linking. Improve Activity page with richer formatting and filtering.
Update Dashboard with live metrics. Add reports-to agent link in AgentProperties.
Various small fixes: StatusIcon centering, CopyText ref init, agent detail
run-issue cross-links.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-19 09:10:07 -06:00
|
|
|
invalidateIssue();
|
2026-02-17 12:24:48 -06:00
|
|
|
queryClient.invalidateQueries({ queryKey: queryKeys.issues.comments(issueId!) });
|
|
|
|
|
},
|
|
|
|
|
});
|
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>
2026-02-17 09:57:06 -06:00
|
|
|
|
2026-02-26 16:33:48 -06:00
|
|
|
const addCommentAndReassign = useMutation({
|
|
|
|
|
mutationFn: ({
|
|
|
|
|
body,
|
|
|
|
|
reopen,
|
|
|
|
|
reassignment,
|
|
|
|
|
}: {
|
|
|
|
|
body: string;
|
|
|
|
|
reopen?: boolean;
|
|
|
|
|
reassignment: CommentReassignment;
|
|
|
|
|
}) =>
|
|
|
|
|
issuesApi.update(issueId!, {
|
|
|
|
|
comment: body,
|
|
|
|
|
assigneeAgentId: reassignment.assigneeAgentId,
|
|
|
|
|
assigneeUserId: reassignment.assigneeUserId,
|
|
|
|
|
...(reopen ? { status: "todo" } : {}),
|
|
|
|
|
}),
|
2026-03-07 08:42:58 -06:00
|
|
|
onSuccess: () => {
|
2026-02-26 16:33:48 -06:00
|
|
|
invalidateIssue();
|
|
|
|
|
queryClient.invalidateQueries({ queryKey: queryKeys.issues.comments(issueId!) });
|
|
|
|
|
},
|
|
|
|
|
});
|
|
|
|
|
|
2026-02-20 10:32:32 -06:00
|
|
|
const uploadAttachment = useMutation({
|
|
|
|
|
mutationFn: async (file: File) => {
|
|
|
|
|
if (!selectedCompanyId) throw new Error("No company selected");
|
|
|
|
|
return issuesApi.uploadAttachment(selectedCompanyId, issueId!, file);
|
|
|
|
|
},
|
|
|
|
|
onSuccess: () => {
|
|
|
|
|
setAttachmentError(null);
|
|
|
|
|
queryClient.invalidateQueries({ queryKey: queryKeys.issues.attachments(issueId!) });
|
|
|
|
|
invalidateIssue();
|
|
|
|
|
},
|
|
|
|
|
onError: (err) => {
|
|
|
|
|
setAttachmentError(err instanceof Error ? err.message : "Upload failed");
|
|
|
|
|
},
|
|
|
|
|
});
|
|
|
|
|
|
2026-03-13 21:30:48 -05:00
|
|
|
const importMarkdownDocument = useMutation({
|
|
|
|
|
mutationFn: async (file: File) => {
|
|
|
|
|
const baseName = fileBaseName(file.name);
|
|
|
|
|
const key = slugifyDocumentKey(baseName);
|
|
|
|
|
const existing = (issue?.documentSummaries ?? []).find((doc) => doc.key === key) ?? null;
|
|
|
|
|
const body = await file.text();
|
|
|
|
|
const inferredTitle = titleizeFilename(baseName);
|
|
|
|
|
const nextTitle = existing?.title ?? inferredTitle ?? null;
|
|
|
|
|
return issuesApi.upsertDocument(issueId!, key, {
|
|
|
|
|
title: key === "plan" ? null : nextTitle,
|
|
|
|
|
format: "markdown",
|
|
|
|
|
body,
|
|
|
|
|
baseRevisionId: existing?.latestRevisionId ?? null,
|
|
|
|
|
});
|
|
|
|
|
},
|
|
|
|
|
onSuccess: () => {
|
|
|
|
|
setAttachmentError(null);
|
|
|
|
|
invalidateIssue();
|
|
|
|
|
},
|
|
|
|
|
onError: (err) => {
|
|
|
|
|
setAttachmentError(err instanceof Error ? err.message : "Document import failed");
|
|
|
|
|
},
|
|
|
|
|
});
|
|
|
|
|
|
2026-02-20 10:32:32 -06:00
|
|
|
const deleteAttachment = useMutation({
|
|
|
|
|
mutationFn: (attachmentId: string) => issuesApi.deleteAttachment(attachmentId),
|
|
|
|
|
onSuccess: () => {
|
|
|
|
|
setAttachmentError(null);
|
|
|
|
|
queryClient.invalidateQueries({ queryKey: queryKeys.issues.attachments(issueId!) });
|
|
|
|
|
invalidateIssue();
|
|
|
|
|
},
|
|
|
|
|
onError: (err) => {
|
|
|
|
|
setAttachmentError(err instanceof Error ? err.message : "Delete failed");
|
|
|
|
|
},
|
|
|
|
|
});
|
|
|
|
|
|
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>
2026-02-17 09:57:06 -06:00
|
|
|
useEffect(() => {
|
2026-03-05 12:20:43 -06:00
|
|
|
const titleLabel = issue?.title ?? issueId ?? "Issue";
|
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>
2026-02-17 09:57:06 -06:00
|
|
|
setBreadcrumbs([
|
2026-03-10 20:59:55 -05:00
|
|
|
sourceBreadcrumb,
|
2026-03-05 12:20:43 -06:00
|
|
|
{ label: hasLiveRuns ? `🔵 ${titleLabel}` : titleLabel },
|
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>
2026-02-17 09:57:06 -06:00
|
|
|
]);
|
2026-03-10 20:59:55 -05:00
|
|
|
}, [setBreadcrumbs, sourceBreadcrumb, issue, issueId, hasLiveRuns]);
|
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>
2026-02-17 09:57:06 -06:00
|
|
|
|
2026-02-20 16:04:05 -06:00
|
|
|
// Redirect to identifier-based URL if navigated via UUID
|
|
|
|
|
useEffect(() => {
|
|
|
|
|
if (issue?.identifier && issueId !== issue.identifier) {
|
2026-03-10 20:59:55 -05:00
|
|
|
navigate(`/issues/${issue.identifier}`, { replace: true, state: location.state });
|
2026-02-20 16:04:05 -06:00
|
|
|
}
|
2026-03-10 20:59:55 -05:00
|
|
|
}, [issue, issueId, navigate, location.state]);
|
2026-02-20 16:04:05 -06:00
|
|
|
|
2026-03-06 08:34:19 -06:00
|
|
|
useEffect(() => {
|
|
|
|
|
if (!issue?.id) return;
|
|
|
|
|
if (lastMarkedReadIssueIdRef.current === issue.id) return;
|
|
|
|
|
lastMarkedReadIssueIdRef.current = issue.id;
|
|
|
|
|
markIssueRead.mutate(issue.id);
|
|
|
|
|
}, [issue?.id]); // eslint-disable-line react-hooks/exhaustive-deps
|
|
|
|
|
|
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>
2026-02-17 09:57:06 -06:00
|
|
|
useEffect(() => {
|
|
|
|
|
if (issue) {
|
|
|
|
|
openPanel(
|
2026-02-17 12:24:48 -06:00
|
|
|
<IssueProperties issue={issue} onUpdate={(data) => updateIssue.mutate(data)} />
|
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>
2026-02-17 09:57:06 -06:00
|
|
|
);
|
|
|
|
|
}
|
|
|
|
|
return () => closePanel();
|
|
|
|
|
}, [issue]); // eslint-disable-line react-hooks/exhaustive-deps
|
|
|
|
|
|
2026-02-17 12:24:48 -06:00
|
|
|
if (isLoading) return <p className="text-sm text-muted-foreground">Loading...</p>;
|
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>
2026-02-17 09:57:06 -06:00
|
|
|
if (error) return <p className="text-sm text-destructive">{error.message}</p>;
|
|
|
|
|
if (!issue) return null;
|
|
|
|
|
|
2026-02-17 20:16:57 -06:00
|
|
|
// Ancestors are returned oldest-first from the server (root at end, immediate parent at start)
|
|
|
|
|
const ancestors = issue.ancestors ?? [];
|
|
|
|
|
|
2026-02-20 10:32:32 -06:00
|
|
|
const handleFilePicked = async (evt: ChangeEvent<HTMLInputElement>) => {
|
2026-03-13 21:30:48 -05:00
|
|
|
const files = evt.target.files;
|
|
|
|
|
if (!files || files.length === 0) return;
|
|
|
|
|
for (const file of Array.from(files)) {
|
|
|
|
|
if (isMarkdownFile(file)) {
|
|
|
|
|
await importMarkdownDocument.mutateAsync(file);
|
|
|
|
|
} else {
|
|
|
|
|
await uploadAttachment.mutateAsync(file);
|
|
|
|
|
}
|
|
|
|
|
}
|
2026-02-20 10:32:32 -06:00
|
|
|
if (fileInputRef.current) {
|
|
|
|
|
fileInputRef.current.value = "";
|
|
|
|
|
}
|
|
|
|
|
};
|
|
|
|
|
|
2026-03-13 21:30:48 -05:00
|
|
|
const handleAttachmentDrop = async (evt: DragEvent<HTMLDivElement>) => {
|
|
|
|
|
evt.preventDefault();
|
|
|
|
|
setAttachmentDragActive(false);
|
|
|
|
|
const files = evt.dataTransfer.files;
|
|
|
|
|
if (!files || files.length === 0) return;
|
|
|
|
|
for (const file of Array.from(files)) {
|
|
|
|
|
if (isMarkdownFile(file)) {
|
|
|
|
|
await importMarkdownDocument.mutateAsync(file);
|
|
|
|
|
} else {
|
|
|
|
|
await uploadAttachment.mutateAsync(file);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
};
|
|
|
|
|
|
2026-02-20 10:32:32 -06:00
|
|
|
const isImageAttachment = (attachment: IssueAttachment) => attachment.contentType.startsWith("image/");
|
2026-03-14 06:02:46 -05:00
|
|
|
const attachmentList = attachments ?? [];
|
|
|
|
|
const hasAttachments = attachmentList.length > 0;
|
|
|
|
|
const attachmentUploadButton = (
|
|
|
|
|
<div
|
|
|
|
|
className={cn(
|
|
|
|
|
"rounded-md border border-dashed border-border p-1 transition-colors",
|
|
|
|
|
attachmentDragActive && "border-primary bg-primary/5",
|
|
|
|
|
)}
|
|
|
|
|
>
|
|
|
|
|
<input
|
|
|
|
|
ref={fileInputRef}
|
|
|
|
|
type="file"
|
|
|
|
|
accept="image/*,application/pdf,text/plain,text/markdown,application/json,text/csv,text/html,.md,.markdown"
|
|
|
|
|
className="hidden"
|
|
|
|
|
onChange={handleFilePicked}
|
|
|
|
|
multiple
|
|
|
|
|
/>
|
|
|
|
|
<Button
|
|
|
|
|
variant="outline"
|
|
|
|
|
size="sm"
|
|
|
|
|
onClick={() => fileInputRef.current?.click()}
|
|
|
|
|
disabled={uploadAttachment.isPending || importMarkdownDocument.isPending}
|
|
|
|
|
className={cn(
|
|
|
|
|
"border-transparent bg-transparent shadow-none",
|
|
|
|
|
attachmentDragActive && "bg-transparent",
|
|
|
|
|
)}
|
|
|
|
|
>
|
|
|
|
|
<Paperclip className="h-3.5 w-3.5 mr-1.5" />
|
|
|
|
|
{uploadAttachment.isPending || importMarkdownDocument.isPending ? "Uploading..." : "Upload attachment"}
|
|
|
|
|
</Button>
|
|
|
|
|
</div>
|
|
|
|
|
);
|
2026-02-20 10:32:32 -06:00
|
|
|
|
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>
2026-02-17 09:57:06 -06:00
|
|
|
return (
|
|
|
|
|
<div className="max-w-2xl space-y-6">
|
2026-02-17 20:16:57 -06:00
|
|
|
{/* Parent chain breadcrumb */}
|
|
|
|
|
{ancestors.length > 0 && (
|
|
|
|
|
<nav className="flex items-center gap-1 text-xs text-muted-foreground flex-wrap">
|
|
|
|
|
{[...ancestors].reverse().map((ancestor, i) => (
|
|
|
|
|
<span key={ancestor.id} className="flex items-center gap-1">
|
|
|
|
|
{i > 0 && <ChevronRight className="h-3 w-3 shrink-0" />}
|
|
|
|
|
<Link
|
2026-02-20 16:04:05 -06:00
|
|
|
to={`/issues/${ancestor.identifier ?? ancestor.id}`}
|
2026-03-10 20:59:55 -05:00
|
|
|
state={location.state}
|
2026-02-17 20:16:57 -06:00
|
|
|
className="hover:text-foreground transition-colors truncate max-w-[200px]"
|
|
|
|
|
title={ancestor.title}
|
|
|
|
|
>
|
|
|
|
|
{ancestor.title}
|
|
|
|
|
</Link>
|
|
|
|
|
</span>
|
|
|
|
|
))}
|
|
|
|
|
<ChevronRight className="h-3 w-3 shrink-0" />
|
|
|
|
|
<span className="text-foreground/60 truncate max-w-[200px]">{issue.title}</span>
|
|
|
|
|
</nav>
|
|
|
|
|
)}
|
|
|
|
|
|
2026-02-20 07:11:06 -06:00
|
|
|
{issue.hiddenAt && (
|
|
|
|
|
<div className="flex items-center gap-2 rounded-md border border-destructive/30 bg-destructive/10 px-3 py-2 text-sm text-destructive">
|
|
|
|
|
<EyeOff className="h-4 w-4 shrink-0" />
|
|
|
|
|
This issue is hidden
|
|
|
|
|
</div>
|
|
|
|
|
)}
|
|
|
|
|
|
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>
2026-02-17 09:57:06 -06:00
|
|
|
<div className="space-y-3">
|
2026-02-25 17:40:13 -06:00
|
|
|
<div className="flex items-center gap-2 min-w-0 flex-wrap">
|
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>
2026-02-17 09:57:06 -06:00
|
|
|
<StatusIcon
|
|
|
|
|
status={issue.status}
|
2026-02-17 12:24:48 -06:00
|
|
|
onChange={(status) => updateIssue.mutate({ status })}
|
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>
2026-02-17 09:57:06 -06:00
|
|
|
/>
|
|
|
|
|
<PriorityIcon
|
|
|
|
|
priority={issue.priority}
|
2026-02-17 12:24:48 -06:00
|
|
|
onChange={(priority) => updateIssue.mutate({ priority })}
|
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>
2026-02-17 09:57:06 -06:00
|
|
|
/>
|
2026-02-25 17:40:13 -06:00
|
|
|
<span className="text-sm font-mono text-muted-foreground shrink-0">{issue.identifier ?? issue.id.slice(0, 8)}</span>
|
|
|
|
|
|
|
|
|
|
{hasLiveRuns && (
|
2026-02-26 16:33:48 -06:00
|
|
|
<span className="inline-flex items-center gap-1.5 rounded-full bg-cyan-500/10 border border-cyan-500/30 px-2 py-0.5 text-[10px] font-medium text-cyan-600 dark:text-cyan-400 shrink-0">
|
2026-02-25 17:40:13 -06:00
|
|
|
<span className="relative flex h-1.5 w-1.5">
|
ui: apply interface polish from design article review
- Add global font smoothing (antialiased) to body
- Add tabular-nums to all numeric displays: MetricCard values, Costs page,
AgentDetail token/cost grids and tables, IssueDetail cost summary,
Companies page budget display
- Replace markdown image hard border with subtle inset box-shadow overlay
- Replace all animate-ping status dots with calmer animate-pulse across
AgentDetail, IssueDetail, Agents, sidebar, kanban, issues list, and
active agents panel
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-11 08:20:24 -05:00
|
|
|
<span className="animate-pulse absolute inline-flex h-full w-full rounded-full bg-cyan-400 opacity-75" />
|
2026-02-25 17:40:13 -06:00
|
|
|
<span className="relative inline-flex rounded-full h-1.5 w-1.5 bg-cyan-400" />
|
|
|
|
|
</span>
|
|
|
|
|
Live
|
|
|
|
|
</span>
|
|
|
|
|
)}
|
2026-02-19 15:44:05 -06:00
|
|
|
|
2026-02-23 14:41:21 -06:00
|
|
|
{issue.projectId ? (
|
|
|
|
|
<Link
|
|
|
|
|
to={`/projects/${issue.projectId}`}
|
2026-02-25 17:40:13 -06:00
|
|
|
className="inline-flex items-center gap-1 text-xs text-muted-foreground hover:text-foreground transition-colors rounded px-1 -mx-1 py-0.5 min-w-0"
|
2026-02-23 14:41:21 -06:00
|
|
|
>
|
|
|
|
|
<Hexagon className="h-3 w-3 shrink-0" />
|
2026-02-25 17:40:13 -06:00
|
|
|
<span className="truncate">{(projects ?? []).find((p) => p.id === issue.projectId)?.name ?? issue.projectId.slice(0, 8)}</span>
|
2026-02-23 14:41:21 -06:00
|
|
|
</Link>
|
|
|
|
|
) : (
|
|
|
|
|
<span className="inline-flex items-center gap-1 text-xs text-muted-foreground opacity-50 px-1 -mx-1 py-0.5">
|
|
|
|
|
<Hexagon className="h-3 w-3 shrink-0" />
|
|
|
|
|
No project
|
|
|
|
|
</span>
|
|
|
|
|
)}
|
2026-02-20 09:01:28 -06:00
|
|
|
|
2026-02-23 19:49:43 -06:00
|
|
|
{(issue.labels ?? []).length > 0 && (
|
|
|
|
|
<div className="hidden sm:flex items-center gap-1">
|
|
|
|
|
{(issue.labels ?? []).slice(0, 4).map((label) => (
|
|
|
|
|
<span
|
|
|
|
|
key={label.id}
|
|
|
|
|
className="inline-flex items-center rounded-full border px-2 py-0.5 text-[10px] font-medium"
|
|
|
|
|
style={{
|
|
|
|
|
borderColor: label.color,
|
|
|
|
|
color: label.color,
|
|
|
|
|
backgroundColor: `${label.color}1f`,
|
|
|
|
|
}}
|
|
|
|
|
>
|
|
|
|
|
{label.name}
|
|
|
|
|
</span>
|
|
|
|
|
))}
|
|
|
|
|
{(issue.labels ?? []).length > 4 && (
|
|
|
|
|
<span className="text-[10px] text-muted-foreground">+{(issue.labels ?? []).length - 4}</span>
|
|
|
|
|
)}
|
|
|
|
|
</div>
|
|
|
|
|
)}
|
|
|
|
|
|
|
|
|
|
<Button
|
|
|
|
|
variant="ghost"
|
|
|
|
|
size="icon-xs"
|
2026-02-25 17:40:13 -06:00
|
|
|
className="ml-auto md:hidden shrink-0"
|
2026-02-23 19:49:43 -06:00
|
|
|
onClick={() => setMobilePropsOpen(true)}
|
|
|
|
|
title="Properties"
|
|
|
|
|
>
|
|
|
|
|
<SlidersHorizontal className="h-4 w-4" />
|
|
|
|
|
</Button>
|
|
|
|
|
|
2026-03-03 15:06:42 -06:00
|
|
|
<div className="hidden md:flex items-center md:ml-auto shrink-0">
|
2026-03-03 14:56:32 -06:00
|
|
|
<Button
|
|
|
|
|
variant="ghost"
|
|
|
|
|
size="icon-xs"
|
2026-03-03 15:06:42 -06:00
|
|
|
className={cn(
|
|
|
|
|
"shrink-0 transition-opacity duration-200",
|
|
|
|
|
panelVisible ? "opacity-0 pointer-events-none w-0 overflow-hidden" : "opacity-100",
|
|
|
|
|
)}
|
2026-03-03 14:56:32 -06:00
|
|
|
onClick={() => setPanelVisible(true)}
|
|
|
|
|
title="Show properties"
|
|
|
|
|
>
|
|
|
|
|
<SlidersHorizontal className="h-4 w-4" />
|
|
|
|
|
</Button>
|
|
|
|
|
|
2026-03-03 15:06:42 -06:00
|
|
|
<Popover open={moreOpen} onOpenChange={setMoreOpen}>
|
|
|
|
|
<PopoverTrigger asChild>
|
|
|
|
|
<Button variant="ghost" size="icon-xs" className="shrink-0">
|
|
|
|
|
<MoreHorizontal className="h-4 w-4" />
|
|
|
|
|
</Button>
|
|
|
|
|
</PopoverTrigger>
|
2026-02-19 15:44:05 -06:00
|
|
|
<PopoverContent className="w-44 p-1" align="end">
|
|
|
|
|
<button
|
|
|
|
|
className="flex items-center gap-2 w-full px-2 py-1.5 text-xs rounded hover:bg-accent/50 text-destructive"
|
|
|
|
|
onClick={() => {
|
|
|
|
|
updateIssue.mutate(
|
|
|
|
|
{ hiddenAt: new Date().toISOString() },
|
2026-02-20 07:11:06 -06:00
|
|
|
{ onSuccess: () => navigate("/issues/all") },
|
2026-02-19 15:44:05 -06:00
|
|
|
);
|
|
|
|
|
setMoreOpen(false);
|
|
|
|
|
}}
|
|
|
|
|
>
|
|
|
|
|
<EyeOff className="h-3 w-3" />
|
|
|
|
|
Hide this Issue
|
|
|
|
|
</button>
|
|
|
|
|
</PopoverContent>
|
2026-03-03 15:06:42 -06:00
|
|
|
</Popover>
|
|
|
|
|
</div>
|
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>
2026-02-17 09:57:06 -06:00
|
|
|
</div>
|
|
|
|
|
|
|
|
|
|
<InlineEditor
|
|
|
|
|
value={issue.title}
|
2026-03-13 21:30:48 -05:00
|
|
|
onSave={(title) => updateIssue.mutateAsync({ title })}
|
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>
2026-02-17 09:57:06 -06:00
|
|
|
as="h2"
|
|
|
|
|
className="text-xl font-bold"
|
|
|
|
|
/>
|
|
|
|
|
|
|
|
|
|
<InlineEditor
|
|
|
|
|
value={issue.description ?? ""}
|
2026-03-13 21:30:48 -05:00
|
|
|
onSave={(description) => updateIssue.mutateAsync({ description })}
|
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>
2026-02-17 09:57:06 -06:00
|
|
|
as="p"
|
2026-03-10 20:55:41 -05:00
|
|
|
className="text-[15px] leading-7 text-foreground"
|
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>
2026-02-17 09:57:06 -06:00
|
|
|
placeholder="Add a description..."
|
|
|
|
|
multiline
|
2026-03-02 13:31:58 -06:00
|
|
|
mentions={mentionOptions}
|
Add MarkdownEditor component, asset image upload, and rich description editing
Introduce MarkdownEditor built on @mdxeditor/editor with headings,
lists, links, quotes, image upload with drag-and-drop, and themed CSS
integration. Add asset image upload API (routes, service, storage) and
wire image upload into InlineEditor multiline mode, NewIssueDialog,
NewProjectDialog, GoalDetail, IssueDetail, and ProjectDetail
description fields. Tighten prompt template editor styling.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-20 12:50:45 -06:00
|
|
|
imageUploadHandler={async (file) => {
|
|
|
|
|
const attachment = await uploadAttachment.mutateAsync(file);
|
|
|
|
|
return attachment.contentPath;
|
|
|
|
|
}}
|
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>
2026-02-17 09:57:06 -06:00
|
|
|
/>
|
|
|
|
|
</div>
|
|
|
|
|
|
2026-03-13 21:30:48 -05:00
|
|
|
<IssueDocumentsSection
|
|
|
|
|
issue={issue}
|
|
|
|
|
canDeleteDocuments={Boolean(session?.user?.id)}
|
|
|
|
|
mentions={mentionOptions}
|
|
|
|
|
imageUploadHandler={async (file) => {
|
|
|
|
|
const attachment = await uploadAttachment.mutateAsync(file);
|
|
|
|
|
return attachment.contentPath;
|
|
|
|
|
}}
|
2026-03-14 06:02:46 -05:00
|
|
|
extraActions={!hasAttachments ? attachmentUploadButton : undefined}
|
2026-03-13 21:30:48 -05:00
|
|
|
/>
|
|
|
|
|
|
2026-03-14 06:02:46 -05:00
|
|
|
{hasAttachments ? (
|
|
|
|
|
<div
|
2026-03-13 21:30:48 -05:00
|
|
|
className={cn(
|
|
|
|
|
"space-y-3 rounded-lg transition-colors",
|
|
|
|
|
)}
|
|
|
|
|
onDragEnter={(evt) => {
|
|
|
|
|
evt.preventDefault();
|
|
|
|
|
setAttachmentDragActive(true);
|
|
|
|
|
}}
|
|
|
|
|
onDragOver={(evt) => {
|
|
|
|
|
evt.preventDefault();
|
|
|
|
|
setAttachmentDragActive(true);
|
|
|
|
|
}}
|
|
|
|
|
onDragLeave={(evt) => {
|
|
|
|
|
if (evt.currentTarget.contains(evt.relatedTarget as Node | null)) return;
|
|
|
|
|
setAttachmentDragActive(false);
|
|
|
|
|
}}
|
|
|
|
|
onDrop={(evt) => void handleAttachmentDrop(evt)}
|
|
|
|
|
>
|
2026-02-20 10:32:32 -06:00
|
|
|
<div className="flex items-center justify-between gap-2">
|
|
|
|
|
<h3 className="text-sm font-medium text-muted-foreground">Attachments</h3>
|
2026-03-14 06:02:46 -05:00
|
|
|
{attachmentUploadButton}
|
2026-02-20 10:32:32 -06:00
|
|
|
</div>
|
|
|
|
|
|
|
|
|
|
{attachmentError && (
|
|
|
|
|
<p className="text-xs text-destructive">{attachmentError}</p>
|
|
|
|
|
)}
|
|
|
|
|
|
2026-03-14 06:02:46 -05:00
|
|
|
<div className="space-y-2">
|
|
|
|
|
{attachmentList.map((attachment) => (
|
|
|
|
|
<div key={attachment.id} className="border border-border rounded-md p-2">
|
|
|
|
|
<div className="flex items-center justify-between gap-2">
|
|
|
|
|
<a
|
|
|
|
|
href={attachment.contentPath}
|
|
|
|
|
target="_blank"
|
|
|
|
|
rel="noreferrer"
|
|
|
|
|
className="text-xs hover:underline truncate"
|
|
|
|
|
title={attachment.originalFilename ?? attachment.id}
|
|
|
|
|
>
|
|
|
|
|
{attachment.originalFilename ?? attachment.id}
|
|
|
|
|
</a>
|
|
|
|
|
<button
|
|
|
|
|
type="button"
|
|
|
|
|
className="text-muted-foreground hover:text-destructive"
|
|
|
|
|
onClick={() => deleteAttachment.mutate(attachment.id)}
|
|
|
|
|
disabled={deleteAttachment.isPending}
|
|
|
|
|
title="Delete attachment"
|
|
|
|
|
>
|
|
|
|
|
<Trash2 className="h-3.5 w-3.5" />
|
|
|
|
|
</button>
|
2026-02-20 10:32:32 -06:00
|
|
|
</div>
|
2026-03-14 06:02:46 -05:00
|
|
|
<p className="text-[11px] text-muted-foreground">
|
|
|
|
|
{attachment.contentType} · {(attachment.byteSize / 1024).toFixed(1)} KB
|
|
|
|
|
</p>
|
|
|
|
|
{isImageAttachment(attachment) && (
|
|
|
|
|
<a href={attachment.contentPath} target="_blank" rel="noreferrer">
|
|
|
|
|
<img
|
|
|
|
|
src={attachment.contentPath}
|
|
|
|
|
alt={attachment.originalFilename ?? "attachment"}
|
|
|
|
|
className="mt-2 max-h-56 rounded border border-border object-contain bg-accent/10"
|
|
|
|
|
loading="lazy"
|
|
|
|
|
/>
|
|
|
|
|
</a>
|
|
|
|
|
)}
|
|
|
|
|
</div>
|
|
|
|
|
))}
|
|
|
|
|
</div>
|
|
|
|
|
</div>
|
|
|
|
|
) : null}
|
2026-02-20 10:32:32 -06:00
|
|
|
|
|
|
|
|
<Separator />
|
|
|
|
|
|
2026-02-25 08:39:31 -06:00
|
|
|
<Tabs value={detailTab} onValueChange={setDetailTab} className="space-y-3">
|
|
|
|
|
<TabsList variant="line" className="w-full justify-start gap-1">
|
|
|
|
|
<TabsTrigger value="comments" className="gap-1.5">
|
|
|
|
|
<MessageSquare className="h-3.5 w-3.5" />
|
|
|
|
|
Comments
|
|
|
|
|
</TabsTrigger>
|
|
|
|
|
<TabsTrigger value="subissues" className="gap-1.5">
|
|
|
|
|
<ListTree className="h-3.5 w-3.5" />
|
|
|
|
|
Sub-issues
|
|
|
|
|
</TabsTrigger>
|
|
|
|
|
<TabsTrigger value="activity" className="gap-1.5">
|
|
|
|
|
<ActivityIcon className="h-3.5 w-3.5" />
|
|
|
|
|
Activity
|
|
|
|
|
</TabsTrigger>
|
|
|
|
|
</TabsList>
|
|
|
|
|
|
|
|
|
|
<TabsContent value="comments">
|
|
|
|
|
<CommentThread
|
|
|
|
|
comments={commentsWithRunMeta}
|
2026-03-03 12:19:26 -06:00
|
|
|
linkedRuns={timelineRuns}
|
2026-02-25 08:39:31 -06:00
|
|
|
issueStatus={issue.status}
|
|
|
|
|
agentMap={agentMap}
|
|
|
|
|
draftKey={`paperclip:issue-comment-draft:${issue.id}`}
|
2026-03-02 16:56:05 -06:00
|
|
|
enableReassign
|
2026-02-26 16:33:48 -06:00
|
|
|
reassignOptions={commentReassignOptions}
|
2026-03-02 16:56:05 -06:00
|
|
|
currentAssigneeValue={currentAssigneeValue}
|
2026-03-02 13:31:58 -06:00
|
|
|
mentions={mentionOptions}
|
2026-02-26 16:33:48 -06:00
|
|
|
onAdd={async (body, reopen, reassignment) => {
|
|
|
|
|
if (reassignment) {
|
|
|
|
|
await addCommentAndReassign.mutateAsync({ body, reopen, reassignment });
|
|
|
|
|
return;
|
|
|
|
|
}
|
2026-02-25 08:39:31 -06:00
|
|
|
await addComment.mutateAsync({ body, reopen });
|
|
|
|
|
}}
|
|
|
|
|
imageUploadHandler={async (file) => {
|
|
|
|
|
const attachment = await uploadAttachment.mutateAsync(file);
|
|
|
|
|
return attachment.contentPath;
|
|
|
|
|
}}
|
2026-02-25 17:40:13 -06:00
|
|
|
onAttachImage={async (file) => {
|
|
|
|
|
await uploadAttachment.mutateAsync(file);
|
|
|
|
|
}}
|
2026-03-03 11:06:41 -06:00
|
|
|
liveRunSlot={<LiveRunWidget issueId={issueId!} companyId={issue.companyId} />}
|
2026-02-25 08:39:31 -06:00
|
|
|
/>
|
|
|
|
|
</TabsContent>
|
|
|
|
|
|
|
|
|
|
<TabsContent value="subissues">
|
|
|
|
|
{childIssues.length === 0 ? (
|
|
|
|
|
<p className="text-xs text-muted-foreground">No sub-issues.</p>
|
|
|
|
|
) : (
|
2026-02-20 14:48:30 -06:00
|
|
|
<div className="border border-border rounded-lg divide-y divide-border">
|
|
|
|
|
{childIssues.map((child) => (
|
|
|
|
|
<Link
|
|
|
|
|
key={child.id}
|
2026-02-20 16:04:05 -06:00
|
|
|
to={`/issues/${child.identifier ?? child.id}`}
|
2026-03-10 20:59:55 -05:00
|
|
|
state={location.state}
|
2026-02-23 19:52:43 -06:00
|
|
|
className="flex items-center justify-between px-3 py-2 text-sm hover:bg-accent/20 transition-colors"
|
2026-02-20 14:48:30 -06:00
|
|
|
>
|
|
|
|
|
<div className="flex items-center gap-2 min-w-0">
|
|
|
|
|
<StatusIcon status={child.status} />
|
|
|
|
|
<PriorityIcon priority={child.priority} />
|
|
|
|
|
<span className="font-mono text-muted-foreground shrink-0">
|
|
|
|
|
{child.identifier ?? child.id.slice(0, 8)}
|
|
|
|
|
</span>
|
|
|
|
|
<span className="truncate">{child.title}</span>
|
|
|
|
|
</div>
|
|
|
|
|
{child.assigneeAgentId && (() => {
|
|
|
|
|
const name = agentMap.get(child.assigneeAgentId)?.name;
|
|
|
|
|
return name
|
|
|
|
|
? <Identity name={name} size="sm" />
|
|
|
|
|
: <span className="text-muted-foreground font-mono">{child.assigneeAgentId.slice(0, 8)}</span>;
|
|
|
|
|
})()}
|
|
|
|
|
</Link>
|
|
|
|
|
))}
|
|
|
|
|
</div>
|
2026-02-25 08:39:31 -06:00
|
|
|
)}
|
|
|
|
|
</TabsContent>
|
|
|
|
|
|
|
|
|
|
<TabsContent value="activity">
|
|
|
|
|
{!activity || activity.length === 0 ? (
|
|
|
|
|
<p className="text-xs text-muted-foreground">No activity yet.</p>
|
|
|
|
|
) : (
|
|
|
|
|
<div className="space-y-1.5">
|
|
|
|
|
{activity.slice(0, 20).map((evt) => (
|
|
|
|
|
<div key={evt.id} className="flex items-center gap-1.5 text-xs text-muted-foreground">
|
|
|
|
|
<ActorIdentity evt={evt} agentMap={agentMap} />
|
|
|
|
|
<span>{formatAction(evt.action, evt.details)}</span>
|
|
|
|
|
<span className="ml-auto shrink-0">{relativeTime(evt.createdAt)}</span>
|
|
|
|
|
</div>
|
|
|
|
|
))}
|
|
|
|
|
</div>
|
|
|
|
|
)}
|
|
|
|
|
</TabsContent>
|
|
|
|
|
</Tabs>
|
2026-02-20 14:48:30 -06:00
|
|
|
|
UI: approval detail page, agent hiring UX, costs breakdown, sidebar badges, and dashboard improvements
Add ApprovalDetail page with comment thread, revision request/resubmit flow,
and ApprovalPayload component for structured payload display. Extend AgentDetail
with permissions management, config revision history, and duplicate action.
Add agent hire dialog with permission-gated access. Rework Costs page with
per-agent breakdown table and period filtering. Add sidebar badge counts for
pending approvals and inbox items. Enhance Dashboard with live metrics and
sparkline trends. Extend Agents list with pending_approval status and bulk
actions. Update IssueDetail with approval linking. Various component improvements
to MetricCard, InlineEditor, CommentThread, and StatusBadge.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-19 13:03:08 -06:00
|
|
|
{linkedApprovals && linkedApprovals.length > 0 && (
|
2026-02-25 08:39:31 -06:00
|
|
|
<Collapsible
|
|
|
|
|
open={secondaryOpen.approvals}
|
|
|
|
|
onOpenChange={(open) => setSecondaryOpen((prev) => ({ ...prev, approvals: open }))}
|
|
|
|
|
className="rounded-lg border border-border"
|
|
|
|
|
>
|
|
|
|
|
<CollapsibleTrigger className="flex w-full items-center justify-between px-3 py-2 text-left">
|
|
|
|
|
<span className="text-sm font-medium text-muted-foreground">
|
|
|
|
|
Linked Approvals ({linkedApprovals.length})
|
|
|
|
|
</span>
|
|
|
|
|
<ChevronDown
|
|
|
|
|
className={cn("h-4 w-4 text-muted-foreground transition-transform", secondaryOpen.approvals && "rotate-180")}
|
|
|
|
|
/>
|
|
|
|
|
</CollapsibleTrigger>
|
|
|
|
|
<CollapsibleContent>
|
|
|
|
|
<div className="border-t border-border divide-y divide-border">
|
UI: approval detail page, agent hiring UX, costs breakdown, sidebar badges, and dashboard improvements
Add ApprovalDetail page with comment thread, revision request/resubmit flow,
and ApprovalPayload component for structured payload display. Extend AgentDetail
with permissions management, config revision history, and duplicate action.
Add agent hire dialog with permission-gated access. Rework Costs page with
per-agent breakdown table and period filtering. Add sidebar badge counts for
pending approvals and inbox items. Enhance Dashboard with live metrics and
sparkline trends. Extend Agents list with pending_approval status and bulk
actions. Update IssueDetail with approval linking. Various component improvements
to MetricCard, InlineEditor, CommentThread, and StatusBadge.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-19 13:03:08 -06:00
|
|
|
{linkedApprovals.map((approval) => (
|
|
|
|
|
<Link
|
|
|
|
|
key={approval.id}
|
|
|
|
|
to={`/approvals/${approval.id}`}
|
|
|
|
|
className="flex items-center justify-between px-3 py-2 text-xs hover:bg-accent/20 transition-colors"
|
|
|
|
|
>
|
|
|
|
|
<div className="flex items-center gap-2">
|
|
|
|
|
<StatusBadge status={approval.status} />
|
|
|
|
|
<span className="font-medium">
|
|
|
|
|
{approval.type.replace(/_/g, " ").replace(/\b\w/g, (c) => c.toUpperCase())}
|
|
|
|
|
</span>
|
|
|
|
|
<span className="font-mono text-muted-foreground">{approval.id.slice(0, 8)}</span>
|
|
|
|
|
</div>
|
|
|
|
|
<span className="text-muted-foreground">{relativeTime(approval.createdAt)}</span>
|
|
|
|
|
</Link>
|
|
|
|
|
))}
|
|
|
|
|
</div>
|
2026-02-25 08:39:31 -06:00
|
|
|
</CollapsibleContent>
|
|
|
|
|
</Collapsible>
|
UI: approval detail page, agent hiring UX, costs breakdown, sidebar badges, and dashboard improvements
Add ApprovalDetail page with comment thread, revision request/resubmit flow,
and ApprovalPayload component for structured payload display. Extend AgentDetail
with permissions management, config revision history, and duplicate action.
Add agent hire dialog with permission-gated access. Rework Costs page with
per-agent breakdown table and period filtering. Add sidebar badge counts for
pending approvals and inbox items. Enhance Dashboard with live metrics and
sparkline trends. Extend Agents list with pending_approval status and bulk
actions. Update IssueDetail with approval linking. Various component improvements
to MetricCard, InlineEditor, CommentThread, and StatusBadge.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-19 13:03:08 -06:00
|
|
|
)}
|
|
|
|
|
|
2026-02-25 08:39:31 -06:00
|
|
|
{linkedRuns && linkedRuns.length > 0 && (
|
|
|
|
|
<Collapsible
|
|
|
|
|
open={secondaryOpen.cost}
|
|
|
|
|
onOpenChange={(open) => setSecondaryOpen((prev) => ({ ...prev, cost: open }))}
|
|
|
|
|
className="rounded-lg border border-border"
|
|
|
|
|
>
|
|
|
|
|
<CollapsibleTrigger className="flex w-full items-center justify-between px-3 py-2 text-left">
|
|
|
|
|
<span className="text-sm font-medium text-muted-foreground">Cost Summary</span>
|
|
|
|
|
<ChevronDown
|
|
|
|
|
className={cn("h-4 w-4 text-muted-foreground transition-transform", secondaryOpen.cost && "rotate-180")}
|
|
|
|
|
/>
|
|
|
|
|
</CollapsibleTrigger>
|
|
|
|
|
<CollapsibleContent>
|
|
|
|
|
<div className="border-t border-border px-3 py-2">
|
|
|
|
|
{!issueCostSummary.hasCost && !issueCostSummary.hasTokens ? (
|
|
|
|
|
<div className="text-xs text-muted-foreground">No cost data yet.</div>
|
|
|
|
|
) : (
|
ui: apply interface polish from design article review
- Add global font smoothing (antialiased) to body
- Add tabular-nums to all numeric displays: MetricCard values, Costs page,
AgentDetail token/cost grids and tables, IssueDetail cost summary,
Companies page budget display
- Replace markdown image hard border with subtle inset box-shadow overlay
- Replace all animate-ping status dots with calmer animate-pulse across
AgentDetail, IssueDetail, Agents, sidebar, kanban, issues list, and
active agents panel
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-11 08:20:24 -05:00
|
|
|
<div className="flex flex-wrap gap-3 text-xs text-muted-foreground tabular-nums">
|
2026-02-25 08:39:31 -06:00
|
|
|
{issueCostSummary.hasCost && (
|
|
|
|
|
<span className="font-medium text-foreground">
|
|
|
|
|
${issueCostSummary.cost.toFixed(4)}
|
|
|
|
|
</span>
|
|
|
|
|
)}
|
|
|
|
|
{issueCostSummary.hasTokens && (
|
|
|
|
|
<span>
|
|
|
|
|
Tokens {formatTokens(issueCostSummary.totalTokens)}
|
|
|
|
|
{issueCostSummary.cached > 0
|
|
|
|
|
? ` (in ${formatTokens(issueCostSummary.input)}, out ${formatTokens(issueCostSummary.output)}, cached ${formatTokens(issueCostSummary.cached)})`
|
|
|
|
|
: ` (in ${formatTokens(issueCostSummary.input)}, out ${formatTokens(issueCostSummary.output)})`}
|
|
|
|
|
</span>
|
|
|
|
|
)}
|
UI: Identity component, LiveRunWidget, issue identifiers, and UX improvements
Add Identity component (avatar + name) used across agent/issue displays. Add
LiveRunWidget for real-time streaming of active heartbeat runs on issue detail
pages via WebSocket. Display issue identifiers (PAP-42) instead of UUID
fragments throughout Issues, Inbox, CommandPalette, and detail pages.
Enhance CommentThread with re-open checkbox, Cmd+Enter submit, sorted display,
and run linking. Improve Activity page with richer formatting and filtering.
Update Dashboard with live metrics. Add reports-to agent link in AgentProperties.
Various small fixes: StatusIcon centering, CopyText ref init, agent detail
run-issue cross-links.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-19 09:10:07 -06:00
|
|
|
</div>
|
2026-02-25 08:39:31 -06:00
|
|
|
)}
|
UI: Identity component, LiveRunWidget, issue identifiers, and UX improvements
Add Identity component (avatar + name) used across agent/issue displays. Add
LiveRunWidget for real-time streaming of active heartbeat runs on issue detail
pages via WebSocket. Display issue identifiers (PAP-42) instead of UUID
fragments throughout Issues, Inbox, CommandPalette, and detail pages.
Enhance CommentThread with re-open checkbox, Cmd+Enter submit, sorted display,
and run linking. Improve Activity page with richer formatting and filtering.
Update Dashboard with live metrics. Add reports-to agent link in AgentProperties.
Various small fixes: StatusIcon centering, CopyText ref init, agent detail
run-issue cross-links.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-19 09:10:07 -06:00
|
|
|
</div>
|
2026-02-25 08:39:31 -06:00
|
|
|
</CollapsibleContent>
|
|
|
|
|
</Collapsible>
|
2026-02-20 10:32:32 -06:00
|
|
|
)}
|
2026-02-23 19:49:43 -06:00
|
|
|
|
|
|
|
|
{/* Mobile properties drawer */}
|
|
|
|
|
<Sheet open={mobilePropsOpen} onOpenChange={setMobilePropsOpen}>
|
2026-02-25 21:36:06 -06:00
|
|
|
<SheetContent side="bottom" className="max-h-[85dvh] pb-[env(safe-area-inset-bottom)]">
|
2026-02-23 19:49:43 -06:00
|
|
|
<SheetHeader>
|
|
|
|
|
<SheetTitle className="text-sm">Properties</SheetTitle>
|
|
|
|
|
</SheetHeader>
|
|
|
|
|
<ScrollArea className="flex-1 overflow-y-auto">
|
|
|
|
|
<div className="px-4 pb-4">
|
2026-02-26 08:53:03 -06:00
|
|
|
<IssueProperties issue={issue} onUpdate={(data) => updateIssue.mutate(data)} inline />
|
2026-02-23 19:49:43 -06:00
|
|
|
</div>
|
|
|
|
|
</ScrollArea>
|
|
|
|
|
</SheetContent>
|
|
|
|
|
</Sheet>
|
2026-03-07 20:07:39 -06:00
|
|
|
<ScrollToBottom />
|
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>
2026-02-17 09:57:06 -06:00
|
|
|
</div>
|
|
|
|
|
);
|
|
|
|
|
}
|