Task Issue 1375 ReqEdit Revision On Save - sebiboga/testlink-upgraded GitHub Wiki
Task 1375 — reqEdit: revision-creation + log-message prompt on save (gap vs legacy)
Issue: #1375 (Refs #798)
Status: IMPLEMENTED (2026-09-16) — branch task/issue-1375
The gap
The modern Requirement Editor (gui/templates/requirements/reqEdit.html, BFF
api/reqedit/index.php) dropped the legacy revision-on-save flow:
- Legacy (
lib/requirements/reqCommands.class.phpdoUpdate()): after saving a version, it runssimpleCompare()against the previous row. A change of status/type/expected_coverage/req_doc_id/title →diff['force'], a scope-only change →diff['suggest']. The TPL (reqEdit.tpl) then shows theprompt4revision/prompt4logdialogs asking for a log message; on confirm a new revision is created for the version viarequirement_mgr::create_new_revision()with that log message (req_versions.revision++, snapshot row inreq_revisions). An attribute-only change always forced the revision prompt; a scope-only change merely suggested it (Cancel = save without revision). - Modern (pre-fix): the save handler called
requirement_mgr::update()with nocreate_revision/log_messageparameters, no revision was ever created, nolog_messagerecorded and no dialog existed.
Legacy source of truth
lib/requirements/reqCommands.class.php:301-377—doUpdate():simpleCompare()(force/suggest/nochange),prompt_for_log,suggest_revision, second-passupdate(..., $createRev, $log_message).lib/requirements/reqCommands.class.php:804-854—simpleCompare()field arrays:force_revision = {status:reqStatus, type:reqType, expected_coverage:expected_coverage, req_doc_id:reqDocId, title:title};suggest_revision = {scope:scope}; precedence force > suggest, thennochange.lib/functions/requirement_mgr.class.php:430-517—update()params 13/14 =$create_revision,$log_msg; when true it callscreate_new_revision().lib/functions/requirement_mgr.class.php:2954-2998—create_new_revision():req_revisionssnapshot (copy_version_as_revision),req_versions.revision++,log_messagestored,creation_ts=now,modifier_id=NULL.gui/templates/dashio/requirements/reqEdit.tpl:115-151— theprompt4log(mandatory 'Revision Log' / 'Please add a log message') andprompt4revision('Attention!! - Do you want to create a new revision?' / 'You changed ONLY the scope…') dialogs.locale/en_US/strings.txt:1000-1003—revision_log_title,please_add_revision_log,suggest_create_revision_html,warning_suggest_create_revisionstrings.
Modern implementation (port)
Backend api/reqedit/index.php
- New
simpleReqCompare($old, $posted)porting legacysimpleCompare(): returns'force'(status/type/expected_coverage/req_doc_id/title changed),'suggest'(only scope changed), ornull(nochange). The legacy custom-field comparison is skipped — the modern screen has no CF section. - The
POST ?action=saveedit-mode branch:- loads the pre-save row via
requirement_mgr::get_by_id($reqId, $versionId), - computes
revision_prompt, - still persists the data on the first round-trip (legacy first-submit
parity) and returns
revision_prompt+revision_createdin the JSON, - honours body
create_revision+log_messageby forwarding them intoupdate(..., null, null, 0, (bool)$createRevision, $logMessage)→ on confirm the manager runscreate_new_revision()with the log. - When the body explicitly carries
create_revision,revision_promptis forced tonullso the second round-trip never re-prompts (no loop).
- loads the pre-save row via
Frontend gui/templates/requirements/reqEdit.html
- Save split into
doSave(payload, onOk)(the single AJAX call, reused by both round-trips) andshowSaved(r)(info bar:reqe.revisionCreatedwhenrevision_created=1, elsereqe.saved). save()inspectsr.revision_prompt:'suggest'→window.prompt(reqe.revScopePrompt)— OK = second round-trip withcreate_revision:true, log_message; Cancel =showSavedwithout a revision (legacysave_rev=0parity: the scope change is still saved).'force'→window.prompt(reqe.revLogPrompt)— OK = revision + log; Cancel = save only (legacy prompt4log dismissal parity).null→ plain save (create mode, or nothing changed).
i18n — new keys in all 10 locale bundles (en/ro/de/es/fr/it/ja/pt/ru/zh):
reqe.revisionCreated, reqe.revScopePrompt, reqe.revLogPrompt. Strings
mirror revision_log_title / please_add_revision_log /
warning_suggest_create_revision / suggest_create_revision_html.
Verification (browser, headless Chrome — admin/admin, fresh DB)
Fixture: test project #1 Revisions demo (requirements ON), spec REV-SPEC-1,
requirement RE-1 (id=4, version_id=5, initial revision=1).
| Case | Result |
|---|---|
| Scope-only change → Save ⇒ "Attention!! - Do you want to create a new revision?" prompt | PASS |
Prompt OK + log → second POST create_revision:true; revision_created:1; DB revision=2, log_message stored, 1 row in req_revisions |
PASS |
Scope change → prompt → Cancel ⇒ saved, no new revision (revision unchanged, req_revisions count unchanged) |
PASS |
| Title (attribute) change → Save ⇒ "Revision Log / Please add a log message" (force) prompt | PASS |
Force prompt OK + log ⇒ revision=3, second snapshot, log recorded |
PASS |
| Force prompt Cancel ⇒ title saved, no revision | PASS |
| No-change Save ⇒ no prompt, data re-saved idempotently, no revision | PASS |
Create mode (?spec_id=) ⇒ no prompt, plain create |
PASS |
First POST response carries revision_prompt; second carries revision_prompt:null (no loop) |
PASS |
| Console: 0 errors; Event Viewer/events: only INFO entries, 0 new Error/Warning | PASS |
Screenshots: docs/screenshots/issue-1375-reqedit-editor-form.png (editor form
after a confirmed revision), prompt dialogs are native window.prompt (not
capturable in headless screenshots).
Files
api/reqedit/index.php—simpleReqCompare()+ save-handler revision logicgui/templates/requirements/reqEdit.html—doSave/showSaved/save()prompt flowgui/templates/i18n/{en,ro,de,es,fr,it,ja,pt,ru,zh}.json— 3 newreqe.*keys