Add mass update functionality for feed URLs with preview
All checks were successful
Test and build Docker image / docker (push) Successful in 24s
All checks were successful
Test and build Docker image / docker (push) Successful in 24s
This commit is contained in:
parent
bf94f3f3e4
commit
955b94456d
6 changed files with 952 additions and 26 deletions
73
discord_rss_bot/templates/_webhook_mass_update_preview.html
Normal file
73
discord_rss_bot/templates/_webhook_mass_update_preview.html
Normal file
|
|
@ -0,0 +1,73 @@
|
|||
{% if preview_rows %}
|
||||
<p class="small text-muted mb-1">
|
||||
{{ preview_change_count }} feed URL{{ 's' if preview_change_count != 1 else '' }} ready to update.
|
||||
</p>
|
||||
<div class="small text-muted mb-2 d-flex flex-wrap gap-2">
|
||||
<span class="badge bg-secondary">Total: {{ preview_summary.total }}</span>
|
||||
<span class="badge bg-info text-dark">Matched: {{ preview_summary.matched }}</span>
|
||||
<span class="badge bg-success">Will update: {{ preview_summary.will_update }}</span>
|
||||
<span class="badge bg-warning text-dark">Conflicts: {{ preview_summary.conflicts }}</span>
|
||||
<span class="badge bg-warning">Force overwrite: {{ preview_summary.force_overwrite }}</span>
|
||||
<span class="badge bg-warning text-dark">Force ignore errors: {{ preview_summary.force_ignore_errors }}</span>
|
||||
<span class="badge bg-danger">Resolve errors: {{ preview_summary.resolve_errors }}</span>
|
||||
<span class="badge bg-secondary">No change: {{ preview_summary.no_change }}</span>
|
||||
<span class="badge bg-secondary">No match: {{ preview_summary.no_match }}</span>
|
||||
</div>
|
||||
<form action="/bulk_change_feed_urls" method="post" class="mb-2">
|
||||
<input type="hidden" name="webhook_url" value="{{ webhook_url }}" />
|
||||
<input type="hidden" name="replace_from" value="{{ replace_from }}" />
|
||||
<input type="hidden" name="replace_to" value="{{ replace_to }}" />
|
||||
<input type="hidden"
|
||||
name="resolve_urls"
|
||||
value="{{ 'true' if resolve_urls else 'false' }}" />
|
||||
<input type="hidden"
|
||||
name="force_update"
|
||||
value="{{ 'true' if force_update else 'false' }}" />
|
||||
<button type="submit"
|
||||
class="btn btn-warning w-100"
|
||||
{% if preview_change_count == 0 %}disabled{% endif %}
|
||||
onclick="return confirm('Apply these feed URL updates?');">Apply mass update</button>
|
||||
</form>
|
||||
<div class="table-responsive mt-2">
|
||||
<table class="table table-sm table-dark table-striped align-middle mb-0">
|
||||
<thead>
|
||||
<tr>
|
||||
<th scope="col">Old URL</th>
|
||||
<th scope="col">New URL</th>
|
||||
<th scope="col">Status</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
{% for row in preview_rows %}
|
||||
<tr>
|
||||
<td>
|
||||
<code>{{ row.old_url }}</code>
|
||||
</td>
|
||||
<td>
|
||||
<code>{{ row.resolved_url if resolve_urls else row.candidate_url }}</code>
|
||||
</td>
|
||||
<td>
|
||||
{% if not row.has_match %}
|
||||
<span class="badge bg-secondary">No match</span>
|
||||
{% elif row.will_force_ignore_errors %}
|
||||
<span class="badge bg-warning text-dark">Will force update (ignore resolve error)</span>
|
||||
{% elif row.resolution_error %}
|
||||
<span class="badge bg-danger">{{ row.resolution_error }}</span>
|
||||
{% elif row.will_force_overwrite %}
|
||||
<span class="badge bg-warning">Will force overwrite</span>
|
||||
{% elif row.target_exists %}
|
||||
<span class="badge bg-warning text-dark">Conflict: target URL exists</span>
|
||||
{% elif row.will_change %}
|
||||
<span class="badge bg-success">Will update</span>
|
||||
{% else %}
|
||||
<span class="badge bg-secondary">No change</span>
|
||||
{% endif %}
|
||||
</td>
|
||||
</tr>
|
||||
{% endfor %}
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
{% elif replace_from %}
|
||||
<p class="small text-muted mb-0">No preview rows found for that replacement pattern.</p>
|
||||
{% endif %}
|
||||
|
|
@ -1,13 +1,12 @@
|
|||
<!DOCTYPE html>
|
||||
<html lang="en">
|
||||
|
||||
<head>
|
||||
<meta charset="UTF-8" />
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1" />
|
||||
<meta name="description"
|
||||
content="Stay updated with the latest news and events with our easy-to-use RSS bot. Never miss a message or announcement again with real-time notifications directly to your Discord server." />
|
||||
content="Stay updated with the latest news and events with our easy-to-use RSS bot. Never miss a message or announcement again with real-time notifications directly to your Discord server." />
|
||||
<meta name="keywords"
|
||||
content="discord, rss, bot, notifications, announcements, updates, real-time, server, messages, news, events, feed." />
|
||||
content="discord, rss, bot, notifications, announcements, updates, real-time, server, messages, news, events, feed." />
|
||||
<link href="/static/bootstrap.min.css" rel="stylesheet" />
|
||||
<link href="/static/styles.css" rel="stylesheet" />
|
||||
<link rel="icon" href="/static/favicon.ico" type="image/x-icon" />
|
||||
|
|
@ -18,19 +17,20 @@
|
|||
{% block head %}
|
||||
{% endblock head %}
|
||||
</head>
|
||||
|
||||
<body class="text-white-50">
|
||||
{% include "nav.html" %}
|
||||
<div class="p-2 mb-2">
|
||||
<div class="container-fluid">
|
||||
<div class="d-grid p-2">
|
||||
{% if messages %}
|
||||
<div class="alert alert-warning alert-dismissible fade show" role="alert">
|
||||
<pre>{{ messages }}</pre>
|
||||
<button type="button" class="btn-close" data-bs-dismiss="alert" aria-label="Close"></button>
|
||||
</div>
|
||||
<div class="alert alert-warning alert-dismissible fade show" role="alert">
|
||||
<pre>{{ messages }}</pre>
|
||||
<button type="button"
|
||||
class="btn-close"
|
||||
data-bs-dismiss="alert"
|
||||
aria-label="Close"></button>
|
||||
</div>
|
||||
{% endif %}
|
||||
|
||||
{% block content %}
|
||||
{% endblock content %}
|
||||
<footer class="d-flex flex-wrap justify-content-between align-items-center py-3 my-4 border-top">
|
||||
|
|
@ -41,18 +41,20 @@
|
|||
<ul class="nav col-md-4 justify-content-end">
|
||||
<li class="nav-item">
|
||||
<a href="https://github.com/TheLovinator1/discord-rss-bot/issues"
|
||||
class="nav-link px-2 text-muted">Report an issue</a>
|
||||
class="nav-link px-2 text-muted">Report an issue</a>
|
||||
</li>
|
||||
<li class="nav-item">
|
||||
<a href="https://github.com/TheLovinator1/discord-rss-bot/issues"
|
||||
class="nav-link px-2 text-muted">Send feedback</a>
|
||||
class="nav-link px-2 text-muted">Send feedback</a>
|
||||
</li>
|
||||
</ul>
|
||||
</footer>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<script src="https://cdn.jsdelivr.net/npm/htmx.org@2.0.8/dist/htmx.min.js"
|
||||
integrity="sha384-/TgkGk7p307TH7EXJDuUlgG3Ce1UVolAOFopFekQkkXihi5u/6OCvVKyz1W+idaz"
|
||||
crossorigin="anonymous"></script>
|
||||
<script src="/static/bootstrap.min.js" defer></script>
|
||||
</body>
|
||||
|
||||
</html>
|
||||
|
|
|
|||
|
|
@ -32,11 +32,10 @@
|
|||
{% for hook_from_context in webhooks %}
|
||||
<div class="p-2 mb-3 border border-dark">
|
||||
<div class="d-flex justify-content-between align-items-center mb-3">
|
||||
<h2 class="h5 mb-0">
|
||||
<a class="text-muted"
|
||||
href="/webhook_entries?webhook_url={{ hook_from_context.url|encode_url }}">{{ hook_from_context.name }}</a>
|
||||
</h2>
|
||||
<a class="text-muted"
|
||||
<h2 class="h5 mb-0">{{ hook_from_context.name }}</h2>
|
||||
<a class="text-muted fs-6 btn btn-outline-light btn-sm ms-auto me-2"
|
||||
href="/webhook_entries?webhook_url={{ hook_from_context.url|encode_url }}">Settings</a>
|
||||
<a class="text-muted fs-6 btn btn-outline-light btn-sm"
|
||||
href="/webhook_entries?webhook_url={{ hook_from_context.url|encode_url }}">View Latest Entries</a>
|
||||
</div>
|
||||
<!-- Group feeds by domain within each webhook -->
|
||||
|
|
|
|||
|
|
@ -3,6 +3,7 @@
|
|||
| {{ webhook_name }}
|
||||
{% endblock title %}
|
||||
{% block content %}
|
||||
{% if message %}<div class="alert alert-info" role="alert">{{ message }}</div>{% endif %}
|
||||
<div class="card mb-3 border border-dark p-3 text-light">
|
||||
<div class="d-flex flex-column flex-md-row justify-content-between gap-3">
|
||||
<div>
|
||||
|
|
@ -61,6 +62,57 @@
|
|||
Delete Webhook
|
||||
</button>
|
||||
</form>
|
||||
<hr class="border-secondary my-3" />
|
||||
<h3 class="h6">Mass update feed URLs</h3>
|
||||
<p class="text-muted small mb-2">Replace part of feed URLs for all feeds attached to this webhook.</p>
|
||||
<form action="/webhook_entries"
|
||||
method="get"
|
||||
class="row g-2 mb-2"
|
||||
hx-get="/webhook_entries_mass_update_preview"
|
||||
hx-target="#mass-update-preview"
|
||||
hx-swap="innerHTML">
|
||||
<input type="hidden" name="webhook_url" value="{{ webhook_url|encode_url }}" />
|
||||
<div class="col-12">
|
||||
<label for="replace_from" class="form-label small">Replace this</label>
|
||||
<input type="text"
|
||||
name="replace_from"
|
||||
id="replace_from"
|
||||
class="form-control border text-muted bg-dark"
|
||||
value="{{ replace_from }}"
|
||||
placeholder="https://old-domain.example" />
|
||||
</div>
|
||||
<div class="col-12">
|
||||
<label for="replace_to" class="form-label small">With this</label>
|
||||
<input type="text"
|
||||
name="replace_to"
|
||||
id="replace_to"
|
||||
class="form-control border text-muted bg-dark"
|
||||
value="{{ replace_to }}"
|
||||
placeholder="https://new-domain.example" />
|
||||
</div>
|
||||
<div class="col-12 form-check ms-1">
|
||||
<input class="form-check-input"
|
||||
type="checkbox"
|
||||
value="true"
|
||||
id="resolve_urls"
|
||||
name="resolve_urls"
|
||||
{% if resolve_urls %}checked{% endif %} />
|
||||
<label class="form-check-label small" for="resolve_urls">Resolve final URL with redirects (uses httpx)</label>
|
||||
</div>
|
||||
<div class="col-12 form-check ms-1">
|
||||
<input class="form-check-input"
|
||||
type="checkbox"
|
||||
value="true"
|
||||
id="force_update"
|
||||
name="force_update"
|
||||
{% if force_update %}checked{% endif %} />
|
||||
<label class="form-check-label small" for="force_update">Force update (overwrite conflicting target feed URLs)</label>
|
||||
</div>
|
||||
<div class="col-12">
|
||||
<button type="submit" class="btn btn-outline-warning w-100">Preview changes</button>
|
||||
</div>
|
||||
</form>
|
||||
<div id="mass-update-preview">{% include "_webhook_mass_update_preview.html" %}</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="col-lg-7">
|
||||
|
|
@ -77,6 +129,7 @@
|
|||
{{ feed.url }}
|
||||
{% endif %}
|
||||
</a>
|
||||
{% if feed.title %}<span class="text-muted">- {{ feed.url }}</span>{% endif %}
|
||||
{% if not feed.updates_enabled %}<span class="text-warning">Disabled</span>{% endif %}
|
||||
{% if feed.last_exception %}<span class="text-danger">({{ feed.last_exception.value_str }})</span>{% endif %}
|
||||
</li>
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue