agent_tracker/templates/profile.html
2025-08-17 07:23:53 -05:00

345 lines
No EOL
10 KiB
HTML

{% extends "base.html" %}
{% block title %}My Profile - AgentHub{% endblock %}
{% block content %}
<div class="container my-5">
<div class="row">
<div class="col-12">
<div class="d-flex justify-content-between align-items-center mb-4">
<div>
<h2><i class="fas fa-user me-3"></i>My Profile</h2>
<p class="text-muted mb-0">Manage your account information and activity</p>
</div>
</div>
</div>
</div>
<!-- Profile Information -->
<div class="row mb-4">
<div class="col-12">
<div class="card shadow-sm border-0">
<div class="card-header bg-white">
<h5 class="mb-0"><i class="fas fa-user-circle me-2"></i>Profile Information</h5>
</div>
<div class="card-body">
<div class="row">
<div class="col-md-2 text-center mb-3">
<div class="profile-avatar">
{{ current_user.full_name[0] if current_user.full_name else current_user.email[0] }}
</div>
</div>
<div class="col-md-10">
<div class="row">
<div class="col-md-6">
<div class="info-item">
<span class="info-label">Full Name</span>
<span class="info-value">{{ current_user.full_name or 'Not set' }}</span>
</div>
</div>
<div class="col-md-6">
<div class="info-item">
<span class="info-label">Email Address</span>
<span class="info-value">{{ current_user.email }}</span>
</div>
</div>
<div class="col-md-6">
<div class="info-item">
<span class="info-label">Account Type</span>
<span class="info-value">
{% if current_user.is_admin %}
<span class="badge bg-danger">Administrator</span>
{% else %}
<span class="badge bg-primary">User</span>
{% endif %}
</span>
</div>
</div>
<div class="col-md-6">
<div class="info-item">
<span class="info-label">Member Since</span>
<span class="info-value">{{ current_user.created_at.strftime('%B %Y') if current_user.created_at else 'Unknown' }}</span>
</div>
</div>
</div>
</div>
</div>
</div>
</div>
</div>
</div>
<!-- Account Overview -->
<div class="row mb-4">
<div class="col-12">
<div class="card shadow-sm border-0">
<div class="card-header bg-white">
<h5 class="mb-0"><i class="fas fa-chart-bar me-2"></i>Account Overview</h5>
</div>
<div class="card-body">
<div class="row">
<div class="col-md-3 text-center">
<div class="stat-card">
<div class="stat-number" id="totalAgents">-</div>
<div class="stat-label">Total Agents</div>
</div>
</div>
<div class="col-md-3 text-center">
<div class="stat-card">
<div class="stat-number" id="activeAgents">-</div>
<div class="stat-label">Active Agents</div>
</div>
</div>
<div class="col-md-3 text-center">
<div class="stat-card">
<div class="stat-number" id="developmentAgents">-</div>
<div class="stat-label">In Development</div>
</div>
</div>
<div class="col-md-3 text-center">
<div class="stat-card">
<div class="stat-number" id="lastLoginDate">-</div>
<div class="stat-label">Last Activity</div>
</div>
</div>
</div>
</div>
</div>
</div>
</div>
<!-- Recent Activity -->
<div class="row">
<div class="col-12">
<div class="card shadow-sm border-0">
<div class="card-header bg-white">
<div class="d-flex justify-content-between align-items-center">
<h5 class="mb-0"><i class="fas fa-clock me-2"></i>Recent Activity</h5>
<a href="{{ base_path }}/agent-management?view=my" class="btn btn-outline-primary btn-sm">
<i class="fas fa-robot me-1"></i>View All My Agents
</a>
</div>
</div>
<div class="card-body">
<div id="recentActivity">
<div class="text-center py-3">
<div class="spinner-border text-primary" role="status">
<span class="visually-hidden">Loading...</span>
</div>
</div>
</div>
</div>
</div>
</div>
</div>
</div>
<style>
.profile-avatar {
width: 80px;
height: 80px;
border-radius: 50%;
background: linear-gradient(135deg, var(--primary-color), var(--secondary-color));
display: flex;
align-items: center;
justify-content: center;
color: white;
font-size: 2rem;
font-weight: bold;
margin: 0 auto;
margin-bottom: 1rem;
}
.info-item {
padding: 0.75rem 0;
}
.info-label {
display: block;
font-weight: 500;
color: var(--text-light);
font-size: 0.9rem;
margin-bottom: 0.25rem;
}
.info-value {
display: block;
color: var(--text-dark);
font-weight: 600;
}
.stat-card {
padding: 1rem;
border-radius: 12px;
background: rgba(102, 126, 234, 0.05);
margin-bottom: 1rem;
}
.stat-number {
font-size: 2rem;
font-weight: bold;
color: var(--primary-color);
margin-bottom: 0.25rem;
}
.stat-label {
font-size: 0.9rem;
color: var(--text-light);
font-weight: 500;
}
.recent-activity-item {
padding: 0.75rem 0;
border-bottom: 1px solid var(--border-color);
}
.recent-activity-item:last-child {
border-bottom: none;
}
.activity-icon {
width: 32px;
height: 32px;
border-radius: 8px;
display: flex;
align-items: center;
justify-content: center;
font-size: 0.875rem;
color: white;
}
.activity-created { background-color: #28a745; }
.activity-updated { background-color: #ffc107; }
.activity-deleted { background-color: #dc3545; }
@media (max-width: 768px) {
.info-item {
padding: 0.5rem 0;
text-align: center;
}
.stat-card {
margin-bottom: 0.5rem;
}
}
</style>
<script>
let userAgents = [];
document.addEventListener('DOMContentLoaded', function() {
loadUserStats();
loadRecentActivity();
});
async function loadUserStats() {
try {
const response = await fetch('{{ base_path }}/api/agents', {
credentials: 'include'
});
if (response.ok) {
userAgents = await response.json();
updateStats();
} else if (response.status === 401) {
window.location.href = '{{ base_path }}/login';
} else {
throw new Error('Failed to load agent statistics');
}
} catch (error) {
console.error('Error loading stats:', error);
document.getElementById('totalAgents').textContent = 'Error';
}
}
function updateStats() {
const totalAgents = userAgents.length;
const activeAgents = userAgents.filter(a => a.agent_status === 'Active').length;
const developmentAgents = userAgents.filter(a => a.agent_status === 'Development').length;
document.getElementById('totalAgents').textContent = totalAgents;
document.getElementById('activeAgents').textContent = activeAgents;
document.getElementById('developmentAgents').textContent = developmentAgents;
document.getElementById('lastLoginDate').textContent = 'Today';
}
function loadRecentActivity() {
if (userAgents.length === 0) {
setTimeout(loadRecentActivity, 500);
return;
}
// Sort agents by last updated date
const recentAgents = [...userAgents]
.sort((a, b) => new Date(b.agent_updated_at || b.agent_created_at) - new Date(a.agent_updated_at || a.agent_created_at))
.slice(0, 5);
if (recentAgents.length === 0) {
document.getElementById('recentActivity').innerHTML = `
<div class="text-center py-4">
<div class="mb-3">
<i class="fas fa-robot fa-2x text-muted"></i>
</div>
<h6>No Agent Activity Yet</h6>
<p class="text-muted mb-3">Create your first agent to see activity here</p>
<a href="{{ base_path }}/agent-register" class="btn btn-success">
<i class="fas fa-plus me-2"></i>Create Your First Agent
</a>
</div>
`;
return;
}
const activityHtml = recentAgents.map(agent => {
const isNew = !agent.agent_updated_at || agent.agent_updated_at === agent.agent_created_at;
const activityType = isNew ? 'created' : 'updated';
const activityDate = new Date(agent.agent_updated_at || agent.agent_created_at);
return `
<div class="recent-activity-item">
<div class="d-flex align-items-center">
<div class="activity-icon activity-${activityType} me-3">
<i class="fas ${isNew ? 'fa-plus' : 'fa-edit'}"></i>
</div>
<div class="flex-grow-1">
<div class="d-flex justify-content-between align-items-start">
<div>
<h6 class="mb-1">${agent.agent_name}</h6>
<small class="text-muted">Agent ${activityType}${formatRelativeDate(activityDate)}</small>
</div>
<span class="badge bg-${getStatusColor(agent.agent_status)}">${agent.agent_status || 'Development'}</span>
</div>
</div>
</div>
</div>
`;
}).join('');
document.getElementById('recentActivity').innerHTML = activityHtml;
}
function formatRelativeDate(date) {
const now = new Date();
const diffMs = now - date;
const diffMins = Math.floor(diffMs / (1000 * 60));
const diffHours = Math.floor(diffMs / (1000 * 60 * 60));
const diffDays = Math.floor(diffMs / (1000 * 60 * 60 * 24));
if (diffMins < 1) return 'Just now';
if (diffMins < 60) return `${diffMins} minutes ago`;
if (diffHours < 24) return `${diffHours} hours ago`;
if (diffDays < 7) return `${diffDays} days ago`;
return date.toLocaleDateString();
}
function getStatusColor(status) {
const colors = {
'Active': 'success',
'Development': 'warning',
'Inactive': 'secondary',
'Deprecated': 'danger'
};
return colors[status] || 'secondary';
}
</script>
{% endblock %}