Spaces:
Running
Running
| <template> | |
| <div | |
| class="saap-agent-card" | |
| :class="[ | |
| `status-${agent.status}`, | |
| { 'loading': loading, 'interactive': !loading } | |
| ]" | |
| > | |
| <!-- Agent Header --> | |
| <div class="agent-header"> | |
| <div class="agent-avatar" :style="{ backgroundColor: agent.color || '#6B7280' }"> | |
| <span class="avatar-text">{{ agent.name.charAt(0).toUpperCase() }}</span> | |
| </div> | |
| <div class="agent-info"> | |
| <h3 class="agent-name">{{ agent.name }}</h3> | |
| <p class="agent-type">{{ agent.type }}</p> | |
| </div> | |
| <div class="status-indicator"> | |
| <div class="status-dot" :class="`status-${agent.status}`"></div> | |
| <span class="status-text">{{ formatStatus(agent.status) }}</span> | |
| </div> | |
| </div> | |
| <!-- Agent Description --> | |
| <div class="agent-description"> | |
| <p class="description-text">{{ agent.description || 'No description available' }}</p> | |
| </div> | |
| <!-- Agent Metrics --> | |
| <div v-if="agent.metrics" class="agent-metrics"> | |
| <div class="metric"> | |
| <span class="metric-label">Messages</span> | |
| <span class="metric-value">{{ agent.metrics.messages_processed || 0 }}</span> | |
| </div> | |
| <div class="metric"> | |
| <span class="metric-label">Avg. Response</span> | |
| <span class="metric-value"> | |
| {{ agent.metrics.average_response_time ? `${agent.metrics.average_response_time.toFixed(1)}s` : 'N/A' }} | |
| </span> | |
| </div> | |
| </div> | |
| <!-- Agent Actions --> | |
| <div class="agent-actions"> | |
| <button | |
| v-if="agent.status === 'inactive'" | |
| @click="handleStartAgent" | |
| :disabled="loading" | |
| class="action-button start-button" | |
| > | |
| <PlayIcon class="action-icon" /> | |
| <span>Start</span> | |
| </button> | |
| <button | |
| v-if="agent.status === 'active'" | |
| @click="handleStopAgent" | |
| :disabled="loading" | |
| class="action-button stop-button" | |
| > | |
| <StopIcon class="action-icon" /> | |
| <span>Stop</span> | |
| </button> | |
| <button | |
| v-if="agent.status === 'starting'" | |
| disabled | |
| class="action-button starting-button" | |
| > | |
| <div class="saap-loading-spinner-sm"></div> | |
| <span>Starting...</span> | |
| </button> | |
| <button | |
| @click="handleChatAgent" | |
| :disabled="loading || agent.status !== 'active'" | |
| class="action-button chat-button" | |
| > | |
| <ChatBubbleLeftIcon class="action-icon" /> | |
| <span>Chat</span> | |
| </button> | |
| <button | |
| @click="handleAgentClick" | |
| :disabled="loading" | |
| class="action-button details-button" | |
| > | |
| <InformationCircleIcon class="action-icon" /> | |
| <span>Details</span> | |
| </button> | |
| </div> | |
| <!-- Loading Overlay --> | |
| <div v-if="loading" class="loading-overlay"> | |
| <div class="saap-loading-spinner"></div> | |
| </div> | |
| </div> | |
| </template> | |
| <script setup> | |
| import { computed } from 'vue' | |
| import { | |
| PlayIcon, | |
| StopIcon, | |
| ChatBubbleLeftIcon, | |
| InformationCircleIcon | |
| } from '@heroicons/vue/24/outline' | |
| const props = defineProps({ | |
| agent: { | |
| type: Object, | |
| required: true | |
| }, | |
| loading: { | |
| type: Boolean, | |
| default: false | |
| } | |
| }) | |
| const emit = defineEmits([ | |
| 'agent-click', | |
| 'start-agent', | |
| 'stop-agent', | |
| 'chat-agent' | |
| ]) | |
| const formatStatus = (status) => { | |
| const statusMap = { | |
| 'active': 'Active', | |
| 'inactive': 'Inactive', | |
| 'starting': 'Starting', | |
| 'error': 'Error' | |
| } | |
| return statusMap[status] || status | |
| } | |
| const handleAgentClick = () => { | |
| emit('agent-click', props.agent) | |
| } | |
| const handleStartAgent = () => { | |
| emit('start-agent', props.agent.id) | |
| } | |
| const handleStopAgent = () => { | |
| emit('stop-agent', props.agent.id) | |
| } | |
| const handleChatAgent = () => { | |
| emit('chat-agent', props.agent.id) | |
| } | |
| </script> | |
| <style scoped> | |
| .saap-agent-card { | |
| @apply bg-white rounded-xl border border-saap-gray-200; | |
| @apply p-4 relative overflow-hidden; | |
| @apply transition-all duration-200; | |
| @apply max-w-sm mx-auto; | |
| @apply flex flex-col; | |
| height: 380px; | |
| } | |
| .saap-agent-card.interactive:hover { | |
| @apply shadow-md border-saap-primary-300; | |
| transform: translateY(-2px); | |
| } | |
| .saap-agent-card.loading { | |
| @apply opacity-75; | |
| } | |
| /* Agent Header */ | |
| .agent-header { | |
| @apply flex items-start space-x-3 mb-4; | |
| flex-shrink: 0; | |
| } | |
| .agent-avatar { | |
| @apply w-12 h-12 rounded-lg flex items-center justify-center; | |
| @apply flex-shrink-0; | |
| } | |
| .avatar-text { | |
| @apply text-white font-semibold text-lg; | |
| } | |
| .agent-info { | |
| @apply flex-1 min-w-0; | |
| } | |
| .agent-name { | |
| @apply text-lg font-semibold text-saap-gray-900 truncate; | |
| } | |
| .agent-type { | |
| @apply text-sm text-saap-gray-600 capitalize; | |
| } | |
| .status-indicator { | |
| @apply flex items-center space-x-1 flex-shrink-0; | |
| } | |
| .status-dot { | |
| @apply w-2 h-2 rounded-full; | |
| } | |
| .status-dot.status-active { | |
| @apply bg-saap-secondary-500; | |
| } | |
| .status-dot.status-inactive { | |
| @apply bg-saap-gray-400; | |
| } | |
| .status-dot.status-starting { | |
| @apply bg-saap-accent-500; | |
| } | |
| .status-dot.status-error { | |
| @apply bg-red-500; | |
| } | |
| .status-text { | |
| @apply text-xs font-medium text-saap-gray-600; | |
| } | |
| /* Agent Description */ | |
| .agent-description { | |
| @apply mb-4; | |
| flex-shrink: 0; | |
| } | |
| .description-text { | |
| @apply text-sm text-saap-gray-600 leading-relaxed; | |
| display: -webkit-box; | |
| -webkit-line-clamp: 2; | |
| -webkit-box-orient: vertical; | |
| overflow: hidden; | |
| min-height: 2.5rem; | |
| } | |
| /* Agent Metrics */ | |
| .agent-metrics { | |
| @apply flex items-center justify-between; | |
| @apply p-3 bg-saap-gray-50 rounded-lg mb-4; | |
| flex: 1 1 auto; | |
| align-content: center; | |
| } | |
| .metric { | |
| @apply flex flex-col items-center text-center; | |
| } | |
| .metric-label { | |
| @apply text-xs text-saap-gray-500 font-medium; | |
| } | |
| .metric-value { | |
| @apply text-sm font-semibold text-saap-gray-900; | |
| } | |
| /* Agent Actions */ | |
| .agent-actions { | |
| @apply flex flex-wrap gap-2; | |
| flex-shrink: 0; | |
| margin-top: auto; | |
| } | |
| .action-button { | |
| @apply inline-flex items-center space-x-1.5 px-3 py-2; | |
| @apply text-xs font-medium rounded-lg; | |
| @apply transition-all duration-200; | |
| @apply focus:outline-none focus:ring-2 focus:ring-offset-2; | |
| @apply disabled:opacity-50 disabled:cursor-not-allowed; | |
| } | |
| .action-icon { | |
| @apply w-4 h-4 flex-shrink-0; | |
| } | |
| .start-button { | |
| @apply bg-saap-secondary-50 text-saap-secondary-600 border border-saap-secondary-200; | |
| @apply hover:bg-saap-secondary-100 hover:border-saap-secondary-300 focus:ring-saap-secondary-500; | |
| } | |
| .start-button .action-icon { | |
| @apply text-saap-secondary-600; | |
| } | |
| .stop-button { | |
| @apply bg-red-50 text-red-600 border border-red-200; | |
| @apply hover:bg-red-100 hover:border-red-300 focus:ring-red-500; | |
| } | |
| .stop-button .action-icon { | |
| @apply text-red-600; | |
| } | |
| .starting-button { | |
| @apply bg-saap-accent-50 text-saap-accent-600 border border-saap-accent-200; | |
| } | |
| .chat-button { | |
| @apply bg-saap-primary-50 text-saap-primary-600 border border-saap-primary-200; | |
| @apply hover:bg-saap-primary-100 hover:border-saap-primary-300 focus:ring-saap-primary-500; | |
| } | |
| .chat-button .action-icon { | |
| @apply text-saap-primary-600; | |
| } | |
| .details-button { | |
| @apply bg-saap-gray-50 text-saap-gray-600 border border-saap-gray-200; | |
| @apply hover:bg-saap-gray-100 hover:border-saap-gray-300 focus:ring-saap-gray-500; | |
| } | |
| .details-button .action-icon { | |
| @apply text-saap-gray-600; | |
| } | |
| /* Loading Overlay */ | |
| .loading-overlay { | |
| @apply absolute inset-0 bg-white bg-opacity-75; | |
| @apply flex items-center justify-center z-10; | |
| } | |
| /* Status-based card styling */ | |
| .saap-agent-card.status-active { | |
| @apply border-saap-secondary-200; | |
| } | |
| .saap-agent-card.status-error { | |
| @apply border-red-200; | |
| } | |
| /* Responsive Design */ | |
| @media (max-width: 640px) { | |
| .saap-agent-card { | |
| @apply max-w-none; | |
| } | |
| .agent-header { | |
| @apply flex-col space-x-0 space-y-3 text-center; | |
| } | |
| .agent-avatar { | |
| @apply mx-auto; | |
| } | |
| .status-indicator { | |
| @apply justify-center; | |
| } | |
| .agent-metrics { | |
| @apply flex-col space-y-2; | |
| } | |
| .metric { | |
| @apply flex-row items-center justify-between w-full; | |
| } | |
| .agent-actions { | |
| @apply grid grid-cols-2 gap-2; | |
| } | |
| .action-button { | |
| @apply justify-center w-full; | |
| } | |
| } | |
| @media (max-width: 480px) { | |
| .agent-actions { | |
| @apply grid-cols-1; | |
| } | |
| } | |
| /* Line clamp utility */ | |
| .line-clamp-2 { | |
| display: -webkit-box; | |
| -webkit-line-clamp: 2; | |
| -webkit-box-orient: vertical; | |
| overflow: hidden; | |
| } | |
| </style> | |