TestCase Editor Design Custom Fields - sebiboga/testlink-upgraded GitHub Wiki
The modern Test Case Editor (gui/templates/testcases/tcEdit.html +
api/testcasesedit/index.php) regains the legacy design-time custom fields
the 1.9.20 editor rendered in the design view.
Legacy testcaseEdit.php?doAction=edit renders ONE OR MORE custom-field
blocks (gui/templates/dashio/testcases/tcEditViewer.inc.tpl:47-137), each
covering a subset of the CFs linked to the test project, positioned at the
7 legacy design-time locations; values live in cfield_design_values and are
persisted on save by testcaseCommands::show() after update() via
cfield_mgr->design_values_to_db() (lib/testcases/testcaseCommands.class.php:1228-1235).
The modern editor shipped no custom-field rendering and no persistence — the
edit payload carried neither per-location HTML nor CF metadata, so all
design-time CFs silently disappeared and their saved values stayed frozen.
BFF api/testcasesedit/index.php:
-
tceDesignCustomFields()— renders per-location legacy input HTML viatestcase::html_table_of_custom_field_inputs($tcaseId, null, 'design', '', $tcverId, null, $tprojId, $locFilter)for every entry ofbuildCFLocationMap()(skip_location is left true, so hiddenhide_because_is_used_as_variableCFs are not rendered), plus a structuredmetalist fromget_linked_cfields_at_design(id / name / label / type / type_verbose / possible_values / required / location / current value fromcfield_design_values). -
editpayload gainscustom_fields: {locations, html, meta}. -
updatehandler: whenbody.custom_fieldsis a hash shaped exactly like the legacy$_REQUEST(custom_field_<type>_<id>…), rebuilds the project design-CF map viacfield_mgr->getLinkedCfieldsAtDesign(['tproject_id'=>..,'enabled'=>1,'node_type'=>'testcase'], ['location'=>[1..7]])and persists throughcfield_mgr->design_values_to_db($body['custom_fields'], $tcverId, $cfMap). The location filter keeps hidden variable-CFs (location 8) whose values are never submitted by the editor from being wiped by_build_cfield's seed-and-overwrite logic.
HTML gui/templates/testcases/tcEdit.html:
- 7 location blocks:
cf_after_title,cf_before_summary,cf_after_summary,cf_before_preconditions,cf_after_preconditions,cf_before_steps_results,cf_standard_location, styled with.design-cf-blockDashio CSS. -
renderCustomFields()injects each served block verbatim inside an<form onsubmit="return false" novalidate>wrapper — the legacy markup (and itsthis.form.<name>references used by the text-area counter) works without a real<form>, andnovalidateprevents native HTML5 constraint bubbles from ever intercepting save. -
window.textCountershim (mirror ofgui/javascript/validate.js:235) andwindow.showCalshim (native date-picker overlay writing back through the legacy strftime format) so the served legacy date/textarea markup is fully interactive. -
collectCustomFields()walks the injected block controls and produces the legacy hash (checkbox/radio groups →[]arrays, empty groups →''so the stored row is deleted);validateCustomFields()runs the required gate plus numeric/float/email checks (mirror ofexecSetResults.html); both are wired intodoSave(custom_fieldsin the update payload). -
#formCardchange-tracking selector extended tocheckbox/radio/email/number/date.
i18n: tcedit.cfRequired (The custom field "{field}" is required.) and
tcedit.cfInvalid added to ALL 10 locale bundles.

- Browser-verified on fixture
tmp/fixtures_1312.php(TCEDDemo, tcA v2): Severity (list) + Priority Flag (checkbox) render after preconditions using the exact legacy markup; Notes (textarea) renders at standard location. - UI save round-trips all three values through
cfield_design_values; reload re-renders the saved state. - Required gate measured: empty required field blocks save with
The custom field "Severity" is required. - Browser console clean (only pre-existing a11y "no label" issues), Event Viewer shows only INFO audit rows for the feature saves.
- Suite 1312 7/7 PASS in
tmp/TLU_Test_Cases.md.
- Bug #1571: design-time datetime CF values are wiped on save because
legacy
cfield_mgr::_build_cfield(lib/functions/cfield_mgr.class.php:1924-1973) reads$value['input']from a last-suffix-wins array →E_WARNING+DELETE. Filed separately (repro + measured evidence); fix belongs in the legacy class, outside this task's scope.