more UI tweaks

This commit is contained in:
dgtlmoon
2026-06-01 18:16:36 +02:00
parent e5151f2777
commit cddf261e47
7 changed files with 83 additions and 40 deletions
@@ -46,6 +46,7 @@ def construct_blueprint(datastore: ChangeDetectionStore, update_q, queuedWatchMe
sorted_watches = []
with_errors = request.args.get('with_errors') == "1"
unread_only = request.args.get('unread') == "1"
active_processor = request.args.get('processor', '').strip()
errored_count = 0
search_q = request.args.get('q').strip().lower() if request.args.get('q') else False
for uuid, watch in datastore.data['watching'].items():
@@ -57,6 +58,9 @@ def construct_blueprint(datastore: ChangeDetectionStore, update_q, queuedWatchMe
if active_tag_uuid and not active_tag_uuid in watch['tags']:
continue
if active_processor and watch.get('processor') != active_processor:
continue
if watch.get('last_error'):
errored_count += 1
@@ -91,6 +95,7 @@ def construct_blueprint(datastore: ChangeDetectionStore, update_q, queuedWatchMe
"watch-overview.html",
active_tag=active_tag,
active_tag_uuid=active_tag_uuid,
active_processor=active_processor,
app_rss_token=datastore.data['settings']['application'].get('rss_access_token'),
datastore=datastore,
errored_count=errored_count,
@@ -173,6 +173,30 @@ window.watchOverviewI18n = {
{%- endif -%}
{%- endfor -%}
</div>
<ul id="list-related-buttons">
<li id="post-list-with-errors" style="display: none;" >
<a href="{{url_for('watchlist.index', with_errors=1, tag=request.args.get('tag')) }}" class="pure-button button-tag button-error">{{ _('With errors') }} ({{ errored_count }})</a>
</li>
<li id="post-list-mark-views" style="display: none;" >
<a href="{{url_for('ui.mark_all_viewed',with_errors=request.args.get('with_errors',0)) }}" class="pure-button button-tag " id="mark-all-viewed">{{ _('Mark all viewed') }}</a>
</li>
{%- if active_tag_uuid -%}
<li id="post-list-mark-views-tag">
<a href="{{url_for('ui.mark_all_viewed', tag=active_tag_uuid) }}" class="pure-button button-tag " id="mark-all-viewed">{{ _("Mark all viewed in '%(title)s'", title=active_tag.title) }}</a>
</li>
{%- endif -%}
<li id="post-list-unread" style="display: none;" >
<a href="{{url_for('watchlist.index', unread=1, tag=request.args.get('tag')) }}" class="pure-button button-tag">{{ _('Unread') }} (<span id="unread-tab-counter">{{ unread_changes_count }}</span>)</a>
</li>
<li>
<a href="{{ url_for('ui.form_watch_checknow', tag=active_tag_uuid, with_errors=request.args.get('with_errors',0)) }}" class="pure-button button-tag" id="recheck-all">{{ _('Recheck all') }} {% if active_tag_uuid %} {{ _("in '%(title)s'", title=active_tag.title) }}{%endif%}</a>
</li>
<li>
<a href="{{ url_for('rss.feed', tag=active_tag_uuid, token=app_rss_token)}}"><img alt="RSS Feed" id="feed-icon" src="{{url_for('static_content', group='images', filename='generic_feed-icon.svg')}}" height="15"></a>
</li>
</ul>
{%- set table_classes = [
'favicon-enabled' if 'favicons_enabled' not in ui_settings or ui_settings['favicons_enabled'] else 'favicon-not-enabled',
] -%}
@@ -259,7 +283,7 @@ window.watchOverviewI18n = {
{% endif %}
<div class="watch-text-info">
{%- if watch['processor'] and watch['processor'] in processor_badge_texts -%}
<span class="processor-badge processor-badge-{{ watch['processor'] }}" title="{{ processor_descriptions.get(watch['processor'], watch['processor']) }}">{{ processor_badge_texts[watch['processor']] }}</span>
<a href="{{ url_for('watchlist.index', tag=active_tag_uuid, processor=watch['processor']) }}" class="processor-badge processor-badge-{{ watch['processor'] }}{{ ' active' if active_processor == watch['processor'] else '' }}" title="{{ processor_descriptions.get(watch['processor'], watch['processor']) }}">{{ processor_badge_texts[watch['processor']] }}</a>
{%- endif -%}
<span class="watch-title">
{% if system_use_url_watchlist or watch.get('use_page_title_in_list') %}
@@ -358,28 +382,6 @@ window.watchOverviewI18n = {
{%- endfor -%}
</tbody>
</table>
<ul id="post-list-buttons">
<li id="post-list-with-errors" style="display: none;" >
<a href="{{url_for('watchlist.index', with_errors=1, tag=request.args.get('tag')) }}" class="pure-button button-tag button-error">{{ _('With errors') }} ({{ errored_count }})</a>
</li>
<li id="post-list-mark-views" style="display: none;" >
<a href="{{url_for('ui.mark_all_viewed',with_errors=request.args.get('with_errors',0)) }}" class="pure-button button-tag " id="mark-all-viewed">{{ _('Mark all viewed') }}</a>
</li>
{%- if active_tag_uuid -%}
<li id="post-list-mark-views-tag">
<a href="{{url_for('ui.mark_all_viewed', tag=active_tag_uuid) }}" class="pure-button button-tag " id="mark-all-viewed">{{ _("Mark all viewed in '%(title)s'", title=active_tag.title) }}</a>
</li>
{%- endif -%}
<li id="post-list-unread" style="display: none;" >
<a href="{{url_for('watchlist.index', unread=1, tag=request.args.get('tag')) }}" class="pure-button button-tag">{{ _('Unread') }} (<span id="unread-tab-counter">{{ unread_changes_count }}</span>)</a>
</li>
<li>
<a href="{{ url_for('ui.form_watch_checknow', tag=active_tag_uuid, with_errors=request.args.get('with_errors',0)) }}" class="pure-button button-tag" id="recheck-all">{{ _('Recheck all') }} {% if active_tag_uuid %} {{ _("in '%(title)s'", title=active_tag.title) }}{%endif%}</a>
</li>
<li>
<a href="{{ url_for('rss.feed', tag=active_tag_uuid, token=app_rss_token)}}"><img alt="RSS Feed" id="feed-icon" src="{{url_for('static_content', group='images', filename='generic_feed-icon.svg')}}" height="15"></a>
</li>
</ul>
{{ pagination.links }}
</div>
</form>
+4 -2
View File
@@ -407,8 +407,10 @@ def get_processor_badge_css():
colors = generate_processor_badge_colors(sub_package_name)
# Light mode rule
# Double class (.processor-badge.processor-badge-{name}) bumps specificity so the
# color survives the browser's a:visited rule now that the badge is rendered as a link.
css_rules.append(
f".processor-badge-{sub_package_name} {{\n"
f".processor-badge.processor-badge-{sub_package_name} {{\n"
f" background-color: {colors['light']['bg']};\n"
f" color: {colors['light']['color']};\n"
f"}}"
@@ -416,7 +418,7 @@ def get_processor_badge_css():
# Dark mode rule
css_rules.append(
f"html[data-darkmode=\"true\"] .processor-badge-{sub_package_name} {{\n"
f"html[data-darkmode=\"true\"] .processor-badge.processor-badge-{sub_package_name} {{\n"
f" background-color: {colors['dark']['bg']};\n"
f" color: {colors['dark']['color']};\n"
f"}}"
@@ -289,28 +289,33 @@ body.has-queue {
#watch-table-wrapper {
display: inline-block; /* so the tabs at the bottom align */
width: 100%; /* so the table always grows to the tab sizes if theres lots of tabs and full is OK too */
/* general styling */
#post-list-buttons {
#list-related-buttons {
text-align: right;
padding: 0px;
margin: 0px;
padding-top: 1rem;
margin-block-start: 0;
margin-block-end: 0;
padding-inline-start: 0;
margin: 0;
li {
display: inline-block;
}
a {
border-top-left-radius: initial;
border-top-right-radius: initial;
border-bottom-left-radius: 5px;
border-bottom-right-radius: 5px;
border-top-left-radius: 5px;
border-top-right-radius: 5px;
border-bottom-left-radius: 0;
border-bottom-right-radius: 0;
}
}
/* post list dynamically on/off stuff */
&.has-error {
#post-list-buttons {
#list-related-buttons {
#post-list-with-errors {
display: inline-block !important;
}
@@ -318,7 +323,7 @@ body.has-queue {
}
&.has-unread-changes {
#post-list-buttons {
#list-related-buttons {
#post-list-unread, #post-list-mark-views, #post-list-unread {
display: inline-block !important;
}
@@ -332,7 +337,7 @@ body.has-queue {
&.active-tag {
.button-tag {
opacity: 0.35;
&.active {
&.active, &:hover {
opacity: 1;
}
}
@@ -250,6 +250,21 @@ code {
.processor-badge {
@extend .inline-tag;
font-weight: 900;
/* Used as a link to filter the watchlist by processor */
text-decoration: none;
&:hover {
text-decoration: none;
opacity: 0.8;
cursor: pointer;
}
/* Highlight the processor currently used as a filter */
&.active {
outline: 2px solid var(--color-link);
outline-offset: 1px;
}
}
.watch-tag-list {
@@ -335,15 +350,13 @@ a.pure-button-selected {
background: var(--color-background-button-tag);
color: var(--color-text-button);
font-size: 75%;
border-bottom-left-radius: initial;
border-bottom-right-radius: initial;
border-top-left-radius: 6px;
border-top-right-radius: 6px;
border-radius: 6px;
margin-right: 4px;
&.active {
background: var(--color-background-button-tag-active);
font-weight: bold;
}
margin-bottom: 1px;
}
.button-error {
File diff suppressed because one or more lines are too long
@@ -104,6 +104,22 @@ def test_check_ldjson_price_autodetect(client, live_server, measure_memory_usage
assert b'Embedded price data' not in res.data
assert b'processor-badge-restock_diff' in res.data
# The processor badge should be a link that filters the watchlist by processor (?processor=restock_diff).
# The "processor=restock_diff" string only appears in a rendered badge link's href (not in the injected
# <style> block, which contains rules for every processor regardless of which watches are shown), so it's
# a reliable marker for whether the restock watch's row is actually present.
assert b'processor=restock_diff' in res.data, "Processor badge must link to a processor filter"
# Filtering by the watch's own processor should keep its row (and badge link) visible
res = client.get(url_for("watchlist.index", processor='restock_diff'))
assert res.status_code == 200
assert b'processor=restock_diff' in res.data, "Watch must remain visible when filtering by its processor"
# Filtering by a different processor should hide this watch's row entirely
res = client.get(url_for("watchlist.index", processor='text_json_diff'))
assert res.status_code == 200
assert b'processor=restock_diff' not in res.data, "Watch must be filtered out when its processor doesn't match"
# and last snapshop (via API) should be just the price
api_key = live_server.app.config['DATASTORE'].data['settings']['application'].get('api_access_token')
res = client.get(