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 + */ +?> + +