* Finish task#44397

This commit is contained in:
zenggang
2021-11-18 10:27:39 +00:00
parent 8fc6867523
commit 95e04b9bf0
14 changed files with 1142 additions and 2 deletions

View File

@@ -486,7 +486,7 @@ class gitlab extends control
}
/**
* Browse gitlab project.
* Browse gitlab user.
*
* @param int $gitlabID
* @access public
@@ -501,7 +501,7 @@ class gitlab extends control
}
/**
* Creat a gitlab project.
* Creat a gitlab user.
*
* @param int $gitlabID
* @access public

View File

@@ -2186,4 +2186,17 @@ class gitlabModel extends model
return false;
}
/**
* Get products which scm is GitLab by projects.
*
* @param array $projectIDs
* @return array
*/
public function getProductsByProjects($projectIDs)
{
return $this->dao->select('path,product')->from(TABLE_REPO)->where('deleted')->eq('0')
->andWhere('SCM')->eq('Gitlab')
->andWhere('path')->in($projectIDs)
->fetchPairs('path', 'product');
}
}

View File

@@ -389,6 +389,333 @@ class mr extends control
return $this->send($this->mr->reopen($MR));
}
/**
* link MR list.
*
* @param int $MRID
* @param string $type
* @param string $orderBy
* @param string $link
* @param string $param
* @param int $recTotal
* @param int $recPerPage
* @param int $pageID
* @return void
*/
public function link($MRID, $type = 'story', $orderBy = 'id_desc', $link = 'false', $param = '', $recTotal = 0, $recPerPage = 100, $pageID = 1)
{
$this->app->loadLang('productplan');
$this->app->loadLang('bug');
$this->app->loadLang('task');
$MR = $this->mr->getByID($MRID);
$products = $this->loadModel('gitlab')->getProductsByProjects(array($MR->targetProject, $MR->sourceProject));
$product = $this->loadModel('product')->getById(array_shift($products));
/* Load pager. */
$this->app->loadClass('pager', $static = true);
$storyPager = new pager(0, $recPerPage, $type == 'story' ? $pageID : 1);
$bugPager = new pager(0, $recPerPage, $type == 'bug' ? $pageID : 1);
$taskPager = new pager(0, $recPerPage, $type == 'task' ? $pageID : 1);
$stories = $this->mr->getLinkList($MRID, $product->id, 'story', $orderBy, $storyPager);
$bugs = $this->mr->getLinkList($MRID, $product->id, 'bug', $orderBy, $bugPager);
$tasks = $this->mr->getLinkList($MRID, $product->id, 'task', $orderBy, $taskPager);
$this->view->MR = $MR;
$this->view->canBeChanged = true;
$this->view->modulePairs = $this->loadModel('tree')->getOptionMenu($product->id, 'story');
$this->view->users = $this->loadModel('user')->getPairs('noletter');
$this->view->stories = $stories;
$this->view->summary = $this->product->summary($stories);
$this->view->bugs = $bugs;
$this->view->tasks = $tasks;
$this->view->products = $products;
$this->view->product = $product;
$this->view->storyPager = $storyPager;
$this->view->bugPager = $bugPager;
$this->view->taskPager = $taskPager;
$this->view->type = $type;
$this->view->orderBy = $orderBy;
$this->view->link = $link;
$this->view->param = $param;
$this->display();
}
/**
* Link story to mr.
*
* @param int $MRID
* @param int $productID
* @param string $browseType
* @param int $param
* @param string $orderBy
* @param int $recTotal
* @param int $recPerPage
* @param int $pageID
* @access public
* @return void
*/
public function linkStory($MRID, $productID = 0, $browseType = '', $param = 0, $orderBy = 'id_desc', $recTotal = 0, $recPerPage = 100, $pageID = 1)
{
if(!empty($_POST['stories']))
{
$this->mr->link($MRID, $productID, 'story');
die(js::locate(inlink('link', "MRID=$MRID&type=story&orderBy=$orderBy"), 'parent'));
}
$this->loadModel('story');
$this->app->loadLang('productplan');
$product = $this->loadModel('product')->getById($productID);
$modules = $this->loadModel('tree')->getOptionMenu($productID, $viewType = 'story');
/* Build search form. */
$storyStatusList = $this->lang->story->statusList;
unset($storyStatusList['closed']);
$queryID = ($browseType == 'bySearch') ? (int) $param : 0;
unset($this->config->product->search['fields']['product']);
$this->config->product->search['actionURL'] = $this->createLink('mr', 'link', "$MRID=$MRID&type=story&orderBy=$orderBy&link=true&param=" . helper::safe64Encode('&browseType=bySearch&queryID=myQueryID'));
$this->config->product->search['queryID'] = $queryID;
$this->config->product->search['style'] = 'simple';
$this->config->product->search['params']['product']['values'] = array($product) + array('all' => $this->lang->product->allProductsOfProject);
$this->config->product->search['params']['plan']['values'] = $this->loadModel('productplan')->getForProducts(array($productID => $productID));
$this->config->product->search['params']['module']['values'] = $modules;
$this->config->product->search['params']['status'] = array('operator' => '=', 'control' => 'select', 'values' => $storyStatusList);
if($this->session->currentProductType == 'normal')
{
unset($this->config->product->search['fields']['branch']);
unset($this->config->product->search['params']['branch']);
}
else
{
$this->config->product->search['fields']['branch'] = $this->lang->product->branch;
$branches = array('' => '') + $this->loadModel('branch')->getPairs($productID, 'noempty');
$this->config->product->search['params']['branch']['values'] = $branches;
}
$this->loadModel('search')->setSearchParams($this->config->product->search);
$MR = $this->mr->getByID($MRID);
$relatedStories = $this->mr->getCommitedLink($MR->gitlabID, $MR->targetProject, $MR->mriid, 'story');
$linkedStories = $this->mr->getLinkList($MRID, $product->id, '', 'story');
if($browseType == 'bySearch')
{
$allStories = $this->story->getBySearch($productID, 0, $queryID, 'id', '', 'story', array_keys($linkedStories), null);
}
else
{
$allStories = $this->story->getProductStories($productID, 0, $moduleID = '0', $status = 'draft,active,changed', 'story', 'id_desc', $hasParent = false, array_keys($linkedStories), null);
}
$this->view->modules = $modules;
$this->view->users = $this->loadModel('user')->getPairs('noletter');
$this->view->allStories = $allStories;
$this->view->relatedStories = $relatedStories;
$this->view->product = $product;
$this->view->MRID = $MRID;
$this->view->browseType = $browseType;
$this->view->param = $param;
$this->view->orderBy = $orderBy;
$this->display();
}
/**
* Link bug to mr.
*
* @param int $MRID
* @param int $productID
* @param string $browseType
* @param int $param
* @param string $orderBy
* @param int $recTotal
* @param int $recPerPage
* @param int $pageID
* @access public
* @return void
*/
public function linkBug($MRID, $productID = 0, $browseType = '', $param = 0, $orderBy = 'id_desc', $recTotal = 0, $recPerPage = 100, $pageID = 1)
{
if(!empty($_POST['bugs']))
{
$this->mr->link($MRID, $productID, 'bug');
die(js::locate(inlink('link', "MRID=$MRID&type=bug&orderBy=$orderBy"), 'parent'));
}
$this->loadModel('bug');
$this->app->loadLang('productplan');
$queryID = ($browseType == 'bysearch') ? (int)$param : 0;
$product = $this->loadModel('product')->getById($productID);
$modules = $this->loadModel('tree')->getOptionMenu($productID, $viewType = 'bug');
/* Build search form. */
$this->config->bug->search['actionURL'] = $this->createLink('mr', 'link', "$MRID=$MRID&type=bug&orderBy=$orderBy&link=true&param=" . helper::safe64Encode('&browseType=bySearch&queryID=myQueryID'));
$this->config->bug->search['queryID'] = $queryID;
$this->config->bug->search['style'] = 'simple';
$this->config->bug->search['params']['plan']['values'] = $this->loadModel('productplan')->getForProducts(array($productID => $productID));
$this->config->bug->search['params']['module']['values'] = $modules;
$this->config->bug->search['params']['project']['values'] = $this->product->getExecutionPairsByProduct($productID);
$this->config->bug->search['params']['openedBuild']['values'] = $this->loadModel('build')->getProductBuildPairs($productID, $branch = 0, $params = '');
$this->config->bug->search['params']['resolvedBuild']['values'] = $this->loadModel('build')->getProductBuildPairs($productID, $branch = 0, $params = '');
unset($this->config->bug->search['fields']['product']);
if($this->session->currentProductType == 'normal')
{
unset($this->config->bug->search['fields']['branch']);
unset($this->config->bug->search['params']['branch']);
}
else
{
$this->config->bug->search['fields']['branch'] = $this->lang->product->branch;
$branches = array('' => '') + $this->loadModel('branch')->getPairs($productID, 'noempty');
$this->config->bug->search['params']['branch']['values'] = $branches;
}
$this->loadModel('search')->setSearchParams($this->config->bug->search);
$MR = $this->mr->getByID($MRID);
$relatedBugs = $this->mr->getCommitedLink($MR->gitlabID, $MR->targetProject, $MR->mriid, 'bug');
$linkedBugs = $this->mr->getLinkList($MRID, $product->id, '','bug');
if($browseType == 'bySearch')
{
$allBugs = $this->bug->getBySearch($productID, 0, $queryID, 'id_desc', array_keys($linkedBugs), null);
}
else
{
$allBugs = $this->bug->getActiveBugs($productID, 0, '0', array_keys($linkedBugs), null);
}
$this->view->modules = $modules;
$this->view->users = $this->loadModel('user')->getPairs('noletter');
$this->view->allBugs = $allBugs;
$this->view->relatedBugs = $relatedBugs;
$this->view->product = $product;
$this->view->MRID = $MRID;
$this->view->browseType = $browseType;
$this->view->param = $param;
$this->view->orderBy = $orderBy;
$this->display();
}
/**
* Link task to mr.
*
* @param int $MRID
* @param int $productID
* @param string $browseType
* @param int $param
* @param string $orderBy
* @param int $recTotal
* @param int $recPerPage
* @param int $pageID
* @access public
* @return void
*/
public function linkTask($MRID, $productID = 0, $browseType = 'unclosed', $param = 0, $orderBy = 'id_desc', $recTotal = 0, $recPerPage = 100, $pageID = 1)
{
if(!empty($_POST['tasks']))
{
$this->mr->link($MRID, $productID, 'task');
die(js::locate(inlink('link', "MRID=$MRID&type=task&orderBy=$orderBy"), 'parent'));
}
$this->loadModel('execution');
$this->loadModel('product');
$this->app->loadLang('task');
/* Set browse type. */
$browseType = strtolower($browseType);
$queryID = ($browseType == 'bysearch') ? (int)$param : 0;
$product = $this->loadModel('product')->getById($productID);
$modules = $this->loadModel('tree')->getOptionMenu($productID, $viewType = 'task');
/* Build search form. */
$this->config->execution->search['actionURL'] = $this->createLink('mr', 'link', "$MRID=$MRID&type=task&orderBy=$orderBy&link=true&param=" . helper::safe64Encode('&browseType=bySearch&queryID=myQueryID'));
$this->config->execution->search['queryID'] = $queryID;
$this->config->execution->search['params']['module']['values'] = $modules;
$this->loadModel('search')->setSearchParams($this->config->execution->search);
$MR = $this->mr->getByID($MRID);
$relatedTasks = $this->mr->getCommitedLink($MR->gitlabID, $MR->targetProject, $MR->mriid, 'task');
$linkedTasks = $this->mr->getLinkList($MRID, $product->id, '','task');
/* Get executions by product. */
$productExecutions = $this->product->getExecutionPairsByProduct($productID);
$productExecutionIDs = array_filter(array_keys($productExecutions));
$this->config->execution->search['params']['execution']['values'] = array_filter($productExecutions);
/* Get tasks by executions. */
$allTasks = array();
foreach($productExecutionIDs as $productExecutionID)
{
$tasks = $this->execution->getTasks(0, $productExecutionID, array(), $browseType, $queryID, 0, $orderBy, null);
$allTasks = array_merge($tasks, $allTasks);
}
/* Filter linked tasks. */
$linkedTaskIDs = array_keys($linkedTasks);
foreach($allTasks as $key => $task)
{
if(in_array($task->id, $linkedTaskIDs)) unset($allTasks[$key]);
}
$this->view->modules = $modules;
$this->view->users = $this->loadModel('user')->getPairs('noletter');
$this->view->allTasks = $allTasks;
$this->view->relatedTasks = $relatedTasks;
$this->view->product = $product;
$this->view->MRID = $MRID;
$this->view->browseType = $browseType;
$this->view->param = $param;
$this->view->orderBy = $orderBy;
$this->display();
}
/**
* UnLink an mr link.
*
* @param int $MRID
* @param int $productID
* @param string $type
* @param int $linkID
* @param string $confirm
* @access public
* @return mix
*/
public function unlink($MRID, $productID, $type, $linkID, $confirm = 'no')
{
$this->app->loadLang('productplan');
if($confirm == 'no')
{
die(js::confirm($this->lang->productplan->confirmUnlinkStory, $this->createLink('mr', 'unlink', "MRID=$MRID&productID=$productID&linkID=$linkID&type=$type&confirm=yes")));
}
else
{
$this->mr->unlink($MRID, $productID, $type, $linkID);
/* if ajax request, send result. */
if($this->server->ajax)
{
if(dao::isError())
{
$response['result'] = 'fail';
$response['message'] = dao::getError();
}
else
{
$response['result'] = 'success';
$response['message'] = '';
}
return $this->send($response);
}
die(js::reload('parent'));
}
}
/**
* Add a Bug for this review.
*

25
module/mr/css/link.css Normal file
View File

@@ -0,0 +1,25 @@
#storyList th {border: none;}
#bugList th {border: none;}
#taskList th {border: none;}
.hide-side .col-main {width: 100%;}
.hide-side .col-side .main-side {width: 0; display: none;}
.dropdown-menu.with-search {padding: 0; min-width: 150px; overflow: hidden; max-height: 302px;}
.dropdown-menu > .menu-search .input-group {width: 100%;}
.dropdown-menu > .menu-search .input-group-addon {position: absolute; right: 10px; top: 0; z-index: 10; background: none; border: none; color: #666;}
.dropdown-menu > .menu-search .form-control {border: none !important; box-shadow: none !important; border-top: 1px solid #ddd !important;}
.dropdown-list {display: block; padding: 0; max-height: 270px; overflow-y: auto;}
.dropdown-list > li > a {display: block; padding: 3px 20px; clear: both; font-weight: normal; line-height: 1.53846154; color: #141414; white-space: nowrap;}
.dropdown-list > li > a:hover,
.dropdown-list > li > a:focus {color: #1a4f85; text-decoration: none; background-color: #ddd;}
.checkbox.btn {margin-top: 0px;}
.linkBox #queryBox .search-form .form-actions {padding-bottom: 5px;}
.linkBox .table-header {padding: 8px 15px; border-bottom: 1px solid #cbd0db;}
#unlinkStoryList, #unlinkBugList, #unlinkTaskList{border-top: 1px solid #cbd0db;}
.fixed-footer .text {color: #fff;}
ol, ul {padding-left: 20px;}
#tabsNav .tab-pane>.main-table {border-radius: 0;}
.body-modal #mainMenu>.btn-toolbar {width: auto;}
.body-modal #mainContent {min-height: 240px;}

86
module/mr/js/link.js Normal file
View File

@@ -0,0 +1,86 @@
function showLink(productID, type, orderBy, param)
{
if(type == 'story') method = 'linkStory';
else if(type == 'bug') method = 'linkBug';
else if(type == 'task') method = 'linkTask';
loadURL(createLink('mr', method, 'MRID=' + MRID + '&productID=' + productID + (typeof(param) == 'undefined' ? '' : param) + (typeof(orderBy) == 'undefined' ? '' : "&orderBy=" + orderBy)), type);
$('.actions').find("a[href*='" + type + "']").addClass('hidden');
}
/**
* Load URL.
*
* @param string $url
* @param string $type
* @access public
* @return void
*/
function loadURL(url, type)
{
$.get(url, function(data)
{
var $pane = $(type == 'story' ? '#stories' : (type == 'bug' ? '#bugs' : '#tasks'));
$pane.find('.main-table').hide();
var $linkBox = $pane.find('.linkBox').html(data).removeClass('hidden');
$linkBox.html(data).removeClass('hidden');
$linkBox.find('[data-ride="table"]').table();
$linkBox.find('[data-ride="pager"]').pager();
$linkBox.find('[data-ride="pager"] li a.pager-item').click(function()
{
loadURL($(this).attr('href'), type);
return false;
});
$linkBox.find('[data-ride="pager"] .pager-size-menu a[data-size]').off('click');
$linkBox.find('[data-ride="pager"] .pager-size-menu a[data-size]').click(function()
{
line = $linkBox.find('[data-ride="pager"]').attr('data-link-creator');
line = line.replace('{recPerPage}', $(this).attr('data-size')).replace('{page}', $linkBox.find('[data-ride="pager"]').attr('data-page'));
$.cookie($linkBox.find('[data-ride="pager"]').attr('data-page-cookie'), $(this).attr('data-size'), {expires:config.cookieLife, path:config.webRoot});
loadURL(line, type);
return false;
});
$.toggleQueryBox(true, $linkBox.find('#queryBox'));
});
}
$(function()
{
if(link == 'true') showLink(productID, type, orderBy, param);
var infoShowed = false;
$('.nav.nav-tabs a[data-toggle="tab"]').on('shown.zui.tab', function(e)
{
var href = $(e.target).attr('href');
var tabPane = $(href + '.tab-pane');
if(tabPane.size() == 0) return;
var formID = tabPane.find('.linkBox').find('form:last');
if(formID.size() == 0) formID = tabPane.find('form:last');
if(href == '#planInfo' && !infoShowed)
{
$('#planInfo img').each(function()
{
var $tr = $('#planInfo .detail-content .table-data tbody tr:first');
width = $tr.width() - $tr.find('th').width();
if($(this).parent().prop('tagName').toLowerCase() == 'a') $(this).unwrap();
setImageSize($(this), width, 0);
});
infoShowed = true;
}
});
$('#storyList').on('sort.sortable', function(e, data)
{
var list = '';
for(i = 0; i < data.list.length; i++) list += $(data.list[i].item).attr('data-id') + ',';
$.post(createLink('productplan', 'ajaxStorySort', 'productID=' + productID), {'stories' : list, 'orderBy' : orderBy, 'pageID' : storyPageID, 'recPerPage' : storyRecPerPage, 'recTotal' : storyRecTotal}, function()
{
var $target = $(data.element[0]);
$target.hide();
$target.fadeIn(1000);
order = 'order_asc';
history.pushState({}, 0, createLink('productplan', 'view', "productID=" + productID + '&type=story&orderBy=' + order));
});
});
});

