Files
Control-Center/frontend/src/app/command-hub/components/agent-card/agent-card.component.ts

127 lines
4.0 KiB
TypeScript
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.
import {
ChangeDetectionStrategy,
Component,
Input,
computed,
} from '@angular/core';
import { CommonModule } from '@angular/common';
import { RouterModule } from '@angular/router';
import { MatIconModule } from '@angular/material/icon';
import { MatButtonModule } from '@angular/material/button';
import { MatProgressBarModule } from '@angular/material/progress-bar';
import { MatTooltipModule } from '@angular/material/tooltip';
import { AgentStatus } from '../../../models/agent.model';
// ============================================================================
// AgentCard Component
// Per spec Section 7.3: Composes Agent Status Badge, Task Progress Bar,
// and QuickJump Button into a card with leftborder status accent.
// ============================================================================
@Component({
selector: 'app-agent-card',
standalone: true,
imports: [
CommonModule,
RouterModule,
MatIconModule,
MatButtonModule,
MatProgressBarModule,
MatTooltipModule,
],
templateUrl: './agent-card.component.html',
styleUrl: './agent-card.component.scss',
changeDetection: ChangeDetectionStrategy.OnPush,
})
export class AgentCardComponent {
// --- Six required inputs per spec ---
/** Agent status — drives badge color and leftborder accent */
@Input({ required: true }) status!: AgentStatus;
/** Current task description, e.g. "Reviewing PR #42" */
@Input() task = '';
/** Task progress percentage 0100 */
@Input() progress = 0;
/** Full session key for quickjump navigation */
@Input({ required: true }) sessionKey = '';
/** Communication channel, e.g. "telegram" */
@Input({ required: true }) channel = '';
/** Timestamp of last agent activity */
@Input({ required: true }) lastActivity!: Date;
// --- Additional display inputs ---
/** Short agent ID, e.g. "otto" */
@Input() agentId = '';
/** Display name, e.g. "Otto" */
@Input() displayName = '';
/** Role description, e.g. "Orchestrator Agent" */
@Input() role = '';
/** Error message (shown only when status is 'error') */
@Input() errorMessage = '';
// --- Computed values ---
/** Map status → CSS custom property for the leftborder accent */
readonly statusBorderColor = computed(() => {
const map: Record<AgentStatus, string> = {
active: 'var(--status-active)',
idle: 'var(--status-idle)',
thinking: 'var(--status-thinking)',
error: 'var(--status-error)',
offline: 'var(--status-offline)',
};
return map[this.status] ?? 'var(--status-offline)';
});
/** Humanreadable status label */
readonly statusLabel = computed(() => {
const labels: Record<AgentStatus, string> = {
active: 'Active',
idle: 'Idle',
thinking: 'Thinking…',
error: 'Error',
offline: 'Offline',
};
return labels[this.status] ?? this.status;
});
/** CSS class suffix for the status badge dot */
readonly statusDotClass = computed(() => `status-dot--${this.status}`);
/** Material icon name for the channel */
readonly channelIcon = computed(() => {
const icons: Record<string, string> = {
telegram: 'telegram', // falls back to font icon if no SVG registered
slack: 'chat',
discord: 'forum',
whatsapp: 'chat',
webchat: 'language',
email: 'email',
};
return icons[this.channel] ?? 'chat';
});
/** Relative time string for lastActivity */
readonly lastActivityLabel = computed(() => {
if (!this.lastActivity) return '';
const now = Date.now();
const then = this.lastActivity.getTime();
const diffSec = Math.max(0, Math.floor((now - then) / 1000));
if (diffSec < 60) return 'just now';
if (diffSec < 3600) return `${Math.floor(diffSec / 60)}m ago`;
if (diffSec < 86400) return `${Math.floor(diffSec / 3600)}h ago`;
return `${Math.floor(diffSec / 86400)}d ago`;
});
/** Quickjump route derived from sessionKey */
readonly jumpRoute = computed(() => `/sessions/${this.sessionKey}`);
}