diff --git a/changedetectionio/blueprint/add_watch_ui/__init__.py b/changedetectionio/blueprint/add_watch_ui/__init__.py index dddeac1f..7d502ee4 100644 --- a/changedetectionio/blueprint/add_watch_ui/__init__.py +++ b/changedetectionio/blueprint/add_watch_ui/__init__.py @@ -1,4 +1,5 @@ -from flask import Blueprint, render_template, request, jsonify, make_response +from flask import Blueprint, render_template, request, jsonify, make_response, flash, redirect, url_for +from flask_babel import gettext from loguru import logger from changedetectionio import forms @@ -17,6 +18,14 @@ def construct_blueprint(datastore: ChangeDetectionStore): from changedetectionio.llm.evaluator import get_llm_config as _get_llm_config from changedetectionio.llm.ui_strings import LLM_INTENT_WATCH_PLACEHOLDER + # Same gate that hides the sidebar link (sidebar-nav.html): with no browser that can + # render a preview there is nothing for the visual selector to work on, so bounce + # direct navigation rather than serving a page whose only outcome is an error. + if not browser_config.has_visual_browser(datastore): + flash(gettext("Adding a watch with a browser needs an interactive browser " + "(screenshots + element data) - none is configured."), 'error') + return redirect(url_for('watchlist.index')) + form = forms.quickWatchForm(None) llm_configured = bool(_get_llm_config(datastore)) diff --git a/changedetectionio/blueprint/add_watch_ui/browser_config.py b/changedetectionio/blueprint/add_watch_ui/browser_config.py index 2b36a60e..ad9fe23f 100644 --- a/changedetectionio/blueprint/add_watch_ui/browser_config.py +++ b/changedetectionio/blueprint/add_watch_ui/browser_config.py @@ -83,6 +83,15 @@ def list_visual_browser_choices(datastore): return choices +def has_visual_browser(datastore): + """True when at least one installed browser can render a live preview. + + Gates the whole Add-Watch page (sidebar link + the route itself): without one there + is nothing for the visual selector to work on, so the page can only fail. + """ + return bool(list_visual_browser_choices(datastore)) + + def default_visual_browser(datastore): """Which browser the Add-Watch page should start on. diff --git a/changedetectionio/flask_app.py b/changedetectionio/flask_app.py index 8cc0961b..93937850 100644 --- a/changedetectionio/flask_app.py +++ b/changedetectionio/flask_app.py @@ -611,6 +611,14 @@ def changedetection_app(config=None, datastore_o=None): from changedetectionio.llm.evaluator import is_llm_features_disabled return dict(llm_features_disabled=is_llm_features_disabled()) + @app.context_processor + def inject_has_visual_browser(): + # Whether any installed content fetcher can render the Add-Watch live preview - + # sidebar-nav.html hides the Add-Watch link without one. Same capability lookup the + # page's browser picker and /snapshot use, so they can't disagree. + from changedetectionio.blueprint.add_watch_ui import browser_config + return dict(has_visual_browser=browser_config.has_visual_browser(datastore)) + # Set up a request hook to check authentication for all routes @app.before_request def check_authentication(): diff --git a/changedetectionio/static/styles/scss/parts/_watch_table.scss b/changedetectionio/static/styles/scss/parts/_watch_table.scss index 91d089c4..3e9492cd 100644 --- a/changedetectionio/static/styles/scss/parts/_watch_table.scss +++ b/changedetectionio/static/styles/scss/parts/_watch_table.scss @@ -387,8 +387,8 @@ body.watch-selection-active #checkbox-operations { transparent ); outline-offset: 1px; - border-radius: 4px; } + border-radius: var(--common-round-border); } // Reserved for future use diff --git a/changedetectionio/templates/sidebar-nav.html b/changedetectionio/templates/sidebar-nav.html index 2c0b0fb6..0baac75c 100644 --- a/changedetectionio/templates/sidebar-nav.html +++ b/changedetectionio/templates/sidebar-nav.html @@ -18,6 +18,9 @@ {%- endif -%} + {# Add-Watch needs a browser that can render a live preview (see the add_watch_ui + blueprint's browser_config) - without one the page can only fail, so don't offer it #} + {%- if has_visual_browser -%}