Repository navigation
Test Project Create Edit Modernized
Modernization of the Test Project Create/Edit screen (the legacy
lib/project/projectEdit.php, actions create/edit/doCreate/doUpdate/
doDelete/setActive/setInactive/enableRequirements/
disableRequirements) — GitHub issue
#967.
The legacy admin-only form is replaced by a standalone Dashio page
(gui/templates/projects/projectEdit.html) backed by a plain-PHP REST BFF
(api/projectedit/index.php, session-based auth, JSON I/O). Every in-app
entry point that reached lib/project/projectEdit.php now points at the new
screen: the zero-test-projects admin bootstrap redirect in
lib/functions/common.php and the "Create/Edit" actions of the modernized
projectsView.html (rows' Edit button taskbar + toolbar).
Path: gui/templates/projects/projectEdit.html (create) or
gui/templates/projects/projectEdit.html?tproject_id=<id> (edit)
BFF API: api/projectedit/index.php (?action=init|create|update|delete|toggle_active|toggle_requirements)
Rights: mgt_modify_product (the legacy checkRights());
the BFF also reports mgt_view_events so the screen can expose the event history.
Screenshots: Test_Project_CreateEdit-create.png,
Test_Project_CreateEdit-edit.png,
Test_Project_CreateEdit-error.png,
Test_Project_CreateEdit-eventviewer.png.
-
Create mode (no
tproject_id): a Source data card appears only when at least one test project already exists, exposing Create from existing Test Project? — the legacycopy_from_tproject_id/copy_asclone. -
Basic Information card: project name (required), test-case ID prefix
(required, with the legacy hint icon "Up to 16 characters allowed, but we
recommend using at most five") and description (
notes). -
Features card: Enable Requirements / Priority / Automation / Inventory
checkboxes — the legacy
optReq/optPriority/optAutomation/optInventory(priority and automation default on, matchingconfig.inc.phptestcase_priority/testcase_automationdefaults). -
Issue Tracker / Code Tracker / Requirement Management System cards:
integration dropdowns with an Enabled checkbox. The checkbox toggles the
dropdown's disabled state (legacy
manageTracker('/behavior); with no tracker interfaces registered the dropdowns list only "-- none --" and the checkboxes stay disabled. -
Availability card: Active and Public checkboxes (legacy
active/is_public). -
API Key card (edit mode only): read-only display of the project's
api_key(legacy parity — the key exists ontestprojectsand is shown, never edited). -
Event history button (edit mode only): opens the modern Event Viewer
pre-filtered to the project via
eventviewer.html?objectId=<id>&objectType=testprojects. -
Save: client validation (empty name / empty prefix dialogs reusing the
legacy warning wording), server cross-checks (
crossChecksBFF— duplicate name or duplicate prefix, with the legacy messages) then a success toast and auto-redirect to the modernprojectsView.html. In edit mode the same flow saves throughupdateand records the legacyaudit_testproject_savedevent. -
Cancel: returns to
projectsView.html.
Base: api/projectedit/index.php. Session cookie required; mgt_modify_product
(right checkRights()) gates every mutating route (the init route returns a
canManage grant and a notAllowed flag instead of a hard 403 so the screen
can render a friendly error).
-
tproject_idomitted /0→ create-mode model:mode: "create",project: {id:0, name:'', prefix:'', description:'', api_key:'', active:1, isPublic:1, optReq:0, optPriority:1, optAutomation:1, optInventory:0},copyFromProjects(list of existing projects for the clone dropdown),issueTrackers/codeTrackers/reqMgrSystemsoption lists (from the DB tracker interfaces), grants{canManage, mgt_view_events}. 401 unauthenticated; 403 attempt against a project the user cannot manage is still reported throughcanManage:false. -
tproject_id=<id>→ edit-mode model with the current row preloaded (options decoded to the feature booleans) andmode: "edit". Returns 404 for unknown project ids.
Body (JSON, application/json): copy_from_tproject_id, name, prefix,
description, active, isPublic, optReq/optPriority/optAutomation/optInventory,
issue_tracker_id+issue_tracker_enabled,
code_tracker_id+code_tracker_enabled,
reqmgrsystem_id+reqmgr_integration_enabled.
- Cross-checks duplicates/empties (
Project name and prefix are required,Test Case ID prefix … already exists,Test Project name … already exists), then legacytestproject::create($item, ['doChecks'=>true, 'setSessionProject'=>true]), tracker apply (applyTrackers),protectFromLockout, and optionalcopy_asclone of the picked source project. Logsaudit_testproject_created(and the role-add event) just like the legacy controller. - 200
{success,id,message}; 400 on validation; 500 wrapped server errors.
Same body semantics with partial-update safety (only fields present in the
body are touched). 404 unknown project; 400 empty name/prefix; cross-checks
exclude the edited project itself so a no-op save is legal. Logs
audit_testproject_saved.
Full legacy cascade testproject::delete(); 404 unknown; 409 when the
operation reports failure (message prefixed by info_product_not_deleted_check_log);
200 + test_project_deleted localized message.
POST ?action=toggle_active&tproject_id=<id>&enable=0|1 / ?action=toggle_requirements&tproject_id=<id>&enable=0|1
Legacy one-liners setActive/setInactive/enableRequirements/
disableRequirements — active and requirement feature toggles.
- Action map
create/edit/doCreate/doUpdate/doDelete/setActive/setInactive/ enableRequirements/disableRequirements→init(+mode)/create/update/delete/toggle_active/toggle_requirements. -
testlinkInitPage($db,true,false,'checkRights')→ BFFmgt_modify_productgate on every mutating route +canManagegrant oninit. -
doCreatecall shape preserved:create($item,['doChecks'=>true, 'setSessionProject'=>true])thenenable_issue_tracker/enable_code_tracker/enable_reqmgrequivalents (applyTrackers) andprotectFromLockout. - Legacy labels re-used verbatim where the keys exist (
locale/en_GB/strings.txtlines 1636-1666): create-from prompt, prefix hint, the empty-name / empty-prefix warnings and theEdit %s/Create a new projectcaptions. -
web_editorlegacy field dropped by design (editor toolbar is outside the scope of the modernized project form). - The zero-test-projects bootstrap path in
lib/functions/common.phpnow redirects togui/templates/projects/projectEdit.htmlinstead oflib/project/projectEdit.php?doAction=create(this is how a fresh TestLink install with no projects is sent to the create form immediately after login).
pedit.* flat namespace in all 10 locale bundles
(gui/templates/i18n/{de,en,es,fr,it,ja,pt,ro,ru,zh}.json) plus one footer
key (footers.projectEdit). Keys added:
pedit.createProjectTitle, pedit.editProjectTitle (interpolates {name} via
TLi18n.t), pedit.subtitle, pedit.createFrom, pedit.createFromSection,
pedit.prefixHint, pedit.warningEmptyName, pedit.warningEmptyPrefix,
pedit.apiKey, pedit.eventHistory, pedit.createSuccess,
pedit.updateSuccess, pedit.saveError, pedit.loadError, pedit.notFound,
pedit.no, footers.projectEdit.
-
AuthN: session cookie required; unauthenticated calls get 401
(
$_SESSION['userID']check shared with every other BFF). -
AuthZ:
mgt_modify_productchecked on every mutating route (403);crossChecksBFFguards duplicate names/prefixes with project scoping (excludeIdfor self on update). -
Origin guard: the shared
api/_guard.phpbffSameOriginGuard()(safe GET/HEAD pass; unsafe verbs needX-Requested-Withor a matchingOrigin/Referer). -
Output encoding: all server-supplied option labels / project names are
HTML-escaped (
esc()) beforeinnerHTMLuse; ids areparseInt'd. - No secrets: API keys are displayed read-only, never logged or echoed into hidden inputs.
Full browser walkthrough (admin session): create with defaults and with
features toggled; empty-name and empty-prefix dialogs; duplicate name/prefix
server errors rendered inline; create-from-copy clone; edit-mode prefill +
update persistence; event-history popup pre-filtered; active/requirements
toggles; delete cascade. Verified in DB (testprojects,
nodes_hierarchy, events) that every write lands and each audit event
(audit_testproject_created / audit_testproject_saved /
audit_testproject_deleted) is recorded with no ERROR/WARNING rows. Suite in
tmp/TLU_Test_Cases.md (Refs #967); a legacy copy_as E_WARNING on empty
sources is tracked separately in issue #968.