View File

@@ -12,6 +12,7 @@ $lang->mr->source = 'source';
$lang->mr->target = 'target';
$lang->mr->viewDiff = 'View diff';
$lang->mr->viewInGitlab = 'View in GitLab';
$lang->mr->link = 'Link stories,bugs,tasks';
$lang->mr->id = 'ID';
$lang->mr->mriid = "raw MR ID";
@@ -141,3 +142,10 @@ $lang->mr->commandDocument = <<< EOD
EOD;
$lang->mr->noChanges = "Currently there are no changes in this merge request's source branch. Please push new commits or use a different branch.";
$lang->mr->linkTask = "Link task";
$lang->mr->unlinkTask = "Remove task";
$lang->mr->linkedTasks = 'Task';
$lang->mr->unlinkedTasks = 'Task not linked';
$lang->mr->confirmUnlinkTask = "Are you sure to remove this task?";
$lang->mr->taskSummary = "There are <strong>%s</strong> tasks on this page";

View File

@@ -12,6 +12,7 @@ $lang->mr->source = '源项目分支';
$lang->mr->target = '目标项目分支';
$lang->mr->viewDiff = '比对代码';
$lang->mr->viewInGitlab = '在GitLab查看';
$lang->mr->link = '关联需求、bug、任务';
$lang->mr->id = 'ID';
$lang->mr->mriid = "MR原始ID";
@@ -141,3 +142,10 @@ $lang->mr->commandDocument = <<< EOD
EOD;
$lang->mr->noChanges = "目前在这个合并请求的源分支中没有变化,请推送新的提交或使用不同的分支。";
$lang->mr->linkTask = "关联任务";
$lang->mr->unlinkTask = "移除任务";
$lang->mr->linkedTasks = '任务';
$lang->mr->unlinkedTasks = '未关联任务';
$lang->mr->confirmUnlinkTask = "您确认移除该任务吗?";
$lang->mr->taskSummary = "本页共 <strong>%s</strong> 个任务";

