UI - Search modal - keep the search scoped to the tag you were viewing (#4425)
Build and push containers / metadata (push) Canceled after 0s
Build and push containers / build-push-containers (push) Canceled after 0s
Publish Python 🐍distribution 📦 to PyPI and TestPyPI / Build distribution 📦 (push) Canceled after 0s
ChangeDetection.io Container Build Test / Build linux/amd64 (alpine) (push) Canceled after 0s
ChangeDetection.io Container Build Test / Build linux/arm64 (alpine) (push) Canceled after 0s
ChangeDetection.io Container Build Test / Build linux/amd64 (main) (push) Canceled after 0s
ChangeDetection.io Container Build Test / Build linux/arm/v7 (main) (push) Canceled after 0s
ChangeDetection.io Container Build Test / Build linux/arm/v8 (main) (push) Canceled after 0s
ChangeDetection.io Container Build Test / Build linux/arm64 (main) (push) Canceled after 0s
ChangeDetection.io App Test / lint-code (push) Canceled after 0s
ChangeDetection.io App Test / lint-translations (push) Canceled after 0s
ChangeDetection.io App Test / lint-template-i18n (push) Canceled after 0s
Publish Python 🐍distribution 📦 to PyPI and TestPyPI / Test the built package works basically. (push) Canceled after 0s
Publish Python 🐍distribution 📦 to PyPI and TestPyPI / Publish Python 🐍 distribution 📦 to PyPI (push) Canceled after 0s
ChangeDetection.io App Test / test-application-3-11 (push) Canceled after 0s
ChangeDetection.io App Test / test-application-3-12 (push) Canceled after 0s
ChangeDetection.io App Test / test-application-3-13 (push) Canceled after 0s
ChangeDetection.io App Test / test-application-3-14 (push) Canceled after 0s

The modal submitted the active tag as `tags=<uuid>`, but the watchlist filters on
`tag` - nothing reads `tags`. So searching from inside a tag view silently
searched every watch, despite the label promising "URL or Title in '<tag>'".

The test pulls the hidden field straight out of the rendered modal and feeds it
back to the watchlist, so the field name can't drift from the arg again.

Co-authored-by: Claude Opus 5 (1M context) <noreply@anthropic.com>
This commit is contained in:
dgtlmoon
2026-09-12 17:48:48 +02:00
committed by GitHub
co-authored by Claude Opus 5
parent 7cc62f8321
commit 718295f30b
37 changed files with 165 additions and 128 deletions
+7 -2
View File
@@ -321,9 +321,14 @@
(SCRIPT_NAME), so no client-side URL building is needed. #}
<form id="search-form" method="GET" action="{{ url_for('watchlist.index') }}">
<div class="pure-control-group">
<label for="search-modal-input">{% if active_tag_uuid %}{{ _("URL or Title in '%(title)s'", title=active_tag.title) }}{% else %}{{ _('URL or Title') }}{% endif %}</label>
{# Matches watch_passes_search() in blueprint/watchlist/filters.py - title, URL and last error text #}
<label for="search-modal-input">{{ _('URL, title or error text') }}</label>
<input id="search-modal-input" class="m-d" name="q" placeholder="{{ _('Enter search term...') }}" required type="text" value="" autofocus>
{% if active_tag_uuid %}<input name="tags" type="hidden" value="{{ active_tag_uuid }}">{% endif %}
{# 'tag' (not 'tags') - that's the arg the watchlist filters on #}
{% if active_tag_uuid %}
<input name="tag" type="hidden" value="{{ active_tag_uuid }}">
<span class="pure-form-message-inline">{{ _("Searching in current group '%(title)s' only", title=active_tag.title) }}</span>
{% endif %}
</div>
</form>
</div>
+32
View File
@@ -1,5 +1,6 @@
from flask import url_for
from .util import set_original_response, set_modified_response, live_server_setup
import re
import time
@@ -72,6 +73,7 @@ def test_search_in_tag_limit(client, live_server, measure_memory_usage, datastor
assert urls[1].split(' ')[0].encode('utf-8') not in res.data, urls[0].encode('utf-8')
def test_search_modal_form_action(client, live_server, measure_memory_usage, datastore_path):
# The search modal submits as a plain GET form, so its action has to carry the
# reverse-proxy sub-path (SCRIPT_NAME), otherwise search jumps to the host root.
@@ -80,3 +82,33 @@ def test_search_modal_form_action(client, live_server, measure_memory_usage, dat
res = client.get("/", base_url="http://localhost/sub-path")
assert b'<form id="search-form" method="GET" action="/sub-path/">' in res.data
def test_search_modal_tag_field_is_filterable(client, live_server, measure_memory_usage, datastore_path):
# The modal carries the active tag as a hidden field so a search stays scoped to the
# tag you were viewing. The field name has to be the one the watchlist filters on.
urls = ['https://localhost:12300?first-result=1 tag-one',
'https://localhost:5000?second-result=1 tag-two'
]
res = client.post(
url_for("imports.import_page"),
data={"urls": "\r\n".join(urls)},
follow_redirects=True
)
assert b"2 Imported" in res.data
res = client.get(url_for("watchlist.index") + "?tag=tag-one")
form = re.search(rb'<form id="search-form".*?</form>', res.data, re.DOTALL)
assert form, "search modal form not rendered"
field = re.search(rb'<input name="([^"]+)" type="hidden" value="([^"]+)"', form.group(0))
assert field, f"no populated hidden tag field in {form.group(0)}"
name, value = field.group(1).decode(), field.group(2).decode()
# The scoping is spelled out in the modal, so narrowed results aren't a surprise
assert b'Searching in current group' in form.group(0)
assert b'tag-one' in form.group(0)
# 'localhost' matches both watches, so only the tag field can narrow it down
res = client.get(url_for("watchlist.index") + f"?q=localhost&{name}={value}")
assert urls[0].split(' ')[0].encode('utf-8') in res.data
assert urls[1].split(' ')[0].encode('utf-8') not in res.data, f"'{name}' is not filtered on by the watchlist"
@@ -4571,18 +4571,18 @@ msgid "Search"
msgstr "Hledat"
#: changedetectionio/templates/base.html
#, python-format
msgid "URL or Title in '%(title)s'"
msgstr ""
#: changedetectionio/templates/base.html
msgid "URL or Title"
msgstr ""
msgid "URL, title or error text"
msgstr "URL, název nebo text chyby"
#: changedetectionio/templates/base.html
msgid "Enter search term..."
msgstr ""
#: changedetectionio/templates/base.html
#, python-format
msgid "Searching in current group '%(title)s' only"
msgstr "Hledá se pouze ve skupině '%(title)s'"
#: changedetectionio/templates/edit/include_llm_intent.html
msgid ""
"<strong>On</strong> &ndash; every watch in this group uses the AI settings below, unless it fills in its own. "
@@ -4625,18 +4625,18 @@ msgid "Search"
msgstr "Suchen"
#: changedetectionio/templates/base.html
#, python-format
msgid "URL or Title in '%(title)s'"
msgstr "URL oder Titel in '%(title)s'"
#: changedetectionio/templates/base.html
msgid "URL or Title"
msgstr "URL oder Titel"
msgid "URL, title or error text"
msgstr "URL, Titel oder Fehlertext"
#: changedetectionio/templates/base.html
msgid "Enter search term..."
msgstr "Suchbegriff eingeben..."
#: changedetectionio/templates/base.html
#, python-format
msgid "Searching in current group '%(title)s' only"
msgstr "Suche nur in Gruppe '%(title)s'"
#: changedetectionio/templates/edit/include_llm_intent.html
msgid ""
"<strong>On</strong> &ndash; every watch in this group uses the AI settings below, unless it fills in its own. "
@@ -4563,18 +4563,18 @@ msgid "Search"
msgstr ""
#: changedetectionio/templates/base.html
#, python-format
msgid "URL or Title in '%(title)s'"
msgstr ""
#: changedetectionio/templates/base.html
msgid "URL or Title"
msgstr ""
msgid "URL, title or error text"
msgstr "URL, title or error text"
#: changedetectionio/templates/base.html
msgid "Enter search term..."
msgstr ""
#: changedetectionio/templates/base.html
#, python-format
msgid "Searching in current group '%(title)s' only"
msgstr "Searching in current group '%(title)s' only"
#: changedetectionio/templates/edit/include_llm_intent.html
msgid ""
"<strong>On</strong> &ndash; every watch in this group uses the AI settings below, unless it fills in its own. "
@@ -4563,18 +4563,18 @@ msgid "Search"
msgstr ""
#: changedetectionio/templates/base.html
#, python-format
msgid "URL or Title in '%(title)s'"
msgstr ""
#: changedetectionio/templates/base.html
msgid "URL or Title"
msgstr ""
msgid "URL, title or error text"
msgstr "URL, title or error text"
#: changedetectionio/templates/base.html
msgid "Enter search term..."
msgstr ""
#: changedetectionio/templates/base.html
#, python-format
msgid "Searching in current group '%(title)s' only"
msgstr "Searching in current group '%(title)s' only"
#: changedetectionio/templates/edit/include_llm_intent.html
msgid ""
"<strong>On</strong> &ndash; every watch in this group uses the AI settings below, unless it fills in its own. "
@@ -4640,18 +4640,18 @@ msgid "Search"
msgstr "Buscar"
#: changedetectionio/templates/base.html
#, python-format
msgid "URL or Title in '%(title)s'"
msgstr "URL o título en '%(title)s'"
#: changedetectionio/templates/base.html
msgid "URL or Title"
msgstr "URL o título"
msgid "URL, title or error text"
msgstr "URL, título o texto de error"
#: changedetectionio/templates/base.html
msgid "Enter search term..."
msgstr "Introduzca el término de búsqueda..."
#: changedetectionio/templates/base.html
#, python-format
msgid "Searching in current group '%(title)s' only"
msgstr "Buscando solo en el grupo '%(title)s'"
#: changedetectionio/templates/edit/include_llm_intent.html
msgid ""
"<strong>On</strong> &ndash; every watch in this group uses the AI settings below, unless it fills in its own. "
@@ -4578,18 +4578,18 @@ msgid "Search"
msgstr "Rechercher"
#: changedetectionio/templates/base.html
#, python-format
msgid "URL or Title in '%(title)s'"
msgstr ""
#: changedetectionio/templates/base.html
msgid "URL or Title"
msgstr ""
msgid "URL, title or error text"
msgstr "URL, titre ou texte d'erreur"
#: changedetectionio/templates/base.html
msgid "Enter search term..."
msgstr ""
#: changedetectionio/templates/base.html
#, python-format
msgid "Searching in current group '%(title)s' only"
msgstr "Recherche uniquement dans le groupe '%(title)s'"
#: changedetectionio/templates/edit/include_llm_intent.html
msgid ""
"<strong>On</strong> &ndash; every watch in this group uses the AI settings below, unless it fills in its own. "
@@ -4684,18 +4684,18 @@ msgid "Search"
msgstr "Cari"
#: changedetectionio/templates/base.html
#, python-format
msgid "URL or Title in '%(title)s'"
msgstr "URL atau Judul di '%(title)s'"
#: changedetectionio/templates/base.html
msgid "URL or Title"
msgstr "URL atau Judul"
msgid "URL, title or error text"
msgstr "URL, judul atau teks kesalahan"
#: changedetectionio/templates/base.html
msgid "Enter search term..."
msgstr "Masukkan istilah pencarian..."
#: changedetectionio/templates/base.html
#, python-format
msgid "Searching in current group '%(title)s' only"
msgstr "Mencari hanya dalam grup '%(title)s'"
#: changedetectionio/templates/edit/include_llm_intent.html
msgid ""
"<strong>On</strong> &ndash; every watch in this group uses the AI settings below, unless it fills in its own. "
@@ -4565,18 +4565,18 @@ msgid "Search"
msgstr "Cerca"
#: changedetectionio/templates/base.html
#, python-format
msgid "URL or Title in '%(title)s'"
msgstr ""
#: changedetectionio/templates/base.html
msgid "URL or Title"
msgstr ""
msgid "URL, title or error text"
msgstr "URL, titolo o testo dell'errore"
#: changedetectionio/templates/base.html
msgid "Enter search term..."
msgstr ""
#: changedetectionio/templates/base.html
#, python-format
msgid "Searching in current group '%(title)s' only"
msgstr "Ricerca solo nel gruppo '%(title)s'"
#: changedetectionio/templates/edit/include_llm_intent.html
msgid ""
"<strong>On</strong> &ndash; every watch in this group uses the AI settings below, unless it fills in its own. "
@@ -4596,18 +4596,18 @@ msgid "Search"
msgstr "検索"
#: changedetectionio/templates/base.html
#, python-format
msgid "URL or Title in '%(title)s'"
msgstr "'%(title)s' 内のURLまたはタイトル"
#: changedetectionio/templates/base.html
msgid "URL or Title"
msgstr "URLまたはタイトル"
msgid "URL, title or error text"
msgstr "URL、タイトル、エラーテキスト"
#: changedetectionio/templates/base.html
msgid "Enter search term..."
msgstr "検索語を入力..."
#: changedetectionio/templates/base.html
#, python-format
msgid "Searching in current group '%(title)s' only"
msgstr "グループ「%(title)s」内のみを検索"
#: changedetectionio/templates/edit/include_llm_intent.html
msgid ""
"<strong>On</strong> &ndash; every watch in this group uses the AI settings below, unless it fills in its own. "
@@ -4573,18 +4573,18 @@ msgid "Search"
msgstr "검색"
#: changedetectionio/templates/base.html
#, python-format
msgid "URL or Title in '%(title)s'"
msgstr "'%(title)s'의 URL 또는 제목"
#: changedetectionio/templates/base.html
msgid "URL or Title"
msgstr "URL 또는 제목"
msgid "URL, title or error text"
msgstr "URL, 제목 또는 오류 텍스트"
#: changedetectionio/templates/base.html
msgid "Enter search term..."
msgstr "검색어를 입력하세요..."
#: changedetectionio/templates/base.html
#, python-format
msgid "Searching in current group '%(title)s' only"
msgstr "'%(title)s' 그룹 내에서만 검색"
#: changedetectionio/templates/edit/include_llm_intent.html
msgid ""
"<strong>On</strong> &ndash; every watch in this group uses the AI settings below, unless it fills in its own. "
+7 -7
View File
@@ -8,7 +8,7 @@ msgid ""
msgstr ""
"Project-Id-Version: changedetection.io 0.60.4\n"
"Report-Msgid-Bugs-To: EMAIL@ADDRESS\n"
"POT-Creation-Date: 2026-09-12 15:41+0200\n"
"POT-Creation-Date: 2026-09-12 17:18+0200\n"
"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n"
"Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
"Language-Team: LANGUAGE <LL@li.org>\n"
@@ -4562,18 +4562,18 @@ msgid "Search"
msgstr ""
#: changedetectionio/templates/base.html
#, python-format
msgid "URL or Title in '%(title)s'"
msgstr ""
#: changedetectionio/templates/base.html
msgid "URL or Title"
msgid "URL, title or error text"
msgstr ""
#: changedetectionio/templates/base.html
msgid "Enter search term..."
msgstr ""
#: changedetectionio/templates/base.html
#, python-format
msgid "Searching in current group '%(title)s' only"
msgstr ""
#: changedetectionio/templates/edit/include_llm_intent.html
msgid ""
"<strong>On</strong> &ndash; every watch in this group uses the AI settings below, unless it fills in its own. "
@@ -4745,18 +4745,18 @@ msgid "Search"
msgstr "Wyszukiwanie"
#: changedetectionio/templates/base.html
#, python-format
msgid "URL or Title in '%(title)s'"
msgstr "Adres URL lub tytuł w „%(title)s”"
#: changedetectionio/templates/base.html
msgid "URL or Title"
msgstr "Adres URL lub tytuł"
msgid "URL, title or error text"
msgstr "URL, tytuł lub treść błędu"
#: changedetectionio/templates/base.html
msgid "Enter search term..."
msgstr "Wpisz szukane hasło..."
#: changedetectionio/templates/base.html
#, python-format
msgid "Searching in current group '%(title)s' only"
msgstr "Szukanie tylko w grupie '%(title)s'"
#: changedetectionio/templates/edit/include_llm_intent.html
msgid ""
"<strong>On</strong> &ndash; every watch in this group uses the AI settings below, unless it fills in its own. "
@@ -4615,18 +4615,18 @@ msgid "Search"
msgstr "Pesquisar"
#: changedetectionio/templates/base.html
#, python-format
msgid "URL or Title in '%(title)s'"
msgstr "URL ou Título em '%(title)s'"
#: changedetectionio/templates/base.html
msgid "URL or Title"
msgstr "URL ou Título"
msgid "URL, title or error text"
msgstr "URL, título ou texto de erro"
#: changedetectionio/templates/base.html
msgid "Enter search term..."
msgstr "Digite o termo de busca..."
#: changedetectionio/templates/base.html
#, python-format
msgid "Searching in current group '%(title)s' only"
msgstr "Buscando apenas no grupo '%(title)s'"
#: changedetectionio/templates/edit/include_llm_intent.html
msgid ""
"<strong>On</strong> &ndash; every watch in this group uses the AI settings below, unless it fills in its own. "
@@ -4693,18 +4693,18 @@ msgid "Search"
msgstr "Поиск"
#: changedetectionio/templates/base.html
#, python-format
msgid "URL or Title in '%(title)s'"
msgstr "URL-адрес или заголовок в формате «%(title)s»"
#: changedetectionio/templates/base.html
msgid "URL or Title"
msgstr "URL или заголовок"
msgid "URL, title or error text"
msgstr "URL, заголовок или текст ошибки"
#: changedetectionio/templates/base.html
msgid "Enter search term..."
msgstr "Введите поисковый запрос..."
#: changedetectionio/templates/base.html
#, python-format
msgid "Searching in current group '%(title)s' only"
msgstr "Поиск только в группе '%(title)s'"
#: changedetectionio/templates/edit/include_llm_intent.html
msgid ""
"<strong>On</strong> &ndash; every watch in this group uses the AI settings below, unless it fills in its own. "
@@ -4620,18 +4620,18 @@ msgid "Search"
msgstr "Ara"
#: changedetectionio/templates/base.html
#, python-format
msgid "URL or Title in '%(title)s'"
msgstr "'%(title)s' içinde URL veya Başlık"
#: changedetectionio/templates/base.html
msgid "URL or Title"
msgstr "URL veya Başlık"
msgid "URL, title or error text"
msgstr "URL, başlık veya hata metni"
#: changedetectionio/templates/base.html
msgid "Enter search term..."
msgstr "Arama terimini girin..."
#: changedetectionio/templates/base.html
#, python-format
msgid "Searching in current group '%(title)s' only"
msgstr "Yalnızca '%(title)s' grubunda aranıyor"
#: changedetectionio/templates/edit/include_llm_intent.html
msgid ""
"<strong>On</strong> &ndash; every watch in this group uses the AI settings below, unless it fills in its own. "
@@ -4597,18 +4597,18 @@ msgid "Search"
msgstr "Пошук"
#: changedetectionio/templates/base.html
#, python-format
msgid "URL or Title in '%(title)s'"
msgstr "URL або Назва у '%(title)s'"
#: changedetectionio/templates/base.html
msgid "URL or Title"
msgstr "URL або Назва"
msgid "URL, title or error text"
msgstr "URL, заголовок або текст помилки"
#: changedetectionio/templates/base.html
msgid "Enter search term..."
msgstr "Введіть пошуковий запит..."
#: changedetectionio/templates/base.html
#, python-format
msgid "Searching in current group '%(title)s' only"
msgstr "Пошук лише в групі '%(title)s'"
#: changedetectionio/templates/edit/include_llm_intent.html
msgid ""
"<strong>On</strong> &ndash; every watch in this group uses the AI settings below, unless it fills in its own. "
@@ -4571,18 +4571,18 @@ msgid "Search"
msgstr "搜索"
#: changedetectionio/templates/base.html
#, python-format
msgid "URL or Title in '%(title)s'"
msgstr "'%(title)s' 中的 URL 或标题"
#: changedetectionio/templates/base.html
msgid "URL or Title"
msgstr "URL 或标题"
msgid "URL, title or error text"
msgstr "URL、标题或错误文本"
#: changedetectionio/templates/base.html
msgid "Enter search term..."
msgstr "输入搜索关键词..."
#: changedetectionio/templates/base.html
#, python-format
msgid "Searching in current group '%(title)s' only"
msgstr "仅在分组「%(title)s」中搜索"
#: changedetectionio/templates/edit/include_llm_intent.html
msgid ""
"<strong>On</strong> &ndash; every watch in this group uses the AI settings below, unless it fills in its own. "
@@ -4574,18 +4574,18 @@ msgid "Search"
msgstr "搜尋"
#: changedetectionio/templates/base.html
#, python-format
msgid "URL or Title in '%(title)s'"
msgstr "URL 或標題 在 '%(title)s'"
#: changedetectionio/templates/base.html
msgid "URL or Title"
msgstr "URL 或標題"
msgid "URL, title or error text"
msgstr "URL、標題或錯誤文字"
#: changedetectionio/templates/base.html
msgid "Enter search term..."
msgstr "輸入搜尋關鍵字 ..."
#: changedetectionio/templates/base.html
#, python-format
msgid "Searching in current group '%(title)s' only"
msgstr "僅在群組「%(title)s」中搜尋"
#: changedetectionio/templates/edit/include_llm_intent.html
msgid ""
"<strong>On</strong> &ndash; every watch in this group uses the AI settings below, unless it fills in its own. "