Merge branch 'sprint/devops16' of https://gitlab.zcorp.cc/easycorp/zentaopms into devops16

This commit is contained in:
liyuchun
2021-12-10 08:26:02 +08:00
27 changed files with 941 additions and 558 deletions
+7
View File
@@ -0,0 +1,7 @@
ALTER TABLE `zt_task` ADD `repo` mediumint unsigned NOT NULL AFTER `activatedDate`;
ALTER TABLE `zt_task` ADD `entry` varchar(255) NOT NULL AFTER `repo`;
ALTER TABLE `zt_task` ADD `lines` varchar(10) NOT NULL AFTER `entry`;
ALTER TABLE `zt_task` ADD `v1` varchar(40) NOT NULL AFTER `lines`;
ALTER TABLE `zt_task` ADD `v2` varchar(40) NOT NULL AFTER `v1`;
ALTER TABLE `zt_task` ADD `mr` mediumint(8) unsigned NOT NULL AFTER `repo`;
ALTER TABLE `zt_bug` ADD `mr` mediumint(8) unsigned NOT NULL AFTER `repo`;
+3
View File
@@ -8,6 +8,9 @@ $config->gitlab->edit->requiredFields = 'name,url,token';
$config->gitlab->createbranch = new stdclass;
$config->gitlab->createbranch->requiredFields = 'branch,ref';
$config->gitlab->createbranchpriv = new stdclass;
$config->gitlab->createbranchpriv->requiredFields = 'name';
$config->gitlab->labelPattern = new stdclass;
$config->gitlab->labelPattern->task = '/^zentao_task\/\d+$/';
$config->gitlab->labelPattern->bug = '/^zentao_bug\/\d+$/';
+132
View File
@@ -798,6 +798,138 @@ class gitlab extends control
$this->display();
}
/**
* Browse gitlab protect branch.
*
* @param int $gitlabID
* @param int $projectID
* @param string $orderBy
* @param int $recTotal
* @param int $recPerPage
* @param int $pageID
* @access public
* @return void
*/
public function browseBranchPriv($gitlabID, $projectID, $orderBy = 'id_desc', $recTotal = 0, $recPerPage = 15, $pageID = 1)
{
$keyword = fixer::input('post')->setDefault('keyword', '')->get('keyword');
$branches = $this->gitlab->apiGetBranchPrivs($gitlabID, $projectID, $keyword, $orderBy);
$project = $this->gitlab->apiGetSingleProject($gitlabID, $projectID);
/* Pager. */
$this->app->loadClass('pager', $static = true);
$recTotal = count($branches);
$pager = new pager($recTotal, $recPerPage, $pageID);
$branchList = array_chunk($branches, $pager->recPerPage);
$this->view->keyword = $keyword;
$this->view->pager = $pager;
$this->view->title = $this->lang->gitlab->common . $this->lang->colon . $this->lang->gitlab->browseBranchPriv;
$this->view->levelLang = $this->lang->gitlab->branch->branchCreationLevelList;
$this->view->gitlabID = $gitlabID;
$this->view->projectID = $projectID;
$this->view->project = $project;
$this->view->orderBy = $orderBy;
$this->view->branchList = empty($branchList) ? $branchList: $branchList[$pageID - 1];
$this->display();
}
/**
* Set a gitlab protect branch.
*
* @param int $gitlabID
* @param int $projectID
* @param string $branch
* @access public
* @return void
*/
public function createBranchPriv($gitlabID, $projectID, $branch = '')
{
if($_POST)
{
$this->gitlab->createBranchPriv($gitlabID, $projectID, $branch);
if(dao::isError()) return $this->send(array('result' => 'fail', 'message' => dao::getError()));
return $this->send(array('result' => 'success', 'message' => $this->lang->saveSuccess, 'locate' => inlink('browseBranchPriv', "gitlabID=$gitlabID&projectID=$projectID")));
}
$branchPriv = new stdClass();
$branchPriv->name = '';
$branchPriv->mergeAccessLevel = 40; // Initialize data, and the operation authority is the maintainers by default.
$branchPriv->pushAccessLevel = 40; // Initialize data, and the operation authority is the maintainers by default.
$gitlab = $this->gitlab->getByID($gitlabID);
$title = $this->lang->gitlab->createBranchPriv;
if($branch)
{
$title = $this->lang->gitlab->editBranchPriv;
$branchPriv = $this->gitlab->apiGetSingleBranchPriv($gitlabID, $projectID, $branch);
$branchPriv->mergeAccessLevel = $this->gitlab->checkAccessLevel($branchPriv->merge_access_levels);
$branchPriv->pushAccessLevel = $this->gitlab->checkAccessLevel($branchPriv->push_access_levels);
}
$gitlabBranches = $this->gitlab->apiGetBranches($gitlabID, $projectID);
$protectBranches = $this->gitlab->apiGetBranchPrivs($gitlabID, $projectID, '', 'name_asc');
$protectNames = array_keys($protectBranches);
$branches = array();
foreach($gitlabBranches as $oneBranch)
{
if(!in_array($oneBranch->name, $protectNames) || $oneBranch->name == $branch) $branches[$oneBranch->name] = $oneBranch->name;
}
$this->view->title = $this->lang->gitlab->common . $this->lang->colon . $title;
$this->view->pageTitle = $title;
$this->view->gitlab = $gitlab;
$this->view->gitlabID = $gitlabID;
$this->view->branch = $branch;
$this->view->projectID = $projectID;
$this->view->branches = $branches;
$this->view->branchPriv = $branchPriv;
$this->display();
}
/**
* Edit a gitlab branch protect.
*
* @param int $gitlabID
* @param int $projectID
* @param string $branch
* @access public
* @return void
*/
public function editBranchPriv($gitlabID, $projectID, $branch)
{
echo $this->fetch('gitlab', 'createBranchPriv', "gitlabID=$gitlabID&projectID=$projectID&branch=$branch");
}
/**
* Delete a gitlab protect branch.
*
* @param int $gitlabID
* @param int $projectID
* @param string $branch
* @param string $confirm
* @access public
* @return void
*/
public function deleteBranchPriv($gitlabID, $projectID, $branch, $confirm = 'no')
{
if($confirm != 'yes') die(js::confirm($this->lang->gitlab->branch->confirmDelete , inlink('deleteBranchPriv', "gitlabID=$gitlabID&projectID=$projectID&branch=$branch&confirm=yes")));
$reponse = $this->gitlab->apiDeleteBranchPriv($gitlabID, $projectID, $branch);
/* If the status code beginning with 20 is returned or empty is returned, it is successful. */
if(!$reponse or substr($reponse->message, 0, 2) == '20')
{
$this->loadModel('action')->create('gitlabbranchPriv', $branch, 'deleted', '', $branch);
die(js::reload('parent'));
}
die(js::alert($reponse->message));
}
/**
* Import gitlab issue to zentaopms.
*
+2
View File
@@ -0,0 +1,2 @@
.text-c-counts > span {margin-left: 5px;}
#mainMenu .pull-left {margin-right: 15px;}
+2
View File
@@ -0,0 +1,2 @@
.table-form>tbody>tr>th {width: 110px;}
.table-form {width: 50%;}
+23
View File
@@ -0,0 +1,23 @@
$(document).ready(function()
{
$('#branchSearch').click(function()
{
triggerSearch();
});
$('#keyword').keypress(function(event)
{
if(event.which == 13) triggerSearch();
})
});
/**
* Trigger filtering function.
*
* @access public
* @return void
*/
function triggerSearch()
{
$("#branchPrivForm").submit();
}
+2 -2
View File
@@ -41,6 +41,6 @@ function addItem(obj)
*/
function deleteItem(obj)
{
if($('#teamForm .table tbody').children().length < 2) return false;
if($('#teamForm .table-form tbody').children().length < 2) return false;
$(obj).closest('tr').remove();
}
}
+2 -2
View File
@@ -41,6 +41,6 @@ function addItem(obj)
*/
function deleteItem(obj)
{
if($('#teamForm .table tbody').children().length < 2) return false;
if($('#teamForm .table-form tbody').children().length < 2) return false;
$(obj).closest('tr').remove();
}
}
+21 -6
View File
@@ -47,6 +47,10 @@ $lang->gitlab->deleteUser = 'Delete user';
$lang->gitlab->createBranch = 'Add branch';
$lang->gitlab->manageGroupMembers = 'Manage group member';
$lang->gitlab->createWebhook = 'Create Webhook';
$lang->gitlab->browseBranchPriv = 'Protect branch';
$lang->gitlab->createBranchPriv = 'Cerate branch protected';
$lang->gitlab->editBranchPriv = 'Edit branch protected';
$lang->gitlab->deleteBranchPriv = 'Delete branch protected';
$lang->gitlab->id = 'ID';
$lang->gitlab->name = "GitLab Name";
@@ -128,7 +132,7 @@ $lang->gitlab->user->projectsLimit = "Projects limit";
$lang->gitlab->user->canCreateGroup = "Can create group";
$lang->gitlab->user->external = "External";
$lang->gitlab->user->externalTip = "External users cannot see internal or private projects unless access is explicitly granted. Also, external users cannot create projects, groups, or personal snippets.";
$lang->gitlab->user->bind = "Bind Zentao user";
$lang->gitlab->user->bind = "Zentao user";
$lang->gitlab->user->avatar = "Avatar";
$lang->gitlab->user->skype = "Skype";
$lang->gitlab->user->linkedin = "Linkedin";
@@ -180,8 +184,19 @@ $lang->gitlab->group->memberExpiresAt = 'Expiration time
$lang->gitlab->group->repeatError = "Group members cannot be added repeatedly";
$lang->gitlab->branch = new stdclass();
$lang->gitlab->branch->name = 'Branch Name';
$lang->gitlab->branch->from = 'Create from';
$lang->gitlab->branch->create = 'Create';
$lang->gitlab->branch->lastCommitter = 'Last Committer';
$lang->gitlab->branch->lastCommittedDate = 'Last Committed Date';
$lang->gitlab->branch->name = 'Branch Name';
$lang->gitlab->branch->from = 'Create from';
$lang->gitlab->branch->create = 'Create';
$lang->gitlab->branch->lastCommitter = 'Last Committer';
$lang->gitlab->branch->lastCommittedDate = 'Last Committed Date';
$lang->gitlab->branch->accessLevel = "Branch protection list";
$lang->gitlab->branch->mergeAllowed = "Merge Allowed";
$lang->gitlab->branch->pushAllowed = "Push Allowed";
$lang->gitlab->branch->placeholderSearch = "Branch name";
$lang->gitlab->branch->placeholderSelect = "Branch name";
$lang->gitlab->branch->confirmDelete = 'Branch will be writable for developers. Are you sure?';
$lang->gitlab->branch->branchCreationLevelList[40] = "Maintainers";
$lang->gitlab->branch->branchCreationLevelList[30] = "Developers + Maintainers";
$lang->gitlab->branch->branchCreationLevelList[0] = "No one";
$lang->gitlab->branch->emptyPrivNameError = "Branch cannot be empty.";
$lang->gitlab->branch->issetPrivNameError = "The protection branch already exists";
+21 -6
View File
@@ -47,6 +47,10 @@ $lang->gitlab->deleteUser = '删除用户';
$lang->gitlab->createBranch = '添加分支';
$lang->gitlab->manageGroupMembers = '群组成员管理';
$lang->gitlab->createWebhook = '创建Webhook';
$lang->gitlab->browseBranchPriv = '分支保护管理';
$lang->gitlab->createBranchPriv = '创建分支保护';
$lang->gitlab->editBranchPriv = '编辑分支保护';
$lang->gitlab->deleteBranchPriv = '删除分支保护';
$lang->gitlab->id = 'ID';
$lang->gitlab->name = "{$lang->gitlab->common}名称";
@@ -128,7 +132,7 @@ $lang->gitlab->user->projectsLimit = "限制项目";
$lang->gitlab->user->canCreateGroup = "可创建组";
$lang->gitlab->user->external = "外部人员";
$lang->gitlab->user->externalTip = "除非明确授予访问权限,否则外部用户无法查看内部或私有项目。另外,外部用户无法创建项目,群组或个人代码片段。";
$lang->gitlab->user->bind = "绑定禅道用户";
$lang->gitlab->user->bind = "禅道用户";
$lang->gitlab->user->avatar = "头像";
$lang->gitlab->user->skype = "Skype";
$lang->gitlab->user->linkedin = "Linkedin";
@@ -180,8 +184,19 @@ $lang->gitlab->group->memberExpiresAt = '过期时间';
$lang->gitlab->group->repeatError = "群组成员不能重复添加";
$lang->gitlab->branch = new stdclass();
$lang->gitlab->branch->name = '分支名';
$lang->gitlab->branch->from = '创建自';
$lang->gitlab->branch->create = '创建';
$lang->gitlab->branch->lastCommitter = '最后提交';
$lang->gitlab->branch->lastCommittedDate = '最后修改时间';
$lang->gitlab->branch->name = '分支名';
$lang->gitlab->branch->from = '创建自';
$lang->gitlab->branch->create = '创建';
$lang->gitlab->branch->lastCommitter = '最后提交';
$lang->gitlab->branch->lastCommittedDate = '最后修改时间';
$lang->gitlab->branch->accessLevel = "分支保护列表";
$lang->gitlab->branch->mergeAllowed = "允许合并到";
$lang->gitlab->branch->pushAllowed = "允许推送到";
$lang->gitlab->branch->placeholderSearch = "请输入分支名称";
$lang->gitlab->branch->placeholderSelect = "请选择分支";
$lang->gitlab->branch->confirmDelete = '确定删除分支保护?';
$lang->gitlab->branch->branchCreationLevelList[40] = "维护者";
$lang->gitlab->branch->branchCreationLevelList[30] = "开发者 + 维护者";
$lang->gitlab->branch->branchCreationLevelList[0] = "禁止";
$lang->gitlab->branch->emptyPrivNameError = "分支不能为空";
$lang->gitlab->branch->issetPrivNameError = "已存在该保护分支";
+130
View File
@@ -2332,4 +2332,134 @@ class gitlabModel extends model
->andWhere('path')->in($projectIDs)
->fetchPairs('path', 'product');
}
/**
* Get protect branches of one project.
*
* @param int $gitlabID
* @param int $projectID
* @param string $keyword
* @param string $orderBy
* @access public
* @return array
*/
public function apiGetBranchPrivs($gitlabID, $projectID, $keyword = '', $orderBy = 'id_desc')
{
$keyword = urlencode($keyword);
$url = sprintf($this->getApiRoot($gitlabID), "/projects/$projectID/protected_branches");
$branches = json_decode(commonModel::http($url));
/* Parse order string. */
$order = explode('_', $orderBy);
$newBranches = array();
foreach($branches as $branch)
{
if(empty($keyword) || stristr($branch->name, $keyword)) $newBranches[$branch->{$order[0]}] = $branch;
}
if($order[1] == 'asc') ksort($newBranches);
if($order[1] == 'desc') krsort($newBranches);
return $newBranches;
}
/**
* Get single protct branch by API.
*
* @param int $gitlabID
* @param int $projectID
* @param string $branch
* @access public
* @return object
*/
public function apiGetSingleBranchPriv($gitlabID, $projectID, $branch)
{
$url = sprintf($this->getApiRoot($gitlabID), "/projects/$projectID/protected_branches/$branch");
return json_decode(commonModel::http($url));
}
/**
* Create gitlab potect branch.
*
* @param int $gitlabID
* @param int $projectID
* @param string $branch
* @access public
* @return bool
*/
public function createBranchPriv($gitlabID, $projectID, $branch = '')
{
$priv = fixer::input('post')->get();
if(empty($priv->name)) dao::$errors['name'][] = $this->lang->gitlab->branch->emptyPrivNameError;
$singleBranch = $this->apiGetSingleBranchPriv($gitlabID, $projectID, $priv->name);
if(empty($branch) && !empty($singleBranch->id)) dao::$errors['name'][] = $this->lang->gitlab->branch->issetPrivNameError;
if(dao::isError()) return false;
if(!empty($branch) && !empty($singleBranch->id)) $this->apiDeleteBranchPriv($gitlabID, $projectID, $branch);
$response = $this->apiCreateBranchPriv($gitlabID, $projectID, $priv);
if(!empty($response->id))
{
$action = empty($branch) ? 'created' : 'edited';
$this->loadModel('action')->create('gitlabbranchpriv', $response->id, $action, '', $response->name);
return true;
}
return $this->apiErrorHandling($response);
}
/**
* Create a gitab protect branch by api.
*
* @param int $gitlabID
* @param int $projectID
* @param object $priv
* @access public
* @return object
*/
public function apiCreateBranchPriv($gitlabID, $projectID, $priv)
{
if(empty($priv->name)) return false;
$url = sprintf($this->getApiRoot($gitlabID), "/projects/" . $projectID . '/protected_branches');
return json_decode(commonModel::http($url, $priv));
}
/**
* Delete a gitab protect branch by api.
*
* @param int $gitlabID
* @param int $projectID
* @param string $branch
* @access public
* @return object
*/
public function apiDeleteBranchPriv($gitlabID, $projectID, $branch)
{
$apiRoot = $this->getApiRoot($gitlabID);
$url = sprintf($apiRoot, "/projects/{$projectID}/protected_branches/{$branch}");
return json_decode(commonModel::http($url, array(), $options = array(CURLOPT_CUSTOMREQUEST => 'DELETE')));
}
/**
* Check access level.
*
* @param array $accessLevels
* @access public
* @return int
*/
public function checkAccessLevel($accessLevels)
{
$noAccess = 0;
$developerAccess = 30;
$maintainerAccess = 40;
if(is_array($accessLevels))
{
$levels = array();
foreach($accessLevels as $level) $levels[] = (int)$level->access_level;
if(in_array($noAccess, $levels)) return $noAccess;
if(in_array($developerAccess, $levels)) return $developerAccess;
}
return $maintainerAccess;
}
}
+1 -1
View File
@@ -50,7 +50,7 @@
common::printLink('gitlab', 'browseProject', "gitlabID=$id", "<i class='icon icon-list-box'></i> ", '',"title={$lang->gitlab->browseProject} class='btn btn-primary'");
common::printLink('gitlab', 'browseGroup', "gitlabID=$id", "<i class='icon icon-groups'></i> ", '', "title={$lang->gitlab->browseGroup} class='btn btn-primary'");
common::printLink('gitlab', 'edit', "gitlabID=$id", "<i class='icon icon-edit'></i> ", '',"title={$lang->gitlab->edit} class='btn btn-primary'");
common::printLink('gitlab', 'browseUser', "gitlabID=$id", "<i class='icon icon-persons'></i> ", '', "title={$lang->gitlab->browseUser} class='btn {$disabled}' ,'disabled'");
common::printLink('gitlab', 'browseUser', "gitlabID=$id", "<i class='icon icon-person'></i> ", '', "title={$lang->gitlab->browseUser} class='btn {$disabled}' ,'disabled'");
common::printLink('gitlab', 'bindUser', "id=$id", "<i class='icon icon-link'></i> ", '', "title={$lang->gitlab->bindUser} class='btn {$disabled}' ,'disabled'");
if(common::hasPriv('gitlab', 'delete')) echo html::a($this->createLink('gitlab', 'delete', "gitlabID=$id"), '<i class="icon-trash"></i>', 'hiddenwin', "title='{$lang->gitlab->delete}' class='btn'");
?>
@@ -0,0 +1,79 @@
<?php
/**
* The browse view file of gitlab protext branch 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 Yanyi Cao <caoyanyi@easycorp.ltd>
* @package gitlab
* @version $Id$
* @link http://www.zentao.net
*/
?>
<?php include '../../common/view/header.html.php';?>
<div id="mainMenu" class="clearfix">
<div class='pull-left'>
<?php echo html::a($this->createLink('gitlab', 'browseProject', "gitlabID=$gitlabID"), "<i class='icon icon-back icon-sm'></i> " . $lang->goback, '', "class='btn btn-secondary'");?>
</div>
<div id="sidebarHeader">
<div class="title" title="<?php echo $project->name_with_namespace; ?>"><?php echo $project->name_with_namespace; ?></div>
</div>
<div class="btn-toolbar pull-left">
<div>
<form id='branchPrivForm' method='post'>
<?php echo html::input('keyword', $keyword, "class='form-control' placeholder='{$lang->gitlab->branch->placeholderSearch}' style='display: inline-block;width:auto;margin:0 10px'");?>
<a id="branchSearch" class="btn btn-primary"><?php echo $lang->gitlab->search?></a>
</form>
</div>
</div>
<div class="btn-toolbar pull-right">
<?php if(common::hasPriv('gitlab', 'createBranchPriv')) common::printLink('gitlab', 'createBranchPriv', "gitlabID=$gitlabID&projectID=$projectID", "<i class='icon icon-plus'></i> " . $lang->gitlab->createBranchPriv, '', "class='btn btn-primary'");?>
</div>
</div>
<?php if(empty($branchList)):?>
<div class="table-empty-tip">
<p>
<span class="text-muted"><?php echo $lang->noData;?></span>
<?php if(empty($keyword) and common::hasPriv('gitlab', 'createProject')):?>
<?php echo html::a($this->createLink('gitlab', 'createBranchPriv', "gitlabID=$gitlabID&projectID=$projectID"), "<i class='icon icon-plus'></i> " . $lang->gitlab->createBranchPriv, '', "class='btn btn-info'");?>
<?php endif;?>
</p>
</div>
<?php else:?>
<div id='mainContent' class='main-row'>
<form class='main-table' id='ajaxForm' method='post'>
<table id='branchList' class='table has-sort-head table-fixed'>
<?php $vars = "gitlabID={$gitlabID}&projectID={$projectID}&orderBy=%s&recTotal={$pager->recTotal}&recPerPage={$pager->recPerPage}&pageID={$pager->pageID}";?>
<thead>
<tr>
<th class='c-name text-left'><?php common::printOrderLink('name', $orderBy, $vars, $lang->gitlab->branch->name);?></th>
<th class='text-left'><?php echo $lang->gitlab->branch->mergeAllowed;?></th>
<th class='text-left'><?php echo $lang->gitlab->branch->pushAllowed;?></th>
<th class='c-actions-4'><?php echo $lang->actions;?></th>
</tr>
</thead>
<tbody>
<?php foreach ($branchList as $id => $branch): ?>
<?php $branch->merge_access_level = $this->gitlab->checkAccessLevel($branch->merge_access_levels); ?>
<?php $branch->push_access_level = $this->gitlab->checkAccessLevel($branch->push_access_levels); ?>
<tr class='text'>
<td class='text-c-name' title='<?php echo $branch->name;?>'><?php echo $branch->name;?></td>
<td class-'text' title="<?php echo $levelLang[$branch->merge_access_level];?>"><?php echo $levelLang[$branch->merge_access_level];?></td>
<td class='text' title="<?php echo $levelLang[$branch->push_access_level];?>"><?php echo $levelLang[$branch->push_access_level];?></td>
<td class='c-actions text-left'>
<?php
if(common::hasPriv('gitlab', 'editBranchPriv')) common::printLink('gitlab', 'editBranchPriv', "gitlabID=$gitlabID&projectID=$projectID&branch=$branch->name", "<i class='icon icon-edit'></i> ", '', "title={$lang->gitlab->editBranchPriv} class='btn btn-primary'");
if(common::hasPriv('gitlab', 'deleteBranchPriv')) echo html::a($this->createLink('gitlab', 'deleteBranchPriv', "gitlabID=$gitlabID&projectID=$projectID&branch=$branch->name"), '<i class="icon-trash"></i>', 'hiddenwin', "title='{$lang->gitlab->deleteBranchPriv}' class='btn'");
?>
</td>
</tr>
<?php endforeach;?>
</tbody>
</table>
<?php if($branchList):?>
<div class='table-footer'><?php $pager->show('right', 'pagerjs');?></div>
<?php endif;?>
</form>
</div>
<?php endif;?>
<?php include '../../common/view/footer.html.php';?>
+2 -1
View File
@@ -15,7 +15,7 @@
<?php js::set('gitlabID', $gitlabID)?>
<div id="mainMenu" class="clearfix">
<div class='pull-left'>
<?php echo html::backButton('<i class="icon icon-back icon-sm"></i> ' . $lang->goback, '', 'btn btn-secondary');?>
<?php echo html::a($this->createLink('gitlab', 'browse'), "<i class='icon icon-back icon-sm'></i> " . $lang->goback, '', "class='btn btn-secondary'");?>
</div>
<div id="sidebarHeader">
<div class="title"><?php echo $this->lang->gitlab->common . ':' . $gitlab->name; ?></div>
@@ -68,6 +68,7 @@
<td class='c-actions text-left'>
<?php
common::printLink('gitlab', 'browseBranch', "gitlabID=$gitlabID&projectID=$gitlabProject->id", "<i class='icon icon-treemap'></i> ", '', "title={$lang->gitlab->browseBranch} class='btn btn-primary'");
common::printLink('gitlab', 'browseBranchPriv', "gitlabID=$gitlabID&projectID=$gitlabProject->id", "<i class='icon icon-lock'></i> ", '', "title={$lang->gitlab->branch->accessLevel} class='btn btn-primary'");
common::printLink('gitlab', 'editProject', "gitlabID=$gitlabID&projectID=$gitlabProject->id", "<i class='icon icon-edit'></i> ", '', "title={$lang->gitlab->project->edit} class='btn btn-primary'");
if(common::hasPriv('gitlab', 'delete')) echo html::a($this->createLink('gitlab', 'deleteProject', "gitlabID=$gitlabID&projectID=$gitlabProject->id"), '<i class="icon-trash"></i>', 'hiddenwin', "title='{$lang->gitlab->deleteProject}' class='btn'");
?>
@@ -0,0 +1,47 @@
<?php
/**
* The create view file of protext branch 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 Yanyi Cao <caoyanyi@easycorp.ltd>
* @package gitlab
* @version $Id$
* @link http://www.zentao.net
*/
?>
<?php include '../../common/view/header.html.php';?>
<div id='mainContent' class='main-row'>
<div class='main-col main-content'>
<div class='center-block'>
<div class='main-header'>
<h2><?php echo $pageTitle;?></h2>
</div>
<form id='branchForm' method='post' class='form-ajax' enctype="multipart/form-data">
<?php if($branch) echo html::hidden('name', $branch);?>
<table class='table table-form'>
<tr>
<th><?php echo $lang->gitlab->branch->name;?></th>
<td><?php echo html::select('name', $branches, $branchPriv->name, "class='form-control chosen' data-placeholder='{$lang->gitlab->branch->placeholderSelect}' " . ($branch ? 'disabled' : ''));?></td>
</tr>
<tr>
<th><?php echo $lang->gitlab->branch->mergeAllowed;?></th>
<td><?php echo html::select('merge_access_level', $lang->gitlab->branch->branchCreationLevelList, $branchPriv->mergeAccessLevel, "class='form-control'");?></td>
</tr>
<tr>
<th><?php echo $lang->gitlab->branch->pushAllowed;?></th>
<td><?php echo html::select('push_access_level', $lang->gitlab->branch->branchCreationLevelList, $branchPriv->pushAccessLevel, "class='form-control'");?></td>
</tr>
<tr>
<th></th>
<td class='text-center form-actions'>
<?php echo html::submitButton();?>
<?php if(!isonlybody()) echo html::a(inlink('browseBranchPriv', "gitlabID=$gitlabID&projectID=$projectID"), $lang->goback, '', 'class="btn btn-wide"');?>
</td>
</tr>
</table>
</form>
</div>
</div>
</div>
<?php include '../../common/view/footer.html.php';?>
+6 -2
View File
@@ -1250,6 +1250,10 @@ $lang->resource->gitlab->browseBranch = 'browseBranch';
$lang->resource->gitlab->webhook = 'webhook';
$lang->resource->gitlab->createWebhook = 'createWebhook';
$lang->resource->gitlab->manageProjectMembers = 'manageProjectMembers';
$lang->resource->gitlab->browseBranchPriv = 'browseBranchPriv';
$lang->resource->gitlab->createBranchPriv = 'createBranchPriv';
$lang->resource->gitlab->editBranchPriv = 'editBranchPriv';
$lang->resource->gitlab->deleteBranchPriv = 'deleteBranchPriv';
$lang->gitlab->methodOrder[5] = 'browse';
$lang->gitlab->methodOrder[10] = 'create';
@@ -1294,7 +1298,7 @@ $lang->resource->mr->unlink = 'unlink';
$lang->resource->mr->approval = 'approval';
$lang->resource->mr->close = 'close';
$lang->resource->mr->reopen = 'reopen';
$lang->resource->mr->addBug = 'addBug';
$lang->resource->mr->addReview = 'addReview';
$lang->mr->methodOrder[10] = 'create';
$lang->mr->methodOrder[15] = 'browse';
@@ -1311,7 +1315,7 @@ $lang->mr->methodOrder[75] = 'unlink';
$lang->mr->methodOrder[80] = 'approval';
$lang->mr->methodOrder[85] = 'close';
$lang->mr->methodOrder[90] = 'reopen';
$lang->mr->methodOrder[95] = 'addBug';
$lang->mr->methodOrder[95] = 'addReview';
/* Git. */
$lang->resource->git = new stdclass();
+13 -25
View File
@@ -300,7 +300,7 @@ class mr extends control
* @access public
* @return void
*/
public function diff($MRID, $encoding= '')
public function diff($MRID, $encoding = '')
{
$this->app->loadLang('productplan');
$this->app->loadLang('bug');
@@ -316,7 +316,7 @@ class mr extends control
$this->view->rawMR = $rawMR;
if(!isset($rawMR->id) or (isset($rawMR->message) and $rawMR->message == '404 Not found') or empty($rawMR)) return $this->display();
$diffs = $this->mr->getDiffs($MR, $encoding = '');
$diffs = $this->mr->getDiffs($MR, $encoding);
$arrange = $this->cookie->arrange ? $this->cookie->arrange : 'inline';
if($this->server->request_method == 'POST')
@@ -782,49 +782,37 @@ class mr extends control
}
/**
* Add a Bug for this review.
* Add a review for this review.
*
* @param int $repoID
* @param string $file
* @param int $mr
* @param int $v1
* @param int $v2
* @access public
* @return void
*/
public function addBug($repoID, $file, $v1, $v2)
public function addReview($repoID, $mr, $v1, $v2)
{
/* Handle the exception that when $repoID is empty. */
if($repoID == "0") $this->send(array());
$this->loadModel('repo');
if($this->get->repoPath) $file = $this->get->repoPath;
if(!empty($_POST))
{
$result = $this->mr->saveBug($repoID, $file, $v1, $v2);
if($this->post->reviewType == 'bug') $result = $this->mr->saveBug($repoID, $mr, $v1, $v2);
if($this->post->reviewType == 'task') $result = $this->mr->saveTask($repoID, $mr, $v1, $v2);
if(dao::isError()) die(json_encode($result));
$bugID = $result['id'];
$objectID = $result['id'];
$repo = $this->repo->getRepoById($repoID);
/* Handle the exception that when $repo is empty. */
if(empty($repo)) $this->send(array());
if(empty($repo) or empty($result)) $this->send(json_encode(array()));
$entry = isset($repo->name) ? $repo->name . '/' . $this->repo->decodePath($file) : '';
$location = sprintf($this->lang->repo->reviewLocation, $entry, $repo->SCM != 'Subversion' ? substr($v2, 0, 10) : $v2, $this->post->begin, $this->post->end);
if(empty($v1))
{
$revision = $repo->SCM != 'Subversion' ? substr($v2, 0, 10) : $v2;
$link = $this->repo->createLink('view', "repoID=$repoID&objectID=0&entry={$file}&revision=$v2&showBug=true") . '#L' . $this->post->begin;
}
else
{
$revision = $repo->SCM != 'Subversion' ? substr($v1, 0, 10) : $v1;
$revision .= ' : ';
$revision .= $repo->SCM != 'Subversion' ? substr($v2, 0, 10) : $v2;
$link = $this->repo->createLink('diff', "repoID=$repoID&objectID=0&entry={$file}&oldRevision=$v1&newRevision=$v2&showBug=true") . '#L' . $this->post->begin;
}
$location = sprintf($this->lang->repo->reviewLocation, $this->post->entry ? base64_decode($this->post->entry) : '', $repo->SCM != 'Subversion' ? substr($v2, 0, 10) : $v2, $this->post->begin, $this->post->end);
$link = $this->createLink('mr', 'diff', "mr=$mr") . '#L' . $this->post->begin;
$actionID = $this->loadModel('action')->create('bug', $bugID, 'repoCreated', '', html::a($link, $location));
$this->loadModel('mail')->sendmail($bugID, $actionID);
$actionID = $this->loadModel('action')->create($this->post->reviewType, $objectID, 'repoCreated', '', html::a($link, $location));
$this->loadModel('mail')->sendmail($objectID, $actionID);
echo json_encode($result);
}
+20 -20
View File
@@ -88,8 +88,8 @@ h3 {font-size: 16px;}
/* repo action form */
.repoCode .comment-list, .repoCode .comment-actions {max-width: 900px;}
.repoCode .bugFormContainer {border: 1px solid #bbb; margin: 0 0 0 15px; padding: 10px 20px 10px 10px; max-width: 880px; background: #fff;}
.repoCode .bugFormContainer th {width: 70px;}
.repoCode .reviewFormContainer {border: 1px solid #bbb; margin: 0 0 0 15px; padding: 10px 20px 10px 10px; max-width: 880px; background: #fff;}
.repoCode .reviewFormContainer th {width: 70px;}
.repoCode .action-row {display: none;}
.repoCode .with-action-row .action-row {display: table-row;}
@@ -106,26 +106,26 @@ h3 {font-size: 16px;}
.repoCode .comment-cell .panel-body {padding: 6px 10px;}
.repoCode .comment-cell .panel-actions.pull-right {margin-right: 0; margin-top: 0;}
.repoCode .comment-cell .editing .panel-body, .repoCode .comment-cell .commentContainer.show-form .panel-body {display: none;}
.repoCode .comment-cell .bug-edit-form, {padding: 10px; display: none;}
.repoCode .comment-cell .editing .bug-edit-form, .repoCode .comment-cell .commentContainer.show-form .comment-edit-form {display: block;}
.repoCode .comment-cell .review-edit-form, {padding: 10px; display: none;}
.repoCode .comment-cell .editing .review-edit-form, .repoCode .comment-cell .commentContainer.show-form .comment-edit-form {display: block;}
.repoCode .comment {border: 1px solid #e5e5e5; background: #fafafa; padding: 5px 10px; margin-bottom: 10px;}
.repoCode .comment .comment-edit-form {margin-top: 10px;}
.repoCode .panel-bug .steps {background: #f1f1f1; padding: 5px 10px;}
.repoCode .panel-bug .bug-edit-form {margin-bottom: 10px;}
.repoCode .panel-bug .panel-body {display: none;}
.repoCode .panel-bug .panel-heading {cursor: pointer;}
.repoCode .panel-bug.show .panel-body {display: block;}
.repoCode .panel-bug.show .icon-chevron-sign-down:before {content: '\e711';}
.repoCode .panel-bug.show-edit-form .bug-edit-form,
.repoCode .panel-bug.show-form .commentForm,
.repoCode .panel-review .steps {background: #f1f1f1; padding: 5px 10px;}
.repoCode .panel-review .review-edit-form {margin-bottom: 10px;}
.repoCode .panel-review .panel-body {display: none;}
.repoCode .panel-review .panel-heading {cursor: pointer;}
.repoCode .panel-review.show .panel-body {display: block;}
.repoCode .panel-review.show .icon-chevron-sign-down:before {content: '\e711';}
.repoCode .panel-review.show-edit-form .review-edit-form,
.repoCode .panel-review.show-form .commentForm,
.repoCode .comment.show-form .comment-edit-form {display: block;}
.repoCode .panel-bug .bug-edit-form,
.repoCode .panel-bug.show-form .addComment,
.repoCode .panel-bug .commentForm,
.repoCode .panel-review .review-edit-form,
.repoCode .panel-review.show-form .addComment,
.repoCode .panel-review .commentForm,
.repoCode .comment .comment-edit-form,
.repoCode .panel-bug.show-edit-form .panel-body .title,
.repoCode .panel-bug.show-edit-form .bug-date,
.repoCode .panel-review.show-edit-form .panel-body .title,
.repoCode .panel-review.show-edit-form .bug-date,
.repoCode .comment.show-form .comment-content, .repoCode .comment.show-form .comment-date {display: none;}
.repoCode .text-content {white-space: normal; white-space: pre-line;}
@@ -154,8 +154,8 @@ h3 {font-size: 16px;}
.repoCode #diff tr.commented .row-tip {right: 0;}
.repoCode #diff tr.commented .icon-chat-dot {left: 0;}
.repoCode .panel, .bugFormContainer {transition: border 0.4s;}
.repoCode .panel.highlight, #bugForm.highlight .bugFormContainer {border-color: #e48600;}
.repoCode .panel, .reviewFormContainer {transition: border 0.4s;}
.repoCode .panel.highlight, #reviewForm.highlight .reviewFormContainer {border-color: #e48600;}
#bugsPreview {white-space: normal;}
#bugsPreview .dropdown-menu {top: -100%; left: 30%; padding-top: 0; min-width: 300px; max-width: 500px;}
@@ -166,7 +166,7 @@ h3 {font-size: 16px;}
.icon-comments {position: relative; left: -50px;}
/* bug form */
#bugForm, #bugForm table {margin: 0; padding: 0;}
#reviewForm, #reviewForm table {margin: 0; padding: 0;}
.panel .table + .panel-footer {border-top: 0; background: #fff;}
+118 -311
View File
@@ -5,6 +5,13 @@ $(document).ready(function()
$(".label-exchange").click(function(){ $('#exchange').submit();});
});
/**
* Change encoding.
*
* @param string $encoding
* @access public
* @return void
*/
function changeEncoding(encoding)
{
$('#encoding').val(encoding);
@@ -14,11 +21,8 @@ function changeEncoding(encoding)
$(document).ready(function()
{
var $diffCode = $('.diff');
var hidePreview;
var $bugsPreview = $('#bugsPreview');
var $bugsPreviewMenu = $('#bugsPreview').children('.dropdown-menu');
var $rows = $diffCode.find('tr');
var rowTip = $('#rowTip').html();
var $rows = $diffCode.find('tr');
var rowTip = $('#rowTip').html();
var lastLine;
$rows.each(function()
{
@@ -48,13 +52,11 @@ $(document).ready(function()
$(this).removeClass("over");
});
var isInline = $.cookie('arrange') == 'inline';
var $bugFormRow = $('<tr class="action-row"><th></th>' + (isInline ? '<th></th><td class="action-cell"></td>' : '<td colspan="3" class="action-cell"></td>') + '</tr>');
var $bugForm = $('#bugForm');
var $commentCell = $('#commentCell');
var $bugPanel = $('#bugPanel');
// $bugForm.find('input[name="begin"], input[name="end"]').attr('max', lastLine);
$bugFormRow.find('td').append($bugForm.removeClass('hide'));
var isInline = $.cookie('arrange') == 'inline';
var $reviewFormRow = $('<tr class="action-row"><th></th>' + (isInline ? '<th></th><td class="action-cell"></td>' : '<td colspan="3" class="action-cell"></td>') + '</tr>');
var $reviewForm = $('#reviewForm');
var $reviewPanel = $('#reviewPanel');
$reviewFormRow.find('td').append($reviewForm.removeClass('hide'));
var highlight = function($e)
{
@@ -62,76 +64,47 @@ $(document).ready(function()
$e.addClass('highlight');
};
var createComment = function(comment, $comments)
var createReview = function(review, line, show)
{
console.log();
var $comment = $commentCell.clone()
.removeClass('hide')
.attr('id', 'comment-' + comment.id)
.attr('data-comment', comment.id);
$comment.find('.realname').text(comment.realname);
$comment.find('.comment-content').text(comment.comment);
$comment.find('.date').text(comment.date);
$comment.find('.edit').toggle(comment.edit);
$comment.find('.comment-edit-form').attr('action', createLink('repo', 'editComment', 'commentID=' + comment.id));
var $review = $reviewPanel.clone().removeClass('hide').attr('id', review.objectType + '-' + review.id);
$review.find('.realname').text(review.realname);
$review.find('.openedDate').text(review.openedDate);
$review.find('.title').text(review.title);
$review.find('.content').toggle(review.content != '').html(review.content);
$review.find('.code-lines').text(review.lines);
$review.find('input[name="objectID"]').val(review.id);
$review.data(review);
if($comments)
{
if(typeof $comments !== 'object') $comments = $('#bug-' + $comments + ' .comments');
($comments.hasClass('comments') ? $comments : $comments.find('.comments')).append($comment);
}
id = review.objectType == 'bug' ? 'Bug' : 'Task';
id += '#' + review.id;
if(review.view) id = "<a href='" + createLink(review.objectType, 'view', 'id=' + review.id) + "'>" + id + "</a>";
$review.find('.title').closest('.panel-heading').find('.panel-actions').prepend(id);
if(!review.delete) $review.find('.title').closest('.panel-heading').find('.panel-actions .reviewDelete').hide();
return $comment;
};
$review.toggleClass('show', show > 1);
if(show > 2) highlight($review);
var createBug = function(bug, line, $commentRow, show)
{
var commentCount, j;
var $bug = $bugPanel.clone().removeClass('hide').attr('id', 'bug-' + bug.id).attr('data-bug', bug.id);
$bug.find('.bugid').text(bug.id);
$bug.find('.realname').text(bug.realname);
$bug.find('.openedDate').text(bug.openedDate);
$bug.find('.title').text(bug.title);
$bug.find('.steps').toggle(bug.steps != '').html(bug.steps);
$bug.find('.edit').toggle(bug.edit);
$bug.find('.code-lines').text(bug.lines);
$bug.find('.delete').toggle(bug.delete);
$bug.find('input[name="objectID"]').val(bug.id);
$bug.find('.bug-edit-form').attr('action', createLink('repo', 'editBug', 'bugID=' + bug.id));
$bug.find('a.view-bug').attr('href', createLink('bug', 'view', "bugID=" + bug.id));
$bug.data('data', bug);
$bug.toggleClass('show', show > 1);
if(show > 2) highlight($bug);
if(bug.comments)
{
commentCount = bug.comments.length;
$bugComments = $bug.find('.comments');
for(j = 0; j < commentCount; j++)
{
createComment(bug.comments[j], $bugComments);
}
}
if(!line && bug.line) line = bug.line;
if(!line && review.line) line = review.line;
if(line)
{
if(!$commentRow)
var $row = $rows.filter('[data-line="' + line + '"]').last();
if(review.entry) $row = $('#diff[data-entry="' + review.entry + '"]').find('tr').filter('[data-line="' + line + '"]');
if($row.length == 0) return false;
$commentRow = $row.next('tr');
if($row.hasClass('commented')) $commentRow = $row.nextAll('tr.comment-row').first();
if(!$commentRow.hasClass('comment-row'))
{
var $row = $rows.filter('[data-line="' + line + '"]').last();
$commentRow = $row.next('tr');
if(!$commentRow.hasClass('comment-row'))
{
$commentRow = $('<tr class="comment-row"><th></th>' + (isInline ? '<th></th><td class="comment-cell"><div class="comment-list"></div></td>' : '<td colspan="3" class="comment-cell"><div class="comment-list"></div></td>') + '</tr>');
$row.addClass('commented').after($commentRow);
}
$commentRow = $('<tr class="comment-row"><th></th>' + (isInline ? '<th></th><td class="comment-cell"><div class="comment-list"></div></td>' : '<td colspan="3" class="comment-cell"><div class="comment-list"></div></td>') + '</tr>');
$row.addClass('commented').after($commentRow);
}
($commentRow.hasClass('comment-list') ? $commentRow : $commentRow.find('.comment-list')).append($bug);
$commentRow.find('.comment-list').append($review);
if(show && $commentRow.hasClass('comment-row')) $commentRow.addClass('show');
}
return $bug;
return $review;
};
var toggleComment = function($row, show)
@@ -182,233 +155,50 @@ $(document).ready(function()
$rows.removeClass('with-action-row')
$row.addClass('with-action-row');
$bugForm.find('input[name="begin"]').val(line);
$bugForm.find('input[name="end"]').attr('min', line).val(line);
$bugForm.find('select#assignedTo').val(blamePairs[line]);
$bugForm.find('select#assignedTo').trigger("chosen:updated");
$reviewForm.find('input[name="begin"]').val(line);
$reviewForm.find('input[name="end"]').attr('min', line).val(line);
$reviewForm.find('select#assignedTo').trigger("chosen:updated");
$reviewForm.find('input#entry').val($row.closest('table#diff').data('entry'));
$row.after($bugFormRow);
$row.after($reviewFormRow);
KindEditor.remove('#commentText');
$('#commentText').kindeditor();
var getCommiterLink = createLink('repo', 'ajaxgetcommitter', 'repoID=' + repoID + "&entry=" + file + "&revision=" + revision + "&line=" + line);
var connector = getCommiterLink.indexOf('&') >= 0 ? '&' : '?';
getCommiterLink = getCommiterLink + connector + 'entry=' + file;
$.ajax({url: getCommiterLink}).done(function(responseText)
{
$bugForm.find('#assignedTo').val(responseText).trigger("chosen:updated");
});
}
highlight($bugForm);
$bugForm.find('input[name="title"]').focus();
highlight($reviewForm);
$reviewForm.find('input[name="title"]').focus();
$row.addClass('selected');
}
e.stopPropagation();
}).on('click', '.bugCancel', function()
}).on('click', '.reviewDelete', function(e)
{
$rows.removeClass('selected');
$diffCode.removeClass('with-action-row');
}).on('click', '.bugEdit', function(e)
{
var $panelBug = $(this).closest('.panel-bug');
var $review = $(this).closest('.panel-review');
if(!$review.length) return;
if($panelBug.hasClass('show-edit-form'))
if(confirm(confirmDelete))
{
$panelBug.removeClass('show-edit-form');
e.stopPropagation();
return;
}
$panelBug.addClass('show show-edit-form').find('input[name="commentText"]').val($panelBug.find('.title').first().text()).focus();
e.stopPropagation();
return false;
}).on('submit', '.bug-edit-form', function()
{
var $form = $(this);
$(this).ajaxSubmit(
{
success:function(text)
{
var $bug = $form.closest('.panel-bug');
$bug.find('.title').text(text);
$bug.removeClass('show-edit-form');
},
beforeSubmit:function(formData, jqForm)
{
var form = jqForm[0];
if(!form.commentText.value)
{
alert(contentError);
return false;
}
}
});
return false;
}).on('click', '.bugEditCancel', function()
{
$(this).closest('.panel-bug').removeClass('show-edit-form');
}).on('click', '.bugDelete', function(e)
{
var $bug = $(this).closest('.panel-bug');
if(!$bug.length) return;
if(confirm(confirmDelete))
{
var link = createLink('repo', 'deleteBug', 'bugID=' + $bug.data('bug') + '&confirm=yes');
var link = createLink($review.data('objectType'), 'delete', 'id=' + $review.data('id') + '&confirm=yes');
$.get(link, function(data)
{
if(data == 'deleted')
var $commentRow = $review.closest('.comment-row');
if($commentRow.find('.panel-review').length === 1)
{
var $commentRow = $bug.closest('.comment-row');
if($commentRow.find('.panel-bug').length === 1)
{
$commentRow.removeClass('show').prev('tr').removeClass('commented');
}
$bug.remove();
$commentRow.removeClass('show').prev('tr').removeClass('commented');
}
$review.remove();
});
}
e.stopPropagation();
return false;
}).on('click', '.addComment', function()
{
$(this).closest('.panel-bug').addClass('show-form').find('.commentForm textarea').focus();
}).on('click', '.commentCancel', function()
{
$(this).closest('.panel-bug').removeClass('show-form');
}).on('submit', '.commentForm', function()
{
var $form = $(this);
$form.ajaxSubmit(
{
success:function(json)
{
var $panelBug = $form.closest('.panel-bug');
$form.find('textarea').val('');
$panelBug.removeClass('show-form');
createComment($.parseJSON(json), $panelBug.data('bug'));
},
beforeSubmit:function(formData, jqForm)
{
var form = jqForm[0];
if(!form.comment.value)
{
alert(commentError);
return false;
}
}
});
return false;
}).on('click', '.commentEdit', function()
{
var $comment = $(this).closest('.comment');
if($comment.hasClass('show-form'))
{
$comment.removeClass('show-form');
return;
}
$comment.addClass('show-form').find('textarea').val($comment.find('.comment-content').text()).focus();
}).on('click', '.commentEditCancel', function()
{
$(this).closest('.comment').removeClass('show-form');
}).on('submit', '.comment-edit-form', function()
{
var $form = $(this);
$form.ajaxSubmit(
{
success:function(html)
{
var $comment = $form.closest('.comment');
$comment.find('.comment-content').html(html);
$comment.removeClass('show-form');
},
beforeSubmit:function(formData, jqForm)
{
var form = jqForm[0];
if(!form.commentText.value)
{
alert(contentError);
return false;
}
}
});
return false;
}).on('click', '.commentDelete', function()
{
var $container = $(this).closest('.commentContainer');
if(!$container.length) return;
if(confirm(confirmDeleteComment))
{
var commentID = $container.data('comment');
var link = createLink('repo', 'deleteComment', 'commentID=' + commentID + '&confirm=yes');
$.get(link, function(data)
{
if(data == 'deleted')
{
var $commentRow = $container.closest('.comment-row');
if($commentRow.find('.bugContainer, .commentContainer').length === 1)
{
$commentRow.removeClass('show').prev('tr').removeClass('commented');
}
$container.remove();
}
});
}
return false;
}).on('click', 'tr.commented', function()
{
toggleComment($(this));
}).on('click', '.panel-bug > .panel-heading', function()
}).on('click', '.panel-review > .panel-heading', function()
{
$(this).closest('.panel-bug').toggleClass('show');
}).on('mouseenter', 'tr.commented td .preview-icon', function(e)
{
var $cell = $(this).closest('td');
var $row = $cell.closest('tr');
var $commentRow = $row.next('tr');
var $bugs = $commentRow.find('.panel-bug'), line = '?';
$bugsPreviewMenu.children('li:not(.dropdown-header)').remove();
$bugsPreviewMenu.find('.bug-count').text($bugs.length);
$bugsPreviewMenu.find('.comment-count').text($commentRow.find('.comment').length);
$bugs.each(function()
{
var bug = $(this).data('data');
line = bug.line;
$bugsPreviewMenu.append('<li><a href="javascript:;" data-id="#bug-' + bug.id + '"><small class="text-muted">#' + bug.id + '</small> ' + bug.title + '</a></li>');
});
$bugsPreviewMenu.find('.code-line').text(line);
$bugsPreview.prependTo($cell);
clearTimeout(hidePreview);
$bugsPreviewMenu.css({top: 0-$bugsPreviewMenu.outerHeight(), left: Math.max(0, e.offsetX-$bugsPreviewMenu.outerWidth())}).addClass('show');
setTimeout(function(){$bugsPreviewMenu.addClass('in');}, 50);
}).on('mouseleave', 'tr.commented td', function()
{
$bugsPreviewMenu.removeClass('in');
hidePreview = setTimeout(function(){$bugsPreviewMenu.removeClass('show');}, 200);
$(this).closest('.panel-review').toggleClass('show');
});
$bugsPreviewMenu.on('click', 'li', function(e)
{
var $bug = $($(this).find('a').data('id'));
if($bug.length)
{
$bug.addClass('show');
toggleComment($bug.closest('tr.comment-row'), true);
highlight($bug);
$bugsPreviewMenu.removeClass('in');
hidePreview = setTimeout(function(){$bugsPreviewMenu.removeClass('show');}, 200);
}
e.stopPropagation();
});
$bugForm.submit(function()
$reviewForm.submit(function()
{
$(this).ajaxSubmit(
{
@@ -417,20 +207,42 @@ $(document).ready(function()
json = $.parseJSON(json);
if(json.result == 'fail')
{
alert(json.message);
return false;
var message = '';
if(typeof(json.message) != 'string')
{
for(i in json.message)
{
if(typeof(json.message[i]) == 'string')
{
message += json.message[i] + '\n';
}
else
{
for(j in json.message[i])
{
message += json.message[i][j] + '\n';
}
}
}
}
else
{
message += json.message + '\n';
}
alert(message);
return false;
}
createBug(json, null, null, 3);
createReview(json, json.line, 3);
$diffCode.removeClass('with-action-row');
$diffCode.find('tr.with-action-row.selected').removeClass('selected');
$bugForm.find('#title').val('');
$reviewForm.find('#title').val('');
KindEditor.html('#commentText', '');
},
beforeSubmit:function(formData, jqForm)
{
var form = jqForm[0];
if(!form.product.value)
if(!form.product.value)
{
alert(productError);
return false;
@@ -438,7 +250,7 @@ $(document).ready(function()
if(!form.title.value)
{
alert(titleError);
$bugForm.find('input[name="title"]').focus();
$reviewForm.find('input[name="title"]').focus();
return false;
}
}
@@ -447,27 +259,22 @@ $(document).ready(function()
}).on('change', 'input[name="begin"]', function()
{
var begin = $(this).val();
var $end = $bugForm.find('input[name="end"]').attr('min', begin);
var $end = $reviewForm.find('input[name="end"]').attr('min', begin);
if(parseInt($end.val()) < parseInt(begin))
{
$end.val(begin);
}
});
if(bugs)
if(reviews)
{
var lineBugs, bugsCount, i;
for(var line in bugs)
var lineReviews;
for(var line in reviews)
{
if(line)
{
lineBugs = bugs[line];
bugsCount = lineBugs.length;
for(i = 0; i < bugsCount; i++)
{
createBug(lineBugs[i], line);
}
{
lineReviews = reviews[line];
for(var i in lineReviews) createReview(lineReviews[i], line);
}
}
}
@@ -479,30 +286,30 @@ $(document).ready(function()
$('.highlight').removeClass('highlight');
});
/**
* Anchor
*
* @access public
* @return void
*/
function anchor()
{
var hash = window.location.hash;
if(hash)
var hash = window.location.hash;
if(!hash) return false;
var line = hash.substr(1).replace('L', '');
var $row = $('.diff tr[data-line="' + line +'"]').first();
if($row.length) return false;
var anchor = $row.offset().top;
$('body,html').animate({scrollTop:anchor - 50}, 500);
$row.addClass('highlight');
if($row.hasClass('commented'))
{
var line = hash.substr(1).replace('L', '');
var $row = $('.diff tr[data-line="' + line +'"]').first();
if($row.length)
{
var anchor = $row.offset().top;
$('body,html').animate({scrollTop:anchor - 50}, 500);
$row.addClass('highlight');
if($row.hasClass('commented'))
{
toggleComment($row, true);
var $commentRow = $row.next('tr');
if($commentRow.hasClass('comment-row'))
{
$commentRow.addClass('highlight');
}
}
}
toggleComment($row, true);
var $commentRow = $row.next('tr');
if($commentRow.hasClass('comment-row')) $commentRow.addClass('highlight');
}
}
});
+8 -3
View File
@@ -21,11 +21,11 @@ $lang->mr->linkStory = 'Link Stories';
$lang->mr->linkBug = 'Link Bugs';
$lang->mr->linkTask = 'Link Tasks';
$lang->mr->unlink = 'UnLink of stories,Bugs,tasks';
$lang->mr->addBug = 'Add Review';
$lang->mr->addReview = 'Add Review';
$lang->mr->id = 'ID';
$lang->mr->mriid = "raw MR ID";
$lang->mr->title = 'Name';
$lang->mr->title = 'Name';
$lang->mr->status = 'Status';
$lang->mr->author = 'Author';
$lang->mr->assignee = 'Assignee';
@@ -46,7 +46,12 @@ $lang->mr->reject = 'Reject';
$lang->mr->close = 'Close';
$lang->mr->reopen = 'Reopen';
$lang->mr->approvalResult = 'Approval result';
$lang->mr->reviewType = 'Review Type';
$lang->mr->reviewTypeList = array();
$lang->mr->reviewTypeList['bug'] = 'Bug';
$lang->mr->reviewTypeList['task'] = 'Task';
$lang->mr->approvalResult = 'Approval result';
$lang->mr->approvalResultList = array();
$lang->mr->approvalResultList['approve'] = 'Approve';
$lang->mr->approvalResultList['reject'] = 'Reject';
+8 -3
View File
@@ -21,7 +21,7 @@ $lang->mr->linkStory = '关联需求';
$lang->mr->linkBug = '关联Bug';
$lang->mr->linkTask = '关联任务';
$lang->mr->unlink = '取消关联需求、Bug、任务';
$lang->mr->addBug = '添加评审';
$lang->mr->addReview = '添加评审';
$lang->mr->id = 'ID';
$lang->mr->mriid = "MR原始ID";
@@ -46,7 +46,12 @@ $lang->mr->reject = '拒绝';
$lang->mr->close = '关闭';
$lang->mr->reopen = '重新打开';
$lang->mr->approvalResult = '评审意见';
$lang->mr->reviewType = '评审类型';
$lang->mr->reviewTypeList = array();
$lang->mr->reviewTypeList['bug'] = 'Bug';
$lang->mr->reviewTypeList['task'] = '任务';
$lang->mr->approvalResult = '评审意见';
$lang->mr->approvalResultList = array();
$lang->mr->approvalResultList['approve'] = '通过';
$lang->mr->approvalResultList['reject'] = '拒绝';
@@ -102,7 +107,7 @@ $lang->mr->closeSuccess = "已关闭合并请求。";
$lang->mr->apiErrorMap[0] = "You can't use same project/branch for source and target";
$lang->mr->errorLang[0] = '源项目分支不能和目标项目分支一样';
$lang->mr->errorLang[0] = '源项目分支目标项目分支不能相同';
$lang->mr->from = "";
$lang->mr->to = "合并到";
+157 -40
View File
@@ -552,7 +552,7 @@ class mrModel extends model
public function getDiffs($MR, $encoding = '')
{
$diffVersions = $this->apiGetDiffVersions($MR->gitlabID, $MR->targetProject, $MR->mriid);
$gitlab = $this->gitlab->getByID($MR->gitlabID);
$gitlab = $this->gitlab->getByID($MR->gitlabID);
$this->loadModel('repo');
$repo = new stdclass;
@@ -570,7 +570,7 @@ class mrModel extends model
foreach ($diffVersions as $diffVersion)
{
$singleDiff = $this->apiGetSingleDiffVersion($MR->gitlabID, $MR->targetProject, $MR->mriid, $diffVersion->id);
if ($singleDiff->state == 'empty') continue;
if($singleDiff->state == 'empty') continue;
$commits = $singleDiff->commits;
$diffs = $singleDiff->diffs;
foreach ($diffs as $index => $diff)
@@ -586,9 +586,10 @@ class mrModel extends model
$lines[] = sprintf("--a/%s", $diff->old_path);
$lines[] = sprintf("--b/%s", $diff->new_path);
$diffLines = explode("\n", $diff->diff);
foreach ($diffLines as $diffLine) $lines[] = $diffLine;
foreach($diffLines as $diffLine) $lines[] = $diffLine;
}
}
$scm = $this->app->loadClass('scm');
$scm->setEngine($repo);
$diff = $scm->engine->parseDiff($lines);
@@ -785,45 +786,46 @@ class mrModel extends model
* Get review.
*
* @param int $repoID
* @param string $entry
* @param int $MRID
* @param string $revision
* @access public
* @return array
*/
public function getReview($repoID, $entry, $revision)
public function getReview($repoID, $MRID, $revision = '')
{
$reviews = array();
$bugs = $this->dao->select('t1.*, t2.realname')->from(TABLE_BUG)->alias('t1')
->leftJoin(TABLE_USER)->alias('t2')
->on('t1.openedBy = t2.account')
->leftJoin(TABLE_USER)->alias('t2')->on('t1.openedBy = t2.account')
->where('t1.repo')->eq($repoID)
->andWhere('t1.entry')->eq($entry)
->andWhere('t1.v2')->eq($revision)
->andWhere('t1.mr')->eq($MRID)
->beginIF($revision)->andWhere('t1.v2')->eq($revision)->fi()
->andWhere('t1.deleted')->eq(0)
->fetchAll('id');
$comments = $this->dao->select('t1.*, t2.realname')->from(TABLE_ACTION)->alias('t1')
->leftJoin(TABLE_USER)->alias('t2')
->on('t1.actor = t2.account')
->where('t1.objectType')->eq('bug')
->andWhere('t1.objectID')->in(array_keys($bugs))
->andWhere('t1.action')->eq('commented')
->fetchGroup('objectID', 'id');
foreach($bugs as $bug)
{
if(common::hasPriv('bug', 'edit')) $bug->edit = true;
if(common::hasPriv('bug', 'delete')) $bug->delete = true;
if(common::hasPriv('bug', 'view')) $bug->view = true;
$lines = explode(',', trim($bug->lines, ','));
$line = $lines[0];
$reviews[$line]['bugs'][$bug->id] = $bug;
$reviews[$line]['bug'][$bug->id] = $bug;
}
if(isset($comments[$bug->id]))
{
foreach($comments[$bug->id] as $key => $comment)
{
if($comment->actor == $this->app->user->account) $comment->edit = true;
}
$reviews[$line]['comments'] = $comments;
}
$tasks = $this->dao->select('t1.*, t2.realname')->from(TABLE_TASK)->alias('t1')
->leftJoin(TABLE_USER)->alias('t2')->on('t1.openedBy = t2.account')
->where('t1.repo')->eq($repoID)
->andWhere('t1.mr')->eq($MRID)
->beginIF($revision)->andWhere('t1.v2')->eq($revision)->fi()
->andWhere('t1.deleted')->eq(0)
->fetchAll('id');
foreach($tasks as $task)
{
if(common::hasPriv('task', 'edit')) $task->edit = true;
if(common::hasPriv('task', 'delete')) $task->delete = true;
if(common::hasPriv('task', 'view')) $task->view = true;
$lines = explode(',', trim($task->lines, ','));
$line = $lines[0];
$reviews[$line]['task'][$task->id] = $task;
}
return $reviews;
@@ -881,43 +883,154 @@ class mrModel extends model
* Save bug.
*
* @param int $repoID
* @param string $file
* @param int $mr
* @param int $v1
* @param int $v2
* @access public
* @return array
*/
public function saveBug($repoID, $file, $v1, $v2)
public function saveBug($repoID, $mr, $v1, $v2)
{
$now = helper::now();
$data = fixer::input('post')
->add('severity', 3)
->stripTags('commentText', $this->config->allowedTags)
->add('pri', 2)
->add('severity', 2)
->add('openedBy', $this->app->user->account)
->add('openedDate', $now)
->add('openedBuild', 'trunk')
->add('assignedDate', $now)
->add('type', 'codeimprovement')
->add('type', 'codeerror')
->add('repo', $repoID)
->add('entry', $file)
->add('mr', $mr)
->add('lines', $this->post->begin . ',' . $this->post->end)
->add('v1', $v1)
->add('v2', $v2)
->remove('commentText,begin,end,uid')
->cleanInt('module,execution,mr,repo')
->remove('begin,end,uid,reviewType,taskExecution,taskModule,taskAssignedTo')
->get();
$data->steps = $this->loadModel('file')->pasteImage($this->post->commentText, $this->post->uid);
$this->dao->insert(TABLE_BUG)->data($data)->exec();
$data->steps = $this->loadModel('file')->pasteImage($data->commentText, $this->post->uid);
if($data->assignedTo) $data->assignedDate = $now;
unset($data->commentText);
$this->loadModel('bug');
foreach(explode(',', $this->config->bug->create->requiredFields) as $requiredField)
{
$requiredField = trim($requiredField);
if(empty($requiredField)) continue;
if(!isset($data->$requiredField)) continue;
if(empty($data->$requiredField))
{
$fieldName = $requiredField;
if(isset($this->lang->bug->$requiredField)) $fieldName = $this->lang->bug->$requiredField;
dao::$errors[] = sprintf($this->lang->error->notempty, $fieldName);
}
}
if(dao::isError()) return array('result' => 'fail', 'message' => dao::getError());
$this->dao->insert(TABLE_BUG)->data($data)->autocheck()->exec();
if(!dao::isError())
{
$bugID = $this->dao->lastInsertID();
$this->file->updateObjectID($this->post->uid, $bugID, 'bug');
$this->loadModel('file')->updateObjectID($this->post->uid, $bugID, 'bug');
setcookie("repoPairs[$repoID]", $data->product);
return array('result' => 'success', 'id' => $bugID, 'realname' => $this->app->user->realname, 'openedDate' => substr($now, 5, 11), 'edit' => true, 'delete' => true, 'lines' => $data->lines, 'line' => $this->post->begin, 'steps' => $data->steps, 'title' => $data->title);
$bugInfo = array();
$bugInfo['result'] = 'success';
$bugInfo['id'] = $bugID;
$bugInfo['realname'] = $this->app->user->realname;
$bugInfo['openedDate'] = substr($now, 5, 11);
$bugInfo['edit'] = common::hasPriv('bug', 'edit');
$bugInfo['view'] = common::hasPriv('bug', 'view');
$bugInfo['delete'] = common::hasPriv('bug', 'delete');
$bugInfo['lines'] = $data->lines;
$bugInfo['line'] = $this->post->begin;
$bugInfo['content'] = $data->steps;
$bugInfo['title'] = $data->title;
$bugInfo['objectType'] = 'bug';
$bugInfo['entry'] = $data->entry;
return $bugInfo;
}
return array('result' => 'fail', 'message' => join("\n", dao::getError()));
return array('result' => 'fail', 'message' => dao::getError());
}
/**
* Save task.
*
* @param int $repoID
* @param int $mr
* @param int $v1
* @param int $v2
* @access public
* @return array
*/
public function saveTask($repoID, $mr, $v1, $v2)
{
$now = helper::now();
$data = fixer::input('post')->stripTags('commentText', $this->config->allowedTags)->get();
$task = new stdclass();
$task->execution = (int)$data->taskExecution;
$task->project = (int)$this->dao->select('project')->from(TABLE_PROJECT)->where('id')->eq($task->execution)->fetch('project');
$task->module = (int)$data->taskModule;
$task->name = $data->title;
$task->type = 'devel';
$task->pri = '2';
$task->status = 'wait';
$task->version = '1';
$task->openedBy = $this->app->user->account;
$task->assignedTo = $data->taskAssignedTo;
$task->repo = (int)$repoID;
$task->mr = (int)$mr;
$task->lines = $this->post->begin . ',' . $this->post->end;
$task->entry = $data->entry;
$task->v1 = $v1;
$task->v2 = $v2;
$task->desc = $this->loadModel('file')->pasteImage($data->commentText, $this->post->uid);
if($task->assignedTo) $task->assignedDate = $now;
$this->loadModel('task');
foreach(explode(',', $this->config->task->create->requiredFields) as $requiredField)
{
$requiredField = trim($requiredField);
if(empty($requiredField)) continue;
if(!isset($task->$requiredField)) continue;
if(empty($task->$requiredField))
{
$fieldName = $requiredField;
if(isset($this->lang->task->$requiredField)) $fieldName = $this->lang->task->$requiredField;
dao::$errors[] = sprintf($this->lang->error->notempty, $fieldName);
}
}
if(dao::isError()) return array('result' => 'fail', 'message' => dao::getError());
$this->dao->insert(TABLE_TASK)->data($task)->autocheck()->exec();
if(!dao::isError())
{
$taskID = $this->dao->lastInsertID();
$this->file->updateObjectID($this->post->uid, $taskID, 'task');
$taskInfo = array();
$taskInfo['result'] = 'success';
$taskInfo['id'] = $taskID;
$taskInfo['realname'] = $this->app->user->realname;
$taskInfo['openedDate'] = substr($now, 5, 11);
$taskInfo['edit'] = common::hasPriv('task', 'edit');
$taskInfo['view'] = common::hasPriv('task', 'view');
$taskInfo['delete'] = common::hasPriv('task', 'delete');
$taskInfo['lines'] = $task->lines;
$taskInfo['line'] = $this->post->begin;
$taskInfo['content'] = $task->desc;
$taskInfo['title'] = $data->title;
$taskInfo['objectType'] = 'task';
$taskInfo['entry'] = $task->entry;
return $taskInfo;
}
return array('result' => 'fail', 'message' => dao::getError());
}
/**
@@ -963,13 +1076,17 @@ class mrModel extends model
/**
* Get last review info.
*
* @param string $entry
* @param int $repoID
* @access public
* @return object
*/
public function getLastReviewInfo($entry)
public function getLastReviewInfo($repoID)
{
return $this->dao->select('*')->from(TABLE_BUG)->where('entry')->eq($entry)->orderby('id_desc')->fetch();
$lastReview = new stdclass();
$lastReview->bug = $this->dao->select('*')->from(TABLE_BUG)->where('repo')->eq($repoID)->orderby('id_desc')->fetch();
$lastReview->task = $this->dao->select('*')->from(TABLE_TASK)->where('repo')->eq($repoID)->orderby('id_desc')->fetch();
return $lastReview;
}
/**
+1 -1
View File
@@ -69,7 +69,7 @@
</div>
<?php foreach($diffs as $diffFile):?>
<div class='repoCode'>
<table class='table diff' id='diff'>
<table class='table diff' id='diff' data-entry='<?php echo base64_encode($diffFile->fileName);?>'>
<caption><?php echo $diffFile->fileName;?></caption>
<?php if(empty($diffFile->contents)) continue;?>
<?php foreach($diffFile->contents as $content):?>
+134 -129
View File
@@ -1,9 +1,6 @@
<?php
$file= '';
$suffix = '';
/* get last review info in this file. */
$lastReview = $this->mr->getLastReviewInfo($file);
$repoModule = isset($lastReview) && isset($lastReview->module) ? $lastReview->module : '';
$lastReview = $this->mr->getLastReviewInfo($repo->id);
/* Get product pairs. */
if(isset($repo->product) and $repo->product)
@@ -16,108 +13,92 @@ else
}
/* get product by cookie or last review in this file. */
$repoProduct = isset($_COOKIE['repoPairs'][$repoID]) ? $_COOKIE['repoPairs'][$repoID] : '';
$repoProduct = isset($lastReview) && isset($lastReview->product) ? $lastReview->product : $repoProduct;
$repoProduct = isset($products[$repoProduct]) ? $repoProduct : key($products);
$executions = $this->mr->getExecutionPairs($repoProduct);
$modules = $this->loadModel('tree')->getOptionMenu($repoProduct, $viewType = 'bug', $startModuleID = 0);
$users = $this->loadModel('user')->getPairs('devfirst|nodeleted|noclosed');
$products = array('' => '') + $products;
$executions = array('' => '') + $executions;
$repoProduct = isset($_COOKIE['repoPairs'][$repoID]) ? $_COOKIE['repoPairs'][$repoID] : '';
$repoProduct = (!empty($lastReview->bug) && isset($lastReview->bug->product)) ? $lastReview->bug->product : $repoProduct;
$repoProduct = isset($products[$repoProduct]) ? $repoProduct : key($products);
$bugRepoModule = (!empty($lastReview->bug) && $lastReview->bug->product == $repoProduct) ? $lastReview->bug->module : '';
$executions = $this->mr->getExecutionPairs($repoProduct);
$modules = $this->loadModel('tree')->getOptionMenu($repoProduct, $viewType = 'bug', $startModuleID = 0);
$users = $this->loadModel('user')->getPairs('devfirst|nodeleted|noclosed');
$products = array('' => '') + $products;
$executions = array('' => '') + $executions;
$cwd = getcwd();
$commiters = $this->user->getCommiters();
$blamePairs = array();
if($suffix and $suffix != 'binary' and strpos($this->config->repo->images, "|$suffix|") === false)
$taskExecutions = $executions;
if(empty($repo->product)) $taskExecutions = array('' => '') + $this->loadModel('execution')->getPairs();
$repoExecution = (!empty($lastReview->task) && isset($lastReview->task->execution)) ? $lastReview->task->execution : $this->session->execution;
$repoExecution = isset($taskExecutions[$repoExecution]) ? $repoExecution : key($taskExecutions);
$taskModules = array('' => '');
$taskRepoModule = 0;
$taskMembers = array('' => '');
if($repoExecution)
{
$blames = $this->scm->blame($entry, $info->revision);
foreach($blames as $line => $blame)
{
if(!isset($blame['committer']))
{
if(isset($blamePairs[$line - 1])) $blamePairs[$line] = $blamePairs[$line - 1];
continue;
}
$blamePairs[$line] = zget($commiters, $blame['committer'], $blame['committer']);
}
$taskModules = $this->loadModel('tree')->getTaskOptionMenu($repoExecution, 0, 0, 'allModule');
$taskRepoModule = (!empty($lastReview->task) && $lastReview->task->execution == $repoExecution) ? $lastReview->task->module : '';
$taskMembers = $this->loadModel('user')->getTeamMemberPairs($repoExecution, 'execution', 'nodeleted');
}
chdir($cwd);
//$reviews = $this->mr->getReview($repoID, $file, $info->revision);
$reviews = $this->mr->getReview($repoID, $file, '');
$v1 = isset($oldRevision) ? $oldRevision : 0;
$reviews = $this->mr->getReview($repoID, $MR->id);
$v1 = isset($oldRevision) ? $oldRevision : 0;
$this->loadModel('repo');
// $bugUrl = $this->repo->createLink('addBug', "repoID=$repoID&file=$file&v1=$v1&v2={$info->revision}");
$bugUrl = $this->createLink('mr', 'addBug', "repoID=$repoID&file=$file&v1=$v1&v2=");
$commentUrl = $this->createLink('mr', 'addComment');
$taskModuleSelect = html::select('taskModule', $taskModules, $taskRepoModule, 'class="form-control chosen"');
$taskUserSelect = html::select('taskAssignedTo', $taskMembers, '', 'class="form-control chosen"');
$taskExecutionSelect = html::select('taskExecution', $taskExecutions, $repoExecution, 'class="form-control chosen"');
$reviewUrl = $this->createLink('mr', 'addReview', "repoID=$repoID&mr={$MR->id}&v1=$v1&v2=");
$productSelect = html::select('product', $products, $repoProduct, 'class="product form-control chosen" onchange="changeProduct(this)"');
$branches = $this->loadModel('branch')->getPairs($repoProduct);
$moduleSelect = html::select('module', $modules, $repoModule, 'class="form-control chosen"');
$executionSelect = html::select('execution', $executions, '', 'class="form-control chosen"');
$moduleSelect = html::select('module', $modules, $bugRepoModule, 'class="form-control chosen"');
$executionSelect = html::select('execution', $executions, '', 'class="form-control chosen" onchange="changeExecution(this)"');
$typeSelect = html::select('repoType', $lang->repo->typeList, '', 'class="form-control chosen"');
$userSelect = html::select('assignedTo', $users, '', 'class="form-control chosen assignedTo"');
$bugs = array();
$lineReviews = array();
foreach($reviews as $line => $lineReview)
{
$lineBugs = array();
foreach ($lineReview['bugs'] as $bugID => $bug)
foreach($lineReview as $objectType => $objects)
{
$lineBug = array();
$lineBug['id'] = $bugID;
$lineBug['line'] = $line;
$lineBug['title'] = $bug->title;
$lineBug['steps'] = $bug->steps;
$lineBug['realname'] = $bug->realname;
$lineBug['openedDate'] = substr($bug->openedDate, 5, 11);
$lineBug['lines'] = $bug->lines;
if($bug->edit) $lineBug['edit'] = true;
if($bug->delete) $lineBug['delete'] = true;
if(isset($lineReview['comments']))
foreach($objects as $objectID => $object)
{
if(isset($lineReview['comments'][$bugID]))
{
$comments = $lineReview['comments'][$bugID];
$bugComments = array();
foreach ($comments as $commentID => $comment)
{
$bugComment = array(
'id' => $comment->id,
'edit' => $comment->edit,
'realname' => $comment->realname,
'date' => substr($comment->date, 5, 11),
'comment' => $comment->comment,
);
$bugComments[] = $bugComment;
}
$lineBug['comments'] = $bugComments;
}
$lineReview = array();
$lineReview['id'] = $objectID;
$lineReview['line'] = $line;
$lineReview['title'] = $objectType == 'bug' ? $object->title : $object->name;
$lineReview['content'] = $objectType == 'bug' ? $object->steps : $object->desc;
$lineReview['realname'] = $object->realname;
$lineReview['openedDate'] = substr($object->openedDate, 5, 11);
$lineReview['lines'] = $object->lines;
$lineReview['objectType'] = $objectType;
$lineReview['entry'] = $object->entry;
$lineReview['edit'] = common::hasPriv($objectType, 'edit');
$lineReview['delete'] = common::hasPriv($objectType, 'delete');
$lineReview['view'] = common::hasPriv($objectType, 'view');
$lineReviews[$line][] = $lineReview;
}
$lineBugs[] = $lineBug;
}
$bugs[$line] = $lineBugs;
}
js::set('bugs', $bugs);
js::set('reviews', $lineReviews);
js::set('productError', $lang->repo->error->product);
js::set('contentError', $lang->repo->error->commentText);
js::set('titleError', $lang->repo->error->title);
js::set('commentError', $lang->repo->error->comment);
js::set('submit', $lang->repo->submit);
js::set('cancel', $lang->repo->cancel);
js::set('confirmDelete', $lang->repo->notice->deleteBug);
js::set('confirmDeleteComment', $lang->repo->notice->deleteComment);
js::set('confirmDelete', $lang->repo->notice->deleteReview);
js::set('repoID', $repoID);
// js::set('revision', $info->revision);
js::set('MRID', $MR->id);
js::set('revision', '');
js::set('file', $file);
js::set('blamePairs', $blamePairs);
?>
<?php if(common::hasPriv('mr', 'addBug')):?>
<form id="bugForm" class="bugForm main-form hide" method="post" action="<?php echo $bugUrl?>">
<div class="bugFormContainer">
<?php if(common::hasPriv('mr', 'addReview')):?>
<form id="reviewForm" class="reviewForm main-form hide" method="post" action="<?php echo $reviewUrl?>">
<div class="reviewFormContainer">
<table class='table table-form'>
<tr>
<th><?php echo $lang->mr->reviewType;?></th>
<td><?php echo html::select('reviewType', $lang->mr->reviewTypeList, 'bug', "class='form-control' onchange=changeReviewType(this)")?></td>
</tr>
<tr>
<th><?php echo $lang->repo->product?></th>
<td class='w-p45'>
@@ -131,13 +112,22 @@ js::set('blamePairs', $blamePairs);
</tr>
<tr>
<th><?php echo $lang->repo->execution?></th>
<td><?php echo $executionSelect?></td>
<td>
<div class='bugExecutionBox'><?php echo $executionSelect?></div>
<div class='taskExecutionBox hide required'><?php echo $taskExecutionSelect?></div>
</td>
<th><?php echo $lang->repo->type?></th>
<td><?php echo $typeSelect?></td>
</tr>
<tr class='taskModuleBox hide'>
<th><?php echo $lang->repo->module?></th>
<td><?php echo $taskModuleSelect?></td>
<tr>
<th><?php echo $lang->repo->assign?></th>
<td><?php echo $userSelect?></td>
<td>
<div class='bugAssignedToBox'><?php echo $userSelect?></div>
<div class='taskAssignedToBox hide'><?php echo $taskUserSelect?></div>
</td>
<th><?php echo $lang->repo->lines?></th>
<td class='lines'>
<div class="input-group">
@@ -149,7 +139,7 @@ js::set('blamePairs', $blamePairs);
</tr>
<tr>
<th><?php echo $lang->repo->title?></th>
<td colspan='3'>
<td colspan='3' class='required'>
<?php echo html::input('title', '', "class='form-control'");?>
</td>
</tr>
@@ -160,8 +150,9 @@ js::set('blamePairs', $blamePairs);
<tr>
<th></th>
<td colspan="3" class='form-actions'>
<?php echo html::submitButton($lang->repo->submit, '', 'btn btn-wide btn-primary bugSubmit');?>
<?php echo html::submitButton($lang->repo->submit, '', 'btn btn-wide btn-primary reviewSubmit');?>
<?php echo html::commonButton($lang->cancel, "onclick='hiddenForm()'", 'btn btn-wide');?>
<input type="hidden" id='entry' name="entry" value=""/>
</td>
</tr>
</table>
@@ -169,73 +160,87 @@ js::set('blamePairs', $blamePairs);
</div>
</form>
<?php else:?>
<form id='bugForm' class='bugForm hide'>
<?php printf($lang->user->errorDeny, $lang->repo->common, $lang->repo->addBug);?>
<form id='reviewForm' class='reviewForm hide'>
<?php printf($lang->user->errorDeny, $lang->repo->common, $lang->repo->addReview);?>
</form>
<?php endif;?>
<div class='panel panel-sm hide panel-bug' id='bugPanel'>
<div class='panel panel-sm hide panel-review' id='reviewPanel'>
<div class='panel-heading'>
<div class='panel-actions pull-right'>
<?php if(common::hasPriv('bug', 'view')):?>
<a href='javascript:;' class='view-bug'>Bug#<span class='bugid'></span></a>
<?php else:?>
Bug#<span class='bugid'></span>
<?php endif;?>
<?php if(common::hasPriv('bug', 'edit')):?>
<a href='javascript:;' class='edit bugEdit'><i class='icon-pencil'></i></a>
<?php endif;?>
<?php if(common::hasPriv('bug', 'delete')):?>
<a href='javascript:;' class='delete bugDelete'><i class='icon-remove'></i></a>
<?php endif;?>
<a href='javascript:;' class='delete reviewDelete'><i class='icon-remove'></i></a>
<a href="javascript:;"><i class='icon-chevron-down'></i></a>
</div>
<i class='icon-bug text-muted'></i> <strong class='title'></strong>
<i class='text-muted'></i> <strong class='title'></strong>
</div>
<div class='panel-body'>
<p><?php echo $lang->repo->lines?> <strong class='code-lines'></strong> &nbsp; <i class='icon-user text-muted'></i> <strong class='realname'></strong> &nbsp;<span class='text-muted bug-date'><i class='icon-time'></i> <span class='openedDate'></span></span></p>
<form method='post' class='bug-edit-form' action>
<input type='text' name='commentText' class='commentInput form-control mgb-10'>
<button type='submit' class='btn btn-sm btn-primary bugEditSubmit'><?php echo $lang->repo->submit?></button>
<button type='button' class='btn btn-sm bugEditCancel'><?php echo $lang->repo->cancel?></button>
</form>
<p class='steps text-content'></p>
<div class='comments'></div>
<?php if(common::hasPriv('repo', 'addComment')):?>
<button class='btn btn-sm addComment' type='button'><?php echo $lang->repo->addComment?></button>
<form class='commentForm' method='post' action='<?php echo $commentUrl?>' id='commentForm'>
<textarea name='comment' class='commentText form-control mgb-10' spellcheck='false' placeholder='<?php echo $lang->repo->notice->commentContent?>'></textarea>
<input class='commentSubmit btn btn-sm btn-primary' type='submit' value='<?php echo $lang->repo->submit?>'>
<input class='commentCancel btn btn-sm' type='button' value='<?php echo $lang->repo->cancel?>'>
<input type='hidden' name='objectID' value=''>
<div class='optional'></div>
</form>
<?php endif;?>
<p class='content text-content'></p>
</div>
</div>
<div class='comment hide' id='commentCell'>
<i class='icon-user text-muted'></i> <strong class='realname'></strong>: <span class='comment-content text-content'></span> <span class='text-muted comment-date'>&nbsp;<i class='icon-time'></i> <span class='date'></span></span> &nbsp;<a href='javascript:;' class='edit commentEdit pull-right'><i class='icon-pencil'></i></a>
<form method='post' class='comment-edit-form' action=''>
<textarea name='commentText' class='commentInput form-control mgb-10'></textarea>
<button type='submit' class='btn btn-sm btn-primary commentEditSubmit'><?php echo $lang->repo->submit?></button>
<button type='button' class='btn btn-sm commentEditCancel'><?php echo $lang->repo->cancel?></button>
</form>
</div>
<div class='dropdown' id="bugsPreview">
<div class='dropdown' id="reviewsPreview">
<ul class='dropdown-menu fade'>
<li class='dropdown-header'><?php echo $lang->repo->line?><strong class='code-line'></strong> &nbsp; <i class='icon-bug'></i> <strong class='bug-count'>0</strong> &nbsp; <i class='icon-comments-alt'></i> <strong class='comment-count'>0</strong></li>
</ul>
</div>
<div id='rowTip' class='hide'><div class='row-tip'><i class='icon-chat-dot preview-icon'></i><div class='on-expand tip'><span><?php echo $lang->repo->expand?> </span><i class='icon-chevron-down'></i></div><div class='on-collapse tip'><span><?php echo $lang->repo->collapse?> </span><i class='icon-chevron-up'></i></div></div></div>
<div id='rowTip' class='hide'><div class='row-tip'><div class='on-expand tip'><span><?php echo $lang->repo->expand?> </span><i class='icon-chevron-down'></i></div><div class='on-collapse tip'><span><?php echo $lang->repo->collapse?> </span><i class='icon-chevron-up'></i></div></div></div>
<script>
function changeReviewType(select)
{
var reviewType = $(select).val();
if(reviewType == 'bug')
{
$('#product').closest('td').show();
$('#product').closest('td').prev().show();
$('#module').closest('td').show();
$('#module').closest('td').prev().show();
$('#repoType').closest('td').show();
$('#repoType').closest('td').prev().show();
$('.taskModuleBox').addClass('hide');
$('.bugAssignedToBox').removeClass('hide');
$('.taskAssignedToBox').addClass('hide');
$('.bugExecutionBox').removeClass('hide');
$('.taskExecutionBox').addClass('hide');
}
else
{
$('#product').closest('td').hide();
$('#product').closest('td').prev().hide();
$('#module').closest('td').hide();
$('#module').closest('td').prev().hide();
$('#repoType').closest('td').hide();
$('#repoType').closest('td').prev().hide();
$('.taskModuleBox').removeClass('hide');
$('.bugAssignedToBox').addClass('hide');
$('.taskAssignedToBox').removeClass('hide');
$('.bugExecutionBox').addClass('hide');
$('.taskExecutionBox').removeClass('hide');
}
}
function changeProduct(select)
{
loadProductBranches(select);
productID = $(select).children('option:selected').val();
link = createLink('repo', 'ajaxGetExecutions', 'productID=' + productID);
$(select).closest('.bugFormContainer').find('select[name=execution]').parent().load(link, '', function(){$('#execution').chosen();});
$(select).closest('.reviewFormContainer').find('select[name=execution]').parent().load(link, '', function(){$('#execution').chosen();});
moduleLink = createLink('tree', 'ajaxGetOptionMenu', 'productID=' + productID + '&viewtype=bug&branch=0&rootModuleID=0&returnType=html');
$(select).closest('.bugFormContainer').find('select[name=module]').parent().load(moduleLink, '', function(){$('#module').chosen();});
$(select).closest('.reviewFormContainer').find('select[name=module]').parent().load(moduleLink, '', function(){$('#module').chosen();});
}
function changeExecution(select)
{
if($('#reviewType').val() == 'bug') return false;
var executionID = $(select).val();
moduleLink = createLink('tree', 'ajaxGetOptionMenu', 'execution=' + executionID + '&viewtype=task&branch=0&rootModuleID=0&returnType=html');
$('.taskModuleBox').find('td:first').load(moduleLink, '', function(){$('.taskModuleBox #module').attr('id', 'taskModule').attr('name', 'taskModule').chosen();});
assignLink = createLink('execution', 'ajaxGetMembers', 'executionID=' + executionID);
$('.taskAssignedToBox').load(assignLink, '', function(){$('.taskAssignedToBox #assignedTo').attr('id', 'taskAssignedTo').attr('name', 'taskAssignedTo').chosen();});
}
function loadProductBranches(select)
@@ -257,9 +262,9 @@ function loadBranch(select)
branch = $(select).val();
productID = $(select).closest('.input-group').find('#product').val();
link = createLink('repo', 'ajaxGetExecutions', 'productID=' + productID + '&branch=' + branch);
$(select).closest('.bugFormContainer').find('select[name=execution]').parent().load(link, '', function(){$('#execution').chosen();});
$(select).closest('.reviewFormContainer').find('select[name=execution]').parent().load(link, '', function(){$('#execution').chosen();});
moduleLink = createLink('tree', 'ajaxGetOptionMenu', 'productID=' + productID + '&viewtype=bug&branch=' + branch + '&rootModuleID=0&returnType=html');
$(select).closest('.bugFormContainer').find('select[name=module]').parent().load(moduleLink, '', function(){$('#module').chosen();});
$(select).closest('.reviewFormContainer').find('select[name=module]').parent().load(moduleLink, '', function(){$('#module').chosen();});
}
function hiddenForm()
-6
View File
@@ -61,12 +61,6 @@
<th class="w-100px"><?php echo $lang->mr->status;?></th>
<td><?php echo zget($lang->mr->statusList, $MR->status);?></td>
</tr>
<?php if(isset($rawMR->head_pipeline->status)): ?>
<tr>
<th><?php echo "{$lang->mr->pipeline}{$lang->mr->status}";?></th>
<td><?php echo zget($lang->mr->pipelineStatus, $rawMR->head_pipeline->status, $lang->mr->pipelineUnknown); ?></td>
</tr>
<?php endif; ?>
<tr>
<th><?php echo $lang->mr->mergeStatus; ?></th>
<?php if(empty($rawMR->changes_count)):?>
+1
View File
@@ -146,6 +146,7 @@ $lang->repo->notice->syncedCount = 'The number of records synchronized is ';
$lang->repo->notice->delete = 'Do you want to delete this repo?';
$lang->repo->notice->successDelete = 'Repository is removed.';
$lang->repo->notice->commentContent = 'Comment';
$lang->repo->notice->deleteReview = 'Do you want to delete this review?';
$lang->repo->notice->deleteBug = 'Do you want to delete this bug?';
$lang->repo->notice->deleteComment = 'Do you want to delete this comment?';
$lang->repo->notice->lastSyncTime = 'Last Sync:';
+1
View File
@@ -146,6 +146,7 @@ $lang->repo->notice->syncedCount = '已经同步记录条数';
$lang->repo->notice->delete = '是否要删除该版本库?';
$lang->repo->notice->successDelete = '已经成功删除版本库。';
$lang->repo->notice->commentContent = '输入回复内容';
$lang->repo->notice->deleteReview = '确认删除该评审?';
$lang->repo->notice->deleteBug = '确认删除该Bug';
$lang->repo->notice->deleteComment = '确认删除该回复?';
$lang->repo->notice->lastSyncTime = '最后更新于:';