View File

@@ -697,6 +697,21 @@ class mrModel extends model
return json_decode(commonModel::http($url));
}
/**
* Get diff commits of MR from GitLab API.
*
* @param int $gitlabID
* @param int $projectID
* @param int $MRID
* @access public
* @return object
*/
public function apiGetDiffCommits($gitlabID, $projectID, $MRID)
{
$url = sprintf($this->gitlab->getApiRoot($gitlabID), "/projects/$projectID/merge_requests/$MRID/commits");
return json_decode(commonModel::http($url));
}
/**
* Reject or Approve this MR.
*
@@ -972,4 +987,130 @@ class mrModel extends model
return $this->dao->select('*')->from(TABLE_BUG)->where('entry')->eq($entry)->orderby('id_desc')->fetch();
}
/**
* Get mr link list.
*
* @param int $MRID
* @param int $productID
* @param string $type
* @param string $orderBy
* @param object $pager
* @access public
* @return array
*/
public function getLinkList($MRID, $productID, $type, $orderBy, $pager = null)
{
$linkIDs = $this->dao->select('BID')->from(TABLE_RELATION)
->where('product')->eq($productID)
->andWhere('relation')->eq('interrated')
->andWhere('AType')->eq('mr')
->andWhere('AID')->eq($MRID)
->andWhere('BType')->eq($type)
->fetchPairs('BID');
$links = array();
if($type == 'story' and !empty($linkIDs))
{
$orderBy = str_replace('name_', 'title_', $orderBy);
$links = $this->dao->select('t1.*, t2.spec, t2.verify, t3.name as productTitle')
->from(TABLE_STORY)->alias('t1')
->leftJoin(TABLE_STORYSPEC)->alias('t2')->on('t1.id=t2.story')
->leftJoin(TABLE_PRODUCT)->alias('t3')->on('t1.product=t3.id')
->where('t1.deleted')->eq(0)
->andWhere('t1.version=t2.version')
->andWhere('t1.id')->in($linkIDs)
->orderBy($orderBy)
->page($pager)
->fetchAll('id');
}
if($type == 'bug' and !empty($linkIDs))
{
$orderBy = str_replace('name_', 'title_', $orderBy);
$links = $this->dao->select('*')->from(TABLE_BUG)
->where('deleted')->eq(0)
->andWhere('id')->in($linkIDs)
->orderBy($orderBy)
->page($pager)
->fetchAll('id');
}
if($type == 'task' and !empty($linkIDs))
{
$orderBy = str_replace('title_', 'name_', $orderBy);
$links = $this->dao->select('*')->from(TABLE_TASK)
->where('deleted')->eq(0)
->andWhere('id')->in($linkIDs)
->orderBy($orderBy)
->page($pager)
->fetchAll('id');
}
return $links;
}
/**
* Create an mr link.
*
* @param int $MRID
* @param int $productID
* @param string $type
* @access public
* @return void
*/
public function link($MRID, $productID, $type)
{
if($type == 'story') $links = $this->post->stories;
if($type == 'bug') $links = $this->post->bugs;
if($type == 'task') $links = $this->post->tasks;
foreach($links as $linkID)
{
$relation = new stdclass;
$relation->product = $productID;
$relation->AType = 'mr';
$relation->AID = $MRID;
$relation->relation = 'interrated';
$relation->BType = $type;
$relation->BID = $linkID;
$this->dao->replace(TABLE_RELATION)->data($relation)->exec();
}
}
/**
* unLink an mr link.
*
* @param int $MRID
* @param int $productID
* @param string $type
* @param int $linkID
* @access public
* @return void
*/
public function unlink($MRID, $productID, $type, $linkID)
{
return $this->dao->delete()->from(TABLE_RELATION)->where('product')->eq($productID)->andWhere('AType')->eq('mr')->andWhere('AID')->eq($MRID)->andWhere('BType')->eq($type)->andWhere('BID')->eq($linkID)->exec();
}
/**
* Get links by mr commites.
*
* @param int $gitlabID
* @param int $projectID
* @param int $MRID
* @param string $type
* @access public
* @return array
*/
public function getCommitedLink($gitlabID, $projectID, $MRID, $type)
{
$DiffCommits = $this->apiGetDiffCommits($gitlabID, $projectID, $MRID);
$commits = array();
foreach($DiffCommits as $DiffCommit)
{
$commits[] = substr($DiffCommit->id, 0, 10);
}
return $this->dao->select('objectID')->from(TABLE_ACTION)->where('objectType')->eq($type)->andWhere('extra')->in($commits)->fetchPairs('objectID');
}
}

