feat(dashboard): rearrange agent + task detail panels
- AgentsView: agent metrics bar moves to the top of the scrolling content (was below the agent list); token-usage panel moves into the controls dropdown next to the heartbeat slider, which is now scrollable so the added content fits on short viewports. - AgentsView mobile: 2x2 grid for the metric cards with tighter padding and smaller value/label text so labels don't crowd off the card on narrow phones. - TaskDetailModal: new "Stats" tab at the end of the fixed tab list hosts the token-usage panel, removed from the inline definition body. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -834,6 +834,29 @@
|
|||||||
}
|
}
|
||||||
|
|
||||||
@media (max-width: 768px) {
|
@media (max-width: 768px) {
|
||||||
|
/* Stats cards: drop to a 2x2 grid with tighter padding so they
|
||||||
|
don't squeeze the labels off the card on narrow phones. */
|
||||||
|
.agent-metrics-bar {
|
||||||
|
display: grid;
|
||||||
|
grid-template-columns: repeat(2, minmax(0, 1fr));
|
||||||
|
gap: var(--space-sm);
|
||||||
|
margin-bottom: var(--space-md);
|
||||||
|
}
|
||||||
|
|
||||||
|
.agent-metric-card {
|
||||||
|
padding: var(--space-sm) var(--space-md);
|
||||||
|
gap: var(--space-sm);
|
||||||
|
min-width: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.agent-metric-value {
|
||||||
|
font-size: 16px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.agent-metric-label {
|
||||||
|
font-size: calc(var(--space-sm) + var(--space-xs) * 0.5);
|
||||||
|
}
|
||||||
|
|
||||||
.agent-org-chart {
|
.agent-org-chart {
|
||||||
padding: var(--space-sm);
|
padding: var(--space-sm);
|
||||||
padding-bottom: calc(var(--space-lg) + var(--space-sm));
|
padding-bottom: calc(var(--space-lg) + var(--space-sm));
|
||||||
|
|||||||
@@ -749,10 +749,11 @@ export function AgentsView({ addToast, projectId }: AgentsViewProps) {
|
|||||||
<div
|
<div
|
||||||
ref={controlsPanelRef}
|
ref={controlsPanelRef}
|
||||||
id={controlsPanelId}
|
id={controlsPanelId}
|
||||||
className="agent-controls-panel"
|
className="agent-controls-panel agent-controls-panel--scrollable"
|
||||||
role="dialog"
|
role="dialog"
|
||||||
aria-label="Agent controls"
|
aria-label="Agent controls"
|
||||||
aria-modal="false"
|
aria-modal="false"
|
||||||
|
style={{ maxHeight: "70vh", overflowY: "auto" }}
|
||||||
>
|
>
|
||||||
<div className="agent-controls">
|
<div className="agent-controls">
|
||||||
<div className="agent-controls-filters">
|
<div className="agent-controls-filters">
|
||||||
@@ -846,11 +847,15 @@ export function AgentsView({ addToast, projectId }: AgentsViewProps) {
|
|||||||
</small>
|
</small>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
<AgentTokenStatsPanel agents={displayAgents} />
|
||||||
</div>
|
</div>
|
||||||
)}
|
)}
|
||||||
|
|
||||||
<div className="agents-view-content">
|
<div className="agents-view-content">
|
||||||
|
|
||||||
|
<AgentMetricsBar stats={stats} />
|
||||||
|
|
||||||
<NewAgentDialog
|
<NewAgentDialog
|
||||||
isOpen={isCreating}
|
isOpen={isCreating}
|
||||||
onClose={() => setIsCreating(false)}
|
onClose={() => setIsCreating(false)}
|
||||||
@@ -1266,8 +1271,6 @@ export function AgentsView({ addToast, projectId }: AgentsViewProps) {
|
|||||||
)}
|
)}
|
||||||
|
|
||||||
{/* Secondary sections after the main collection */}
|
{/* Secondary sections after the main collection */}
|
||||||
<AgentMetricsBar stats={stats} />
|
|
||||||
<AgentTokenStatsPanel agents={displayAgents} />
|
|
||||||
<ActiveAgentsPanel agents={activeAgents} projectId={projectId} onAgentSelect={setSelectedAgentId} />
|
<ActiveAgentsPanel agents={activeAgents} projectId={projectId} onAgentSelect={setSelectedAgentId} />
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
|||||||
@@ -157,7 +157,7 @@ function formatBytes(bytes: number): string {
|
|||||||
return `${(bytes / (1024 * 1024)).toFixed(1)} MB`;
|
return `${(bytes / (1024 * 1024)).toFixed(1)} MB`;
|
||||||
}
|
}
|
||||||
|
|
||||||
type TabId = "definition" | "logs" | "changes" | "comments" | "model" | "workflow" | "documents" | `plugin-${string}`;
|
type TabId = "definition" | "logs" | "changes" | "comments" | "model" | "workflow" | "documents" | "stats" | `plugin-${string}`;
|
||||||
|
|
||||||
interface TaskDetailModalProps {
|
interface TaskDetailModalProps {
|
||||||
task: Task | TaskDetail;
|
task: Task | TaskDetail;
|
||||||
@@ -1286,6 +1286,12 @@ export function TaskDetailModal({
|
|||||||
>
|
>
|
||||||
Workflow
|
Workflow
|
||||||
</button>
|
</button>
|
||||||
|
<button
|
||||||
|
className={`detail-tab${activeTab === "stats" ? " detail-tab-active" : ""}`}
|
||||||
|
onClick={() => setActiveTab("stats")}
|
||||||
|
>
|
||||||
|
Stats
|
||||||
|
</button>
|
||||||
{/* Plugin tabs */}
|
{/* Plugin tabs */}
|
||||||
{pluginTabSlots.map((entry, index) => {
|
{pluginTabSlots.map((entry, index) => {
|
||||||
const pluginTabId = `plugin-${index}` as TabId;
|
const pluginTabId = `plugin-${index}` as TabId;
|
||||||
@@ -1391,6 +1397,13 @@ export function TaskDetailModal({
|
|||||||
<div className="detail-section">
|
<div className="detail-section">
|
||||||
<PluginSlot slotId="task-detail-tab" projectId={projectId} />
|
<PluginSlot slotId="task-detail-tab" projectId={projectId} />
|
||||||
</div>
|
</div>
|
||||||
|
) : activeTab === "stats" ? (
|
||||||
|
<div className="detail-section">
|
||||||
|
<TaskTokenStatsPanel
|
||||||
|
tokenUsage={workingTask.tokenUsage}
|
||||||
|
loading={detailLoading}
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
) : (
|
) : (
|
||||||
<>
|
<>
|
||||||
{/* Summary section - only for done tasks with summary */}
|
{/* Summary section - only for done tasks with summary */}
|
||||||
@@ -1482,12 +1495,6 @@ export function TaskDetailModal({
|
|||||||
<div className="step-progress-empty">(no steps defined)</div>
|
<div className="step-progress-empty">(no steps defined)</div>
|
||||||
)}
|
)}
|
||||||
</div>
|
</div>
|
||||||
<div className="detail-section">
|
|
||||||
<TaskTokenStatsPanel
|
|
||||||
tokenUsage={workingTask.tokenUsage}
|
|
||||||
loading={detailLoading}
|
|
||||||
/>
|
|
||||||
</div>
|
|
||||||
<div className="detail-section">
|
<div className="detail-section">
|
||||||
{!isEditingSpec && (
|
{!isEditingSpec && (
|
||||||
<div className="detail-spec-edit-trigger">
|
<div className="detail-spec-edit-trigger">
|
||||||
|
|||||||
Reference in New Issue
Block a user