Files
nx9-url-shortener/templates/urls.html
T
thakares d398341f01
Rust CI / Test & Quality Checks (push) Canceled after 0s
Rust CI / Build Docker Image (push) Canceled after 0s
release: finalize BZOD v0.8.0
2026-08-21 16:23:32 +05:30

190 lines
12 KiB
HTML

{% extends "layout.html" %}
{% block title %}Global URL Registry - BZOD Admin{% endblock %}
{% block active_urls %}active{% endblock %}
{% block header_title %}Global URL Registry{% endblock %}
{% block content %}
{% if let Some(err) = error %}
<div class="alert alert-error">
{{ err }}
</div>
{% endif %}
<div class="card registered-links-shell" style="padding: 0; overflow: hidden;">
<div class="registered-links-header">
<h3 style="font-size: 1.1rem; display: flex; align-items: center; gap: 0.5rem;">
<svg width="18" height="18" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"><path d="M12 2L2 7l10 5 10-5-10-5zM2 17l10 5 10-5M2 12l10 5 10-5"/></svg>
Global URL Registry
</h3>
{% if let Some(tag) = tag_filter %}
<span class="badge badge-healthy" style="text-transform: none;">
Filtered by tag: {{ tag }}
<a href="/admin/urls" style="color: inherit; text-decoration: none; margin-left: 0.5rem; font-weight: bold;">&times;</a>
</span>
{% endif %}
</div>
<div class="table-container">
<table class="registered-links-table">
<colgroup>
<col class="col-short" style="width: 22%;">
<col class="col-destination" style="width: 26%;">
<col class="col-owner" style="width: 14%;">
<col class="col-health" style="width: 10%;">
<col class="col-qr" style="width: 8%;">
<col class="col-actions" style="width: 20%;">
</colgroup>
<thead>
<tr>
<th>Short Link</th>
<th>Destination</th>
<th>Owner / Tenant</th>
<th>Status / Health</th>
<th>QR Code</th>
<th>Actions</th>
</tr>
</thead>
<tbody>
{% if urls.is_empty() %}
<tr>
<td colspan="6" style="text-align: center; color: var(--text-secondary); padding: 3rem;">
No shortened URLs registered across tenants.
</td>
</tr>
{% else %}
{% for row in urls %}
<tr>
<td data-label="Short Link">
<div class="short-link-wrap">
<div class="short-link-primary">
<a href="/{{ row.url.code }}" target="_blank" class="short-link-anchor">
{{ base_url.replace("https://", "").replace("http://", "") }}/{{ row.url.code }}
</a>
{% if row.url.is_password_protected() %}
<span title="Password Protected" aria-label="Password protected link" style="color: var(--warning-color); display: inline-flex; align-items: center;">
<svg width="12" height="12" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"><rect x="3" y="11" width="18" height="11" rx="2" ry="2"></rect><path d="M7 11V7a5 5 0 0 1 10 0v4"></path></svg>
</span>
{% endif %}
</div>
{% if let Some(title) = row.url.title.as_deref() %}
{% if !title.is_empty() %}
<div class="short-link-title">{{ title }}</div>
{% endif %}
{% endif %}
<div class="short-link-meta">Created {{ row.url.created_at[0..10] }}</div>
</div>
</td>
<td data-label="Destination">
<div class="destination-block">
<a href="{{ row.url.destination }}" target="_blank" class="destination-link" title="{{ row.url.destination }}" aria-label="Destination URL: {{ row.url.destination }}">
{{ row.url.destination }}
</a>
{% if let Some(desc) = row.url.description.as_deref() %}
{% if !desc.is_empty() %}
<div class="destination-description" title="{{ desc }}">{{ desc }}</div>
{% endif %}
{% endif %}
{% if let Some(expires_at) = row.url.expires_at.as_deref() %}
{% if !expires_at.is_empty() %}
<div class="destination-meta expiry">
<svg width="10" height="10" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"><rect x="3" y="4" width="18" height="18" rx="2" ry="2"></rect><line x1="16" y1="2" x2="16" y2="6"></line><line x1="8" y1="2" x2="8" y2="6"></line><line x1="3" y1="10" x2="21" y2="10"></line></svg>
Expires: {{ expires_at[0..10] }}
{% if row.url.expired %}
<span class="badge badge-dead" style="font-size: 0.6rem; padding: 0.1rem 0.25rem; margin-left: 0.25rem;">Expired</span>
{% endif %}
</div>
{% endif %}
{% endif %}
{% if let Some(max) = row.url.max_access_count %}
<div class="destination-meta access">
<svg width="10" height="10" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"><circle cx="12" cy="12" r="10"></circle><polyline points="12 6 12 12 16 14"></polyline></svg>
Clicks: {{ row.url.access_count }} / {{ max }}
{% if row.url.is_access_exhausted() %}
<span class="badge badge-dead" style="font-size: 0.6rem; padding: 0.1rem 0.25rem; margin-left: 0.25rem;">Limit Reached</span>
{% endif %}
</div>
{% else %}
{% if row.url.access_count > 0 %}
<div class="destination-meta neutral">
Clicks: {{ row.url.access_count }}
</div>
{% endif %}
{% endif %}
</div>
</td>
<td data-label="Owner / Tenant">
<div>
{% if let Some(u) = row.owner_username.as_deref() %}
<strong style="color: var(--text-primary);">{{ u }}</strong>
{% else %}
<span class="text-muted">Unassigned</span>
{% endif %}
<div style="font-family: monospace; font-size: 0.72rem; color: var(--text-muted);">{{ row.owner_tenant_id }}</div>
</div>
</td>
<td data-label="Status / Health" class="status-cell">
<span class="badge badge-{{ row.url.status }}">
{{ row.url.status }}
</span>
</td>
{% let code = row.url.code.as_str() %}
{% include "components/qr_preview.html" %}
<td data-label="Actions" class="actions-cell">
<div class="action-stack" style="display: flex; gap: 0.35rem; flex-wrap: wrap;">
<a href="/admin/moderation" class="btn btn-secondary" style="padding: 0.3rem 0.5rem; font-size: 0.75rem; display: inline-flex; align-items: center; gap: 0.2rem;">
🛡️ Moderate
</a>
<a href="/admin/slugs" class="btn btn-secondary" style="padding: 0.3rem 0.5rem; font-size: 0.75rem; display: inline-flex; align-items: center; gap: 0.2rem;">
🔄 Transfer
</a>
<a href="/admin/analytics/url/{{ row.url.id }}" class="btn btn-secondary" style="padding: 0.3rem 0.5rem; font-size: 0.75rem; display: inline-flex; align-items: center; gap: 0.2rem;">
📊 Analytics
</a>
<form action="/admin/urls/delete/{{ row.url.id }}" method="POST" onsubmit="return confirm('Are you sure you want to retire this link?');" style="display: inline;">
<input type="hidden" name="csrf_token" value="{{ csrf_token }}">
<button type="submit" class="btn btn-danger" style="padding: 0.3rem 0.5rem; font-size: 0.75rem;">
Retire
</button>
</form>
</div>
</td>
</tr>
{% endfor %}
{% endif %}
</tbody>
</table>
</div>
<div class="pagination">
{% if current_page > 1 %}
<a href="/admin/urls?page=1{% if let Some(t) = tag_filter %}&tag={{ t }}{% endif %}" class="btn btn-secondary" style="padding: 0.4rem 0.8rem; font-size: 0.85rem;">&lt;&lt; First</a>
<a href="/admin/urls?page={{ current_page - 1 }}{% if let Some(t) = tag_filter %}&tag={{ t }}{% endif %}" class="btn btn-secondary" style="padding: 0.4rem 0.8rem; font-size: 0.85rem;">&lt; Prev</a>
{% else %}
<span class="btn btn-secondary" style="opacity: 0.5; cursor: not-allowed; padding: 0.4rem 0.8rem; font-size: 0.85rem;">&lt;&lt; First</span>
<span class="btn btn-secondary" style="opacity: 0.5; cursor: not-allowed; padding: 0.4rem 0.8rem; font-size: 0.85rem;">&lt; Prev</span>
{% endif %}
{% for p in visible_pages %}
{% if self.is_current(p) %}
<span class="btn btn-primary" style="padding: 0.4rem 0.8rem; font-size: 0.85rem; font-weight: bold;">[{{ p }}]</span>
{% else %}
<a href="/admin/urls?page={{ p }}{% if let Some(t) = tag_filter %}&tag={{ t }}{% endif %}" class="btn btn-secondary" style="padding: 0.4rem 0.8rem; font-size: 0.85rem;">{{ p }}</a>
{% endif %}
{% endfor %}
{% if current_page < total_pages %}
<a href="/admin/urls?page={{ current_page + 1 }}{% if let Some(t) = tag_filter %}&tag={{ t }}{% endif %}" class="btn btn-secondary" style="padding: 0.4rem 0.8rem; font-size: 0.85rem;">Next &gt;</a>
<a href="/admin/urls?page={{ total_pages }}{% if let Some(t) = tag_filter %}&tag={{ t }}{% endif %}" class="btn btn-secondary" style="padding: 0.4rem 0.8rem; font-size: 0.85rem;">Last &gt;&gt;</a>
{% else %}
<span class="btn btn-secondary" style="opacity: 0.5; cursor: not-allowed; padding: 0.4rem 0.8rem; font-size: 0.85rem;">Next &gt;</span>
<span class="btn btn-secondary" style="opacity: 0.5; cursor: not-allowed; padding: 0.4rem 0.8rem; font-size: 0.85rem;">Last &gt;&gt;</span>
{% endif %}
</div>
</div>
{% endblock %}