diff --git a/module/action/lang/en.php b/module/action/lang/en.php index 2db333a59d..53a397e4d2 100755 --- a/module/action/lang/en.php +++ b/module/action/lang/en.php @@ -279,6 +279,7 @@ $lang->action->label->reviewrejected = 'Reject'; $lang->action->label->reviewclarified = 'Clarify'; $lang->action->label->commitsummary = 'Commit Summary'; $lang->action->label->updatetrainee = 'Update Trainee'; +$lang->action->label->setdefaultbranch = 'Set default branch'; /* Dynamic information is grouped by object. */ $lang->action->dynamicAction = new stdclass; @@ -312,10 +313,11 @@ $lang->action->dynamicAction->product['closed'] = 'Close ' . $lang->productCo $lang->action->dynamicAction->product['undeleted'] = 'Restore ' . $lang->productCommon; $lang->action->dynamicAction->product['hidden'] = 'Hide ' . $lang->productCommon; -$lang->action->dynamicAction->branch['opened'] = 'Create Branch'; -$lang->action->dynamicAction->branch['edited'] = 'Edit Branch'; -$lang->action->dynamicAction->branch['closed'] = 'Close Branch'; -$lang->action->dynamicAction->branch['activated'] = 'Activate Branch'; +$lang->action->dynamicAction->branch['opened'] = 'Create Branch'; +$lang->action->dynamicAction->branch['edited'] = 'Edit Branch'; +$lang->action->dynamicAction->branch['closed'] = 'Close Branch'; +$lang->action->dynamicAction->branch['activated'] = 'Activate Branch'; +$lang->action->dynamicAction->branch['setdefaultbranch'] = 'Set Default Branch'; $lang->action->dynamicAction->productplan['opened'] = 'Create Plan'; $lang->action->dynamicAction->productplan['edited'] = 'Edit Plan'; diff --git a/module/action/lang/zh-cn.php b/module/action/lang/zh-cn.php index 37b4303416..7f71f341bc 100755 --- a/module/action/lang/zh-cn.php +++ b/module/action/lang/zh-cn.php @@ -279,6 +279,7 @@ $lang->action->label->reviewrejected = '拒绝'; $lang->action->label->reviewclarified = '有待明确'; $lang->action->label->commitsummary = '提交培训总结'; $lang->action->label->updatetrainee = '更新培训人员'; +$lang->action->label->setdefaultbranch = '设置了默认分支'; /* 动态信息按照对象分组 */ $lang->action->dynamicAction = new stdclass(); @@ -312,10 +313,11 @@ $lang->action->dynamicAction->product['closed'] = '关闭' . $lang->productCo $lang->action->dynamicAction->product['undeleted'] = '还原' . $lang->productCommon; $lang->action->dynamicAction->product['hidden'] = '隐藏' . $lang->productCommon; -$lang->action->dynamicAction->branch['opened'] = '创建分支'; -$lang->action->dynamicAction->branch['edited'] = '编辑分支'; -$lang->action->dynamicAction->branch['closed'] = '关闭分支'; -$lang->action->dynamicAction->branch['activated'] = '激活分支'; +$lang->action->dynamicAction->branch['opened'] = '创建分支'; +$lang->action->dynamicAction->branch['edited'] = '编辑分支'; +$lang->action->dynamicAction->branch['closed'] = '关闭分支'; +$lang->action->dynamicAction->branch['activated'] = '激活分支'; +$lang->action->dynamicAction->branch['setdefaultbranch'] = '设置默认分支'; $lang->action->dynamicAction->productplan['opened'] = "创建计划"; $lang->action->dynamicAction->productplan['edited'] = "编辑计划"; diff --git a/module/action/model.php b/module/action/model.php index e867ba5d54..1f4ad3190d 100755 --- a/module/action/model.php +++ b/module/action/model.php @@ -240,6 +240,12 @@ class actionModel extends model $record->execution = $testtask->execution; } + if($objectType == 'branch' and $objectID == 0) + { + $record = new stdclass(); + $record->product = $extra; + } + if($objectType == 'whitelist' and $extra == 'product') $record->product = $objectID; if($objectType == 'whitelist' and $extra == 'project') $record->project = $objectID; if($objectType == 'whitelist' and ($extra == 'sprint' or $extra == 'stage')) $record->execution = $objectID; @@ -1059,6 +1065,12 @@ class actionModel extends model ->where('t1.id')->in($objectIdList) ->fetchPairs(); } + elseif($objectType == 'branch') + { + $this->app->loadLang('branch'); + $objectName = $this->dao->select("id,name")->from(TABLE_BRANCH)->where('id')->in($objectIdList)->fetchPairs(); + if(in_array(BRANCH_MAIN, $objectIdList)) $objectName[BRANCH_MAIN] = $this->lang->branch->main; + } else { $objectName = $this->dao->select("id, $field AS name")->from($table)->where('id')->in($objectIdList)->fetchPairs(); @@ -1179,8 +1191,7 @@ class actionModel extends model } elseif($action->objectType == 'branch') { - $productID = $this->dao->select('product')->from(TABLE_BRANCH)->where('id')->eq($action->objectID)->fetch('product'); - $params = sprintf($vars, $productID); + $params = sprintf($vars, trim($action->product, ',')); } else { diff --git a/module/branch/control.php b/module/branch/control.php index e36085a73d..c4b5305573 100644 --- a/module/branch/control.php +++ b/module/branch/control.php @@ -23,9 +23,10 @@ class branch extends control * @access public * @return void */ - public function manage($productID, $browseType = 'active', $orderBy = 'order_desc', $recTotal = 0, $recPerPage = 20, $pageID = 1) + public function manage($productID, $browseType = 'active', $orderBy = 'order', $recTotal = 0, $recPerPage = 20, $pageID = 1) { $this->loadModel('product')->setMenu($productID); + $this->session->set('branchManage', $this->app->getURI(true), 'product'); $branchList = $this->branch->getList($productID, $browseType, $orderBy); @@ -89,6 +90,43 @@ class branch extends control $this->display(); } + /** + * Batch edit branch. + * + * @param int $productID + * @access public + * @return void + */ + public function batchEdit($productID) + { + $this->loadModel('action'); + $this->loadModel('product')->setMenu($productID); + + if($this->post->IDList) + { + $changes = $this->branch->batchUpdate($productID); + foreach($changes as $branchID => $change) + { + $extra = $branchID == BRANCH_MAIN ? $productID : ''; + if($change) $this->action->create('branch', $branchID, 'Edited', '', $extra); + } + + die(js::locate($this->session->branchManage, 'parent')); + } + + $branchList = $this->branch->getList($productID, 'all'); + $branchIDList = $this->post->branchIDList; + if(empty($branchIDList)) die(js::locate($this->session->branchManage, 'parent')); + + foreach($branchList as $branch) + { + if(!in_array($branch->id, $branchIDList)) unset($branchList[$branch->id]); + } + + $this->view->branchList = $branchList; + $this->display(); + } + /** * Close a branch. * @@ -207,16 +245,53 @@ class branch extends control * @param int $productID * @param int $oldBranch * @param string $param + * @param int $projectID * @access public * @return void */ - public function ajaxGetBranches($productID, $oldBranch = 0, $param = '') + public function ajaxGetBranches($productID, $oldBranch = 0, $param = '', $projectID = 0) { $product = $this->loadModel('product')->getById($productID); if(empty($product) or $product->type == 'normal') die(); $branches = $this->branch->getPairs($productID, $param); + + /* Remove unlinked branches of the project. */ + if($projectID) + { + $projectProducts = $this->loadModel('project')->getBranchesByProject($projectID); + foreach($branches as $branchID => $branchName) + { + if(!isset($projectProducts[$productID][$branchID])) unset($branches[$branchID]); + } + } + if($oldBranch) $branches = array($oldBranch => $branches[$oldBranch]); die(html::select('branch', $branches, '', "class='form-control' onchange='loadBranch(this)'")); } + + /** + * Set default branch. + * + * @param int $productID + * @param int $branchID + * @param string $confirm yes|no + * @access public + * @return void + */ + public function setDefault($productID, $branchID, $confirm = 'no') + { + if($confirm == 'no') + { + $this->app->loadLang('product'); + $productType = $this->branch->getProductType($branchID); + die(js::confirm(str_replace('@branch@', $this->lang->product->branchName[$productType], $this->lang->branch->confirmSetDefault), inlink('setDefault', "productID=$productID&branchID=$branchID&confirm=yes"))); + } + + $this->branch->setDefault($productID, $branchID); + + $this->loadModel('action')->create('branch', $branchID, 'SetDefaultBranch', '', $productID); + + die(js::reload('parent')); + } } diff --git a/module/branch/css/batchedit.css b/module/branch/css/batchedit.css new file mode 100644 index 0000000000..825aadf755 --- /dev/null +++ b/module/branch/css/batchedit.css @@ -0,0 +1,2 @@ +.c-desc {width : 600px;} +.c-defult {width: 100px;} diff --git a/module/branch/css/manage.css b/module/branch/css/manage.css index 4d9f958f35..35334b5a45 100644 --- a/module/branch/css/manage.css +++ b/module/branch/css/manage.css @@ -1,3 +1,7 @@ .c-desc {width: 500px;} .c-order {width: 70px;} .c-check {width: 40px} + +td.flex {display: flex; flex-flow: row nowrap; justify-content: flex-start; align-items: center;} +td.flex .label-primary {min-width: 40px;} +td.flex .setDefault {min-width: 120px;} diff --git a/module/branch/js/batchedit.js b/module/branch/js/batchedit.js new file mode 100644 index 0000000000..e796f8d187 --- /dev/null +++ b/module/branch/js/batchedit.js @@ -0,0 +1,18 @@ +/** + * Can set default branch. + * + * @param obj $obj + * @access public + * @return void + */ +function canSetDefaultBranch(obj) +{ + if(obj.value == 'active') + { + $(obj).closest('tr').find("input[name^='default']").removeAttr('disabled'); + } + else + { + $(obj).closest('tr').find("input[name^='default']").removeAttr('checked').attr('disabled', 'disabled'); + } +} diff --git a/module/branch/js/manage.js b/module/branch/js/manage.js index 7b371ff1ef..c71d512c56 100644 --- a/module/branch/js/manage.js +++ b/module/branch/js/manage.js @@ -13,16 +13,35 @@ function deleteItem(obj) $(function() { - $('#branches').sortable( + $('#branchTableList').addClass('sortable').sortable( { - selector: '.input-group', + reverse: orderBy === 'order_desc', + selector: 'tr', dragCssClass: 'drag-row', - trigger: $('#branches').find('.sort-handler').length ? '.sort-handler' : null, + trigger: $('#branchTableList').find('.sort-handler').length ? '.sort-handler' : null, + + canMoveHere: function($ele, $target) + { + return $target.data('id') != 0; + }, + finish: function(e) { - var list = ''; - $('#branches').find('.input-group').each(function(){list += $(this).attr('data-id') + ',';}); - $.post(createLink('branch', 'sort'), {'branches' : list}); + var branches = ''; + e.list.each(function() + { + branches += $(this.item).data('id') + ','; + }); + + $.post(createLink('branch', 'sort'), {'branches': branches, 'orderBy': orderBy}); } }); + + $('td.c-name.flex').mouseenter(function() + { + $(this).find('.setDefault').removeClass('hidden'); + }).mouseleave(function() + { + $(this).find('.setDefault').addClass('hidden'); + }) }); diff --git a/module/branch/lang/en.php b/module/branch/lang/en.php index fc8b63f330..f667e54960 100644 --- a/module/branch/lang/en.php +++ b/module/branch/lang/en.php @@ -9,14 +9,18 @@ $lang->branch->manageTitle = '%s Management'; $lang->branch->all = 'All '; $lang->branch->main = 'Main'; -$lang->branch->edit = 'Edit'; -$lang->branch->editAction = 'Edit Branch'; -$lang->branch->activate = 'Activate'; -$lang->branch->activateAction = 'Activate Branch'; -$lang->branch->close = 'Close'; -$lang->branch->closeAction = 'Close Branch'; -$lang->branch->create = 'Create Branch'; -$lang->branch->merge = 'Merge'; +$lang->branch->edit = 'Edit'; +$lang->branch->editAction = 'Edit Branch'; +$lang->branch->activate = 'Activate'; +$lang->branch->activateAction = 'Activate Branch'; +$lang->branch->close = 'Close'; +$lang->branch->closeAction = 'Close Branch'; +$lang->branch->create = 'Create Branch'; +$lang->branch->merge = 'Merge'; +$lang->branch->batchEdit = 'Batch Edit'; +$lang->branch->defaultBranch = 'Default Branch'; +$lang->branch->setDefault = 'Set Default'; +$lang->branch->setDefaultAction = 'Set Default'; $lang->branch->id = 'ID'; $lang->branch->product = 'Product'; @@ -28,12 +32,14 @@ $lang->branch->desc = 'Desc'; $lang->branch->order = 'Order'; $lang->branch->deleted = 'Delete'; $lang->branch->closed = 'Closed'; +$lang->branch->default = 'Default'; -$lang->branch->confirmDelete = 'Do you want to delete this @branch@?'; -$lang->branch->canNotDelete = 'There is data in @branch@. It cannot be deleted.'; -$lang->branch->nameNotEmpty = 'Name must not be empty!'; -$lang->branch->confirmClose = 'Do you want to close this @branch@?'; -$lang->branch->confirmActivate = 'Do you want to activate this @branch@?'; +$lang->branch->confirmDelete = 'Do you want to delete this @branch@?'; +$lang->branch->confirmSetDefault = 'Do you want to set @branch@ as default @branch@? After your setting, the default @branch@ will be selected and shown in its Plan/Release list.'; +$lang->branch->canNotDelete = 'There is data in @branch@. It cannot be deleted.'; +$lang->branch->nameNotEmpty = 'Name must not be empty!'; +$lang->branch->confirmClose = 'Do you want to close this @branch@?'; +$lang->branch->confirmActivate = 'Do you want to activate this @branch@?'; $lang->branch->noData = 'No branches.'; $lang->branch->mainBranch = 'The default main branch of the product.'; diff --git a/module/branch/lang/zh-cn.php b/module/branch/lang/zh-cn.php index 3f5e2f4328..14d7327363 100644 --- a/module/branch/lang/zh-cn.php +++ b/module/branch/lang/zh-cn.php @@ -9,14 +9,18 @@ $lang->branch->manageTitle = '%s管理'; $lang->branch->all = '所有'; $lang->branch->main = '主干'; -$lang->branch->edit = '编辑'; -$lang->branch->editAction = '编辑分支'; -$lang->branch->activate = '激活'; -$lang->branch->activateAction = '激活分支'; -$lang->branch->close = '关闭'; -$lang->branch->closeAction = '关闭分支'; -$lang->branch->create = '新增分支'; -$lang->branch->merge = '合并'; +$lang->branch->edit = '编辑'; +$lang->branch->editAction = '编辑分支'; +$lang->branch->activate = '激活'; +$lang->branch->activateAction = '激活分支'; +$lang->branch->close = '关闭'; +$lang->branch->closeAction = '关闭分支'; +$lang->branch->create = '新增分支'; +$lang->branch->merge = '合并'; +$lang->branch->batchEdit = '批量编辑'; +$lang->branch->defaultBranch = '默认分支'; +$lang->branch->setDefault = '设为默认分支'; +$lang->branch->setDefaultAction = '设置默认分支'; $lang->branch->id = 'ID'; $lang->branch->product = '所属产品'; @@ -28,12 +32,14 @@ $lang->branch->desc = '分支描述'; $lang->branch->order = '排序'; $lang->branch->deleted = '已删除'; $lang->branch->closed = '已关闭'; +$lang->branch->default = '默认'; -$lang->branch->confirmDelete = '是否删除该@branch@?'; -$lang->branch->canNotDelete = '该@branch@下已经有数据,不能删除!'; -$lang->branch->nameNotEmpty = '名称不能为空!'; -$lang->branch->confirmClose = '是否关闭该@branch@?'; -$lang->branch->confirmActivate = '是否激活该@branch@?'; +$lang->branch->confirmDelete = '是否删除该@branch@?'; +$lang->branch->confirmSetDefault = '请确认是否需要将该@branch@设置为默认@branch@,设置成功后计划和发布列表将默认选中默认@branch@。'; +$lang->branch->canNotDelete = '该@branch@下已经有数据,不能删除!'; +$lang->branch->nameNotEmpty = '名称不能为空!'; +$lang->branch->confirmClose = '是否关闭该@branch@?'; +$lang->branch->confirmActivate = '是否激活该@branch@?'; $lang->branch->noData = '暂时没有分支。'; $lang->branch->mainBranch = '产品默认主干分支。'; diff --git a/module/branch/model.php b/module/branch/model.php index 18f5c329cb..7c47f9e09f 100644 --- a/module/branch/model.php +++ b/module/branch/model.php @@ -45,7 +45,7 @@ class branchModel extends model * @access public * @return array */ - public function getList($productID, $browseType = 'active', $orderBy = 'order_desc', $pager = null) + public function getList($productID, $browseType = 'active', $orderBy = 'order', $pager = null) { $branchList = $this->dao->select('*')->from(TABLE_BRANCH) ->where('deleted')->eq(0) @@ -57,12 +57,15 @@ class branchModel extends model if($browseType == 'closed') return $branchList; + $defaultBranch = BRANCH_MAIN; + foreach($branchList as $branch) $defaultBranch = $branch->default ? $branch->id : $defaultBranch; + /* Display the main branch under all and active page. */ $mainBranch = new stdclass(); $mainBranch->id = BRANCH_MAIN; $mainBranch->product = $productID; $mainBranch->name = $this->lang->branch->main; - $mainBranch->default = 1; + $mainBranch->default = $defaultBranch ? 0 : 1; $mainBranch->status = 'active'; $mainBranch->createdDate = ''; $mainBranch->closedDate = ''; @@ -181,6 +184,52 @@ class branchModel extends model return false; } + /** + * Batch update branch. + * + * @access public + * @return array + */ + public function batchUpdate($productID) + { + $data = fixer::input('post')->get(); + $oldBranchList = $this->getList($productID, 'all'); + $branchIDList = array_keys($this->post->IDList); + + foreach($branchIDList as $branchID) + { + if($branchID == BRANCH_MAIN) + { + $newMainBranch = new stdClass(); + $newMainBranch->default = (isset($data->default) and $data->default == BRANCH_MAIN) ? 1 : 0; + + $changes[$branchID] = common::createChanges($oldBranchList[BRANCH_MAIN], $newMainBranch); + } + else + { + $branch = new stdclass(); + $branch->name = $data->name[$branchID]; + $branch->desc = $data->desc[$branchID]; + $branch->status = $data->status[$branchID]; + $branch->default = (isset($data->default) and $branchID == $data->default) ? 1 : 0; + $branch->closedDate = $branch->status == 'closed' ? helper::today() : ''; + + $this->dao->update(TABLE_BRANCH)->data($branch, 'default') + ->batchCheck($this->config->branch->create->requiredFields, 'notempty') + ->where('id')->eq($branchID) + ->exec(); + + if(dao::isError()) die(js::error('branch#' . $branchID . dao::getError(true))); + + $changes[$branchID] = common::createChanges($oldBranchList[$branchID], $branch); + } + } + + if(isset($data->default)) $this->setDefault($productID, $data->default); + + return $changes; + } + /** * Close a branch. * @@ -193,6 +242,7 @@ class branchModel extends model $this->dao->update(TABLE_BRANCH) ->set('status')->eq('closed') ->set('closedDate')->eq(helper::today()) + ->set('`default`')->eq('0') ->where('id')->eq($branchID) ->exec(); } @@ -314,11 +364,18 @@ class branchModel extends model */ public function sort() { - $data = fixer::input('post')->get(); - $branches = trim($data->branches, ','); - foreach(explode(',', $branches) as $order => $branchID) + $orderBy = $this->post->orderBy; + $branchIDList = explode(',', trim($this->post->branches, ',')); + + if(strpos($orderBy, 'order') === false) return false; + if(in_array(BRANCH_MAIN, $branchIDList)) unset($branchIDList[array_search(BRANCH_MAIN, $branchIDList)]); + + $branches = $this->dao->select('id,`order`')->from(TABLE_BRANCH)->where('id')->in($branchIDList)->orderBy($orderBy)->fetchPairs('order', 'id'); + foreach($branches as $order => $id) { - $this->dao->update(TABLE_BRANCH)->set('`order`')->eq($order)->where('id')->eq($branchID)->exec(); + $newID = array_shift($branchIDList); + if($id == $newID) continue; + $this->dao->update(TABLE_BRANCH)->set('`order`')->eq($order)->where('id')->eq($newID)->exec(); } } @@ -362,4 +419,24 @@ class branchModel extends model $linkHtml = strpos('programplan', $module) !== false ? sprintf($link, $projectID, $productID, $branch) : sprintf($link, $productID, $branch); return $linkHtml; } + + /** + * Set default branch. + * + * @param int $productID + * @param int $branchID + * @accesss public + * @return void + */ + public function setDefault($productID, $branchID) + { + $defaultBranch = $this->dao->select('id')->from(TABLE_BRANCH) + ->where('product')->eq($productID) + ->andWhere('`default`')->eq('1') + ->fetch('id'); + + if(!empty($defaultBranch)) $this->dao->update(TABLE_BRANCH)->set('`default`')->eq('0')->where('id')->eq($defaultBranch)->exec(); + + $this->dao->update(TABLE_BRANCH)->set('`default`')->eq('1')->where('id')->eq($branchID)->exec(); + } } diff --git a/module/branch/view/batchedit.html.php b/module/branch/view/batchedit.html.php new file mode 100644 index 0000000000..8302c0a3d4 --- /dev/null +++ b/module/branch/view/batchedit.html.php @@ -0,0 +1,49 @@ + + * @package branch + * @version $Id: batchedit.html.php 4903 2021-11-09 13:14:59Z hfz $ + * @link https://www.zentao.net + */ +?> + +
+
+

