Test Plan Milestones - sebiboga/testlink-upgraded GitHub Wiki
Modernization of Test Plan Milestones (lib/plan/planMilestonesView.php +
lib/plan/planMilestonesEdit.php + planMilestonesCommands.class.php) —
GitHub issue #647.
The legacy Smarty screens are replaced by a standalone Dashio page
(gui/templates/plans/planMilestones.html) backed by a plain-PHP REST BFF
(api/milestones/index.php), following the same pattern as the other
modernized screens. The aside menu entry Test Case Execution → Milestones
now points to the new HTML screen (switched in lib/functions/common.php,
both the milestonesView link and the old mileView launcher entry).

| Feature | Legacy behavior | Modern implementation |
|---|---|---|
| List milestones of current test plan (ordered by target date) |
testplan_planning required (checkGUISecurityClearance rightsAnd) |
GET /api/milestones/index.php/list?tplan_id=N (403 otherwise); aside visibility still gated by testplan_milestone_overview
|
| Create milestone (name, target date, optional start date, priority %) | edit form → do_create; duplicate name per plan; valid dates; target not in past; target ≥ start; % 0–100 |
POST …/create?tplan_id=N returning 400 + stable error codes for every validation branch |
| Edit milestone in modal | name click → edit / do_update
|
row-name button opens prefilled modal → PUT …/update/{id}; past-target check only when date changed (BUGID parity) |
| Delete milestone with confirm dialog | delete icon → delete_confirmation() → doDelete
|
trash icon → Bootstrap confirm modal → DELETE …/delete/{id}
|
| Priority columns High/Medium/Low vs single % column | depends on project option testPriorityEnabled; when disabled only medium is editable (hidden 0 fields) |
same layout switch driven by BFF-provided flag; modal swaps 3 inputs for one input |
| Live "Status of Milestones" report |
tlTestPlanMetrics::getMilestonesMetrics() table: achieved % per priority vs expected %, red/green coloring, overall % |
identical computation reused server-side; client renders green/red badges + (done/total) counters + expected % |
| Execution window semantics | only executions within [start_date, target_date] count |
inherited from the shared metrics class (verified live: execution before start date is excluded) |
| Audit trail | audit_milestone_created/saved/deleted |
identical events written by the BFF |
Edit modal (prefilled; unique-name hint, target/start dates, A/B/C percentage inputs):

Delete confirmation dialog:

- Everything:
testplan_planning— exactly what the legacy controller enforces onplanMilestonesView.php/planMilestonesEdit.php. - The aside menu shows the entry only for users with
testplan_milestone_overview, but the screen/BFF additionally requiretestplan_planning(a read-only user without it gets HTTP 403 on every route).
- Error messages are stable codes (
milestone_name_already_exists,warning_invalid_date,warning_milestone_date,warning_target_before_start,warning_empty_milestone_name,warning_invalid_percentage) localized client-side via thems.*i18n keys present in all 10 locale bundles. -
Percentage mapping quirk preserved: in legacy the edit-form field labeled
High priority % posts as
low_priority_tcases, while reads alias DB columnaashigh_percentage. The modern BFF maps request values so the user-visible round-trip matches legacy exactly (enter X under High → read back X under High). - Dates are stored ISO
YYYY-MM-DD; empty start date persists as0000-00-00(BUGID 3907 parity). - Plans without builds render no metrics section (
getMilestonesMetricsreturns[], cf. issue #634 fix). - Test suite:
tmp/TLU_Test_Cases.mdSuite 647 — 18/18 PASS. -
Event history (added 2026-09-07, Refs #1149): the edit modal now shows a
Show event history button (hidden while creating a new milestone) for users
holding
mgt_view_events. It mirrors the legacyplanMilestonesEdit.tplshowEventHistoryFor(id,'milestones')icon and theplatformsView.htmlpattern: hidden#eventhistoryform postsobject_id/object_type=milestonesto/gui/templates/eventviewer/eventviewer.html. The BFF/listexposesrights.canViewEvents; newms.showEventHistorykey added to all 10 locale bundles. See GitHub issue #1148/#1149.

-
SCREEN-COMPARE (2026-09-07, Refs #1148): re-verified against legacy
lib/plan/planMilestonesView.php/planMilestonesEdit.phpon seeded projectMS Demo Project(planMS Plan One, milestones MS Alpha/Beta/Gamma, 4 TCs + executions for live metrics, no-rights role-3 usermsnorg). Confirmed full parity (list + "Status of Milestones" achieved-vs-expected report, create/edit/ delete + audit CREATE/SAVE/DELETE rows, duplicate-name/past-date/invalid-%/ empty-name validation,testplan_planning403). Only gap was the dropped event-history icon → fixed (#1149) and browser-verified (opens eventviewer filteredmilestones #4, shows the audit SAVE trail). Test suite:tmp/TLU_Test_Cases.mdSuite 1148 — 11/11 PASS.

-
Legacy grid DataTables contract (added 2026-09-27, Fixes #1650): the legacy
screen
lib/plan/planMilestonesView.php→gui/templates/dashio/plan/planMilestonesView.tplalready includedDataTables.inc.tplwithDataTablesSelector="#item_view"(tpl:36), but its table was<table class="common" width="100%">with no id and no<thead>— so$('#item_view').DataTable(config)was a silent no-op on an empty jQuery set (no console error). Measured before the fix:#item_view= 0, no.dataTables_length/.dataTables_filter/.dataTables_info,theadcount 0, while thelengthMenu/stateSaveconfig was emitted into the page. The[planMilestonesView]config added by #1594 (item_view_table="table table-bordered",item_view_thead="thead-dark",pagination_length=20) had no consumer. Fixed by porting the grid to the same contract the sibling Dashio list screens use (buildView.tpl:86,planView.tpl:96,rolesView.tpl:73):<table class="{#item_view_table#}" id="item_view">, header row in<thead class="{#item_view_thead#}">, data rows in<tbody>, and the Delete action column markeddata-orderable="false" class="icon_cell"so it stays out of sorting and out of the global search index. The separate "Milestones Report" (simple_tableruler) table is deliberately untouched. After the fix (both project variants,testPriorityEnabled1 → 7 columns and 0 → 5 columns):#item_view= 1 with classtable table-bordered dataTable no-footer, theadthead-dark,#item_view_wrapperpresent, page-length menu20/40/60/All,.dataTables_info"Showing 1 to 3 of 3 entries", search filters, Name sorting asc/desc,stateSavepersists the page length across reloads, deletedelete_confirmation()handlers andplanMilestonesEdit.phplinks unchanged. The modernized screengui/templates/plans/planMilestones.htmlwas not affected — it already initialises DataTables on#msTable/#reportTable; this gap was confined to the legacy template that is still shipped (cf. the open "Delete legacy …" cleanup tasks). Test suite:tmp/TLU_Test_Cases.mdSuite 1650 — 22/22 PASS; Event Viewer 0 new ERROR/WARNING. See GitHub issue #1650.
