fix(theme): close four parity gaps between the bootstrap theme and the JSP search pages - #3463
Merged
Merged
Conversation
The bootstrap static theme built /go/ links with a 1-based order while the link's data-order stayed 0-based. The JSP search page sent the 0-based loop index (the same value as data-order), and GoAction stores it as ClickLog.order, so click logs from the static theme were off by one. Pass the 0-based position so both UIs record the same order.
The de, es, fr, ko, pt-BR and zh-CN bundles of the bootstrap static theme still carried the English text for the error.detail_* keys shown on the error page (docid_not_found, document_not_found, not_found_on_file_system, unauthorized_request, bad_authentication). Translate them, reusing the terms of the matching errors.* entries in the core fess_message_* bundles.
Paging in the bootstrap static theme only re-ran the search, so start= never reached the address bar and a reload, back/forward or shared link fell back to the first page. The JSP paging links carried start=, and runFromUrl() already reads it. Push the new start= onto history when paging, and correct it in place whenever a search runs with a different offset (a facet or filter change resets to the first page). The URL is written directly rather than via navigate(): the runFromUrl() it dispatches clears the in-memory facet selections, and it would also fetch the page a second time.
The bootstrap static theme always added <link rel="search" href="osdd">, while the JSP pages emitted it only when OsddHelper#hasOpenSearchFile() was true (osdd.link.enabled, which in auto mode turns it off under SSO). With the document not served, browsers were pointed at a missing OSDD. Expose the same decision as features.osdd_link in /api/v2/ui/config, document it in the user OpenAPI spec, and gate the link on it.
This was referenced Sep 21, 2026
marevol
added a commit
to codelibs/fess-test-ui
that referenced
this pull request
Sep 21, 2026
codelibs/fess#3460 makes the bundled bootstrap static-theme SPA the page for /, /search, /help, /profile, /cache, /advance and /error/*, and renders errors in place at the requested URL with the real HTTP status instead of redirecting through error/redirect.jsp to a 200 page. The search modules and four /admin/general/ leaves asserted the JSP pages and the redirect, so they fail against the snapshot image. Rewrite them against the new contract: - Wait for the SPA to render (wait_for_selector / expect_response) instead of reading the DOM right after the load, and address the home form by id (#contentQuery, #home-search-submit): the hidden header copy of input[name=q] comes first in the DOM. - Compare SPA text with the theme's own bundle (themes/bootstrap/i18n/messages.<locale>.json) through a small helper, search/_theme.py; server messages in API error responses still go through tm(). - root_top, form_submit, advance, profile_form, no_results, suggest, sort, facet and cache follow the new markup: relative hrefs resolved against <base href>, pushState navigation, compose() building the advanced query client-side, the client-side password mismatch check, the facet click re-running /api/v2/search with ex_q, and the cached copy shown in a sandboxed iframe. - query_errors expects HTTP 400 from /api/v2/search and the message in #search-error at the unchanged /search/ URL. - error_pages, go_click and jsonResponse assert the status, the X-Fess-Error-Code header and the unchanged URL, now that they are observable; /error/badrequrest/ is simply the catch-all 500. - osdd waits for the <link rel="search"> the SPA adds and expects the site name from /api/v2/ui/config as its title. - root_top checks that no [data-i18n] element still shows its own key (the SPA's untranslated-string symptom) instead of LastaFlute's ???labels.x??? marker, which the SPA never renders. - loginLink, notificationSearchTop and loginRequired observe a guest page (FessContext.guest_page: a separate browser context without the suite's cookies), since the SPA renders the login link and the banner from /api/v2/ui/config and gates a guest behind an unclosable login modal instead of redirecting to /login/. The config fields and the rendered DOM are both asserted. - query waits for the results as well. Two assertions pin codelibs/fess#3463: pagination expects the URL to record the page (start=<page size>), and go_click expects the /go/ order parameter to be the result's 0-based data-order, as the JSP pages sent it. Each runs last in its module so the checks before it still report on an image built before that fix.
marevol
added a commit
to codelibs/fess-test-ui
that referenced
this pull request
Sep 22, 2026
codelibs/fess#3460 makes the bundled bootstrap static-theme SPA the page for /, /search, /help, /profile, /cache, /advance and /error/*, and renders errors in place at the requested URL with the real HTTP status instead of redirecting through error/redirect.jsp to a 200 page. The search modules and four /admin/general/ leaves asserted the JSP pages and the redirect, so they fail against the snapshot image. Rewrite them against the new contract: - Wait for the SPA to render (wait_for_selector / expect_response) instead of reading the DOM right after the load, and address the home form by id (#contentQuery, #home-search-submit): the hidden header copy of input[name=q] comes first in the DOM. - Compare SPA text with the theme's own bundle (themes/bootstrap/i18n/messages.<locale>.json) through a small helper, search/_theme.py; server messages in API error responses still go through tm(). - root_top, form_submit, advance, profile_form, no_results, suggest, sort, facet and cache follow the new markup: relative hrefs resolved against <base href>, pushState navigation, compose() building the advanced query client-side, the client-side password mismatch check, the facet click re-running /api/v2/search with ex_q, and the cached copy shown in a sandboxed iframe. - facet compares counts only within one search response: the badge with the label count of the search that rendered it, and the click's hit count with the label count of the click's own search. The seed's crawl keeps indexing after search_seed returns, so counts from separate searches can differ. - query_errors expects HTTP 400 from /api/v2/search and the message in #search-error at the unchanged /search/ URL. - error_pages, go_click and jsonResponse assert the status, the X-Fess-Error-Code header and the unchanged URL, now that they are observable; /error/badrequrest/ is simply the catch-all 500. - osdd waits for the <link rel="search"> the SPA adds and expects the site name from /api/v2/ui/config as its title. - root_top checks that no [data-i18n] element still shows its own key (the SPA's untranslated-string symptom) instead of LastaFlute's ???labels.x??? marker, which the SPA never renders. - loginLink, notificationSearchTop and loginRequired observe a guest page (FessContext.guest_page: a separate browser context without the suite's cookies), since the SPA renders the login link and the banner from /api/v2/ui/config and gates a guest behind an unclosable login modal instead of redirecting to /login/. The config fields and the rendered DOM are both asserted. - query waits for the results as well. Two assertions pin codelibs/fess#3463: pagination expects the URL to record the page (start=<page size>), and go_click expects the /go/ order parameter to be the result's 0-based data-order, as the JSP pages sent it. Each runs last in its module so the checks before it still report on an image built before that fix.
marevol
added a commit
to codelibs/fess-test-ui
that referenced
this pull request
Sep 22, 2026
#61) * test(search): follow the static-theme default and in-place error pages codelibs/fess#3460 makes the bundled bootstrap static-theme SPA the page for /, /search, /help, /profile, /cache, /advance and /error/*, and renders errors in place at the requested URL with the real HTTP status instead of redirecting through error/redirect.jsp to a 200 page. The search modules and four /admin/general/ leaves asserted the JSP pages and the redirect, so they fail against the snapshot image. Rewrite them against the new contract: - Wait for the SPA to render (wait_for_selector / expect_response) instead of reading the DOM right after the load, and address the home form by id (#contentQuery, #home-search-submit): the hidden header copy of input[name=q] comes first in the DOM. - Compare SPA text with the theme's own bundle (themes/bootstrap/i18n/messages.<locale>.json) through a small helper, search/_theme.py; server messages in API error responses still go through tm(). - root_top, form_submit, advance, profile_form, no_results, suggest, sort, facet and cache follow the new markup: relative hrefs resolved against <base href>, pushState navigation, compose() building the advanced query client-side, the client-side password mismatch check, the facet click re-running /api/v2/search with ex_q, and the cached copy shown in a sandboxed iframe. - facet compares counts only within one search response: the badge with the label count of the search that rendered it, and the click's hit count with the label count of the click's own search. The seed's crawl keeps indexing after search_seed returns, so counts from separate searches can differ. - query_errors expects HTTP 400 from /api/v2/search and the message in #search-error at the unchanged /search/ URL. - error_pages, go_click and jsonResponse assert the status, the X-Fess-Error-Code header and the unchanged URL, now that they are observable; /error/badrequrest/ is simply the catch-all 500. - osdd waits for the <link rel="search"> the SPA adds and expects the site name from /api/v2/ui/config as its title. - root_top checks that no [data-i18n] element still shows its own key (the SPA's untranslated-string symptom) instead of LastaFlute's ???labels.x??? marker, which the SPA never renders. - loginLink, notificationSearchTop and loginRequired observe a guest page (FessContext.guest_page: a separate browser context without the suite's cookies), since the SPA renders the login link and the banner from /api/v2/ui/config and gates a guest behind an unclosable login modal instead of redirecting to /login/. The config fields and the rendered DOM are both asserted. - query waits for the results as well. Two assertions pin codelibs/fess#3463: pagination expects the URL to record the page (start=<page size>), and go_click expects the /go/ order parameter to be the result's 0-based data-order, as the JSP pages sent it. Each runs last in its module so the checks before it still report on an image built before that fix. * test: run the JSP-era tests on Fess 15.8 and earlier The fess15 variants run Fess 15.8.0, which still serves the JSP search pages, so the modules rewritten for the static-theme SPA cannot pass there. Rather than skipping them, which would drop their coverage on the 15.x line, keep the previous tests and pick one by the Fess version. - The fifteen search modules and the jsonResponse, loginLink, notificationSearchTop and loginRequired leaves keep their JSP-era version next to them as <module>_jsp.py, byte-identical to main, and their run() starts with `if run_jsp_variant(context, <module>_jsp): return`. Both lines therefore run real assertions. - fess.test.ui.version asks the server once per run for its version: every /api/admin/* response is an ApiResult whose envelope carries the product version (major.minor), including the 401 an unauthenticated caller gets, on 15.8.0 as on the snapshot. The compose file cannot tell, since the snapshot tag names no version. When the version cannot be read, it raises instead of picking a line. - STATIC_THEME_SINCE = (15, 9) is the one gate. The *_jsp.py modules, the switch and the label/message keys only they use (now marked as such) can go once no workflow targets Fess 15.8 or earlier. - tests/ui/test_version.py covers the parsing, the detection and its failure modes, the dispatch on either side of the gate, and that every switched module names an importable <module>_jsp.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
Fixes four places where the bundled bootstrap static theme, now the default search UI (#3460), still differs from the JSP search pages.
Changes
/go/links carry the 0-based position of the result on the page, the same value as the link'sdata-order, as the JSP pages sent. The theme sent a 1-based rank, soClickLog.orderwas shifted by one.start=to the address bar, so reload, back/forward and shared links land on the same page. Onlystartis written; the page does not go through the router, which would drop the facet selections kept in memory. A filter change that returns to the first page removes a stalestart=in place./api/v2/ui/configreturns a newfeatures.osdd_linkflag, set fromOsddHelper#hasOpenSearchFile()as the JSPosddLinkwas. The theme adds<link rel="search">only when it is true, so the link is no longer advertised whenosdd.link.enabledturns the document off (includingautounder SSO).error.detail_*messages were still in English in the de, es, fr, ko, pt-BR and zh-CN bundles.Verification
mvn test -Dtest='UiConfigHandlerTest,LabelMessageThemeParityTest,BundledBootstrapThemeTest,OsddHelperTest'andmvn test -Dtest='StaticTheme*,ThemeManifestTest,ThemeRegistryTest,org.codelibs.fess.api.v2.**.*Test': 873 tests passed.src/test/js,npx vitest run): 18 files, 572 tests passed.mvn formatter:formatandmvn license:formatleave no changes.