View File

@@ -79,6 +79,7 @@
common::printLink('mr', 'view', "mr={$MR->id}", '<i class="icon icon-eye"></i>', '', "title='{$lang->mr->view}' class='btn btn-info'");
common::printLink('mr', 'edit', "mr={$MR->id}", '<i class="icon icon-edit"></i>', '', "title='{$lang->mr->edit}' class='btn btn-info'");
common::printLink('mr', 'diff', "mr={$MR->id}", '<i class="icon icon-review"></i>', '', "title='{$lang->mr->viewDiff}' class='btn btn-info'");
common::printLink('mr', 'link', "mr={$MR->id}", '<i class="icon icon-link"></i>', '', "title='{$lang->mr->link}' class='btn btn-info'");
common::printLink('mr', 'delete', "mr={$MR->id}", '<i class="icon icon-trash"></i>', 'hiddenwin', "title='{$lang->mr->delete}' class='btn btn-info'");
?>
</td>

View File

@@ -0,0 +1,270 @@
<?php
/**
* The view of productplan module of ZenTaoPMS.
*
* @copyright Copyright 2009-2021 青岛易软天创网络科技有限公司(QingDao Nature Easy Soft Network Technology Co,LTD, www.cnezsoft.com)
* @license ZPL (http://zpl.pub/page/zplv12.html)
* @author gang zeng
* @package repo
* @version $Id: link.html.php $
* @link http://www.zentao.net
*/
?>
<?php include '../../common/view/header.html.php';?>
<?php include '../../common/view/sortable.html.php';?>
<?php include '../../common/view/tablesorter.html.php';?>
<?php js::set('confirmUnlinkStory', $lang->productplan->confirmUnlinkStory)?>
<?php js::set('confirmUnlinkBug', $lang->productplan->confirmUnlinkBug)?>
<?php js::set('confirmUnlinkTask', $lang->mr->confirmUnlinkTask)?>
<?php js::set('productID', $product->id);?>
<?php js::set('MRID', $MR->id);?>
<?php js::set('storyPageID', $storyPager->pageID);?>
<?php js::set('storyRecPerPage', $storyPager->recPerPage);?>
<?php js::set('storyRecTotal', $storyPager->recTotal);?>
<div id='mainMenu' class='clearfix'>
<div class='btn-toolbar pull-left'>
<?php common::printBack(inlink('browse'), 'btn btn-primary');?>
<div class='divider'></div>
<div class='page-title'>
<span class='label label-id'><?php echo $MR->id;?></span>
<span title='<?php echo $MR->title;?>' class='text'><?php echo $MR->title;?></span>
<?php if($product->type !== 'normal') echo "<span title='{$lang->product->branchName[$product->type]}' class='label label-branch label-badge'>" . $branches[$branch] . '</span>';?>
<?php if($MR->deleted):?>
<span class='label label-danger'><?php echo $lang->product->deleted;?></span>
<?php endif; ?>
</div>
</div>
</div>
<div id='mainContent' class='main-content'>
<div class='tabs' id='tabsNav'>
<ul class='nav nav-tabs'>
<li class='<?php if($type == 'story') echo 'active'?>'><a href='#stories' data-toggle='tab'><?php echo html::icon($lang->icons['story'], 'text-primary') . ' ' . $lang->productplan->linkedStories;?></a></li>
<li class='<?php if($type == 'bug') echo 'active'?>'><a href='#bugs' data-toggle='tab'><?php echo html::icon($lang->icons['bug'], 'text-red') . ' ' . $lang->productplan->linkedBugs;?></a></li>
<li class='<?php if($type == 'task') echo 'active'?>'><a href='#tasks' data-toggle='tab'><?php echo html::icon('todo', 'text-info') . ' ' . $lang->mr->linkedTasks;?></a></li>
</ul>
<div class='tab-content'>
<div id='stories' class='tab-pane <?php if($type == 'story') echo 'active'?>'>
<?php $canOrder = false;?>
<div class='actions'>
<?php echo html::a("javascript:showLink($product->id, \"story\")", '<i class="icon-link"></i> ' . $lang->productplan->linkStory, '', "class='btn btn-primary'");?>
</div>
<div class='linkBox cell hidden'></div>
<form class='main-table table-story' data-ride='table' method='post' target='hiddenwin' action="<?php echo inlink('batchUnlinkStory', "planID=$MR->id&orderBy=$orderBy");?>">
<table class='table has-sort-head' id='storyList'>
<?php
$canBatchClose = common::hasPriv('story', 'batchClose');
$canBatchEdit = common::hasPriv('story', 'batchEdit');
$canBatchReview = common::hasPriv('story', 'batchReview');
$canBatchChangeBranch = common::hasPriv('story', 'batchChangeBranch');
$canBatchChangeModule = common::hasPriv('story', 'batchChangeModule');
$canBatchChangePlan = common::hasPriv('story', 'batchChangePlan');
$canBatchChangeStage = common::hasPriv('story', 'batchChangeStage');
$canBatchAssignTo = common::hasPriv('story', 'batchAssignTo');
$vars = "MRID={$MR->id}&type=story&orderBy=%s&link=$link&param=$param";
?>
<thead>
<tr class='text-center'>
<th class='c-id text-left'>
<?php common::printOrderLink('id', $orderBy, $vars, $lang->idAB);?>
</th>
<?php if($canOrder):?>
<th class='w-70px'><?php common::printOrderLink('order', $orderBy, $vars, $lang->productplan->updateOrder);?></th>
<?php endif;?>
<th class='w-70px'> <?php common::printOrderLink('pri', $orderBy, $vars, $lang->priAB);?></th>
<th class='w-150px text-left'><?php common::printOrderLink('module', $orderBy, $vars, $lang->story->module);?></th>
<th class='text-left'><?php common::printOrderLink('title', $orderBy, $vars, $lang->story->title);?></th>
<th class='c-user'> <?php common::printOrderLink('openedBy', $orderBy, $vars, $lang->openedByAB);?></th>
<th class='c-user'> <?php common::printOrderLink('assignedTo', $orderBy, $vars, $lang->assignedToAB);?></th>
<th class='w-70px text-right'> <?php common::printOrderLink('estimate', $orderBy, $vars, $lang->story->estimateAB);?></th>
<th class='w-70px'> <?php common::printOrderLink('status', $orderBy, $vars, $lang->statusAB);?></th>
<th class='w-80px'> <?php common::printOrderLink('stage', $orderBy, $vars, $lang->story->stageAB);?></th>
<th class='c-actions-1'> <?php echo $lang->actions?></th>
</tr>
</thead>
<tbody class='sortable text-center'>
<?php
$totalEstimate = 0.0;
?>
<?php foreach($stories as $story):?>
<?php
$viewLink = $this->createLink('story', 'view', "storyID=$story->id");
$totalEstimate += $story->estimate;
?>
<tr data-id='<?php echo $story->id;?>'>
<td class='c-id text-left'>
<?php printf('%03d', $story->id);?>
</td>
<?php if($canOrder):?><td class='sort-handler'><i class='icon-move'></i></td><?php endif;?>
<td><span class='label-pri <?php echo 'label-pri-' . $story->pri;?>' title='<?php echo zget($lang->story->priList, $story->pri, $story->pri);?>'><?php echo zget($lang->story->priList, $story->pri, $story->pri);?></span></td>
<td class='text-left nobr'><?php echo zget($modulePairs, $story->module, '');?></td>
<td class='text-left nobr' title='<?php echo $story->title?>'>
<?php
if($story->parent > 0) echo "<span class='label label-badge label-light' title={$lang->story->children}>{$lang->story->childrenAB}</span>";
echo html::a($viewLink , $story->title);
?>
</td>
<td><?php echo zget($users, $story->openedBy);?></td>
<td><?php echo zget($users, $story->assignedTo);?></td>
<td class='text-right' title="<?php echo $story->estimate . ' ' . $lang->hourCommon;?>"><?php echo $story->estimate . $config->hourUnit;?></td>
<td>
<span class='status-story status-<?php echo $story->status?>'>
<?php echo $this->processStatus('story', $story);?>
</span>
</td>
<td><?php echo $lang->story->stageList[$story->stage];?></td>
<td class='c-actions'>
<?php
if($canBeChanged and common::hasPriv('productplan', 'unlinkStory'))
{
$unlinkURL = $this->createLink('mr', 'unlink', "MRID=$MR->id&productID=$product->id&type=story&linkID=$story->id&confirm=yes");
echo html::a("javascript:ajaxDelete(\"$unlinkURL\", \"storyList\", confirmUnlinkStory)", '<i class="icon-unlink"></i>', '', "class='btn' title='{$lang->productplan->unlinkStory}'");
}
?>
</td>
</tr>
<?php endforeach;?>
</tbody>
</table>
<?php if($stories):?>
<div class='table-footer'>
<div class='table-statistic'><?php echo $summary;?></div>
<?php
$this->app->rawParams['type'] = 'story';
$storyPager->show('right', 'pagerjs');
$this->app->rawParams['type'] = $type;
?>
</div>
<?php endif;?>
</form>
</div>
<div id='bugs' class='tab-pane <?php if($type == 'bug') echo 'active';?>'>
<div class='actions'>
<?php echo html::a("javascript:showLink($product->id, \"bug\")", '<i class="icon-bug"></i> ' . $lang->productplan->linkBug, '', "class='btn btn-primary'");?>
</div>
<div class='linkBox cell hidden'></div>
<form class='main-table table-bug' data-ride='table' method='post' target='hiddenwin' action="<?php echo inLink('batchUnlinkBug', "planID=$MR->id&orderBy=$orderBy");?>">
<table class='table has-sort-head' id='bugList'>
<?php $canBatchUnlink = $canBeChanged and common::hasPriv('productplan', 'batchUnlinkBug');?>
<?php $vars = "planID={$MR->id}&type=bug&orderBy=%s&link=$link&param=$param"; ?>
<thead>
<tr class='text-center'>
<th class='c-id text-left'>
<?php common::printOrderLink('id', $orderBy, $vars, $lang->idAB);?>
</th>
<th class='w-70px'> <?php common::printOrderLink('pri', $orderBy, $vars, $lang->priAB);?></th>
<th class='text-left'><?php common::printOrderLink('title', $orderBy, $vars, $lang->bug->title);?></th>
<th class='c-user'> <?php common::printOrderLink('openedBy', $orderBy, $vars, $lang->openedByAB);?></th>
<th class='c-user'> <?php common::printOrderLink('assignedTo', $orderBy, $vars, $lang->bug->assignedToAB);?></th>
<th class='w-100px'><?php common::printOrderLink('status', $orderBy, $vars, $lang->bug->status);?></th>
<th class='w-50px'> <?php echo $lang->actions?></th>
</tr>
</thead>
<tbody class='text-center'>
<?php foreach($bugs as $bug):?>
<tr>
<td class='c-id text-left'>
<?php printf('%03d', $bug->id);?>
</td>
<td><span class='label-pri label-pri-<?php echo $bug->pri;?>' title='<?php echo zget($lang->bug->priList, $bug->pri, $bug->pri);?>'><?php echo zget($lang->bug->priList, $bug->pri, $bug->pri);?></span></td>
<td class='text-left nobr' title='<?php echo $bug->title?>'><?php echo html::a($this->createLink('bug', 'view', "bugID=$bug->id"), $bug->title, '', 'data-app="product"');?></td>
<td><?php echo zget($users, $bug->openedBy);?></td>
<td><?php echo zget($users, $bug->assignedTo);?></td>
<td>
<span class='status-bug status-<?php echo $bug->status?>'>
<?php echo $this->processStatus('bug', $bug);?>
</span>
</td>
<td class='c-actions'>
<?php
if($canBeChanged and common::hasPriv('productplan', 'unlinkBug'))
{
$unlinkURL = $this->createLink('mr', 'unlink', "MRID=$MR->id&productID=$product->id&type=bug&linkID=$bug->id&confirm=yes");
echo html::a("javascript:ajaxDelete(\"$unlinkURL\", \"bugList\", confirmUnlinkBug)", '<i class="icon-unlink"></i>', '', "class='btn' title='{$lang->productplan->unlinkBug}'");
}
?>
</td>
</tr>
<?php endforeach;?>
</tbody>
</table>
<?php if($bugs):?>
<div class='table-footer'>
<div class='table-statistic'><?php echo sprintf($lang->productplan->bugSummary, count($bugs));?></div>
<?php
$this->app->rawParams['type'] = 'bug';
$bugPager->show('right', 'pagerjs');
$this->app->rawParams['type'] = $type;
?>
</div>
<?php endif;?>
</form>
</div>
<div id='tasks' class='tab-pane <?php if($type == 'task') echo 'active';?>'>
<div class='actions'>
<?php echo html::a("javascript:showLink($product->id, \"task\")", '<i class="icon-todo"></i> ' . $lang->mr->linkTask, '', "class='btn btn-primary'");?>
</div>
<div class='linkBox cell hidden'></div>
<form class='main-table table-task' data-ride='table' method='post' target='hiddenwin' action="<?php echo inLink('batchUnlinkTask', "planID=$MR->id&orderBy=$orderBy");?>">
<table class='table has-sort-head' id='taskList'>
<?php $canBatchUnlink = $canBeChanged and common::hasPriv('productplan', 'batchUnlinkTask');?>
<?php $vars = "MRID={$MR->id}&type=task&orderBy=%s&link=$link&param=$param"; ?>
<thead>
<tr class='text-center'>
<th class='c-id text-left'>
<?php common::printOrderLink('id', $orderBy, $vars, $lang->idAB);?>
</th>
<th class='w-70px'> <?php common::printOrderLink('pri', $orderBy, $vars, $lang->priAB);?></th>
<th class='text-left'><?php common::printOrderLink('name', $orderBy, $vars, $lang->task->name);?></th>
<th class='c-user'> <?php common::printOrderLink('finishedBy', $orderBy, $vars, $lang->task->finishedByAB);?></th>
<th class='c-user'> <?php common::printOrderLink('assignedTo', $orderBy, $vars, $lang->task->assignedToAB);?></th>
<th class='w-100px'><?php common::printOrderLink('status', $orderBy, $vars, $lang->task->status);?></th>
<th class='w-50px'> <?php echo $lang->actions?></th>
</tr>
</thead>
<tbody class='text-center'>
<?php foreach($tasks as $task):?>
<tr>
<td class='c-id text-left'>
<?php printf('%03d', $task->id);?>
</td>
<td><span class='label-pri label-pri-<?php echo $task->pri;?>' title='<?php echo zget($lang->task->priList, $task->pri, $task->pri);?>'><?php echo zget($lang->task->priList, $task->pri, $task->pri);?></span></td>
<td class='text-left nobr' title='<?php echo $task->name?>'><?php echo html::a($this->createLink('task', 'view', "taskID=$task->id"), $task->name, '', 'data-app="product"');?></td>
<td><?php echo zget($users, $task->finishedBy);?></td>
<td><?php echo zget($users, $task->assignedTo);?></td>
<td>
<span class='status-task status-<?php echo $task->status?>'>
<?php echo $this->processStatus('task', $task);?>
</span>
</td>
<td class='c-actions'>
<?php
$unlinkURL = $this->createLink('mr', 'unlink', "MRID=$MR->id&productID=$product->id&type=task&linkID=$task->id&confirm=yes");
echo html::a("javascript:ajaxDelete(\"$unlinkURL\", \"taskList\", confirmUnlinkTask)", '<i class="icon-unlink"></i>', '', "class='btn' title='{$lang->mr->unlinkTask}'");
?>
</td>
</tr>
<?php endforeach;?>
</tbody>
</table>
<?php if($tasks):?>
<div class='table-footer'>
<div class='table-statistic'><?php echo sprintf($lang->mr->taskSummary, count($tasks));?></div>
<?php
$this->app->rawParams['type'] = 'task';
$taskPager->show('right', 'pagerjs');
$this->app->rawParams['type'] = $type;
?>
</div>
<?php endif;?>
</form>
</div>
</div>
</div>
</div>
<?php js::set('param', helper::safe64Decode($param))?>
<?php js::set('link', $link)?>
<?php js::set('orderBy', $orderBy)?>
<?php js::set('type', $type)?>
<?php include '../../common/view/footer.html.php';?>

