* Finish task#44397
This commit is contained in:
@@ -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
|
||||
|
||||
@@ -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');
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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¶m=" . 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¶m=" . 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¶m=" . 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
25
module/mr/css/link.css
Normal 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
86
module/mr/js/link.js
Normal 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));
|
||||
});
|
||||
});
|
||||
});
|
||||
@@ -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";
|
||||
@@ -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> 个任务";
|
||||
|
||||
@@ -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');
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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>
|
||||
|
||||
270
module/mr/view/link.html.php
Normal file
270
module/mr/view/link.html.php
Normal 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¶m=$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¶m=$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¶m=$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';?>
|
||||
78
module/mr/view/linkbug.html.php
Normal file
78
module/mr/view/linkbug.html.php
Normal 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¶m=$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>
|
||||
91
module/mr/view/linkstory.html.php
Normal file
91
module/mr/view/linkstory.html.php
Normal 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¶m=$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>
|
||||
78
module/mr/view/linktask.html.php
Normal file
78
module/mr/view/linktask.html.php
Normal 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¶m=$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>
|
||||
@@ -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');
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user