Search Requirement Specifications - sebiboga/testlink-upgraded GitHub Wiki

Search Requirement Specifications — Modernized Screen

Path: ASIDE menu > Requirements > Search Requirement Specifications URL: gui/templates/requirements/searchReqSpec.html?tproject_id=<id>&tplan_id=<id> BFF API: api/requirements/index.php routes GET /reqspec-context and GET /reqspec-search (session-based auth, JSON I/O) Prerequisite: mgt_view_req right on the current test project (same rule as legacy menu visibility); the entry is hidden otherwise and both routes return HTTP 403. Replaces: legacy form lib/requirements/reqSpecSearchForm.php + results grid from lib/requirements/reqSpecSearch.php (ExtJS table). Update (#1825): both legacy controllers are now retired session-guarded shims (302 to the modern screen, 405 for a write verb, 405 JSON for an XHR) and the criteria page itself is modern too — see Search Requirement Specifications — Criteria Form. This screen honours ?auto_search=1 (run the search on arrival) and offers a Criteria form button that hands the criteria on screen back to that page.

Bug fix (#1735): the retired legacy controller used to answer HTTP 500 / 0 bytes (count($itemSet) on an uninitialised variable). The retirement removed the defect; the modern BFF serves the search and its no_records_found state without any PHP-8 TypeError. See Bugfix Issue #1735.

Search form


What it does

Searches requirement specifications of the CURRENT test project only, combining all filled criteria with a logical AND (LIKE '%value%' semantics on text fields) — exactly like TestLink 1.9.20.

Like the legacy screen, the search runs against req_specs_revisions (doc id, scope, type, log message are matched per REVISION), so a spec shows up once per matching revision group with all its revision links.

Notices shown above the form:

  • all criteria are combined with AND;
  • search is restricted to the selected test project.

Search criteria

Criterion Behavior
Doc ID LIKE '%value%' on req_specs_revisions.doc_id; offered only when the project has req specs containing requirements (getOptionReqSpec(GET_NOT_EMPTY_REQSPEC), legacy rule)
Title LIKE on spec name (nodes_hierarchy.name)
Type exact match on revision type; domain localized server-side (req_spec_cfg.type_labels): Section / User Req Spec / System Req Spec + "Any"
Scope LIKE on req_specs_revisions.scope
Log message LIKE on req_specs_revisions.log_message
Custom field + value design-time custom fields linked to requirement_spec; values joined on the revision node id (cfield_design_values.node_id = RSPECREV.id), LIKE semantics

Result cap: if more than req_cfg.search.max_qty_for_display (200) specs match, results are not displayed and the legacy warning "Too many results" is returned instead.

Results

Search results

DataTable with columns:

  • Path — full tree path of the spec (empty for root-level specs);
  • Requirement Specification — edit icon + DOCID:Title; opens the modern viewer popup gui/templates/requirements/reqSpecView.html?id=… (was reqSpecView.php?req_spec_id=…, Refs #755);
  • Revisions — one link per matching revision (rev. N, newest first), each opening reqSpecViewRevision.php?item_id=<revision_id> in a popup (still legacy — next piece of #755).

Header line shows the match count ("Matches: N").

Empty state / warnings

No results

  • no matches → red warning box + centered empty-state panel ("No requirement specifications match the given criteria.");
  • too many matches → legacy too_wide_search_criteria warning instead of rows.

i18n

All labels, placeholders and messages use the client-side TLi18n module with the reqspecsearch.* key namespace, present in all 10 locale bundles (en, ro, de, es, fr, it, ja, pt, ru, zh). The type domain is localized server-side like the legacy form.

Romanian locale

Permissions

  • Menu entry rendered only for users with mgt_view_req on the project.
  • Both BFF routes re-check mgt_view_req server-side → HTTP 403 + error toast when missing (verified with a no-rights user).
  • Search is always scoped to the session/current test project.

Implementation notes

  • BFF mirrors reqSpecSearch.php SQL 1:1 (joins on req_specs / req_specs_revisions / nodes_hierarchy, cumulative grouping by spec id, path via tree_manager->get_full_path_verbose(path_as_string)).
  • Deep-link prefill: every criterion can be seeded via URL params (doc_id, name, reqSpecType, scope, log_message, custom_field_id, custom_field_value).

Test coverage

Suite 43 in tmp/TLU_Test_Cases.md (15 cases) covers: criteria matrix, revision-level matching, AND combinations, LIKE partials, reset, deep links, locale switching, permission paths and Event Viewer cleanliness.

Generated-on results footer (Issue #1081)

Legacy closed every result set with the italic "how to read this list" hint plus a "Generated by TestLink on <date>" stamp, both rendered only when the search produced no warning (gui/templates/dashio/requirements/reqSpecSearchResults.tpl:22-33):

<p class="italic">{lang_get s='info_search_req_spec'}</p>
{lang_get s='generated_by_TestLink_on'} {$smarty.now|date_format:$gsmarty_timestamp_format}

The stamp used $gsmarty_timestamp_format, i.e. $tlCfg->locales_timestamp_format[$session locale] (lib/functions/tlsmarty.inc.php:304) — the logged-in user's language format, not the browser locale. The modern screen had dropped the whole block (only the match count remained).

  • BFF GET /reqspec-search now returns generated_on (already localized: tlStrftime($tsFormat, time()), format taken from config_get('locales_timestamp_format')[$_SESSION['locale']] with a default_language fallback) and generated_on_iso (tooltip).
  • Screen renders them in a dedicated #footerGenerated block after every renderResults(); the block is hidden for the no_records_found and too_wide_search_criteria warnings, exactly like the legacy {if !isset($gui->warning_msg)} guard. doSearch() hides it and resetForm() clears it, so a stamp never outlives its result set.
  • #footerInfo keeps Matches: N.
  • i18n: new reqspecsearch.infoSearch key in all 10 bundles (legacy $TLS_info_search_req_spec texts, \n-separated paragraphs rendered as <br>, escaped); the label reuses the already translated common.generatedBy.

generated-on footer

Test suite: Task — Issue #1081 in tmp/TLU_Test_Cases.md (8 cases, all PASS: BFF payload, normal search, no-records, too-wide 205 > cap 200, Reset, German locale, stamp refresh, console/Event Viewer clean).

⚠️ **GitHub.com Fallback** ⚠️