View File

@@ -0,0 +1,78 @@
<?php
/**
* The link bug view of productplan module of ZenTaoPMS.
*
* @copyright Copyright 2009-2021 青岛易软天创网络科技有限公司(QingDao Nature Easy Soft Network Technology Co,LTD, www.cnezsoft.com)
* @license ZPL (http://zpl.pub/page/zplv12.html)
* @author Chunsheng Wang <chunsheng@cnezsoft.com>
* @package mr
* @version $Id: linkbug.html.php$
* @link http://www.zentao.net
*/
?>
<div id='queryBox' data-module='bug' class='show no-margin'></div>
<div id='unlinkBugList'>
<form class='main-table table-bug' data-ride='table' method='post' id='unlinkedBugsForm' target='hiddenwin' action='<?php echo $this->createLink('mr', 'linkBug', "MRID=$MRID&productID=$product->id&browseType=$browseType&param=$param&orderBy=$orderBy")?>'>
<div class='table-header hl-primary text-primary strong'>
<?php echo html::icon('unlink');?> <?php echo $lang->productplan->unlinkedBugs;?>
</div>
<table class='table tablesorter'>
<thead>
<tr class='text-center'>
<th class='c-id text-left'>
<?php if($allBugs):?>
<div class="checkbox-primary check-all tablesorter-noSort" title="<?php echo $lang->selectAll?>">
<label></label>
</div>
<?php endif;?>
<?php echo $lang->idAB;?>
</th>
<th class='c-pri'><?php echo $lang->priAB;?></th>
<th class='text-left'><?php echo $lang->bug->title;?></th>
<th class='c-user'><?php echo $lang->openedByAB;?></th>
<th class='c-user'><?php echo $lang->bug->assignedToAB;?></th>
<th class='c-status'><?php echo $lang->bug->status;?></th>
</tr>
</thead>
<tbody class='text-center'>
<?php $unlinkedCount = 0;?>
<?php foreach($allBugs as $bug):?>
<tr>
<td class='c-id text-left'>
<?php echo html::checkbox('bugs', array($bug->id => sprintf('%03d', $bug->id)), $relatedBugs);?>
</td>
<td><span class='label-pri label-pri-<?php echo $bug->pri;?>' title='<?php echo zget($lang->bug->priList, $bug->pri, $bug->pri)?>'><?php echo zget($lang->bug->priList, $bug->pri, $bug->pri)?></span></td>
<td class='text-left nobr' title='<?php echo $bug->title?>'><?php echo html::a($this->createLink('bug', 'view', "bugID=$bug->id", '', true), $bug->title, '', "data-toggle='modal' data-type='iframe' data-width='90%'");?></td>
<td><?php echo zget($users, $bug->openedBy);?></td>
<td><?php echo zget($users, $bug->assignedTo);?></td>
<td>
<span class='status-bug status-<?php echo $bug->status?>'>
<?php echo $this->processStatus('bug', $bug);?>
</span>
</td>
</tr>
<?php $unlinkedCount++;?>
<?php endforeach;?>
</tbody>
</table>
<div class='table-footer'>
<?php if($unlinkedCount):?>
<div class="checkbox-primary check-all"><label><?php echo $lang->selectAll?></label></div>
<div class="table-actions btn-toolbar">
<?php echo html::submitButton($lang->productplan->linkBug, '', 'btn');?>
</div>
<?php endif;?>
<div class="btn-toolbar">
<?php echo html::a(inlink('link', "MRID=$MRID&type=bug&orderBy=$orderBy"), $lang->goback, '', "class='btn'");?>
</div>
<div class='table-statistic'></div>
</div>
</form>
</div>
<script>
$(function()
{
$('#unlinkBugList .tablesorter').sortTable();
setForm();
});
</script>

