Skip to content

Test Plan with Custom Fields Report Modernized

opencode edited this page Sep 8, 2026 · 7 revisions

Test Plan with Custom Fields Report — Modernized Screen

Modernization of Test Plan with Custom Fields (lib/results/testPlanWithCF.php) — GitHub issue #739.

The legacy Smarty screen is replaced by a standalone Dashio page (gui/templates/results/tplanWithCF.html) backed by a plain-PHP REST BFF action inside api/reports/index.php (action=tplan_with_cf). The ASIDE Reports → Test Plan with Custom Fields entry now points to the new HTML screen when a test plan is selected.

Path: Reports → Test Plan with Custom Fields URL: gui/templates/results/tplanWithCF.html?tproject_id=<id>&tplan_id=<id> BFF API: api/reports/index.php?action=tplan_with_cf&tproject_id=<id>&tplan_id=<id> Right: testplan_metrics enforced server-side (same as legacy).


Table of Contents

  1. What the screen does
  2. REST API Reference
  3. Legacy parity notes
  4. i18n Keys
  5. Security
  6. Testing

1. What the screen does

Feature Legacy behavior Modern implementation
Page load testPlanWithCF.php loads CF definitions via cfield_mgr::get_linked_cfields_at_testplan_design() BFF action fetches same CF definitions, returns them as cf_columns array
Empty state Warning message "There are no test cases on this test plan, with custom fields ENABLED ON Test Plan Design" Same warning message shown in info panel, no DataTable rendered
Results table ExtTable with dynamic columns for each CF, grouped by Test Suite DataTables with sort, search, pagination; grouped by Test Suite path (RowGroup extension), CF columns; extra Test Suite data column hidden
Column sorting Ext grid: EVERY column (Test Suite, Test Case and each custom-field column) is sortable: true; default sort is Test Case ASC (setSortByColumnName('test_case'), sortDirection='ASC') Same — all CF columns are orderable: true in the DataTables config (issue #865); clicking any CF column header sorts the rows by that CF value A→Z / Z→A; default order remains Test Case ASC
Group toolbar ExtTable toolbar: expand/collapse groups button + show all columns button, storeTableState=true Dashio toolbar in section header: Expand all groups, Collapse all groups, Show all columns buttons + match-count badge
Group collapse ExtTable expand/collapse per group; hidden rows stay in result set (filterable) Group headers include chevron + "(N items)"; click a header to collapse/expand that group; hidden rows remain in the DataTables result set
CF values Rendered from CF design values per testplan, filtered rows with all-empty CFs Same data shape; cf_columns drives column headers, rows with all-empty CF values filtered out
Edit link openTCEditWindow() popup to test case editor Edit icon opens tcEdit.html?tcase_id=&tproject_id= (the test case editor) in new window
Footer info Static "Generated by TestLink on ..." text below table Italic info text + "Generated on YYYY-MM-DD HH:MM:SS" + elapsed time in footer
External IDs Correct single glue-char (e.g. "TPWCF-1") Same — buildExternalIdString($prefix, ...) (fix #860 corrected double-glue)
Filtering Ext GridFilters plugin: per-column string filter box under each header (Test Suite, Test Case, each CF column) Per-column footer filter inputs (one under each visible column: Test Case + every custom-field column), wired to DataTables dt.column(i).search() — same per-column behavior (#864)
Reset Filters Ext toolbar "Reset Filters" button (filters.clearFilters()) clears all active column filters at once "Reset Filters" toolbar button clears every column search + footer inputs + redraws; hidden until any column filter is active (#864)
Locale Server-side Smarty lang Client-side TLi18n module; 18 locale switcher

2. REST API Reference

All routes require an authenticated session; callers without testplan_metrics get 403.

GET api/reports/index.php?action=tplan_with_cf

Returns test cases with Test Plan Design custom field values.

Query parameters:

Parameter Required Description
tproject_id Yes Test project ID
tplan_id Yes Test plan ID

Response:

{
  "status": "ok",
  "hasData": true,
  "tproject_id": 1,
  "tplan_id": 10,
  "tproject_name": "TP CF Test",
  "tplan_name": "Test Plan CF",
  "cf_columns": [
    { "id": "CF_TP_Design", "label": "CF TP Design", "name": "CF_TP_Design" }
  ],
  "rows": [
    {
      "tcase_id": 3,
      "tc_external_id": 1,
      "external_id": "TPWCF-1",
      "tcase_name": "Test Case CF 1",
      "suite_path": "Test Suite CF",
      "cfields": { "CF_TP_Design": "Option A" }
    }
  ],
  "warning_msg": "",
  "elapsed_time": 0.01,
  "generated_on": "2026-09-04 16:39:37"
}

Error response (no data):

{
  "status": "ok",
  "hasData": false,
  "warning_msg": "There are no test cases on this test plan, with custom fields ENABLED ON Test Plan Design",
  "elapsed_time": 0,
  "generated_on": "2026-09-04 16:39:37"
}

3. Legacy parity notes

  • CF definitions fetched via same cfield_mgr::get_linked_cfields_at_testplan_design() path
  • CF values joined via testplan_tcversions.id (link_id) — same as legacy
  • getPathLayered() used for Test Suite path display
  • Rows with all-empty CF values are filtered out (legacy parity)
  • Edit link opens tcEdit.html?tcase_id=&tproject_id= (direct editor, same as legacy #848 fix)
  • External IDs use single glue-char via buildExternalIdString($prefix, ...) (#860 fix)
  • Footer shows italic info text + "Generated on" timestamp + elapsed time (#858 #859 fixes)
  • Per-column string filters under each visible column header (Test Case + every custom-field column) using DataTables column().search() — mirrors the legacy Ext GridFilters filter:{type:'string'} (Refs #864); the hidden Test Suite (group-by) column keeps a hidden footer input like the legacy group-by filter
  • "Reset Filters" toolbar button clears every column search + all footer inputs at once — mirrors the legacy filters.clearFilters() toolbar action (Refs #864); the button is shown only while at least one column filter is active
  • Every custom-field column is orderable: true — clicking its header sorts all rows by that CF value (ascending/descending), exactly like the legacy Ext grid where every column had sortable: true with a filter:{type:'string'} and the CF column model rendered {header:"Owner", dataIndex:'id_cf_Owner', filter:{type:'string'}, renderer: columnWrap, sortable: true} (Refs #865). The Test-Suite hidden column keeps the suite ascendant + Test Case ascendant default order (order: [[0,'asc'],[1,'asc']]), matching legacy setSortByColumnName('test_case') + sortDirection='ASC'
  • Multi-column sort — a "Multi sort" toolbar sits between the section header and the table. Any visible column header (Test Case + every custom-field column) can be dragged onto it: each drop creates a sort chip (default direction DESC, mirroring legacy createItem), and dropping several headers builds a combined multi-key sort applied via dt.order([...]).draw(). Chips can be re-ordered by dragging (drop on a later chip = insert-after, on an earlier chip = insert-before), toggled ASC/DESC by click, removed by × or shift+click (legacy button.destroy()), and all cleared by the Clear sorts button (reverts to [[0,'asc'],[1,'asc']]). Duplicate drops are rejected with a toast, mirroring legacy canDrop. This is the client-side port of the legacy Ext.ux.ToolbarReorderer + Ext.ux.ToolbarDroppable multi-sort feature (gui/templates/dashio/include/inc_ext_table.tpl:209-239, lib/results/testPlanWithCF.php:160-166) (Refs #866).

4. i18n Keys

All strings use TLi18n keys; no hardcoded text.

Key English value
tpwcf.header Test Plan with Custom Fields
tpwcf.forPlan for test plan
tpwcf.testProject Test Project
tpwcf.testCases test cases
tpwcf.matchCount Match count
tpwcf.editTC Edit Test Case
tpwcf.elapsed Elapsed
tpwcf.noData No test cases with custom field values found.
tpwcf.infoText This Report shows all test cases with any custom field set while adding test cases to test plan.
tpwcf.generatedOn Generated on
tpwcf.expandAll Expand all groups
tpwcf.collapseAll Collapse all groups
tpwcf.showAllColumns Show all columns
tpwcf.groupItem ({count} item)
tpwcf.groupItems ({count} items)
tpwcf.resetFilters Reset Filters
tpwcf.filtersCleared Filters cleared
tpwcf.columnFilterPlaceholder Filter
tpwcf.multiSortTitle Multi sort
tpwcf.multiSortHint Drag column headers here to sort by multiple columns; click a chip to toggle direction, drag chips to reorder, shift+click or X to remove.
tpwcf.multiSortClear Clear sorts
tpwcf.multiSortToggle Click to toggle ascending/descending; shift+click or X to remove
tpwcf.multiSortRemove Remove sort
tpwcf.multiSortDup Column is already in the sort list
tpwcf.multiSortCleared Sort cleared
tpwcf.sortDesc descending
common.sort Sort

Keys present in all 10 locale bundles (en, ro, de, fr, es, it, ja, pt, ru, zh).

5. Security

  • Session-based authentication enforced at BFF entry point
  • testplan_metrics right checked server-side before any DB query
  • tproject_id and tplan_id validated against user's allowed projects
  • All output escaped via esc() function in JavaScript rendering

6. Testing

Test suite #847 in tmp/TLU_Test_Cases.md — 8 test cases covering:

  • Group headers rendered per Test Suite path with "(N items)" count (RowGroup 1.4.1 via CDN)
  • Per-group header click collapses/expands the group (chevron toggles)
  • Expand all groups toolbar button re-shows all rows
  • Collapse all groups toolbar button hides all data rows
  • Show all columns toolbar button keeps all columns visible
  • i18n keys present in all 10 locale bundles
  • No JS console errors on data load / toolbar interactions
  • DataTable ready state + ordering by suite then test case preserved

Test suite TPWCF-2 in tmp/TLU_Test_Cases.md — 8 test cases covering per-column filters + Reset Filters (#864):

  • Footer renders one filter input per visible column (Test Case + each custom-field column)
  • Filtering the Owner column narrows rows to that owner only
  • Filtering the Test Case column narrows rows to the matching test case
  • Filtering a custom-field column (Tier) narrows rows by that CF value
  • "Reset Filters" button appears only when a column filter is active
  • "Reset Filters" clears every column search, empties the footer inputs, restores all rows
  • No JS console errors during filtering / reset interactions
  • No new Error/Warning in Event Viewer

Test suite #865 in tmp/TLU_Test_Cases.md — 6 test cases covering sortable CF columns (#865):

  • Custom-field columns report orderable: true in the DataTables config (no sorting_disabled class on their headers)
  • Clicking a CF column header sorts asc (A→Z) by the CF value
  • Clicking again sorts desc (Z→A) by the CF value
  • Default order on load stays Test Case ASC (order: [[0,'asc'],[1,'asc']])
  • DataTable order() reflects the CF column index + direction after each click
  • No new Error/Warning in Event Viewer after sort interactions

Test suite #866 in tmp/TLU_Test_Cases.md — 13 test cases covering multi-column sort (Refs #866):

  • Multi-sort toolbar renders above the table with label + hint, no initial chips
  • Dragging the Owner header onto the bar creates an Owner ↓ chip (default DESC), order [[2,'desc']]
  • Dragging a second header (Tier) builds the combined sort [[2,'desc'],[3,'desc']]
  • Clicking a chip toggles ASC/DESC
  • Dropping a duplicate column is rejected with a toast (legacy canDrop)
  • × and shift+click both remove chips (legacy button.destroy())
  • Dragging chips reorders their precedence (insert-before/after) and re-applies the sort
  • "Clear sorts" resets to the default [[0,'asc'],[1,'asc']] order
  • RowGroup headers stay consistent with the combined sort
  • Per-column footer filters keep working while a multi-sort is active
  • No JS console errors; no new Error/Warning in Event Viewer

Test suite TPWCF-1 in tmp/TLU_Test_Cases.md — 12 test cases covering:

  • External IDs show single glue-char (#860)
  • Info text displayed in footer (#858)
  • Generated timestamp shown in footer (#859)
  • Elapsed time shown in footer
  • Edit icon opens tcEdit.html (#848)
  • No-data state shows info text + timestamp
  • BFF returns generated_on field
  • BFF returns single glue-char IDs
  • i18n keys present in all 10 bundles
  • No new Error/Warning in Event Viewer
  • BFF early-return paths include generated_on
  • Syntax check passes

Previous test suite #18 — 9 test cases covering:

  • Screen load without PHP warnings
  • Data display with CF columns
  • Edit link opens test case editor
  • Locale switching translates labels
  • Empty state — no CF values
  • Error state — invalid plan
  • Filter/search works
  • Aside menu links to modernized screen
  • i18n keys present in all locales

Screenshots

Per-column filters + Reset Filters (Refs #864)

Owner column filtered to "Alice" — the per-column footer filter is active and the Reset Filters toolbar button is shown.

Test Plan with Custom Fields - per-column filters

Sortable custom-field columns (Refs #865)

Rows sorted by the Owner custom-field column (descending) — the header shows a sort arrow and all rows are re-ordered by their CF value (Zed corp → Mid corp → Alpha corp), matching the legacy Ext grid where every CF column was sortable: true.

Test Plan with Custom Fields - sortable CF columns

Multi-column sort: drag column headers to the toolbar (Refs #866)

The "Multi sort" bar with no sort keys selected — the drop target for column headers.

Test Plan with Custom Fields - multi-sort toolbar empty

The Owner and Tier column headers have been dragged onto the bar: two sort chips (Owner ↓, Tier ↓) are active and the grid is re-sorted by Owner then Tier (both descending), with the RowGroup headers reflecting the new order — the legacy Ext.ux.ToolbarDroppable multi-sort behavior.

Test Plan with Custom Fields - multi-sort applied

Clone this wiki locally