Files
fusion/packages/dashboard/app/components/AgentsView.css
Fusion 23e2c2514e feat(FN-2932): improve active agent visibility and grouped tool-call UX
- Preserve and emphasize active agent card highlights across hover and modal states, with dedicated CSS updates and regression tests
- Expand dashboard and TUI activity surfaces for grouped tool-call and live agent status/log visibility, including Quick Chat and chat view refinements
- Add route and runtime updates for agent/settings flows plus self-healing coverage for merge recovery behavior
- Include accompanying changesets and test stabilizations for mission activity assertions and active highlight hooks

Fusion-Task-Id: FN-2932
2026-04-29 13:29:00 -07:00

1034 lines
22 KiB
CSS
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
/* === Agent Metrics Bar === */
.agent-metrics-bar {
display: flex;
gap: var(--space-md);
margin-bottom: var(--space-lg);
}
.agent-metric-card {
display: flex;
align-items: center;
gap: var(--space-md);
padding: var(--space-md) var(--space-lg);
background: var(--card);
border: 1px solid var(--border);
border-radius: var(--radius-md);
box-shadow: var(--shadow-sm);
transition: background var(--transition-fast), transform var(--transition-fast), box-shadow var(--transition-fast);
flex: 1;
}
.agent-metric-card:hover {
background: var(--card-hover);
transform: translateY(calc(var(--space-xs) * -0.25));
}
.agent-metric-card--active svg { color: var(--state-active-text); }
.agent-metric-card--tasks svg { color: var(--in-progress); }
.agent-metric-card--success svg { color: var(--color-success); }
.agent-metric-card--runs svg { color: var(--in-progress); }
.agent-metric-info {
display: flex;
flex-direction: column;
}
.agent-metric-value {
font-size: 18px;
font-weight: 700;
font-family: var(--font-mono);
line-height: 1.2;
}
.agent-metric-label {
font-size: calc(var(--space-sm) + var(--space-xs) * 0.75);
color: var(--text-muted);
text-transform: uppercase;
letter-spacing: 0.5px;
}
/* === Agent List View === */
.agents-view {
position: relative;
display: flex;
flex-direction: column;
height: 100%;
overflow: hidden;
}
.agents-view-header {
display: flex;
align-items: center;
justify-content: space-between;
padding: var(--space-lg) 20px;
border-bottom: 1px solid var(--border);
background: var(--surface);
}
.agents-view-title {
display: flex;
align-items: center;
gap: var(--space-sm);
}
.agents-view-title h2 {
font-size: 18px;
font-weight: 600;
margin: 0;
}
.agents-view-controls {
display: flex;
align-items: center;
gap: var(--space-sm);
}
.agents-view-primary-actions {
display: flex;
align-items: center;
gap: var(--space-sm);
}
.agent-controls-trigger {
white-space: nowrap;
}
.agent-controls-trigger--active {
border-color: var(--todo);
box-shadow: var(--focus-ring);
}
.agent-controls-panel {
position: absolute;
top: calc(var(--header-height) + var(--space-sm));
right: var(--space-lg);
width: min(calc(var(--space-2xl) * 16), calc(100% - var(--space-2xl)));
padding: var(--space-md);
border: 1px solid var(--border);
border-radius: var(--radius-md);
background: var(--card);
box-shadow: var(--shadow-lg);
z-index: 20;
display: flex;
flex-direction: column;
gap: var(--space-md);
}
.agent-controls-panel--scrollable {
max-height: 70vh;
overflow-y: auto;
}
.agent-controls-panel .agent-controls {
margin-bottom: 0;
align-items: stretch;
}
.agent-controls-panel .agent-controls-actions {
justify-content: flex-end;
}
.agent-controls-panel .agent-global-controls {
margin-bottom: 0;
padding: var(--space-md);
}
.agents-view-content {
flex: 1;
overflow-y: auto;
padding: 20px;
}
.agents-view-loading {
display: inline-flex;
align-items: center;
justify-content: center;
width: 100%;
min-height: calc(var(--space-2xl) * 6);
gap: var(--space-sm);
color: var(--text-muted);
}
.agent-controls {
display: flex;
align-items: center;
gap: var(--space-md);
margin-bottom: var(--space-lg);
flex-wrap: wrap;
}
.agent-controls-filters {
display: flex;
align-items: center;
gap: var(--space-sm);
padding: var(--space-xs) var(--space-sm);
background: var(--surface);
border: 1px solid var(--border);
border-radius: var(--radius-md);
box-shadow: var(--shadow-sm);
}
.agent-state-filter {
display: flex;
align-items: center;
gap: var(--space-sm);
padding: var(--space-xs) calc(var(--space-sm) + var(--space-xs));
background: var(--bg);
border: 1px solid var(--border);
border-radius: var(--radius-sm);
color: var(--text-muted);
transition: border-color var(--transition-fast), color var(--transition-fast), background var(--transition-fast);
}
.agent-state-filter:hover {
border-color: var(--text-dim);
color: var(--text);
}
.agent-state-filter:focus-within {
border-color: var(--todo);
box-shadow: var(--focus-ring);
}
.agent-state-filter-select {
appearance: none;
background: transparent;
border: none;
color: var(--text);
font-size: 13px;
font-family: var(--font-primary);
cursor: pointer;
outline: none;
padding-right: 4px;
}
.agent-system-filter {
font-size: 13px;
color: var(--text-muted);
cursor: pointer;
display: flex;
align-items: center;
gap: var(--space-sm);
user-select: none;
padding: var(--space-xs) var(--space-sm);
border-radius: var(--radius-sm);
transition: color var(--transition-fast), background var(--transition-fast);
}
.agent-system-filter:hover {
color: var(--text);
}
.agent-system-filter input[type="checkbox"] {
width: 16px;
height: 16px;
accent-color: var(--todo);
cursor: pointer;
}
.agent-create-form {
display: flex;
gap: var(--space-md);
margin-bottom: var(--space-lg);
padding: var(--space-lg);
background: var(--bg-secondary);
border-radius: var(--radius-sm);
}
/* ── Agent Tree View ────────────────────────────────────────────────────── */
.agent-tree__view {
display: flex;
flex-direction: column;
gap: var(--space-xs);
padding: var(--space-sm) 0;
}
.agent-tree__node {
position: relative;
display: flex;
align-items: center;
gap: var(--space-sm);
padding: var(--space-sm) var(--space-md);
border-radius: var(--radius-sm);
transition: background-color var(--transition-fast);
}
.agent-tree__node:hover {
background: var(--card-hover);
}
.agent-tree__node--active,
.agent-tree__node--running {
background: var(--state-active-bg);
}
.agent-tree__indent--0 { padding-left: 0; }
.agent-tree__indent--1 { padding-left: var(--space-xl); }
.agent-tree__indent--2 { padding-left: calc(var(--space-xl) * 2); }
.agent-tree__indent--3 { padding-left: calc(var(--space-xl) * 3); }
.agent-tree__indent--4 { padding-left: calc(var(--space-xl) * 4); }
.agent-tree__toggle {
display: flex;
align-items: center;
justify-content: center;
width: calc(var(--space-md) * 2);
height: calc(var(--space-md) * 2);
cursor: pointer;
border-radius: var(--radius-sm);
color: var(--text-muted);
transition: background-color var(--transition-fast), color var(--transition-fast);
flex-shrink: 0;
background: none;
border: none;
padding: 0;
}
.agent-tree__toggle:hover {
background: var(--card-hover);
color: var(--text);
}
.agent-tree__toggle--leaf {
color: var(--text-muted);
cursor: default;
}
.agent-tree__toggle--leaf:hover {
background: transparent;
color: var(--text-muted);
}
.agent-tree__content {
display: flex;
align-items: center;
gap: var(--space-sm);
cursor: pointer;
flex: 1;
min-width: 0;
}
.agent-tree__icon {
font-size: 16px;
line-height: 1;
flex-shrink: 0;
}
.agent-tree__name {
font-size: 13px;
font-weight: 500;
white-space: nowrap;
overflow: hidden;
text-overflow: ellipsis;
}
.agent-tree__badge {
font-size: 10px;
font-weight: 600;
text-transform: uppercase;
padding: 2px 6px;
border-radius: var(--radius-sm);
flex-shrink: 0;
}
.agent-tree__health {
flex-shrink: 0;
display: flex;
align-items: center;
}
.agent-tree__count {
font-size: 11px;
flex-shrink: 0;
}
.agent-is-child {
background: color-mix(in srgb, var(--accent) 5%, transparent);
border-left: 2px solid var(--accent);
}
.agent-tree__children {
position: relative;
display: flex;
flex-direction: column;
gap: var(--space-xs);
margin-left: calc(var(--space-md) - var(--space-xs));
padding-left: var(--space-md);
border-left: 1px solid var(--border);
}
.agent-tree__children::before {
content: "";
position: absolute;
left: -1px;
top: 0;
bottom: 50%;
width: 1px;
background: var(--border);
}
.agent-board {
display: grid;
grid-template-columns: repeat(auto-fill, minmax(200px, 1fr));
gap: var(--space-lg);
}
.agent-board-card {
display: flex;
flex-direction: column;
gap: var(--space-sm);
padding: var(--space-lg);
background: var(--surface);
border: 1px solid var(--border);
border-top-width: 3px;
border-radius: var(--radius-md);
transition: background var(--transition-fast), border-color var(--transition-fast);
}
.agent-board-card:hover {
background: var(--card-hover);
border-color: var(--text-muted);
}
.agent-board-card--active:hover,
.agent-board-card--running:hover {
background: color-mix(in srgb, var(--state-active-border) 20%, var(--card-hover));
}
.agent-board-header {
display: flex;
align-items: center;
gap: var(--space-sm);
}
.agent-board-icon {
font-size: 20px;
line-height: 1;
}
.agent-board-badge {
font-size: 10px;
font-weight: 600;
text-transform: uppercase;
padding: 2px 6px;
border-radius: var(--radius-sm);
margin-left: auto;
}
.agent-board-health {
display: flex;
align-items: center;
}
.agent-board-name {
font-weight: 600;
font-size: 14px;
white-space: nowrap;
overflow: hidden;
text-overflow: ellipsis;
}
.agent-board-id {
font-size: 11px;
font-family: var(--font-mono);
color: var(--text-muted);
}
.agent-board-clickable {
cursor: pointer;
}
.agent-board-clickable:hover .agent-board-name {
color: var(--todo);
}
.agent-board-actions {
display: flex;
gap: var(--space-xs);
margin-top: var(--space-xs);
padding-top: var(--space-sm);
border-top: 1px solid var(--border);
}
.agent-board-actions .btn {
flex: 1;
justify-content: center;
}
.agent-list {
display: flex;
flex-direction: column;
gap: var(--space-md);
}
.agent-card {
border: 1px solid var(--border);
border-left-width: 4px;
border-radius: var(--radius-md);
padding: var(--space-lg);
background: var(--surface);
}
.agent-card-header {
display: flex;
justify-content: space-between;
align-items: flex-start;
margin-bottom: var(--space-md);
}
.agent-info {
display: flex;
align-items: center;
gap: var(--space-md);
}
.agent-info--clickable {
flex: 1;
display: flex;
align-items: center;
gap: var(--space-md);
cursor: pointer;
padding: 4px;
margin: -4px;
border-radius: var(--radius-sm);
transition: background var(--transition-fast);
}
.agent-info--clickable:hover {
background: var(--card-hover);
}
.agent-info--clickable:hover .agent-name {
color: var(--todo);
}
.agent-icon {
font-size: 24px;
}
.agent-icon--clickable {
cursor: pointer;
transition: opacity var(--transition-fast), transform var(--transition-fast);
user-select: none;
}
.agent-icon--clickable:hover {
opacity: 0.7;
transform: scale(1.1);
}
.agent-icon--clickable:focus {
outline: 2px solid var(--todo);
outline-offset: 2px;
border-radius: var(--radius-sm);
}
.agent-role-select {
font-size: 14px;
padding: 4px var(--space-sm);
min-width: 120px;
width: auto;
cursor: pointer;
}
.agent-meta {
display: flex;
flex-direction: column;
}
.agent-name {
font-weight: 600;
font-size: 16px;
}
.agent-id {
font-size: 12px;
font-family: var(--font-mono);
}
.agent-badges {
display: flex;
gap: var(--space-sm);
flex-wrap: wrap;
}
.agent-card-chevron {
color: var(--text-muted);
margin-left: auto;
opacity: 0;
transition: opacity var(--transition-fast);
}
.agent-info--clickable:hover .agent-card-chevron {
opacity: 1;
}
.agent-card-body {
display: flex;
flex-direction: column;
gap: 4px;
margin-bottom: var(--space-md);
padding: var(--space-sm);
background: var(--bg-secondary);
border-radius: var(--radius-sm);
font-size: 13px;
}
.agent-task,
.agent-heartbeat {
display: flex;
gap: var(--space-sm);
}
.agent-heartbeat-control {
display: flex;
align-items: center;
gap: var(--space-sm);
flex-wrap: wrap;
}
.agent-heartbeat-select {
width: auto;
min-width: calc(var(--space-2xl) + var(--space-xl));
padding: var(--space-xs) var(--space-md);
font-size: var(--space-md);
}
.agent-heartbeat-last,
.agent-heartbeat-next,
.agent-heartbeat-saving {
font-size: var(--space-md);
line-height: 1;
display: inline-flex;
align-items: center;
}
.agent-card-actions {
display: flex;
gap: var(--space-sm);
align-items: center;
flex-wrap: wrap;
}
.agent-card-details-btn {
margin-left: auto;
}
.agent-empty {
display: flex;
flex-direction: column;
align-items: center;
gap: var(--space-sm);
padding: calc(var(--space-2xl) + var(--space-lg));
color: var(--text-muted);
text-align: center;
}
.agent-empty-state__icon {
color: var(--text-dim);
}
.agent-empty-state__title,
.agent-empty-state__description {
margin: 0;
}
.agent-empty .btn {
margin-top: var(--space-sm);
}
/* Agent state badge variants */
.agent-badge--idle {
background: var(--state-idle-bg);
color: var(--state-idle-text);
border: 1px solid var(--state-idle-border);
}
.agent-badge--active,
.agent-badge--running {
background: var(--state-active-bg);
color: var(--state-active-text);
border: 1px solid var(--state-active-border);
}
.agent-badge--paused {
background: var(--state-paused-bg);
color: var(--state-paused-text);
border: 1px solid var(--state-paused-border);
}
.agent-badge--error,
.agent-badge--terminated {
background: var(--state-error-bg);
color: var(--state-error-text);
border: 1px solid var(--state-error-border);
}
.agent-board-card--idle { border-top-color: var(--state-idle-border); }
.agent-board-card--active,
.agent-board-card--running {
border-top-color: var(--state-active-border);
background: var(--state-active-bg);
}
.agent-board-card--paused { border-top-color: var(--state-paused-border); }
.agent-board-card--error,
.agent-board-card--terminated { border-top-color: var(--state-error-border); }
.agent-card--idle { border-left-color: var(--state-idle-border); }
.agent-card--active,
.agent-card--running {
border-left-color: var(--state-active-border);
background: var(--state-active-bg);
}
.agent-card--active:hover,
.agent-card--running:hover {
background: color-mix(in srgb, var(--state-active-border) 20%, var(--card-hover));
}
.agent-card--paused { border-left-color: var(--state-paused-border); }
.agent-card--error,
.agent-card--terminated { border-left-color: var(--state-error-border); }
.spin {
animation: spin 1s linear infinite;
}
/* === FN-1167: Agent Org Chart + Chain of Command === */
.agent-org-chart {
display: flex;
align-items: flex-start;
justify-content: flex-start;
gap: var(--space-xl);
padding: var(--space-lg);
overflow-x: auto;
overflow-y: visible;
min-height: calc(var(--space-xl) * 9 + var(--space-xs));
}
.agent-org-chart__loading,
.chain-of-command-loading {
display: inline-flex;
align-items: center;
gap: var(--space-sm);
color: var(--text-muted);
}
.org-chart-node {
position: relative;
display: flex;
flex-direction: column;
align-items: center;
min-width: calc(var(--space-xl) * 9 + var(--space-xs));
flex: 0 0 auto;
}
.org-chart-node-card {
width: 100%;
background: var(--surface);
border: 1px solid var(--border);
border-radius: var(--radius-lg);
padding: var(--space-md);
color: var(--text);
cursor: pointer;
transition: border-color var(--transition-fast), background-color var(--transition-fast), transform var(--transition-fast);
position: relative;
}
.org-chart-node-card:hover,
.org-chart-node-card:focus-visible {
border-color: var(--accent);
background: var(--card-hover);
transform: translateY(calc(var(--space-xs) * -0.25));
outline: none;
}
.org-chart-node-card--active,
.org-chart-node-card--running {
background: var(--state-active-bg);
}
.org-chart-node__header {
display: flex;
align-items: center;
gap: var(--space-sm);
margin-bottom: var(--space-sm);
}
.org-chart-node__icon {
font-size: var(--space-lg);
}
.org-chart-node__name {
font-weight: 600;
line-height: 1.2;
}
.org-chart-node__meta {
display: flex;
align-items: center;
justify-content: space-between;
gap: var(--space-sm);
}
.org-chart-node__badge {
display: inline-flex;
align-items: center;
padding: calc(var(--space-xs) * 0.5) var(--space-sm);
border-radius: var(--radius-pill);
font-size: calc(var(--space-sm) + var(--space-xs) * 0.75);
text-transform: capitalize;
}
.org-chart-node__health {
display: inline-flex;
align-items: center;
gap: var(--space-xs);
font-size: var(--space-md);
}
.org-chart-node--has-children > .org-chart-node-card::after {
content: "";
position: absolute;
left: 50%;
transform: translateX(-50%);
bottom: calc(var(--space-lg) * -1);
width: 1px;
height: var(--space-lg);
background: var(--border);
}
.org-chart-children {
position: relative;
display: flex;
align-items: flex-start;
justify-content: center;
gap: var(--space-lg);
padding-top: var(--space-xl);
margin-top: var(--space-xs);
}
.org-chart-children::before {
content: "";
position: absolute;
top: 0;
left: var(--space-xl);
right: var(--space-xl);
height: 1px;
background: var(--border);
}
.org-chart-children > .org-chart-node::before {
content: "";
position: absolute;
top: calc(var(--space-xl) * -1);
left: 50%;
transform: translateX(-50%);
width: 1px;
height: var(--space-xl);
background: var(--border);
}
.chain-of-command-path {
display: flex;
flex-wrap: wrap;
align-items: center;
gap: var(--space-xs) var(--space-sm);
}
.chain-of-command-item {
display: inline-flex;
align-items: center;
gap: var(--space-xs);
}
.chain-of-command-node {
display: inline-flex;
align-items: center;
padding: var(--space-xs) calc(var(--space-sm) + var(--space-xs) * 0.5);
border-radius: var(--radius-pill);
border: 1px solid var(--border);
background: var(--surface);
color: var(--text-muted);
font-size: calc(var(--space-sm) + var(--space-xs));
cursor: pointer;
}
.chain-of-command-node:hover:not(:disabled) {
border-color: var(--accent);
color: var(--text);
}
.chain-of-command-node:disabled {
cursor: default;
opacity: 0.9;
}
.chain-of-command-node--current {
border-color: var(--accent);
color: var(--text);
font-weight: 600;
}
.chain-of-command-separator {
color: var(--text-muted);
}
@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 {
padding: var(--space-sm);
padding-bottom: calc(var(--space-lg) + var(--space-sm));
gap: var(--space-sm);
}
.agents-view-loading {
min-height: calc(var(--space-2xl) * 4);
}
.org-chart-node {
min-width: calc(var(--space-2xl) * 5);
}
.org-chart-node-card {
padding: var(--space-sm);
border-radius: var(--radius-md);
}
.org-chart-node__name {
font-size: var(--space-md);
}
.org-chart-node__badge {
font-size: calc(var(--space-sm) + var(--space-xs) * 0.625);
}
}
/* === AgentsView mobile header (cleaner stacked layout) ==================== */
@media (max-width: 768px) {
/* Single-row header: hide the redundant "Agents" title (the icon + page
context already make it obvious), and pack view-toggle + Controls + New
Agent + Refresh into one no-wrap row. */
.agents-view-header {
flex-direction: row;
align-items: center;
flex-wrap: nowrap;
justify-content: flex-start;
gap: var(--space-xs);
padding: var(--space-sm) var(--space-md);
}
.agents-view-title {
flex: 0 0 auto;
gap: var(--space-xs);
flex-wrap: wrap;
white-space: nowrap;
min-width: 0;
}
.agents-view-title h2 {
font-size: 16px;
white-space: nowrap;
}
/* Layout: title (Bot) on the left, view-toggle right after it, then the
primary-actions group pinned to the far right of the row. The flex
container grows to fill remaining space, and `space-between` separates
the toggle (left side) from primary-actions (right side). */
.agents-view-controls {
flex: 1 1 auto;
display: flex;
flex-wrap: wrap;
align-items: center;
justify-content: space-between;
gap: var(--space-xs);
min-width: 0;
}
/* View toggle (List/Board/Tree/Org) — keep the 32px pill chrome from the
base styles. Inner buttons stay at the base 28×28 (centered in the 2px
pill padding). All surrounding header icons below are sized to match
that 28×28 inner footprint so every icon lines up with the view-toggle
buttons. */
.agents-view-controls .view-toggle {
flex: 0 0 auto;
}
.agents-view-primary-actions {
display: flex;
align-items: center;
gap: var(--space-xs);
flex-wrap: nowrap;
flex: 0 0 auto;
}
/* Controls button: icon-only on mobile, sized to match view-toggle buttons */
.agent-controls-trigger {
padding: 0;
width: 28px;
height: 28px;
min-width: 28px;
font-size: 0;
display: inline-flex;
align-items: center;
justify-content: center;
}
/* New Agent: icon-only on mobile, sized to match view-toggle buttons.
Text is visually hidden via font-size: 0 (the SVG icon keeps its size). */
.agents-view-primary-actions .btn-task-create {
width: 28px;
height: 28px;
min-width: 28px;
padding: 0;
font-size: 0;
gap: 0;
white-space: nowrap;
display: inline-flex;
align-items: center;
justify-content: center;
}
.agents-view-primary-actions .btn-icon {
width: 28px;
height: 28px;
min-width: 28px;
}
/* Title row: keep Bot icon + "Agents" text on a single line so the
view-toggle and primary actions get pushed to the right edge. */
.agents-view-title {
height: 32px;
align-items: center;
}
/* Touch target for agent tree toggle */
.agent-tree__toggle {
min-width: 36px;
min-height: 36px;
}
}