Task Issue 963 issuetracker Link Count Delete Gating - sebiboga/testlink-upgraded GitHub Wiki
Task 963 โ Restore link-count delete gating for linked trackers in the Issue Trackers screen (gap vs legacy)
Issue: #963 Status: IMPLEMENTED & VERIFIED (2026-09-24)
The gap
Legacy issueTrackerView.tpl:78-83 renders the per-row delete icon ONLY when
the row is NOT linked to any test project:
{if $gui->canManage != "" && $item_def.link_count == 0}
<i ... onclick="delete_confirmation({$item_def.id},...);"></i>
{/if}
link_count is filled by tlIssueTracker::getAll()
(output=add_link_count, lib/functions/tlIssueTracker.class.php:591-623) with a
COUNT(0) GROUP BY id over testproject_issuetracker. Deleting a linked tracker
is additionally double-guarded in the model
(tlIssueTracker::delete(), tlIssueTracker.class.php:291-335) with
Failure - id %s is linked to: testproject '%s' with id %s.
The modern screen dropped this UI gate: the BFF requested
getAll(output=add_link_count) but trackerToJSON() silently dropped
link_count, and the HTML always rendered an active trash button on every row.
So a linked tracker kept a live delete button that ALWAYS failed with the
model's linked-message guard (HTTP 400) โ worse than legacy, which hid it.
Investigation (measured)
- admin/admin against a fresh import: tracker Bugzilla 963 is linked to test
project
TC963-prj(link_count=1); tracker Free 963 is unlinked (link_count=0). GET /api/issuetrackerreturned both items WITHOUTlink_count.- Clicking trash on Bugzilla 963 โ confirm โ
DELETE /1โ HTTP 400Failure - id 1 is linked to: testproject 'TC963-prj' with id 1โ record NOT removed. - Clicking trash on Free 963 โ confirm โ delete โ record IS removed (SELECT confirms the row is gone).
- Legacy hides the icon entirely for linked trackers; modern showed an always failing button.
Fix
BFF api/issuetracker/index.php:
trackerToJSON()exposeslink_count(int) andlinks(list of linked test-project names, viagetLinkSet(), so the UI can tell linked from free).
HTML gui/templates/issuetracker/issuetrackerView.html:
- Linked tracker (
link_count>0): toolbardeleteaction renders disabled (greyedcursor:not-allowed, noonclick), with a localized tooltip listing the linking test projects. - Unlinked tracker: active delete action (with confirm dialog) as before.
i18n โ new key it.msg.cannotDeleteLinked in all 10 locale bundles
(gui/templates/i18n/{en,de,es,fr,it,ja,pt,ro,ru,zh}.json), e.g. Romanian
"Nu se poate ศterge โ รฎncฤ legat de proiecte de test". All bundles validated
with python3 -m json.tool.
Verification (browser, admin + view-only user)
- Linked tracker (Bugzilla 963): delete action greyed
disabled(cursor:not-allowed), noonclick; clicking triggers NO confirm; record stays in DB. Matches legacy (which hides the icon entirely when link_count>0). - Unlinked tracker (Free 963): delete action active; confirm โ accept โ row removed and gone from DB; confirm โ dismiss โ row kept.
- View-only user (
issuetracker_viewrights only): the actions column and all delete/edit icons are hidden; table still renders. Matches legacyissueTrackerView.tplwhich gates the actions toolset oncanManage.
Screenshots
Modern row with a linked tracker โ delete action disabled with linking-project tooltip:

Test cases
Suite in docs/TLU_Test_Cases.md โ "Suite 963", 6/6 PASS.
Files
api/issuetracker/index.phpgui/templates/issuetracker/issuetrackerView.htmlgui/templates/i18n/*.json(10 bundles)docs/Task-Issue-963-issuetracker-Link-Count-Delete-Gating.md(this mirror)