Requirement Specification Tree reqSpecMgmt - sebiboga/testlink-upgraded GitHub Wiki
Port of the legacy requirement-spec tree semantics (TestLink 1.9.20
lib/requirements/reqSpecListTree.php + lib/ajax/getrequirementnodes.php?mode=reqspec
-
generate_reqspec_tree()/render_reqspec_treenode()/prepare_reqspec_treenode()inlib/functions/treeMenu.inc.php) into the modernizedreqSpecMgmtscreen (gui/templates/requirements/reqSpecMgmt.html+api/reqspec/index.php).
Before this change the modern screen was a flat DataTable:
-
action=specsselectednh.node_orderbut nevernh.parent_id, and the response map emitted neither — a child spec (RS-200 under RS-100) came back as a top-level sibling; - the
Reqsbadge wasCOUNT(*) FROM requirements GROUP BY srs_id, i.e. the direct count, where legacy showed the subtree count (child_req_countintreeMenu.inc.php:1935-1960adds the counters of every nested child spec); - the project-wide total (
count(get_all_requirement_ids()),tlRequirementFilterControl.class.php:275-280) was not exposed at all; - no expand/collapse, no indent, no nesting indicator;
- this screen could not create a nested spec:
create_specalready acceptedparent_id(Refs #1345) but the modal had no parent field.
| field | meaning | legacy counterpart |
|---|---|---|
parent_id |
hierarchy parent, 0 = top level (test project node / orphan / self-parent / cycle) |
nodes_hierarchy.parent_id |
node_order |
sibling order |
position (node_order) |
child_specs |
number of directly nested specs | — (implicit in the tree) |
subtree_reqs |
own + all nested child specs requirements |
child_req_count, treeMenu.inc.php:2149-2150
|
req_count |
direct requirements only (unchanged, now the tooltip) | — |
envelope total_reqs
|
project subtree total | root node "{$name} ({$req_qty})"
|
envelope child_requirements_mgmt
|
req_cfg->child_requirements_mgmt (config.inc.php:1689) |
getrequirementnodes.php:46-51 forbidden_parent guard |
The subtree counters come from a single post-order pass over the
already-loaded rows ($resolve closure, api/reqspec/index.php:658-680), so
the whole screen costs one extra query instead of the legacy
tree::getAllItemsID() N+1 (one recursive query per visible node).
-
orderedSpecTree()does a depth-first walk overparent_id, siblings sorted bynode_orderthenid; a cycle guard prevents an infinite walk. - The DataTable is created with
order: []+paging: falseso the tree order is not destroyed (DataTables otherwise re-sorts by column 0). - Each spec with children gets a
+/-toggle; the toolbar gets Expand all / Collapse all (legacyinc_tree_control.tpl:15-27tree.expandAll()/tree.collapseAll()). - Collapsed state is persisted in
localStorageper test project (TL_req_spec_mgmt_collapsed_<tproject_id>), mirroring the legacyTreePanelState/LocalStorageProvidercookie prefix scheme. - The section header shows the legacy root-node count:
total requirements in <project>: 4. - The create modal gained a Parent specification select (dotted-path
options, a spec can never be its own parent); the picker is only offered when
child_requirements_mgmtis ENABLED and the user may manage specs. A per-row New child specification action pre-fills it.
needOwnedSpec() ended with return @$reqSpecMgr->get_by_id(...). No caller
uses the return value — it is purely an existence/ownership guard. But
get_by_id() resolves the latest revision through the latest_rspec_revision
view and builds ... AND RSPEC_REV.id = with a NULL child id when that row is
absent. That is an uncaught database Exception, not a suppressible warning, so
@ did nothing and the request died with HTTP 500 / empty body.
Reproduced: POST action=create_spec with parent_id: 0 → 200 {"status":"ok"},
with parent_id: 10 → 500 (empty body,
Uncaught Exception: Database error (query failed) … requirement_spec_mgr.class.php(218) … api/reqspec/index.php(138) needOwnedSpec()). This made the entire
nested-spec creation path — including the reqSpecView.html "New Child Spec"
button shipped with #1345 — unusable. Fix: drop the dead get_by_id() call and
return true after the ownership probe.
13 new keys in all 10 locale bundles (de, en, es, fr, it, ja, pt, ro, ru, zh):
rs.expandAll, rs.collapseAll, rs.expandNode, rs.collapseNode,
rs.treeHint, rs.totalReqsOf, rs.reqsInSubtree, rs.childSpecs,
rs.childSpecsShort, rs.newChildSpec, rs.parentSpecLabel,
rs.parentSpecHint, rs.parentTopLevel.
| file | purpose |
|---|---|
api/reqspec/index.php |
specs tree model + needOwnedSpec() fix |
gui/templates/requirements/reqSpecMgmt.html |
tree DataTable, toggles, total line, parent picker |
gui/templates/i18n/*.json |
13 new keys × 10 locales |
CHANGELOG |
[FEATURE GAP] - #1026 entry |
images/issue-1026-spec-tree.png |
the rendered tree |

-
Task #1028 — spec / requirement detail deep links — the legacy tree node
href(REQ_SPEC_MGMT/REQ_MGMT) ported to a per-row eye link intoreqSpecView.html/reqView.html, gated onmgt_view_req.