98 lines
4.2 KiB
HTML
98 lines
4.2 KiB
HTML
{% extends "base.html" %}
|
|
{% block title %}Dashboard — Willhaben Tracker{% endblock %}
|
|
{% block title_in_topbar %}Dashboard{% endblock %}
|
|
|
|
{% block content %}
|
|
{% if data %}
|
|
<h3 style="margin-top: 0;">Overview</h3>
|
|
<div style="display: grid; grid-template-columns: repeat(auto-fit, minmax(240px, 1fr)); gap: 24px; margin-bottom: 32px;">
|
|
|
|
<div class="card stat-card">
|
|
<div class="stat-label">Total Keywords</div>
|
|
<div class="stat-value">{{ data.total_keywords }}</div>
|
|
<div class="stat-subtext success">
|
|
<i class="ph-fill ph-check-circle"></i> {{ data.active_keywords }} active
|
|
</div>
|
|
</div>
|
|
|
|
<div class="card stat-card">
|
|
<div class="stat-label">Total Ads Tracked</div>
|
|
<div class="stat-value">{{ data.total_ads }}</div>
|
|
<div class="stat-subtext muted">Across all time</div>
|
|
</div>
|
|
|
|
<div class="card stat-card">
|
|
<div class="stat-label">Active Users</div>
|
|
<div class="stat-value">{{ data.total_users }}</div>
|
|
<div class="stat-subtext muted">Subscribed to updates</div>
|
|
</div>
|
|
|
|
<div class="card stat-card">
|
|
<div class="stat-label">Notifications Sent</div>
|
|
<div class="stat-value">{{ data.notifications_sent }}</div>
|
|
<div class="stat-subtext muted">Via Telegram</div>
|
|
</div>
|
|
|
|
</div>
|
|
|
|
<h3>System Health</h3>
|
|
<div style="display: grid; grid-template-columns: repeat(auto-fit, minmax(300px, 1fr)); gap: 24px;">
|
|
|
|
<div class="card stat-card" style="border-left: 4px solid var(--border-hover);">
|
|
<div class="stat-label">Last Scheduler Run</div>
|
|
<div class="stat-value" style="font-size: 24px;">
|
|
{{ data.last_scheduler.strftime('%Y-%m-%d %H:%M:%S') if data.last_scheduler else 'Never' }}
|
|
</div>
|
|
<div class="stat-subtext muted">Worker polling rhythm</div>
|
|
</div>
|
|
|
|
<div class="card stat-card" style="border-left: 4px solid {% if data.proxy_enabled %}var(--success-text){% else %}var(--border-hover){% endif %};">
|
|
<div class="stat-label">HTTP Proxy</div>
|
|
<div class="stat-value" style="font-size: 24px; color: {% if data.proxy_enabled %}var(--success-text){% else %}var(--text-primary){% endif %};">
|
|
{{ 'Enabled' if data.proxy_enabled else 'Disabled' }}
|
|
</div>
|
|
<div class="stat-subtext muted">
|
|
{{ 'Outbound scraping uses proxy' if data.proxy_enabled else 'Direct connection' }}
|
|
</div>
|
|
</div>
|
|
|
|
<div class="card stat-card" style="border-left: 4px solid var(--brand-primary);">
|
|
<div class="stat-label">Network Egress</div>
|
|
<div style="display: grid; gap: 10px; margin-top: 10px;">
|
|
<div>
|
|
<div class="stat-subtext muted">System IP</div>
|
|
<div style="font-size: 18px; font-weight: 600; line-height: 1.4;">
|
|
{{ data.system_country_flag }}
|
|
{{ data.system_public_ip or 'Unknown' }}
|
|
{% if data.system_country_code %}
|
|
<span style="font-size: 12px; color: var(--text-muted);">({{ data.system_country_code }})</span>
|
|
{% endif %}
|
|
</div>
|
|
</div>
|
|
<div>
|
|
<div class="stat-subtext muted">Last Used IP</div>
|
|
<div style="font-size: 18px; font-weight: 600; line-height: 1.4; color: var(--brand-primary);">
|
|
{{ data.last_used_country_flag }}
|
|
{{ data.last_used_public_ip or 'Unknown' }}
|
|
{% if data.last_used_country_code %}
|
|
<span style="font-size: 12px; color: var(--text-muted);">({{ data.last_used_country_code }})</span>
|
|
{% endif %}
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
<div class="card stat-card" style="border-left: 4px solid {% if data.queue_dead > 0 %}var(--danger-text){% else %}var(--success-text){% endif %};">
|
|
<div class="stat-label">Delivery Queue</div>
|
|
<div class="stat-value" style="font-size: 24px;">
|
|
{{ data.queue_pending }} pending
|
|
</div>
|
|
<div class="stat-subtext {% if data.queue_dead > 0 %}danger{% else %}muted{% endif %}">
|
|
{{ data.queue_dead }} dead letters
|
|
</div>
|
|
</div>
|
|
|
|
</div>
|
|
{% endif %}
|
|
{% endblock %}
|