From c3fdb74a24a8f66421bdec0c4d11d5082db841ea Mon Sep 17 00:00:00 2001 From: tianshujie Date: Tue, 10 May 2022 10:12:48 +0800 Subject: [PATCH 1/8] * Finish task #53668. --- module/execution/js/kanban.js | 45 ++++++++++++++++++----------------- module/kanban/control.php | 7 ++++++ 2 files changed, 30 insertions(+), 22 deletions(-) diff --git a/module/execution/js/kanban.js b/module/execution/js/kanban.js index ff3a64f56c..8f9eed2557 100644 --- a/module/execution/js/kanban.js +++ b/module/execution/js/kanban.js @@ -328,6 +328,10 @@ if(!window.kanbanDropRules) { backlog: ['ready', 'backlog'], ready: ['backlog', 'ready'], + tested: ['verified'], + verified: ['tested', 'released'], + released: ['verified', 'closed'], + closed: ['released'], }, bug: { @@ -957,30 +961,27 @@ function changeCardColType(cardID, fromColID, toColID, fromLaneID, toLaneID, car /* Story lane. */ if(cardType == 'story') { - if(toColType == 'ready' || toColType == 'backlog') + if(toColType == 'ready' && typeof(reviewStoryParis[objectID]) != 'undefined') { - if(toColType == 'ready' && typeof(reviewStoryParis[objectID]) != 'undefined') - { - bootbox.alert(executionLang.storyDragError); - return false; - } - - var link = createLink('kanban', 'ajaxMoveCard', 'cardID=' + objectID + '&fromColID=' + fromColID + '&toColID=' + toColID + '&fromLaneID=' + fromLaneID + '&toLaneID=' + toLaneID + '&execitionID=' + executionID + '&browseType=' + browseType + '&groupBy=' + groupBy + '®ionID=' + regionID+ '&orderBy=' + orderBy ); - $.ajax( - { - method: 'post', - dataType: 'json', - url: link, - success: function(data) - { - updateRegion(regionID, data[regionID]); - }, - error: function(xhr, status, error) - { - showErrorMessager(error || lang.timeout); - } - }); + bootbox.alert(executionLang.storyDragError); + return false; } + + var link = createLink('kanban', 'ajaxMoveCard', 'cardID=' + objectID + '&fromColID=' + fromColID + '&toColID=' + toColID + '&fromLaneID=' + fromLaneID + '&toLaneID=' + toLaneID + '&execitionID=' + executionID + '&browseType=' + browseType + '&groupBy=' + groupBy + '®ionID=' + regionID+ '&orderBy=' + orderBy ); + $.ajax( + { + method: 'post', + dataType: 'json', + url: link, + success: function(data) + { + updateRegion(regionID, data[regionID]); + }, + error: function(xhr, status, error) + { + showErrorMessager(error || lang.timeout); + } + }); } if(showIframe) diff --git a/module/kanban/control.php b/module/kanban/control.php index eeb922a87d..68b480869f 100644 --- a/module/kanban/control.php +++ b/module/kanban/control.php @@ -1663,6 +1663,13 @@ class kanban extends control ->andWhere('`column`')->eq($toColID) ->exec(); + $toColumn = $this->kanban->getColumnByID($toColID); + if($toColumn->laneType == 'story' and in_array($toColumn->type, array('tested', 'verified', 'released', 'closed'))) + { + $stage = $toColumn->type; + $this->dao->update(TABLE_STORY)->set('stage')->eq($stage)->where('id')->eq($cardID)->exec(); + } + $kanbanGroup = $regionID == 0 ? $this->kanban->getExecutionKanban($executionID, $browseType, $groupBy) : $this->kanban->getRDKanban($executionID, $browseType, $orderBy, $regionID, $groupBy); echo json_encode($kanbanGroup); } From 896e36c90c1d0bdf0e5b049057bc1876b72a985c Mon Sep 17 00:00:00 2001 From: tianshujie Date: Tue, 10 May 2022 10:50:02 +0800 Subject: [PATCH 2/8] * Finish task #53667. --- module/execution/js/taskkanban.js | 49 ++++++++++++++++--------------- 1 file changed, 25 insertions(+), 24 deletions(-) diff --git a/module/execution/js/taskkanban.js b/module/execution/js/taskkanban.js index 8df8beb996..6faa290fb2 100644 --- a/module/execution/js/taskkanban.js +++ b/module/execution/js/taskkanban.js @@ -480,6 +480,10 @@ if(!window.kanbanDropRules) { backlog: ['ready'], ready: ['backlog'], + tested: ['verified'], + verified: ['tested', 'released'], + released: ['verified', 'closed'], + closed: ['released'], }, bug: { @@ -495,7 +499,7 @@ if(!window.kanbanDropRules) { 'wait': ['developing', 'developed', 'canceled', 'closed'], 'developing': ['developed', 'pause', 'canceled'], - 'developed': ['closed'], + 'developed': ['developing', 'closed'], 'pause': ['developing'], 'canceled': ['developing'], 'closed': ['developing'], @@ -683,31 +687,28 @@ function changeCardColType(cardID, fromColID, toColID, fromLaneID, toLaneID, car /* Story lane. */ if(cardType == 'story') { - if(toColType == 'ready' || toColType == 'backlog') + if(toColType == 'ready' && typeof(reviewStoryParis[objectID]) != 'undefined') { - if(toColType == 'ready' && typeof(reviewStoryParis[objectID]) != 'undefined') - { - bootbox.alert(executionLang.storyDragError); - return false; - } - - var link = createLink('kanban', 'ajaxMoveCard', 'cardID=' + objectID + '&fromColID=' + fromColID + '&toColID=' + toColID + '&fromLaneID=' + fromLaneID + '&toLaneID=' + toLaneID + '&execitionID=' + executionID + '&browseType=' + browseType + '&groupBy=' + groupBy); - $.get(link, function(data) - { - if(data) - { - kanbanGroup = $.parseJSON(data); - if(groupBy == 'default') - { - updateKanban('story', kanbanGroup.story); - } - else - { - updateKanban(browseType, kanbanGroup[groupBy]); - } - } - }) + bootbox.alert(executionLang.storyDragError); + return false; } + + var link = createLink('kanban', 'ajaxMoveCard', 'cardID=' + objectID + '&fromColID=' + fromColID + '&toColID=' + toColID + '&fromLaneID=' + fromLaneID + '&toLaneID=' + toLaneID + '&execitionID=' + executionID + '&browseType=' + browseType + '&groupBy=' + groupBy); + $.get(link, function(data) + { + if(data) + { + kanbanGroup = $.parseJSON(data); + if(groupBy == 'default') + { + updateKanban('story', kanbanGroup.story); + } + else + { + updateKanban(browseType, kanbanGroup[groupBy]); + } + } + }); } if(showIframe) From 5c00aa823c43ef454b2b37c0f10c0ef70ba968fd Mon Sep 17 00:00:00 2001 From: tianshujie Date: Tue, 10 May 2022 11:24:17 +0800 Subject: [PATCH 3/8] * Modify language item error. --- module/execution/view/burn.html.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/module/execution/view/burn.html.php b/module/execution/view/burn.html.php index 71da19f850..2d0bd26ae7 100644 --- a/module/execution/view/burn.html.php +++ b/module/execution/view/burn.html.php @@ -22,7 +22,7 @@
' . $lang->execution->computeBurn, 'hiddenwin', "title='{$lang->execution->computeBurn}{$lang->execution->burn}' class='btn btn-primary' id='computeBurn'"); + common::printLink('execution', 'computeBurn', 'reload=yes', ' ' . $lang->execution->computeBurn, 'hiddenwin', "title='{$lang->execution->computeBurn}' class='btn btn-primary' id='computeBurn'"); echo '
'; echo html::a($this->createLink('execution', 'burn', "executionID=$executionID&type=$weekend&interval=$interval"), $lang->execution->$weekend, '', "class='btn btn-link'"); if(common::canModify('execution', $execution)) common::printLink('execution', 'fixFirst', "execution=$execution->id", $lang->execution->fixFirst, '', "class='btn btn-link iframe' data-width='700'"); From 528fa4535787bcf20e3b7b8d372fe64feb2febc8 Mon Sep 17 00:00:00 2001 From: tanghucheng Date: Tue, 10 May 2022 05:13:35 +0000 Subject: [PATCH 4/8] * Fix bug. --- module/custom/model.php | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/module/custom/model.php b/module/custom/model.php index aa725021d4..a8ffc88a32 100644 --- a/module/custom/model.php +++ b/module/custom/model.php @@ -251,7 +251,9 @@ class customModel extends model foreach($item['subMenu'] as $subMenu) { if(!isset($subMenu['link']) or strpos($subMenu['link'], '|') === false) continue; - list($subLabel, $module, $method, $vars) = explode('|', $subMenu['link']); + list($subLabel, $module, $method) = explode('|', $subMenu['link']); + if(count(explode('|', $subMenu['link'])) > 3) list($subLabel, $module, $method, $vars) = explode('|', $subMenu['link']); + $hasPriv = commonModel::hasPriv($module, $method); if($hasPriv) break; } From 4e2de99018e7a692cc599967d930041c00d656c3 Mon Sep 17 00:00:00 2001 From: tianshujie Date: Tue, 10 May 2022 14:25:01 +0800 Subject: [PATCH 5/8] * Stages of updating trunk stories. --- module/kanban/control.php | 1 + 1 file changed, 1 insertion(+) diff --git a/module/kanban/control.php b/module/kanban/control.php index 68b480869f..dc2091238f 100644 --- a/module/kanban/control.php +++ b/module/kanban/control.php @@ -1668,6 +1668,7 @@ class kanban extends control { $stage = $toColumn->type; $this->dao->update(TABLE_STORY)->set('stage')->eq($stage)->where('id')->eq($cardID)->exec(); + $this->dao->update(TABLE_STORYSTAGE)->set('stage')->eq($stage)->where('story')->eq($cardID)->exec(); } $kanbanGroup = $regionID == 0 ? $this->kanban->getExecutionKanban($executionID, $browseType, $groupBy) : $this->kanban->getRDKanban($executionID, $browseType, $orderBy, $regionID, $groupBy); From fe927b1e5ec673f70850b809bedfd64f4a18fce2 Mon Sep 17 00:00:00 2001 From: tanghucheng Date: Tue, 10 May 2022 06:27:22 +0000 Subject: [PATCH 6/8] * Finish task #53593. --- db/update16.5.sql | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/db/update16.5.sql b/db/update16.5.sql index bb437efddd..47c6e3031c 100644 --- a/db/update16.5.sql +++ b/db/update16.5.sql @@ -89,3 +89,17 @@ REPLACE INTO `zt_zoutput` (`id`, `activity`, `name`, `content`, `optional`, `sta DELETE FROM `zt_config` WHERE `section` = 'customMenu'; UPDATE `zt_story` SET `plan` = '' WHERE `plan` = 0; + +UPDATE `zt_workflowfield` set `control` = 'datetime' WHERE `module` = 'testcase' and `field` IN ('openedDate','reviewedDate','lastEditedDate','lastRunDate'); +UPDATE `zt_workflowfield` set `control` = 'select' WHERE `module` = 'testcase' and `field` = 'lib'; + +UPDATE `zt_workflowfield` set `control` = 'date' WHERE `module` = 'testtask' and `field` IN ('begin','end'); +UPDATE `zt_workflowfield` set `control` = 'richtext' WHERE `module` = 'testtask' and `field` = 'desc'; + +UPDATE `zt_workflowfield` set `control` = 'datetime' WHERE `module` IN ('testsuite','caselib') and `field` IN ('addedDate','lastEditedDate'); +UPDATE `zt_workflowfield` set `control` = 'select' WHERE `module` = 'testsuite' and `field` = 'type'; +UPDATE `zt_workflowfield` set `control` = 'richtext' WHERE `module` = 'testsuite' and `field` = 'desc'; + +UPDATE `zt_workflowfield` set `control` = 'datetime' WHERE `module` = 'feedback' and `field` IN ('openedDate','reviewedDate','processedDate','closedDate','editedDate','assignedDate'); +UPDATE `zt_workflowfield` set `control` = 'select' WHERE `module` = 'feedback' and `field` IN ('public','notify'); + From bd06901bfa40f8197df2c548edfd1967c4f50863 Mon Sep 17 00:00:00 2001 From: tanghucheng Date: Tue, 10 May 2022 08:52:05 +0000 Subject: [PATCH 7/8] * Fix bug. --- db/update16.5.sql | 4 ---- 1 file changed, 4 deletions(-) diff --git a/db/update16.5.sql b/db/update16.5.sql index 47c6e3031c..46afc5aa1d 100644 --- a/db/update16.5.sql +++ b/db/update16.5.sql @@ -91,15 +91,11 @@ DELETE FROM `zt_config` WHERE `section` = 'customMenu'; UPDATE `zt_story` SET `plan` = '' WHERE `plan` = 0; UPDATE `zt_workflowfield` set `control` = 'datetime' WHERE `module` = 'testcase' and `field` IN ('openedDate','reviewedDate','lastEditedDate','lastRunDate'); -UPDATE `zt_workflowfield` set `control` = 'select' WHERE `module` = 'testcase' and `field` = 'lib'; UPDATE `zt_workflowfield` set `control` = 'date' WHERE `module` = 'testtask' and `field` IN ('begin','end'); UPDATE `zt_workflowfield` set `control` = 'richtext' WHERE `module` = 'testtask' and `field` = 'desc'; UPDATE `zt_workflowfield` set `control` = 'datetime' WHERE `module` IN ('testsuite','caselib') and `field` IN ('addedDate','lastEditedDate'); -UPDATE `zt_workflowfield` set `control` = 'select' WHERE `module` = 'testsuite' and `field` = 'type'; UPDATE `zt_workflowfield` set `control` = 'richtext' WHERE `module` = 'testsuite' and `field` = 'desc'; UPDATE `zt_workflowfield` set `control` = 'datetime' WHERE `module` = 'feedback' and `field` IN ('openedDate','reviewedDate','processedDate','closedDate','editedDate','assignedDate'); -UPDATE `zt_workflowfield` set `control` = 'select' WHERE `module` = 'feedback' and `field` IN ('public','notify'); - From 5bdb7f521c1d12e79df63323a44e939db5ede36d Mon Sep 17 00:00:00 2001 From: tianshujie Date: Tue, 10 May 2022 17:05:49 +0800 Subject: [PATCH 8/8] * Finish task #53668. --- module/execution/js/kanban.js | 40 ++++++++++++--------- module/execution/js/taskkanban.js | 42 ++++++++++++++--------- module/execution/view/kanban.html.php | 1 + module/execution/view/taskkanban.html.php | 3 +- module/kanban/control.php | 12 +++++-- module/story/control.php | 2 +- module/story/model.php | 2 ++ 7 files changed, 64 insertions(+), 38 deletions(-) diff --git a/module/execution/js/kanban.js b/module/execution/js/kanban.js index 8f9eed2557..b125445210 100644 --- a/module/execution/js/kanban.js +++ b/module/execution/js/kanban.js @@ -961,27 +961,35 @@ function changeCardColType(cardID, fromColID, toColID, fromLaneID, toLaneID, car /* Story lane. */ if(cardType == 'story') { - if(toColType == 'ready' && typeof(reviewStoryParis[objectID]) != 'undefined') + if(toColType == 'closed' && priv.canCloseStory) { - bootbox.alert(executionLang.storyDragError); - return false; + var link = createLink('story', 'close', 'storyID=' + objectID, '', true); + showIframe = true; } - - var link = createLink('kanban', 'ajaxMoveCard', 'cardID=' + objectID + '&fromColID=' + fromColID + '&toColID=' + toColID + '&fromLaneID=' + fromLaneID + '&toLaneID=' + toLaneID + '&execitionID=' + executionID + '&browseType=' + browseType + '&groupBy=' + groupBy + '®ionID=' + regionID+ '&orderBy=' + orderBy ); - $.ajax( + else { - method: 'post', - dataType: 'json', - url: link, - success: function(data) + if(toColType == 'ready' && typeof(reviewStoryParis[objectID]) != 'undefined') { - updateRegion(regionID, data[regionID]); - }, - error: function(xhr, status, error) - { - showErrorMessager(error || lang.timeout); + bootbox.alert(executionLang.storyDragError); + return false; } - }); + + var link = createLink('kanban', 'ajaxMoveCard', 'cardID=' + objectID + '&fromColID=' + fromColID + '&toColID=' + toColID + '&fromLaneID=' + fromLaneID + '&toLaneID=' + toLaneID + '&execitionID=' + executionID + '&browseType=' + browseType + '&groupBy=' + groupBy + '®ionID=' + regionID+ '&orderBy=' + orderBy ); + $.ajax( + { + method: 'post', + dataType: 'json', + url: link, + success: function(data) + { + updateRegion(regionID, data[regionID]); + }, + error: function(xhr, status, error) + { + showErrorMessager(error || lang.timeout); + } + }); + } } if(showIframe) diff --git a/module/execution/js/taskkanban.js b/module/execution/js/taskkanban.js index 6faa290fb2..56a6cf5af4 100644 --- a/module/execution/js/taskkanban.js +++ b/module/execution/js/taskkanban.js @@ -687,28 +687,36 @@ function changeCardColType(cardID, fromColID, toColID, fromLaneID, toLaneID, car /* Story lane. */ if(cardType == 'story') { - if(toColType == 'ready' && typeof(reviewStoryParis[objectID]) != 'undefined') + if(toColType == 'closed' && priv.canCloseStory) { - bootbox.alert(executionLang.storyDragError); - return false; + var link = createLink('story', 'close', 'storyID=' + objectID, '', true); + showIframe = true; } - - var link = createLink('kanban', 'ajaxMoveCard', 'cardID=' + objectID + '&fromColID=' + fromColID + '&toColID=' + toColID + '&fromLaneID=' + fromLaneID + '&toLaneID=' + toLaneID + '&execitionID=' + executionID + '&browseType=' + browseType + '&groupBy=' + groupBy); - $.get(link, function(data) + else { - if(data) + if(toColType == 'ready' && typeof(reviewStoryParis[objectID]) != 'undefined') { - kanbanGroup = $.parseJSON(data); - if(groupBy == 'default') - { - updateKanban('story', kanbanGroup.story); - } - else - { - updateKanban(browseType, kanbanGroup[groupBy]); - } + bootbox.alert(executionLang.storyDragError); + return false; } - }); + + var link = createLink('kanban', 'ajaxMoveCard', 'cardID=' + objectID + '&fromColID=' + fromColID + '&toColID=' + toColID + '&fromLaneID=' + fromLaneID + '&toLaneID=' + toLaneID + '&execitionID=' + executionID + '&browseType=' + browseType + '&groupBy=' + groupBy); + $.get(link, function(data) + { + if(data) + { + kanbanGroup = $.parseJSON(data); + if(groupBy == 'default') + { + updateKanban('story', kanbanGroup.story); + } + else + { + updateKanban(browseType, kanbanGroup[groupBy]); + } + } + }); + } } if(showIframe) diff --git a/module/execution/view/kanban.html.php b/module/execution/view/kanban.html.php index cfddc793bd..ec45f38420 100644 --- a/module/execution/view/kanban.html.php +++ b/module/execution/view/kanban.html.php @@ -105,6 +105,7 @@ js::set('priv', 'canEditStory' => common::hasPriv('story', 'edit'), 'canDeleteStory' => common::hasPriv('story', 'delete'), 'canChangeStory' => common::hasPriv('story', 'change'), + 'canCloseStory' => common::hasPriv('story', 'close'), 'canUnlinkStory' => common::hasPriv('execution', 'unlinkStory'), ) ); diff --git a/module/execution/view/taskkanban.html.php b/module/execution/view/taskkanban.html.php index 4d86ea58cd..7ec69b0041 100644 --- a/module/execution/view/taskkanban.html.php +++ b/module/execution/view/taskkanban.html.php @@ -193,7 +193,8 @@ js::set('priv', 'canStartTask' => common::hasPriv('task', 'start'), 'canAssignBug' => common::hasPriv('bug', 'assignto'), 'canConfirmBug' => common::hasPriv('bug', 'confirmBug'), - 'canActivateBug' => common::hasPriv('bug', 'activate') + 'canActivateBug' => common::hasPriv('bug', 'activate'), + 'canCloseStory' => common::hasPriv('story', 'close') ) ); ?> diff --git a/module/kanban/control.php b/module/kanban/control.php index dc2091238f..ae243b271c 100644 --- a/module/kanban/control.php +++ b/module/kanban/control.php @@ -1666,9 +1666,15 @@ class kanban extends control $toColumn = $this->kanban->getColumnByID($toColID); if($toColumn->laneType == 'story' and in_array($toColumn->type, array('tested', 'verified', 'released', 'closed'))) { - $stage = $toColumn->type; - $this->dao->update(TABLE_STORY)->set('stage')->eq($stage)->where('id')->eq($cardID)->exec(); - $this->dao->update(TABLE_STORYSTAGE)->set('stage')->eq($stage)->where('story')->eq($cardID)->exec(); + $data = new stdclass(); + $data->stage = $toColumn->type; + if($toColumn->type == 'released') + { + $fromColumn = $this->kanban->getColumnByID($fromColID); + if($fromColumn->type == 'closed') $data->status = 'active'; + } + $this->dao->update(TABLE_STORY)->data($data)->where('id')->eq($cardID)->exec(); + $this->dao->update(TABLE_STORYSTAGE)->set('stage')->eq($toColumn->type)->where('story')->eq($cardID)->exec(); } $kanbanGroup = $regionID == 0 ? $this->kanban->getExecutionKanban($executionID, $browseType, $groupBy) : $this->kanban->getRDKanban($executionID, $browseType, $orderBy, $regionID, $groupBy); diff --git a/module/story/control.php b/module/story/control.php index 64527571e3..70dcd47022 100644 --- a/module/story/control.php +++ b/module/story/control.php @@ -1351,7 +1351,7 @@ class story extends control if(isonlybody()) { $execution = $this->execution->getByID($this->session->execution); - if($this->app->tab == 'execution' and $execution->type == 'kanban' and $this->app->tab == 'execution') + if($this->app->tab == 'execution' and $execution->type == 'kanban') { $this->loadModel('kanban')->updateLane($this->session->execution, 'story', $storyID); $kanbanData = $this->kanban->getRDKanban($this->session->execution, $this->session->execLaneType ? $this->session->execLaneType : 'all'); diff --git a/module/story/model.php b/module/story/model.php index 4181c473a1..b079255d91 100644 --- a/module/story/model.php +++ b/module/story/model.php @@ -3042,6 +3042,8 @@ class storyModel extends model public function closeParentRequirement($storyID) { $parentID = $this->dao->select('BID')->from(TABLE_RELATION)->where('AID')->eq($storyID)->fetch(); + if(empty($parentID)) return; + $stories = $this->dao->select('t2.id, t2.status')->from(TABLE_RELATION)->alias('t1') ->leftJoin(TABLE_STORY)->alias('t2')->on('t2.id=t1.AID') ->where('t1.BType')->eq('requirement')