View File

@@ -0,0 +1,91 @@
<?php
/**
* The link story view of mr module of ZenTaoPMS.
*
* @copyright Copyright 2009-2015 青岛易软天创网络科技有限公司(QingDao Nature Easy Soft Network Technology Co,LTD, www.cnezsoft.com)
* @license ZPL (http://zpl.pub/page/zplv12.html)
* @author gang zeng
* @package mr
* @version $Id: linkstory.html.php 5096 2013-07-11 07:02:43Z chencongzhi520@gmail.com $
* @link http://www.zentao.net
*/
?>
<div id='queryBox' data-module='story' class='show no-margin'></div>
<div id='unlinkStoryList'>
<form class="main-table table-story" data-ride="table" method="post" target='hiddenwin' id='unlinkedStoriesForm' action="<?php echo $this->createLink('mr', 'linkStory', "MRID=$MRID&productID=$product->id&browseType=$browseType&param=$param&orderBy=$orderBy")?>">
<div class='table-header hl-primary text-primary strong'>
<?php echo html::icon('unlink');?> <?php echo $lang->productplan->unlinkedStories;?>
</div>
<table class='table tablesorter'>
<thead>
<tr>
<th class='c-id text-left'>
<?php if($allStories):?>
<div class="checkbox-primary check-all tablesorter-noSort" title="<?php echo $lang->selectAll?>">
<label></label>
</div>
<?php endif;?>
<?php echo $lang->idAB;?>
</th>
<th class='c-pri'><?php echo $lang->priAB;?></th>
<th class='c-plan'><?php echo $lang->story->plan;?></th>
<th class='c-module'><?php echo $lang->story->module;?></th>
<th class='text-left'><?php echo $lang->story->title;?></th>
<th class='c-user'><?php echo $lang->openedByAB;?></th>
<th class='c-user'><?php echo $lang->assignedToAB;?></th>
<th class='c-number text-right'><?php echo $lang->story->estimateAB;?></th>
<th class='c-status'><?php echo $lang->statusAB;?></th>
<th class='c-stage'><?php echo $lang->story->stageAB;?></th>
</tr>
</thead>
<tbody>
<?php $unlinkedCount = 0;?>
<?php foreach($allStories as $story):?>
<tr>
<td class='c-id text-left'>
<?php echo html::checkbox('stories', array($story->id => sprintf('%03d', $story->id)), $relatedStories);?>
</td>
<td><span class='label-pri <?php echo 'label-pri-' . $story->pri;?>' title='<?php echo zget($lang->story->priList, $story->pri, $story->pri)?>'><?php echo zget($lang->story->priList, $story->pri, $story->pri)?></span></td>
<td><?php echo $story->planTitle;?></td>
<td title='<?php echo $modules[$story->module]?>' class='text-left'><?php echo $modules[$story->module];?></td>
<td class='text-left nobr' title='<?php echo $story->title?>'>
<?php
if($story->parent > 0) echo "<span class='label label-badge label-light' title={$lang->story->children}>{$lang->story->childrenAB}</span>";
echo html::a($this->createLink('story', 'view', "storyID=$story->id", '', true), $story->title, '', "data-toggle='modal' data-type='iframe' data-width='90%'");
?>
</td>
<td><?php echo zget($users, $story->openedBy);?></td>
<td><?php echo zget($users, $story->assignedTo);?></td>
<td class='text-right'title="<?php echo $story->estimate . ' ' . $lang->hourCommon;?>"><?php echo $story->estimate . $config->hourUnit;?></td>
<td>
<span class='status-story status-<?php echo $story->status?>'>
<?php echo $this->processStatus('story', $story);?>
</span>
</td>
<td class='text-center'><?php echo $lang->story->stageList[$story->stage];?></td>
</tr>
<?php $unlinkedCount++;?>
<?php endforeach;?>
</tbody>
</table>
<div class='table-footer'>
<?php if($unlinkedCount):?>
<div class="checkbox-primary check-all"><label><?php echo $lang->selectAll?></label></div>
<div class="table-actions btn-toolbar">
<?php echo html::submitButton($lang->productplan->linkStory, '', 'btn');?>
</div>
<?php endif;?>
<div class="btn-toolbar">
<?php echo html::a(inlink('link', "MRID=$MRID&type=story&orderBy=$orderBy"), $lang->goback, '', "class='btn'");?>
</div>
<div class='table-statistic'></div>
</div>
</form>
</div>
<script>
$(function()
{
$('#unlinkStoryList .tablesorter').sortTable();
setForm();
});
</script>