branch->common . '-' . $lang->branch->batchEdit;?>

+
+
+ + + + + + + + + + + + + id == BRANCH_MAIN ? 'disabled' : '';?> + + + + + + + + + + + + +
branch->id;?>branch->name;?>branch->desc;?>branch->status;?>branch->defaultBranch;?>
id == BRANCH_MAIN ? '' : $branch->id) . html::hidden("IDList[$branch->id]", $branch);?>id]", $branch->name, "class='form-control chosen' $disabled");?>id]", $branch->desc, "class='form-control' $disabled");?>id]", $lang->branch->statusList, $branch->status, "class='form-control' chosen $disabled onchange='canSetDefaultBranch(this)'");?>default) echo 'checked';?> status == 'closed') echo 'disabled';?>>
+ +
+
+
+ diff --git a/module/branch/view/manage.html.php b/module/branch/view/manage.html.php index 46d6e6c0a8..18027301b7 100644 --- a/module/branch/view/manage.html.php +++ b/module/branch/view/manage.html.php @@ -12,7 +12,9 @@ ?> + + @@ -39,7 +41,7 @@

-
+ @@ -49,7 +51,9 @@
+ + @@ -58,23 +62,43 @@ - + - + id == BRANCH_MAIN;?> + - - + + + + + moduleName == 'product' && $app->methodName == 'browse'):?> + + + + + diff --git a/module/datatable/control.php b/module/datatable/control.php index 1c2ef4cc0e..76c526121f 100644 --- a/module/datatable/control.php +++ b/module/datatable/control.php @@ -38,6 +38,7 @@ class datatable extends control $name = 'datatable.' . $this->post->target . '.' . $this->post->name; $this->loadModel('setting')->setItem($account . '.' . $name, $this->post->value); if($this->post->allModule !== false) $this->setting->setItem("$account.execution.task.allModule", $this->post->allModule); + if($this->post->showBranch !== false) $this->setting->setItem("$account.product.browse.showBranch", $this->post->showBranch); if($this->post->global) $this->setting->setItem('system.' . $name, $this->post->value); if(dao::isError()) return $this->send(array('result' => 'fail', 'message' => 'dao error.')); diff --git a/module/datatable/lang/en.php b/module/datatable/lang/en.php index a2253f5f34..93d550dbd4 100644 --- a/module/datatable/lang/en.php +++ b/module/datatable/lang/en.php @@ -19,10 +19,14 @@ $lang->datatable->branch = 'Branch'; $lang->datatable->platform = 'Platform'; $lang->datatable->moduleSetting = 'Set Module'; +$lang->datatable->listSetting = 'Set list'; $lang->datatable->showModule = 'Show modules in the list'; +$lang->datatable->showBranch = 'Show branches in the list'; $lang->datatable->showAllModule = 'Show product modules'; $lang->datatable->showModuleList[] = 'N/A'; $lang->datatable->showModuleList['base'] = 'Base Node'; $lang->datatable->showModuleList['end'] = 'End Node'; $lang->datatable->showAllModuleList[0] = 'Hide'; $lang->datatable->showAllModuleList[1] = 'Show'; +$lang->datatable->showBranchList[0] = 'Hide'; +$lang->datatable->showBranchList[1] = 'Show'; diff --git a/module/datatable/lang/zh-cn.php b/module/datatable/lang/zh-cn.php index 6b7a4573c8..81cd44b83c 100644 --- a/module/datatable/lang/zh-cn.php +++ b/module/datatable/lang/zh-cn.php @@ -19,10 +19,14 @@ $lang->datatable->branch = '分支'; $lang->datatable->platform = '平台'; $lang->datatable->moduleSetting = '模块设置'; +$lang->datatable->listSetting = '列表设置'; $lang->datatable->showModule = '列表页是否显示模块名'; +$lang->datatable->showBranch = '列表页是否显示分支名'; $lang->datatable->showAllModule = '是否显示完整产品模块'; $lang->datatable->showModuleList[] = '不显示'; $lang->datatable->showModuleList['base'] = '只显示一级模块'; $lang->datatable->showModuleList['end'] = '只显示最后一级模块'; $lang->datatable->showAllModuleList[0] = '不显示'; $lang->datatable->showAllModuleList[1] = '显示'; +$lang->datatable->showBranchList[0] = '不显示'; +$lang->datatable->showBranchList[1] = '显示'; diff --git a/module/execution/control.php b/module/execution/control.php index bedec7a200..beff87bc96 100644 --- a/module/execution/control.php +++ b/module/execution/control.php @@ -1276,17 +1276,29 @@ class execution extends control if($copyExecutionID) { $copyExecution = $this->dao->select('*')->from(TABLE_EXECUTION)->where('id')->eq($copyExecutionID)->fetch(); - $name = $copyExecution->name; - $code = $copyExecution->code; - $team = $copyExecution->team; - $acl = $copyExecution->acl; - $whitelist = $copyExecution->whitelist; - $projectID = $copyExecution->project; - $products = $this->execution->getProducts($copyExecutionID); - foreach($products as $product) + $name = $copyExecution->name; + $code = $copyExecution->code; + $team = $copyExecution->team; + $acl = $copyExecution->acl; + $whitelist = $copyExecution->whitelist; + $projectID = $copyExecution->project; + $products = $this->execution->getProducts($copyExecutionID); + $branches = $this->project->getBranchesByProject($copyExecutionID); + $plans = $this->loadModel('productplan')->getGroupByProduct(array_keys($products)); + $branchGroups = $this->execution->getBranchByProduct(array_keys($products), $projectID); + + $linkedBranches = array(); + foreach($products as $productID => $product) { - $productPlans[$product->id] = $this->loadModel('productplan')->getPairs($product->id); + foreach($branches[$productID] as $branchID => $branch) + { + $linkedBranches[$productID][$branchID] = $branchID; + $productPlans[$productID][$branchID] = isset($plans[$productID][$branchID]) ? $plans[$productID][$branchID] : array(); + } } + + $this->view->branches = $branches; + $this->view->linkedBranches = $linkedBranches; } if(!empty($planID)) @@ -1297,7 +1309,7 @@ class execution extends control ->where('t1.id')->eq($plan->product) ->fetchAll('id'); - $productPlan = $this->loadModel('productplan')->getPairs($plan->product, 0, 'unexpired'); + $productPlan = $this->loadModel('productplan')->getPairs($plan->product, $plan->branch, 'unexpired'); } if(!empty($_POST)) @@ -1322,9 +1334,12 @@ class execution extends control $planID = ''; if(isset($_POST['plans'])) { - foreach($_POST['plans'] as $planID) + foreach($_POST['plans'] as $plans) { - if(!empty($planID)) break; + foreach($plans as $planID) + { + if(!empty($planID)) break; + } } } @@ -1355,34 +1370,35 @@ class execution extends control $rdUsers = $this->user->getPairs('noclosed|nodeleted|devfirst', '', $this->config->maxCount); if(!empty($this->config->user->moreLink)) $this->config->moreLinks["RD"] = $this->config->user->moreLink; - $this->view->title = (($this->app->tab == 'execution') and ($this->config->systemMode == 'new')) ? $this->lang->execution->createExec : $this->lang->execution->create; - $this->view->position[] = $this->view->title; - $this->view->gobackLink = (isset($output['from']) and $output['from'] == 'global') ? $this->createLink('execution', 'all') : ''; - $this->view->executions = array('' => '') + $this->execution->getList($projectID); - $this->view->groups = $this->loadModel('group')->getPairs(); - $this->view->allProducts = array(0 => '') + $this->loadModel('product')->getProductPairsByProject($projectID, 'noclosed'); - $this->view->acl = $acl; - $this->view->plan = $plan; - $this->view->name = $name; - $this->view->code = $code; - $this->view->team = $team; - $this->view->teams = array(0 => '') + $this->execution->getTeamPairsByProject((int)$projectID); - $this->view->allProjects = array(0 => '') + $this->project->getPairsByModel(); - $this->view->executionID = $executionID; - $this->view->productID = $productID; - $this->view->projectID = $projectID; - $this->view->products = $products; - $this->view->productPlan = array(0 => '') + $productPlan; - $this->view->productPlans = array(0 => '') + $productPlans; - $this->view->whitelist = $whitelist; - $this->view->copyExecutionID = $copyExecutionID; - $this->view->branchGroups = $this->loadModel('branch')->getByProducts(array_keys($products)); - $this->view->poUsers = $poUsers; - $this->view->pmUsers = $pmUsers; - $this->view->qdUsers = $qdUsers; - $this->view->rdUsers = $rdUsers; - $this->view->users = $this->loadModel('user')->getPairs('nodeleted|noclosed'); - $this->view->from = $this->app->tab; + $this->view->title = (($this->app->tab == 'execution') and ($this->config->systemMode == 'new')) ? $this->lang->execution->createExec : $this->lang->execution->create; + $this->view->position[] = $this->view->title; + $this->view->gobackLink = (isset($output['from']) and $output['from'] == 'global') ? $this->createLink('execution', 'all') : ''; + $this->view->executions = array('' => '') + $this->execution->getList($projectID); + $this->view->groups = $this->loadModel('group')->getPairs(); + $this->view->allProducts = array(0 => '') + $this->loadModel('product')->getProductPairsByProject($projectID, 'noclosed'); + $this->view->acl = $acl; + $this->view->plan = $plan; + $this->view->name = $name; + $this->view->code = $code; + $this->view->team = $team; + $this->view->teams = array(0 => '') + $this->execution->getTeamPairsByProject((int)$projectID); + $this->view->allProjects = array(0 => '') + $this->project->getPairsByModel(); + $this->view->executionID = $executionID; + $this->view->productID = $productID; + $this->view->projectID = $projectID; + $this->view->products = $products; + $this->view->multiBranchProducts = $this->product->getMultiBranchPairs(); + $this->view->productPlan = array(0 => '') + $productPlan; + $this->view->productPlans = array(0 => '') + $productPlans; + $this->view->whitelist = $whitelist; + $this->view->copyExecutionID = $copyExecutionID; + $this->view->branchGroups = isset($branchGroups) ? $branchGroups : $this->execution->getBranchByProduct(array_keys($products), $projectID); + $this->view->poUsers = $poUsers; + $this->view->pmUsers = $pmUsers; + $this->view->qdUsers = $qdUsers; + $this->view->rdUsers = $rdUsers; + $this->view->users = $this->loadModel('user')->getPairs('nodeleted|noclosed'); + $this->view->from = $this->app->tab; $this->display(); } @@ -1434,14 +1450,19 @@ class execution extends control } /* Link the plan stories. */ - $newPlans = $this->dao->select('plan')->from(TABLE_PROJECTPRODUCT)->where('project')->eq($executionID)->andWhere('plan')->ne(0)->fetchPairs('plan'); + $newPlans = array(); + foreach($_POST['plans'] as $plans) + { + foreach($plans as $planID) $newPlans[$planID] = $planID; + } + $diffResult = array_diff($oldPlans, $newPlans); $diffResult = array_merge($diffResult, array_diff($newPlans, $oldPlans)); if(!empty($newPlans) and !empty($diffResult)) { $projectID = $this->dao->select('project')->from(TABLE_EXECUTION)->where('id')->eq($executionID)->fetch('project'); - $this->loadModel('productplan')->linkProject($executionID, $_POST['plans']); - $this->productplan->linkProject($projectID, $_POST['plans']); + $this->loadModel('productplan')->linkProject($executionID, $newPlans); + $this->productplan->linkProject($projectID, $newPlans); } $this->executeHooks($executionID); @@ -1466,28 +1487,30 @@ class execution extends control $executionProsucts = $this->execution->getProducts($execution->project, true, 'noclosed'); foreach($executionProsucts as $product) $allProducts[$product->id] = $product->name; - $linkedProducts = $this->execution->getProducts($execution->id); - $linkedBranches = array(); + $this->loadModel('productplan'); + $productPlans = array(0 => ''); + $linkedBranches = array(); + $linkedProducts = $this->execution->getProducts($executionID); + $branches = $this->project->getBranchesByProject($executionID); + $plans = $this->productplan->getGroupByProduct(array_keys($linkedProducts)); + $executionStories = $this->project->getStoriesByProject($executionID); /* If the story of the product which linked the execution, you don't allow to remove the product. */ $unmodifiableProducts = array(); + $unmodifiableBranches = array(); foreach($linkedProducts as $productID => $linkedProduct) { - $executionStories = $this->dao->select('*')->from(TABLE_PROJECTSTORY)->where('project')->eq($executionID)->andWhere('product')->eq($productID)->fetchAll('story'); - if(!empty($executionStories)) array_push($unmodifiableProducts, $productID); - } - - foreach($linkedProducts as $product) - { - if(!isset($allProducts[$product->id])) $allProducts[$product->id] = $product->name; - if($product->branch) $linkedBranches[$product->branch] = $product->branch; - } - - $this->loadModel('productplan'); - $productPlans = array(0 => ''); - foreach($linkedProducts as $product) - { - $productPlans[$product->id] = $this->productplan->getPairs($product->id); + if(!isset($allProducts[$productID])) $allProducts[$productID] = $linkedProduct->name; + foreach($branches[$productID] as $branchID => $branch) + { + $linkedBranches[$productID][$branchID] = $branchID; + $productPlans[$productID][$branchID] = isset($plans[$productID][$branchID]) ? $plans[$productID][$branchID] : array(); + if(!empty($executionStories[$productID][$branchID])) + { + array_push($unmodifiableProducts, $productID); + array_push($unmodifiableBranches, $branchID); + } + } } $this->loadModel('user'); @@ -1516,9 +1539,13 @@ class execution extends control $this->view->groups = $this->loadModel('group')->getPairs(); $this->view->allProducts = $allProducts; $this->view->linkedProducts = $linkedProducts; + $this->view->linkedBranches = $linkedBranches; + $this->view->branches = $branches; $this->view->unmodifiableProducts = $unmodifiableProducts; + $this->view->unmodifiableBranches = $unmodifiableBranches; + $this->view->multiBranchProducts = $this->loadModel('product')->getMultiBranchPairs(); $this->view->productPlans = $productPlans; - $this->view->branchGroups = $this->loadModel('branch')->getByProducts(array_keys($linkedProducts), '', $linkedBranches); + $this->view->branchGroups = $this->execution->getBranchByProduct(array_keys($linkedProducts), $execution->project); $this->display(); } @@ -2243,33 +2270,40 @@ class execution extends control $position[] = html::a($browseExecutionLink, $execution->name); $position[] = $this->lang->execution->manageProducts; - $allProducts = $this->config->systemMode == 'classic' ? $this->product->getPairs('noclosed') : $this->product->getProductPairsByProject($execution->project); - $linkedProducts = $this->execution->getProducts($execution->id); - $linkedBranches = array(); + $allProducts = $this->config->systemMode == 'classic' ? $this->product->getPairs('noclosed') : $this->product->getProductPairsByProject($execution->project); + $linkedProducts = $this->execution->getProducts($execution->id); + $linkedBranches = array(); + $branches = $this->project->getBranchesByProject($executionID); + $executionStories = $this->project->getStoriesByProject($executionID); /* If the story of the product which linked the execution, you don't allow to remove the product. */ $unmodifiableProducts = array(); + $unmodifiableBranches = array(); foreach($linkedProducts as $productID => $linkedProduct) { - $executionStories = $this->dao->select('*')->from(TABLE_PROJECTSTORY)->where('project')->eq($executionID)->andWhere('product')->eq($productID)->fetchAll('story'); - if(!empty($executionStories)) array_push($unmodifiableProducts, $productID); - } - - // Merge allProducts and linkedProducts for closed product. - foreach($linkedProducts as $product) - { - if(!isset($allProducts[$product->id])) $allProducts[$product->id] = $product->name; - if(!empty($product->branch)) $linkedBranches[$product->branch] = $product->branch; + $linkedBranches[$productID] = array(); + if(!isset($allProducts[$productID])) $allProducts[$productID] = $linkedProduct->name; + foreach($branches[$productID] as $branchID => $branch) + { + $linkedBranches[$productID][$branchID] = $branchID; + if(!empty($executionStories[$productID][$branchID])) + { + array_push($unmodifiableProducts, $productID); + array_push($unmodifiableBranches, $branchID); + } + } } /* Assign. */ $this->view->title = $title; $this->view->position = $position; $this->view->allProducts = $allProducts; - $this->view->execution = $execution; + $this->view->execution = $execution; $this->view->linkedProducts = $linkedProducts; $this->view->unmodifiableProducts = $unmodifiableProducts; - $this->view->branchGroups = $this->loadModel('branch')->getByProducts(array_keys($allProducts), 'ignoreNormal', $linkedBranches); + $this->view->unmodifiableBranches = $unmodifiableBranches; + $this->view->linkedBranches = $linkedBranches; + $this->view->branchGroups = $this->execution->getBranchByProduct(array_keys($linkedProducts), $execution->project); $this->display(); } diff --git a/module/execution/js/common.js b/module/execution/js/common.js index 91e8ca7acc..92953627e7 100644 --- a/module/execution/js/common.js +++ b/module/execution/js/common.js @@ -127,7 +127,7 @@ function loadBranches(product) $('#productsBox select').each(function() { var $product = $(product); - if($product.val() != 0 && $product.val() == $(this).val() && $product.attr('id') != $(this).attr('id')) + if($product.val() != 0 && $product.val() == $(this).val() && $product.attr('id') != $(this).attr('id') && !multiBranchProducts[$product.val()]) { alert(errorSameProducts); $product.val(0); @@ -152,8 +152,9 @@ function loadBranches(product) if($inputgroup.find('select').size() >= 2) $inputgroup.removeClass('has-branch').find('select:last').remove(); if($inputgroup.find('.chosen-container').size() >= 2) $inputgroup.find('.chosen-container:last').remove(); + var projectID = $('#project').val(); var index = $inputgroup.find('select:first').attr('id').replace('products' , ''); - $.get(createLink('branch', 'ajaxGetBranches', "productID=" + $(product).val()), function(data) + $.get(createLink('branch', 'ajaxGetBranches', "productID=" + $(product).val() + "&oldBranch=0¶m=active&projectID=" + projectID), function(data) { if(data) { @@ -182,7 +183,7 @@ function loadPlans(product, branchID) if(data) { if($("div#plan" + index).size() == 0) $("#plansBox .row").append('
'); - $("div#plan" + index).html(data).find('select').attr('name', 'plans[' + productID + ']').attr('id', 'plans' + productID).chosen(); + $("div#plan" + index).html(data).find('select').attr('name', 'plans[' + productID + '][' + branchID + ']').attr('id', 'plans' + productID).chosen(); adjustPlanBoxMargin(); } diff --git a/module/execution/js/create.js b/module/execution/js/create.js index 2b58cb3af6..3ee176db92 100644 --- a/module/execution/js/create.js +++ b/module/execution/js/create.js @@ -78,6 +78,42 @@ $(function() var acl = $("[name^='acl']:checked").val(); setWhite(acl); + + $('#submit').click(function() + { + var products = new Array(); + var existedBranch = false; + + /* Determine whether the products of the same branch are linked. */ + $("#productsBox select[name^='products']").each(function() + { + var productID = $(this).val(); + products[productID] = new Array(); + if(multiBranchProducts[productID]) + { + $("#productsBox select[name^='branch']").each(function() + { + var branchID = $(this).val(); + if(products[productID][branchID]) + { + existedBranch = true; + return false; + } + else + { + products[productID][branchID] = branchID; + } + }) + if(existedBranch) return false; + } + }) + + if(existedBranch) + { + bootbox.alert(errorSameBranches); + return false; + } + }) }); function showLifeTimeTips() diff --git a/module/execution/js/edit.js b/module/execution/js/edit.js index 6149182c46..81039a601b 100644 --- a/module/execution/js/edit.js +++ b/module/execution/js/edit.js @@ -4,22 +4,70 @@ $().ready(function() { $('#products0').removeAttr("disabled"); $('#branch0').removeAttr("disabled"); - }); + var products = new Array(); + var existedBranch = false; + + /* Determine whether the products of the same branch are linked. */ + $("#productsBox select[name^='products']").each(function() + { + var productID = $(this).val(); + products[productID] = new Array(); + if(multiBranchProducts[productID]) + { + $("#productsBox select[name^='branch']").each(function() + { + var branchID = $(this).val(); + if(products[productID][branchID]) + { + existedBranch = true; + return false; + } + else + { + products[productID][branchID] = branchID; + } + }) + if(existedBranch) return false; + } + }) + + if(existedBranch) + { + bootbox.alert(errorSameBranches); + return false; + } + }) }); $(function() { /* If the story of the product which linked the execution under the project, you don't allow to remove the product. */ - $("#productsBox select").each(function() + $("#productsBox select[name^='products']").each(function() { - var isExisted = $.inArray($(this).attr('data-last'), unmodifiableProducts); - if(isExisted != -1) + var isExistedProduct = $.inArray($(this).attr('data-last'), unmodifiableProducts); + var productType = $(this).attr('data-type'); + if(isExistedProduct != -1 && productType == 'normal') { $(this).prop('disabled', true).trigger("chosen:updated"); $(this).siblings('div').find('span').attr('title', tip); } }); + $("#productsBox select[name^='branch']").each(function() + { + var isExistedBranch = $.inArray($(this).attr('data-last'), unmodifiableBranches); + if(isExistedBranch != -1) + { + var $product = $(this).closest('.has-branch').find("[name^='products']"); + if($.inArray($product.val(), unmodifiableProducts) != -1) + { + $(this).prop('disabled', true).trigger("chosen:updated"); + $product.prop('disabled', true).trigger("chosen:updated"); + $product.siblings('div').find('span').attr('title', tip); + } + } + }); + oldProject = $("#project").val(); $('#project').change(function() { diff --git a/module/execution/lang/en.php b/module/execution/lang/en.php index b909685a16..cbfca1a77d 100644 --- a/module/execution/lang/en.php +++ b/module/execution/lang/en.php @@ -328,6 +328,7 @@ $lang->execution->notAllowedUnlinkStory = "This {$lang->SRCommon} is linke $lang->execution->notAllowRemoveProducts = "The story of this product is linked with the {$lang->executionCommon}. Unlink it before doing any action."; $lang->execution->errorNoLinkedProducts = "No {$lang->productCommon} is linked to {$lang->executionCommon}. You will be directed to {$lang->productCommon} page to link one."; $lang->execution->errorSameProducts = "{$lang->executionCommon} cannot be linked to the same {$lang->productCommon} twice."; +$lang->execution->errorSameBranches = "{$lang->executionCommon} cannot be linked to the same branch twice"; $lang->execution->errorBegin = "The start time of {$lang->executionCommon} cannot be less than the start time of the project %s."; $lang->execution->errorEnd = "The end time of {$lang->executionCommon} cannot be greater than the end time %s of the project."; $lang->execution->accessDenied = "Your access to {$lang->executionCommon} is denied!"; diff --git a/module/execution/lang/zh-cn.php b/module/execution/lang/zh-cn.php index 31a16f3ea0..3e609f0569 100644 --- a/module/execution/lang/zh-cn.php +++ b/module/execution/lang/zh-cn.php @@ -328,6 +328,7 @@ $lang->execution->notAllowedUnlinkStory = "该{$lang->SRCommon}已经与 $lang->execution->notAllowRemoveProducts = "该{$lang->productCommon}中的{$lang->SRCommon}已与该{$lang->executionCommon}进行了关联,请取消关联后再操作。"; $lang->execution->errorNoLinkedProducts = "该{$lang->executionCommon}没有关联的{$lang->productCommon},系统将转到{$lang->productCommon}关联页面"; $lang->execution->errorSameProducts = "{$lang->executionCommon}不能关联多个相同的{$lang->productCommon}。"; +$lang->execution->errorSameBranches = "{$lang->executionCommon}不能关联多个相同的分支。"; $lang->execution->errorBegin = "{$lang->executionCommon}的开始时间不能小于所属项目的开始时间%s。"; $lang->execution->errorEnd = "{$lang->executionCommon}的截止时间不能大于所属项目的结束时间%s。"; $lang->execution->accessDenied = "您无权访问该{$lang->executionCommon}!"; diff --git a/module/execution/model.php b/module/execution/model.php index 3b7102b0d0..54c37ce3e8 100644 --- a/module/execution/model.php +++ b/module/execution/model.php @@ -525,7 +525,7 @@ class executionModel extends model ->exec(); $changedAccounts = array(); - $teamMembers = array(); + $teamMembers = array(); foreach($this->config->execution->ownerFields as $ownerField) { $owner = zget($execution, $ownerField, ''); @@ -542,7 +542,7 @@ class executionModel extends model $this->dao->replace(TABLE_TEAM)->data($member)->exec(); $changedAccounts[$owner] = $owner; - $teamMembers[$ownerField] = $member; + $teamMembers[$ownerField] = $member; } if($execution->project) $this->addProjectMembers($execution->project, $teamMembers); @@ -1655,6 +1655,28 @@ class executionModel extends model return $query->fetchAll('id'); } + /** + * Get branch pairs by product id list. + * + * @param array $products + * @param int $projectID + * @access public + * @return array + */ + public function getBranchByProduct($products, $projectID) + { + $branchGroups = $this->loadModel('branch')->getByProducts($products, 'noclosed'); + $projectProducts = $this->loadModel('project')->getBranchesByProject($projectID); + foreach($branchGroups as $productID => $branchPairs) + { + foreach($branchPairs as $branchID => $branchName) + { + if(!isset($projectProducts[$productID][$branchID])) unset($branchGroups[$productID][$branchID]); + } + } + return $branchGroups; + } + /** * Get ordered executions. * @@ -1817,10 +1839,13 @@ class executionModel extends model foreach($products as $i => $productID) { if(empty($productID)) continue; - if(isset($existedProducts[$productID])) continue; + if(!isset($existedProducts[$productID])) $existedProducts[$productID] = array(); $oldPlan = 0; $branch = isset($branches[$i]) ? $branches[$i] : 0; + + if(isset($existedProducts[$productID][$branch])) continue; + if(isset($oldProducts[$productID][$branch])) { $oldProduct = $oldProducts[$productID][$branch]; @@ -1831,9 +1856,9 @@ class executionModel extends model $data->project = $executionID; $data->product = $productID; $data->branch = $branch; - $data->plan = isset($plans[$productID]) ? $plans[$productID] : $oldPlan; + $data->plan = isset($plans[$productID][$branch]) ? $plans[$productID][$branch] : $oldPlan; $this->dao->insert(TABLE_PROJECTPRODUCT)->data($data)->exec(); - $existedProducts[$productID] = true; + $existedProducts[$productID][$branch] = true; } $oldProductKeys = array_keys($oldProducts); diff --git a/module/execution/view/create.html.php b/module/execution/view/create.html.php index f9811fd15a..0790b4f602 100644 --- a/module/execution/view/create.html.php +++ b/module/execution/view/create.html.php @@ -34,11 +34,13 @@ execution->weekend);?> execution->placeholder);?> execution->errorSameProducts);?> +execution->errorSameBranches);?> systemMode);?> project->common);?> +
@@ -132,12 +134,14 @@ - id, array(0 => ''));?> -
id . "]", $plans, '', "class='form-control chosen'");?>
+ id] as $branchID => $branch):?> + id][$branchID]) ? $productPlans[$product->id][$branchID] : array();?> +
id}][$branchID]", $plans, $branches[$product->id][$branchID]->plan, "class='form-control chosen'");?>
+ -
+
diff --git a/module/execution/view/edit.html.php b/module/execution/view/edit.html.php index 3e614444a5..7328dee226 100644 --- a/module/execution/view/edit.html.php +++ b/module/execution/view/edit.html.php @@ -116,16 +116,24 @@
+ type != 'normal' and isset($branchGroups[$product->id]);?> + id] as $branchID => $branch):?>
- type != 'normal' and isset($branchGroups[$product->id]);?>
- id, "class='form-control chosen' $class onchange='loadBranches(this)' data-last='" . $product->id . "'");?> + id, "class='form-control chosen' $class onchange='loadBranches(this)' data-last='" . $product->id . "' data-type='". $product->type ."'");?> - id], $product->branch, "class='form-control chosen' $class onchange=\"loadPlans('#products{$i}', this.value)\"");?> + id], $branchID, "class='form-control chosen' $class onchange=\"loadPlans('#products{$i}', this.value)\" data-last='" . $branchID . "'");?>
- id, $unmodifiableProducts)) echo html::hidden("products[$i]", $product->id);?> - + id, $unmodifiableProducts) and in_array($branchID, $unmodifiableBranches)) + { + echo html::hidden("products[$i]", $product->id); + echo html::hidden("branch[$i]", $branchID); + } + $i++; + ?> +
@@ -142,10 +150,12 @@
- id, array(0 => ''));?> -
id . "]", $plans, $product->plan, "class='form-control chosen'");?>
+ id] as $branchID => $branch):?> + id][$branchID]) ? $productPlans[$product->id][$branchID] : array();?> +
id}][{$branchID}]", $plans, $branches[$product->id][$branchID]->plan, "class='form-control chosen'");?>
+
@@ -171,7 +181,10 @@
execution->weekend);?> execution->errorSameProducts);?> +execution->errorSameBranches);?> + + execution->notAllowRemoveProducts);?> execution->confirmSyncStories);?> diff --git a/module/execution/view/manageproducts.html.php b/module/execution/view/manageproducts.html.php index 1b7afe4610..b717155f66 100644 --- a/module/execution/view/manageproducts.html.php +++ b/module/execution/view/manageproducts.html.php @@ -22,23 +22,30 @@
execution->linkedProducts;?>
- grade == 2 ? "disabled='disabled'" : '';?> + + grade == 2 ? "disabled='disabled'" : '';?> $productName):?> - - execution->notAllowRemoveProducts : $productName;?> - + + + execution->notAllowRemoveProducts : $productName;?> +
'>
- ";?> + ";?>
- branch, "class='form-control chosen' $class");?> +
- - + + + + + + +
diff --git a/module/group/lang/resource.php b/module/group/lang/resource.php index 26a85ea898..f08660dd09 100644 --- a/module/group/lang/resource.php +++ b/module/group/lang/resource.php @@ -420,13 +420,15 @@ $lang->product->methodOrder[105] = 'unbindWhitelist'; /* Branch. */ $lang->resource->branch = new stdclass(); -$lang->resource->branch->manage = 'manage'; -$lang->resource->branch->create = 'create'; -$lang->resource->branch->edit = 'editAction'; -$lang->resource->branch->close = 'closeAction'; -$lang->resource->branch->activate = 'activateAction'; -$lang->resource->branch->sort = 'sort'; -$lang->resource->branch->delete = 'delete'; +$lang->resource->branch->manage = 'manage'; +$lang->resource->branch->create = 'create'; +$lang->resource->branch->edit = 'editAction'; +$lang->resource->branch->close = 'closeAction'; +$lang->resource->branch->activate = 'activateAction'; +$lang->resource->branch->sort = 'sort'; +$lang->resource->branch->delete = 'delete'; +$lang->resource->branch->batchEdit = 'batchEdit'; +$lang->resource->branch->setDefault = 'setDefaultAction'; $lang->branch->methodOrder[0] = 'manage'; $lang->branch->methodOrder[5] = 'create'; @@ -435,6 +437,7 @@ $lang->branch->methodOrder[15] = 'close'; $lang->branch->methodOrder[20] = 'activate'; $lang->branch->methodOrder[25] = 'sort'; $lang->branch->methodOrder[30] = 'delete'; +$lang->branch->methodOrder[35] = 'batchEdit'; /* Story. */ $lang->resource->story = new stdclass(); diff --git a/module/project/control.php b/module/project/control.php index d0a1b45c26..1a78c40116 100644 --- a/module/project/control.php +++ b/module/project/control.php @@ -542,7 +542,7 @@ class project extends control $unmodifiableBranches = array(); foreach($linkedProducts as $productID => $linkedProduct) { - if(!isset($allProducts[$productID])) $allProducts[$productID] = $product->name; + if(!isset($allProducts[$productID])) $allProducts[$productID] = $linkedProduct->name; foreach($branches[$productID] as $branchID => $branch) { $linkedBranches[$productID][$branchID] = $branchID; @@ -1716,8 +1716,8 @@ class project extends control $unmodifiableBranches = array(); foreach($linkedProducts as $productID => $linkedProduct) { - if(!isset($allProducts[$productID])) $allProducts[$productID] = $product->name; $linkedBranches[$productID] = array(); + if(!isset($allProducts[$productID])) $allProducts[$productID] = $linkedProduct->name; foreach($branches[$productID] as $branchID => $branch) { $linkedBranches[$productID][$branchID] = $branchID; diff --git a/module/project/js/create.js b/module/project/js/create.js index a345bde136..a4aedf2d0d 100644 --- a/module/project/js/create.js +++ b/module/project/js/create.js @@ -28,7 +28,7 @@ $(function() $('#submit').click(function() { - var products = []; + var products = new Array(); var existedBranch = false; /* Determine whether the products of the same branch are linked. */ diff --git a/module/project/js/edit.js b/module/project/js/edit.js index b0da7af1da..5b143b401c 100644 --- a/module/project/js/edit.js +++ b/module/project/js/edit.js @@ -96,7 +96,7 @@ $(function() $('#submit').click(function() { - var products = []; + var products = new Array(); var existedBranch = false; /* Determine whether the products of the same branch are linked. */ diff --git a/module/project/view/edit.html.php b/module/project/view/edit.html.php index 4e151254ed..4e1d96f647 100644 --- a/module/project/view/edit.html.php +++ b/module/project/view/edit.html.php @@ -149,7 +149,7 @@ id] as $branchID => $branch):?> - id][$branchID];?> + id][$branchID]) ? $productPlans[$product->id][$branchID] : array();?>
id}][{$branchID}]", $plans, $branches[$product->id][$branchID]->plan, "class='form-control chosen'");?>
diff --git a/module/report/model.php b/module/report/model.php index 8b01517ab1..b2952578a1 100644 --- a/module/report/model.php +++ b/module/report/model.php @@ -287,37 +287,43 @@ class reportModel extends model if($assign == 'noassign') { - $members = $this->dao->select('t1.account,t2.name,t1.root')->from(TABLE_TEAM)->alias('t1') + $members = $this->dao->select('t1.account,t2.name,t1.root,t3.id as project,t3.name as projectname')->from(TABLE_TEAM)->alias('t1') ->leftJoin(TABLE_EXECUTION)->alias('t2')->on('t2.id = t1.root') + ->leftJoin(TABLE_PROJECT)->alias('t3')->on('t3.id = t2.project') ->where('t2.status')->notin('cancel, closed, done, suspended') ->beginIF($dept)->andWhere('t1.account')->in(array_keys($deptUsers))->fi() ->andWhere('t1.type')->eq('execution') ->andWhere("t1.account NOT IN(SELECT `assignedTo` FROM " . TABLE_TASK . " WHERE `execution` = t1.`root` AND `status` NOT IN('cancel, closed, done, pause') AND assignedTo != '' GROUP BY assignedTo)") ->fetchGroup('account', 'name'); - $workload = array(); + $workload = array(); if(!empty($members)) { foreach($members as $member => $executions) { + $project = array(); if(!empty($executions)) { foreach($executions as $name => $execution) { - $workload[$member]['task'][$name]['count'] = 0; - $workload[$member]['task'][$name]['manhour'] = 0; - $workload[$member]['task'][$name]['executionID'] = $execution->root; - $workload[$member]['total']['count'] = 0; - $workload[$member]['total']['manhour'] = 0; + $project[$execution->projectname]['projectID'] = $execution->project; + $project[$execution->projectname]['execution'][$name]['executionID'] = $execution->root; + $project[$execution->projectname]['execution'][$name]['count'] = 0; + $project[$execution->projectname]['execution'][$name]['manhour'] = 0; + + $workload[$member]['total']['count'] = 0; + $workload[$member]['total']['manhour'] = 0; } } + $workload[$member]['task']['project'] = $project; } } return $workload; } - $stmt = $this->dao->select('t1.*, t2.name as executionName')->from(TABLE_TASK)->alias('t1') + $stmt = $this->dao->select('t1.*, t2.name as executionName,t3.name as projectname')->from(TABLE_TASK)->alias('t1') ->leftJoin(TABLE_EXECUTION)->alias('t2')->on('t1.execution = t2.id') + ->leftJoin(TABLE_PROJECT)->alias('t3')->on('t3.id = t2.project') ->where('t1.deleted')->eq(0) ->andWhere('t1.status')->in('wait,pause,doing') ->andWhere('t2.deleted')->eq(0) @@ -371,17 +377,22 @@ class reportModel extends model { if($user) { + $project = array(); foreach($userTasks as $task) { if(isset($parents[$task->id])) continue; - $workload[$user]['task'][$task->executionName]['count'] = isset($workload[$user]['task'][$task->executionName]['count']) ? $workload[$user]['task'][$task->executionName]['count'] + 1 : 1; - $workload[$user]['task'][$task->executionName]['manhour'] = isset($workload[$user]['task'][$task->executionName]['manhour']) ? $workload[$user]['task'][$task->executionName]['manhour'] + $task->left : $task->left; - $workload[$user]['task'][$task->executionName]['executionID'] = $task->execution; - $workload[$user]['total']['count'] = isset($workload[$user]['total']['count']) ? $workload[$user]['total']['count'] + 1 : 1; + + $project[$task->projectname]['projectID'] = isset($project[$task->projectname]['projectID']) ? $project[$task->projectname]['projectID'] : $task->project; + $project[$task->projectname]['execution'][$task->executionName]['executionID'] = isset($project[$task->projectname]['execution'][$task->executionName]['executionID']) ? $project[$task->projectname]['execution'][$task->executionName]['executionID'] : $task->execution; + $project[$task->projectname]['execution'][$task->executionName]['count'] = isset($project[$task->projectname]['execution'][$task->executionName]['count']) ? $project[$task->projectname]['execution'][$task->executionName]['count'] + 1 : 1; + $project[$task->projectname]['execution'][$task->executionName]['manhour'] = isset($project[$task->projectname]['execution'][$task->executionName]['manhour']) ? $project[$task->projectname]['execution'][$task->executionName]['manhour'] + $task->left : $task->left; + + $workload[$user]['total']['count'] = isset($workload[$user]['total']['count']) ? $workload[$user]['total']['count'] + 1 : 1; $workload[$user]['total']['manhour'] = isset($workload[$user]['total']['manhour']) ? $workload[$user]['total']['manhour'] + $task->left : $task->left; } + $workload[$user]['task']['project'] = $project; } - } + } unset($workload['closed']); return $workload; } diff --git a/module/report/view/workload.html.php b/module/report/view/workload.html.php index df2cffe6ce..2d01a8c7f6 100644 --- a/module/report/view/workload.html.php +++ b/module/report/view/workload.html.php @@ -70,6 +70,7 @@
+ @@ -83,24 +84,31 @@ $load):?> - - - $info):?> - - ';?> - - - - - - - + + $info) foreach($info['execution'] as $exec => $execinfo) $countusername ++;?> + + $info):?> + + + $execinfo):?> + ";?> + + - '; $id ++;?> + + + + + + + + + "; $idprojectname ++; $idusername ++;?> + - +
branch->order;?> branch->name);?> branch->status);?> branch->createdDate);?>actions;?>
id => ''));?> name;?>'> + ';?> + + name;?> + default) + { + echo ' ' . $lang->branch->default . ''; + } + elseif($branch->status == 'active') + { + $setDefaultLink = helper::createLink('branch', 'setDefault', "productID=$productID&branchID=$branch->id", '', true); + $setDefaultHtml = html::a($setDefaultLink, " {$lang->branch->setDefault}", '', "class='iframe btn btn-icon-left btn-sm setDefault hidden'"); + + echo common::hasPriv('branch', 'setDefault') ? $setDefaultHtml : ''; + } + ?> + branch->statusList, $branch->status);?> createdDate) ? '' : $branch->createdDate;?> closedDate) ? '' : $branch->closedDate;?> desc;?> id == BRANCH_MAIN ? 'disabled' : ''; + $disabled = $isMain ? 'disabled' : ''; common::printIcon('branch', 'edit', "branchID=$branch->id", $branch, 'list', '', '', "$disabled iframe", true); if($branch->status == 'active') { @@ -95,13 +119,15 @@
+
- edit, '', 'btn');?> -
-
- branch->merge, '', 'btn');?> + createLink('branch', 'batchEdit', "productID=$productID"); + echo html::submitButton($lang->edit, "data-form-action='$batchEditLink'", 'btn'); + ?>
+ show('right', 'pagerjs');?> diff --git a/module/common/view/datatable.fix.html.php b/module/common/view/datatable.fix.html.php index fbb3031a4e..14cd957edc 100644 --- a/module/common/view/datatable.fix.html.php +++ b/module/common/view/datatable.fix.html.php @@ -6,7 +6,7 @@ $(function() { - $('#sidebar .cell .text-center:last').append("datatable->moduleSetting?>
"); + $('#sidebar .cell .text-center:last').append("moduleName=='product' ? $lang->datatable->listSetting : $lang->datatable->moduleSetting?>
"); var addSettingButton = function() @@ -36,10 +36,12 @@ $(function() $('#setShowModule').click(function() { if('app->user->account?>' == 'guest') return; - datatableId = ''; - var value = $('#showModuleModal input[name="showModule"]:checked').val(); - var allModule = $('#showModuleModal input[name="showAllModule"]:checked').val(); - if(typeof allModule === 'undefined') allModule = false; + datatableId = ''; + var value = $('#showModuleModal input[name="showModule"]:checked').val(); + var allModule = $('#showModuleModal input[name="showAllModule"]:checked').val(); + var showBranch = $('#showModuleModal input[name="showBranch"]:checked').val(); + if(typeof allModule === 'undefined') allModule = false; + if(typeof showBranch === 'undefined') showBranch = false; $.ajax( { type: "POST", @@ -50,6 +52,7 @@ $(function() name: 'showModule', value: value, allModule: allModule, + showBranch: showBranch, }, success:function(){window.location.reload();}, url: 'createLink('datatable', 'ajaxSave')?>' @@ -80,7 +83,7 @@ $(function()
datatable->showAllModuleList, isset($config->execution->task->allModule) ? $config->execution->task->allModule : 0);?>
datatable->showBranch;?>datatable->showBranchList, isset($config->product->browse->showBranch) ? $config->product->browse->showBranch : 1);?>
report->user;?>report->project ;?> report->execution;?> report->task;?> report->remain;?>
createLink('execution', 'view', "executionID={$info['executionID']}"), $execution);?>createLink('project', 'view', "projectID={$info['projectID']}"), $project);?> createLink('execution', 'view', "executionID={$execinfo['executionID']}"), $exec);?>
diff --git a/module/story/model.php b/module/story/model.php index 3d8e97c1b4..06c0220413 100644 --- a/module/story/model.php +++ b/module/story/model.php @@ -3722,7 +3722,7 @@ class storyModel extends model case 'title': if($storyType == 'requirement') echo 'SR '; if($story->parent > 0 and isset($story->parentName)) $story->title = "{$story->parentName} / {$story->title}"; - if($story->branch and isset($branches[$story->branch])) echo "{$branches[$story->branch]} "; + if($story->branch and isset($branches[$story->branch]) and !empty($this->config->product->browse->showBranch)) echo "{$branches[$story->branch]} "; if($story->module and isset($modulePairs[$story->module])) echo "{$modulePairs[$story->module]} "; if($story->parent > 0) echo '' . $this->lang->story->childrenAB . ' '; echo $canView ? html::a($storyLink, $story->title, '', "style='color: $story->color' data-app='$tab'") : "{$story->title}";