Bugfix Issue 1590 IssueTracker Delete Tooltip Key - sebiboga/testlink-upgraded GitHub Wiki
Bug fix β Issue #1590: Issue Tracker delete icon used an undefined label key
Symptom
The legacy Dashio Issue Tracker list rendered its per-row delete icon with
an empty tooltip, and every page load wrote one E_WARNING row per
unlinked tracker into the events table (the Event Viewer source).
Two distinct symptoms, one cause:
- Visible: the
fa-minus-circledelete icon appeared withtitle=""β no text on hover. - Invisible:
E_WARNING Undefined array key "testproject_alt_delete"landed inevents, once for every row that was able to display the icon.
Neither breaks the workflow: the icon renders, the delete_confirmation()
handler still fires, and the list still works. The defect is cosmetic plus
Event Viewer noise, and only affects users holding issuetracker_management
(right 31).
Entry point:
http://localhost:8082/lib/issuetrackers/issueTrackerView.php?tproject_id=1.
![]()
Environment and fixtures
- TestLink 2.0.1, PHP 8.3.35, MariaDB on the local CI instance, commit
pre-fix baseline
922e86e53(the default-branch commit the branch was cut from); the fix itself is0fcf6b793. - The database is freshly imported on every run, so
testprojectsandissuetrackersare both empty and must be recreated:
INSERT INTO testprojects (id,notes,color,active,option_reqs,option_priority,option_automation,options,prefix)
VALUES (1,'Repro project for #1590','#9BD9BD',1,0,0,0,'','REPRO');
INSERT INTO issuetrackers (name,type,cfg) VALUES ('ReproBugTracker1590',1,'');
INSERT INTO issuetrackers (name,type,cfg) VALUES ('ReproBugTracker1590-B',1,'');
INSERT INTO users (id,login,password,role_id,email,first,last,locale,default_testproject_id,active)
VALUES (90,'viewer1590',MD5('viewer1590'),1,'[email protected]','View','Er','en_GB',1,1);
admin/adminβ holds right 31issuetracker_management.viewer1590β used for the non-manager path.
β οΈ
issuetrackers.typemust be a real key oftlIssueTracker::$systems(lib/functions/tlIssueTracker.class.php:31).type=1(bugzilla/xmlrpc) works. A fixture withtype=0makes the screen return HTTP 500 and floodseventswith five unrelated warnings fromtlIssueTracker.class.php:170-171and:604-605. That is a separate pre-existing defect, not #1590 β see Known remaining issues below.
Reproduction before the fix
# login (the login POST uses tl_login / tl_password, not login / password)
curl -s -c cj2.txt http://localhost:8082/login.php -o /dev/null
curl -s -b cj2.txt -c cj2.txt -X POST -d "tl_login=admin&tl_password=admin" \
http://localhost:8082/login.php
# render the screen
curl -s -b cj2.txt "http://localhost:8082/lib/issuetrackers/issueTrackerView.php?tproject_id=1" -o itv.html
# read the tooltip and the Event Viewer
grep -o 'title="[^"]*"' itv.html
mysql -h 127.0.0.1 -utestlink -ptestlink testlink \
-e "SELECT id,log_level,description FROM events ORDER BY id DESC LIMIT 3;"
Measured pre-fix result:
view=200 size=12306
$ grep -o 'title="[^"]*"' itv.html
title="Check connection" <- the BTS env-check cell, correct
title="" <- the delete icon: EMPTY
+----+----------+---------------------------------------------------------------+
| id | log_level | description |
+----+----------+---------------------------------------------------------------+
| 24 | 2 | E_WARNING Undefined array key "testproject_alt_delete" |
| | | - in gui/templates_c/2563b481..._0.file.issueTrackerView.tpl.php
| | | - Line 134 |
+----+----------+---------------------------------------------------------------+
Scaling proof β exactly one warning per row that can display the icon:
| unlinked trackers | grep -c 'fa-minus-circle' |
cumulative events rows mentioning the key |
|---|---|---|
| 1 | 1 | 1 |
| 2 | 2 | 3 (1 previous + 2 new) |
Root cause chain
-
gui/templates/dashio/issuetrackers/issueTrackerView.tpl:12-16β the template's single{lang_get var='labels' ...}call populates$labelswithth_issuetracker, th_issuetracker_type, th_delete, th_description, menu_assign_kw_to_tc, title_issuetracker_mgmt, btn_create, alt_delete, th_issuetracker_env, check_bts_connection, bts_check_ok, bts_check_ko.alt_deleteis loaded.testproject_alt_deleteis not. -
gui/templates/dashio/issuetrackers/issueTrackerView.tpl:81β inside{if $gui->canManage != ""}/{if $item_def.link_count == 0}the delete icon reads a key that was never loaded:<i class="fas fa-minus-circle" title="{$labels.testproject_alt_delete}" -
Smarty compiles that reference to a raw array read with no guard β no
isset(), no|defaultβ confirmed in the generated cachegui/templates_c/2563b481caa80ddabd651341d294cdd1f0429b57_0.file.issueTrackerView.tpl.php:134(pre-fix artifact βgui/templates_c/is gitignored and has since been regenerated withalt_deleteon that line):<?php echo $_smarty_tpl->tpl_vars['labels']->value['testproject_alt_delete'];?>PHP 8 therefore emits
E_WARNING: Undefined array keyand echoes the empty string. That single line produces both halves of the symptom. -
TestLink's error handler persists the warning to the
eventstable, which is why the defect shows up in the Event Viewer as well as on screen.
Why it breaks now: it does not β it is pre-existing, not a regression.
issueTrackerView.tpl has always used {$labels.testproject_alt_delete} while
only ever loading alt_delete, and the warning reproduces on the untouched
branch. The sibling codeTrackerView.tpl was already corrected (by #1580 for
the key, #1582 for the column contract); this Issue Tracker twin was simply
missed by that sweep. The #1591 CHANGELOG entry explicitly left it open as
"the still-undefined testproject_alt_delete tooltip key remains #1590".
The key is not missing β the reference is wrong
An important distinction that rules out the obvious wrong fix:
testproject_alt_delete is a real, fully translated string in every locale
bundle. It means "Delete the Test project and all related data."
(locale/en_US/strings.txt:1635).
$ grep -rl testproject_alt_delete --include=*.tpl gui/templates/ # pre-fix
gui/templates/dashio/issuetrackers/issueTrackerView.tpl <- the bug
gui/templates/dashio/project/projectView.tpl <- correct user
gui/templates/tl-classic/project/projectView.tpl <- correct user
projectView.tpl:31 loads the key and projectView.tpl:153 uses it β both
consistent, both left untouched. So adding the key, or renaming it, would
put the semantically wrong string ("Delete the Test project and all related
data.") on a per-issue-tracker delete button.
The fix
One line, in
gui/templates/dashio/issuetrackers/issueTrackerView.tpl:81:
- <i class="fas fa-minus-circle" title="{$labels.testproject_alt_delete}"
+ <i class="fas fa-minus-circle" title="{$labels.alt_delete}"
Why this method. alt_delete is already loaded by this very template at
line 15, resolves to "delete" in every locale bundle
(locale/en_US/strings.txt:77, locale/en_GB/strings.txt:71), and is the
identical key the sibling codeTrackerView.tpl:78 uses for the same icon on
the sibling screen (fixed by #1580). One line, zero new translation work, zero
risk to any other screen.
Alternatives rejected:
| Alternative | Why rejected |
|---|---|
Add testproject_alt_delete to the {lang_get} list |
Wrong semantics β the tooltip would read "Delete the Test project and all related data." on a tracker delete button. |
Add |default to silence the warning |
Hides the symptom; the tooltip stays empty. |
| Rename the i18n key globally | Breaks the two correct projectView.tpl call sites, which legitimately want that string. |
php -l the template |
Useless β .tpl files are Smarty, not PHP; the real gate is the regenerated templates_c PHP. |
Verification
- Primary symptom β the warning is gone. Baseline
testproject_alt_deleterows cleared, screen re-rendered, re-queried: zero rows. - Primary symptom β the tooltip is restored. With two unlinked trackers:
title="Check connection",title="delete",title="Check connection",title="delete"(wastitle=""). - Live browser DOM (not curl):
[{"title":"delete","hasOnclick":true},{"title":"delete","hasOnclick":true}]β thedelete_confirmation(...)handler is untouched on both icons. - Icon count preserved:
grep -c 'fa-minus-circle'β2, so nothing was hidden to silence the warning.
Full regression matrix (9/9 PASS, recorded in tmp/TLU_Test_Cases.md):
| # | Case | Result | Verdict |
|---|---|---|---|
| 1 | admin, 1 unlinked tracker | HTTP 200, 1 icon, title="delete", 0 new Warning rows |
PASS |
| 2 | admin, 2 unlinked trackers | HTTP 200, 2 icons, both title="delete", 0 new rows |
PASS |
| 3 | tracker linked (testproject_issuetracker) |
icons 2 β 1; the linked row correctly loses the icon; 0 new rows | PASS |
| 4 | non-manager (canManage empty) |
page renders fully (11556 bytes), 0 delete icons β the guard is intact; 0 new rows | PASS |
| 5 | sibling Code Tracker view | HTTP 200, unchanged, 0 new rows | PASS |
| 6 | projectView.tpl β the legitimate owner of testproject_alt_delete |
view=200 (16455 bytes), 1 delete icon, title="Delete the Test project and all related data." β the correct long string survives, 0 new rows |
PASS (live) |
| 7 | locales de_DE / fr_FR / es_ES / ro_RO / it_IT |
de_DE β title="lΓΆschen"; fr_FR/es_ES localized; ro_RO/it_IT (no key) β graceful en_GB fallback "delete"; 0 new Warning rows |
PASS |
| 8 | live browser DOM | both icons title="delete", hasOnclick: true |
PASS |
| 9 | Event Viewer after the whole matrix | 0 new log_level IN (1,2,3) rows from this screen |
PASS |
Gotchas found while reproducing (each cost time)
issuetrackers.typemust be a valid system key.type=0β HTTP 500 and five unrelated warnings fromtlIssueTracker.class.php:170-171,604-605.- Locale tests need a NEW SESSION.
$_SESSION['locale']is cached, so updatingusers.localealone keeps rendering English β that produced a false negative on the first attempt at case 7. Use a fresh cookie jar per locale. - Case 4 is untestable with the stock role matrix.
role_rightsgrantsissuetracker_view(32) andissuetracker_management(31) only to role 8 (admin); a tester/leader account is redirected before the template is reached. I inserted(role_id=7, right_id=32)temporarily and removed it again β verified afterwards withSELECT * FROM role_rights WHERE role_id=7;(the32row is gone). If a future run finds(7,32)already present, that is a leftover, not the stock matrix. - A
testprojectsrow is not enough for project-scoped screens. Inserting intotestprojectsalone leavesnodes_hierarchyempty, andtestproject::get_accessible_for_user()(testproject.class.php:565-573) INNER JOINsnodes_hierarchyβ soprojectView.phpsees$gui->itemQty == 0and answers with a 161-byte redirect stub toprojectEdit.php?doAction=createinstead of the list. My first case-6 attempt looked like "the template is gone" because of this; the template is live and reachable. AddINSERT INTO nodes_hierarchy (id,name,parent_id,node_type_id,node_order) VALUES (1,'REPRO',0,1,1);to the fixture. - Session expiry is easy to misread. An expired session returns a 204-byte
login.php?note=expiredstub that looks like an empty result set. - The
gui/templates_c/Smarty cache recompiles automatically on template mtime change; no manual purge is needed before re-testing. The compiled-PHP excerpt quoted above is therefore a pre-fix artifact β that directory is gitignored and has since been regenerated withalt_deleteon line 134.
Known remaining issues (found while testing, not fixed here β out of scope)
Per ai/FIX-ISSUE.md Β§3 these are separate defects and are not touched by
this one-line fix. They are recorded here so the next run inherits the
evidence.
issuetrackers.typeoutsidetlIssueTracker::$systemsmakes the screen return HTTP 500 and logs 5 warnings per render (tlIssueTracker.class.php:170-171,604-605:Undefined array key 0andTrying to access array offset on null). Reachable whenever a tracker row carries a type that is absent from, or disabled in, the$systemsmap. Filed as a separatebugissue (#1617) β note that #1597 covers the codetracker variant only and is already closed, so nothing was tracking the issuetracker variant.- 7 of 19 locale bundles have no
alt_deletekey βes_AR,fi_FI,id_ID,it_IT,ko_KR,ro_RO,ru_RU. They fall back to en_GB and log alog_level 32LOCALIZATION info event, not a Warning. This is pre-existing and shared with the already-fixedcodeTrackerView.tpl; it is a translation-completeness gap, not a code defect.
Files changed
gui/templates/dashio/issuetrackers/issueTrackerView.tplβ the fix, 1 line (+1 / -1).docs/screenshots/issue-1590-issueTrackerView-delete-tooltip.pngβ post-fix evidence.docs/Bugfix-Issue-1590-IssueTracker-Delete-Tooltip-Key.mdβ this mirror.CHANGELOGβ one-line 2.0.1 summary.tmp/TLU_Test_Cases.mdβ regression suite (committed ind109806f5).tmp/wiki-repo/Bugfix-Issue-1590-IssueTracker-Delete-Tooltip-Key.mdβ the GitHub Wiki page with the screenshot.
Result
Issue #1590 is fixed. The delete icon on the Issue Tracker list now carries the
localized delete tooltip for managers, the E_WARNING "Undefined array key testproject_alt_delete" is gone from the Event Viewer, and the sibling Code
Tracker screen plus the two projectView.tpl files that legitimately use that
key are all untouched β the whole fix is a single line in one template. The
production and test commits were pushed on fix/issue-1590 as 0fcf6b793 and
d109806f5; the documentation phase is tracked by the same branch and issue.