View File

@@ -0,0 +1,78 @@
<?php
/**
* The link task view of productplan module of ZenTaoPMS.
*
* @copyright Copyright 2009-2021 青岛易软天创网络科技有限公司(QingDao Nature Easy Soft Network Technology Co,LTD, www.cnezsoft.com)
* @license ZPL (http://zpl.pub/page/zplv12.html)
* @author Chunsheng Wang <chunsheng@cnezsoft.com>
* @package mr
* @version $Id: linktask.html.php$
* @link http://www.zentao.net
*/
?>
<div id='queryBox' data-module='task' class='show no-margin'></div>
<div id='unlinkTaskList'>
<form class='main-table table-task' data-ride='table' method='post' id='unlinkedTasksForm' target='hiddenwin' action='<?php echo $this->createLink('mr', 'linkTask', "MRID=$MRID&productID=$product->id&browseType=$browseType&param=$param&orderBy=$orderBy")?>'>
<div class='table-header hl-primary text-primary strong'>
<?php echo html::icon('unlink');?> <?php echo $lang->mr->unlinkedTasks;?>
</div>
<table class='table tablesorter'>
<thead>
<tr class='text-center'>
<th class='c-id text-left'>
<?php if($allTasks):?>
<div class="checkbox-primary check-all tablesorter-noSort" title="<?php echo $lang->selectAll?>">
<label></label>
</div>
<?php endif;?>
<?php echo $lang->idAB;?>
</th>
<th class='c-pri'><?php echo $lang->priAB;?></th>
<th class='text-left'><?php echo $lang->task->name;?></th>
<th class='c-user'><?php echo $lang->task->finishedByAB;?></th>
<th class='c-user'><?php echo $lang->task->assignedToAB;?></th>
<th class='c-status'><?php echo $lang->task->status;?></th>
</tr>
</thead>
<tbody class='text-center'>
<?php $unlinkedCount = 0;?>
<?php foreach($allTasks as $task):?>
<tr>
<td class='c-id text-left'>
<?php echo html::checkbox('tasks', array($task->id => sprintf('%03d', $task->id)), $relatedTasks);?>
</td>
<td><span class='label-pri label-pri-<?php echo $task->pri;?>' title='<?php echo zget($lang->task->priList, $task->pri, $task->pri)?>'><?php echo zget($lang->task->priList, $task->pri, $task->pri)?></span></td>
<td class='text-left nobr' title='<?php echo $task->name?>'><?php echo html::a($this->createLink('task', 'view', "taskID=$task->id", '', true), $task->name, '', "data-toggle='modal' data-type='iframe' data-width='90%'");?></td>
<td><?php echo zget($users, $task->finishedBy);?></td>
<td><?php echo zget($users, $task->assignedTo);?></td>
<td>
<span class='status-task status-<?php echo $task->status?>'>
<?php echo $this->processStatus('task', $task);?>
</span>
</td>
</tr>
<?php $unlinkedCount++;?>
<?php endforeach;?>
</tbody>
</table>
<div class='table-footer'>
<?php if($unlinkedCount):?>
<div class="checkbox-primary check-all"><label><?php echo $lang->selectAll?></label></div>
<div class="table-actions btn-toolbar">
<?php echo html::submitButton($lang->mr->linkTask, '', 'btn');?>
</div>
<?php endif;?>
<div class="btn-toolbar">
<?php echo html::a(inlink('link', "MRID=$MRID&type=task&orderBy=$orderBy"), $lang->goback, '', "class='btn'");?>
</div>
<div class='table-statistic'></div>
</div>
</form>
</div>
<script>
$(function()
{
$('#unlinkTaskList .tablesorter').sortTable();
setForm();
});
</script>

View File

@@ -1821,4 +1821,18 @@ class repoModel extends model
$this->loadModel('git')->updateCommit($repo, $commentGroup, false);
}
}
/**
* Get products which scm is GitLab by projects.
*
* @param array $projectIDs
* @return array
*/
public function getGitlabProductsByProjects($projectIDs)
{
return $this->dao->select('path,product')->from(TABLE_REPO)->where('deleted')->eq('0')
->andWhere('SCM')->eq('Gitlab')
->andWhere('path')->in($projectIDs)
->fetchPairs('path', 'product');
}
}