diff --git a/module/gitlab/control.php b/module/gitlab/control.php index 91816b3dae..18a3b4c083 100644 --- a/module/gitlab/control.php +++ b/module/gitlab/control.php @@ -23,7 +23,7 @@ class gitlab extends control if(stripos($this->methodName, 'ajax') === false) { if(!commonModel::hasPriv('space', 'browse')) $this->loadModel('common')->deny('space', 'browse', false); - + if(!in_array(strtolower(strtolower($this->methodName)), array('browseproject', 'browsegroup', 'browseuser', 'browsebranch', 'browsetag'))) { if(!commonModel::hasPriv('instance', 'manage')) $this->loadModel('common')->deny('instance', 'manage', false); @@ -174,7 +174,7 @@ class gitlab extends control $accountList[$user] = $openID; } - if(count($repeatUsers)) return $this->send(array('result' => 'fail', 'message' => sprintf($this->lang->gitlab->bindUserError, join(',', $repeatUsers)))); + if(count($repeatUsers)) return $this->send(array('result' => 'fail', 'message' => sprintf($this->lang->gitlab->bindUserError, join(',', array_unique($repeatUsers))))); $user = new stdclass; $user->providerID = $gitlabID; @@ -423,10 +423,10 @@ class gitlab extends control if(!$this->app->user->admin) { $openID = $this->gitlab->getUserIDByZentaoAccount($gitlabID, $this->app->user->account); - if(!$openID) return print(js::alert($this->lang->gitlab->mustBindUser) . js::locate($this->createLink('gitlab', 'browse'))); + if(!$openID) return print(js::alert($this->lang->gitlab->mustBindUser) . js::locate($this->createLink('space', 'browse'))); $members = $this->gitlab->apiGetGroupMembers($gitlabID, $groupID, $openID); - if(empty($members) or $members[0]->access_level < $this->config->gitlab->accessLevel['owner']) return print(js::alert($this->lang->gitlab->noAccess) . js::locate($this->createLink('gitlab', 'browse'))); + if(empty($members) or $members[0]->access_level < $this->config->gitlab->accessLevel['owner']) return print(js::alert($this->lang->gitlab->noAccess) . js::locate($this->createLink('space', 'browse'))); } if($_POST) diff --git a/module/gitlab/model.php b/module/gitlab/model.php index 23d2bfa039..76023e20e1 100644 --- a/module/gitlab/model.php +++ b/module/gitlab/model.php @@ -655,7 +655,7 @@ class gitlabModel extends model */ public function apiGetGroups($gitlabID, $orderBy = 'id_desc', $minRole = '', $keyword = '') { - $apiRoot = $this->getApiRoot($gitlabID, false); + $apiRoot = $this->getApiRoot($gitlabID, $minRole == 'owner' ? true : false); $url = sprintf($apiRoot, "/groups"); if($minRole == 'owner') { @@ -1270,7 +1270,7 @@ class gitlabModel extends model public function addPushWebhook($repo, $token = '') { $hook = new stdClass; - $hook->url = (defined('RUN_MODE') && RUN_MODE == 'test' ? 'http://unittest' : common::getSysURL()) . '/api.php/v1/gitlab/webhook?repoID='. $repo->id; + $hook->url = common::getSysURL() . '/api.php/v1/gitlab/webhook?repoID='. $repo->id; $hook->push_events = true; $hook->merge_requests_events = true; if($token) $hook->token = $token; diff --git a/module/instance/model.php b/module/instance/model.php index f60221069d..b33cbdc6c0 100644 --- a/module/instance/model.php +++ b/module/instance/model.php @@ -928,7 +928,9 @@ class InstanceModel extends model */ public function createInstance($app, $space, $thirdDomain, $name = '', $k8name = '', $channel = 'stable', $snippets = array()) { + $createdBy = $this->app->user->account; if(empty($k8name)) $k8name = "{$app->chart}-" . date('YmdHis'); //name rule: chartName-userAccount-YmdHis; + if(defined('IN_INSTALL') && IN_INSTALL && empty($this->app->user->account)) $createdBy = trim($this->app->company->admins, ','); //Set createdBy if in login progress; $instanceData = new stdclass; $instanceData->appId = $app->id; diff --git a/module/mr/config.php b/module/mr/config.php index 113e298280..1dd193d229 100644 --- a/module/mr/config.php +++ b/module/mr/config.php @@ -1,5 +1,5 @@ mr = new stdclass(); $config->mr->create = new stdclass(); @@ -56,7 +56,7 @@ $config->mr->actionList['delete']['icon'] = 'trash'; $config->mr->actionList['delete']['hint'] = $lang->mr->delete; $config->mr->actionList['delete']['url'] = helper::createLink('mr', 'delete', "MRID={id}&confirm=yes"); $config->mr->actionList['delete']['data-confirm'] = $lang->mr->confirmDelete; -$config->mr->actionList['delete']['class'] = 'ajax-submit'; +$config->mr->actionList['delete']['className'] = 'ajax-submit'; $config->mr->actionList['accept']['icon'] = 'flow'; $config->mr->actionList['accept']['text'] = $lang->mr->acceptMR; @@ -72,15 +72,28 @@ $config->mr->actionList['reject']['text'] = $lang->mr->reject; $config->mr->actionList['reject']['url'] = helper::createLink('mr', 'approval', "MRID={id}&action=reject"); $config->mr->actionList['reject']['data-toggle'] = 'modal'; -$config->mr->actionList['close']['icon'] = 'off'; -$config->mr->actionList['close']['text'] = $lang->mr->close; -$config->mr->actionList['close']['url'] = helper::createLink('mr', 'close', "MRID={id}"); -$config->mr->actionList['close']['class'] = 'ajax-submit'; +$config->mr->actionList['close']['icon'] = 'off'; +$config->mr->actionList['close']['text'] = $lang->mr->close; +$config->mr->actionList['close']['url'] = helper::createLink('mr', 'close', "MRID={id}"); +$config->mr->actionList['close']['className'] = 'ajax-submit'; -$config->mr->actionList['reopen']['icon'] = 'restart'; -$config->mr->actionList['reopen']['text'] = $lang->mr->reopen; -$config->mr->actionList['reopen']['url'] = helper::createLink('mr', 'reopen', "MRID={id}"); -$config->mr->actionList['reopen']['class'] = 'ajax-submit'; +$config->mr->actionList['reopen']['icon'] = 'restart'; +$config->mr->actionList['reopen']['text'] = $lang->mr->reopen; +$config->mr->actionList['reopen']['url'] = helper::createLink('mr', 'reopen', "MRID={id}"); +$config->mr->actionList['reopen']['className'] = 'ajax-submit'; + +$app->loadLang('release'); +$app->loadLang('story'); +$app->loadLang('bug'); +$app->loadLang('build'); +$app->loadLang('task'); +$config->mr->actionList['unlinkStory']['icon'] = 'unlink'; +$config->mr->actionList['unlinkStory']['hint'] = $lang->release->unlinkStory; +$config->mr->actionList['unlinkStory']['url'] = 'javascript: unlinkObject("story", "{id}")'; + +$config->mr->actionList['unlinkBug']['icon'] = 'unlink'; +$config->mr->actionList['unlinkBug']['hint'] = $lang->release->unlinkBug; +$config->mr->actionList['unlinkBug']['url'] = 'javascript: unlinkObject("bug", "{id}")'; $config->mr->view = new stdclass(); $config->mr->view->operateList = array('accept', 'approval', 'reject', 'close', 'edit', 'reopen', 'delete'); diff --git a/module/mr/config/dtable.php b/module/mr/config/dtable.php index f5cd747e49..64626e1a85 100644 --- a/module/mr/config/dtable.php +++ b/module/mr/config/dtable.php @@ -1,7 +1,7 @@ mr->dtable = new stdclass; +$config->mr->dtable = new stdclass(); $config->mr->dtable->fieldList['id']['name'] = 'id'; $config->mr->dtable->fieldList['id']['title'] = $lang->idAB; @@ -40,7 +40,7 @@ $config->mr->dtable->fieldList['createdBy']['sortType'] = true; $config->mr->dtable->fieldList['createdDate']['name'] = 'createdDate'; $config->mr->dtable->fieldList['createdDate']['title'] = $lang->mr->createdDate; -$config->mr->dtable->fieldList['createdDate']['type'] = 'date'; +$config->mr->dtable->fieldList['createdDate']['type'] = 'datetime'; $config->mr->dtable->fieldList['createdDate']['sortType'] = true; $config->mr->dtable->fieldList['actions']['name'] = 'actions'; @@ -49,3 +49,40 @@ $config->mr->dtable->fieldList['actions']['type'] = 'actions'; $config->mr->dtable->fieldList['actions']['menu'] = array('view', 'edit', 'diff', 'link', 'delete'); $config->mr->dtable->fieldList['actions']['list'] = $config->mr->actionList; +$config->mr->taskDtable = new stdclass(); +$config->mr->taskDtable->fieldList['id']['title'] = $lang->idAB; +$config->mr->taskDtable->fieldList['id']['type'] = 'checkID'; +$config->mr->taskDtable->fieldList['id']['sortType'] = 'desc'; +$config->mr->taskDtable->fieldList['id']['checkbox'] = false; +$config->mr->taskDtable->fieldList['id']['required'] = true; + +$config->mr->taskDtable->fieldList['name']['fixed'] = 'left'; +$config->mr->taskDtable->fieldList['name']['title'] = $lang->task->name; +$config->mr->taskDtable->fieldList['name']['flex'] = ''; +$config->mr->taskDtable->fieldList['name']['type'] = 'nestedTitle'; +$config->mr->taskDtable->fieldList['name']['nestedToggle'] = true; +$config->mr->taskDtable->fieldList['name']['sortType'] = true; +$config->mr->taskDtable->fieldList['name']['link'] = array('module' => 'task', 'method' => 'view', 'params' => 'taskID={id}', 'target' => '_blank'); +$config->mr->taskDtable->fieldList['name']['required'] = true; + +$config->mr->taskDtable->fieldList['pri']['title'] = $lang->priAB; +$config->mr->taskDtable->fieldList['pri']['type'] = 'pri'; +$config->mr->taskDtable->fieldList['pri']['sortType'] = true; +$config->mr->taskDtable->fieldList['pri']['show'] = true; + +$config->mr->taskDtable->fieldList['assignedTo']['type'] = 'desc'; +$config->mr->taskDtable->fieldList['assignedTo']['title'] = $lang->task->assignedTo; +$config->mr->taskDtable->fieldList['assignedTo']['currentUser'] = $app->user->account; +$config->mr->taskDtable->fieldList['assignedTo']['sortType'] = true; +$config->mr->taskDtable->fieldList['assignedTo']['show'] = true; + +$config->mr->taskDtable->fieldList['finishedBy']['title'] = $lang->task->finishedByAB; +$config->mr->taskDtable->fieldList['finishedBy']['type'] = 'user'; +$config->mr->taskDtable->fieldList['finishedBy']['sortType'] = true; +$config->mr->taskDtable->fieldList['finishedBy']['show'] = true; + +$config->mr->taskDtable->fieldList['status']['title'] = $lang->statusAB; +$config->mr->taskDtable->fieldList['status']['type'] = 'status'; +$config->mr->taskDtable->fieldList['status']['statusMap'] = $lang->task->statusList; +$config->mr->taskDtable->fieldList['status']['sortType'] = true; +$config->mr->taskDtable->fieldList['status']['show'] = true; diff --git a/module/mr/control.php b/module/mr/control.php index d7d7867c5a..acc883aae9 100644 --- a/module/mr/control.php +++ b/module/mr/control.php @@ -57,6 +57,7 @@ class mr extends control } $filterProjects = empty($repo->serviceProject) ? array() : array($repo->serviceHost => array($repo->serviceProject => $repo->serviceProject)); $MRList = $this->mr->getList($mode, $param, $orderBy, $pager, $filterProjects, $repoID); + if($repo->SCM == 'Gitlab') { $projectIds = array(); @@ -83,7 +84,6 @@ class mr extends control { $product = $this->mr->getMRProduct($MR); $MR->linkButton = empty($product) ? false : true; - $MR->createdDate = date('m-d H:i', strtotime($MR->createdDate)); } /* Load lang from compile module */ @@ -118,6 +118,7 @@ class mr extends control $this->view->orderBy = $orderBy; $this->view->openIDList = $openIDList; $this->view->users = $this->loadModel('user')->getPairs('noletter'); + $this->view->sortLink = $this->createLink('mr', 'browse', "repoID={$repoID}&mode={$mode}¶m={$param}&objectID={$objectID}&orderBy={orderBy}&recTotal={$recTotal}&recPerPage={$recPerPage}"); $this->display(); } @@ -258,7 +259,7 @@ class mr extends control $this->loadModel('action')->create('mr', $MRID, 'deleted', '', $MR->title); $this->mr->createMRLinkedAction($MRID, 'removemr'); - return $this->send(array('result' => 'success', 'reload' => inlink('browse'))); + return $this->send(array('result' => 'success', 'load' => true)); } /** @@ -271,7 +272,7 @@ class mr extends control public function view($MRID) { $MR = $this->mr->getByID($MRID); - if(!$MR) return print(js::error($this->lang->notFound) . js::locate($this->createLink('mr', 'browse'))); + if(!$MR) return $this->locate($this->createLink('mr', 'browse')); if(isset($MR->hostID)) $rawMR = $this->mr->apiGetSingleMR($MR->hostID, $MR->targetProject, $MR->mriid); if($MR->synced and (!isset($rawMR->id) or (isset($rawMR->message) and $rawMR->message == '404 Not found') or empty($rawMR))) return $this->display(); @@ -287,13 +288,32 @@ class mr extends control $sourceBranch = $this->$scm->apiGetSingleBranch($MR->hostID, $MR->sourceProject, $MR->sourceBranch); $targetBranch = $this->$scm->apiGetSingleBranch($MR->hostID, $MR->targetProject, $MR->targetBranch); - $projectOwner = true; + $projectOwner = $projectEdit = false; if(isset($MR->hostID) and !$this->app->user->admin) { $openID = $this->$scm->getUserIDByZentaoAccount($MR->hostID, $this->app->user->account); if(!$projectOwner and isset($sourceProject->owner->id) and $sourceProject->owner->id == $openID) $projectOwner = true; } + if($scm == 'gitlab') + { + $gitUsers = $this->gitlab->getUserAccountIdPairs($MR->hostID); + $groupIDList = array(0 => 0); + $groups = $this->gitlab->apiGetGroups($MR->hostID, 'name_asc', 'developer'); + foreach($groups as $group) $groupIDList[] = $group->id; + $isDeveloper = $this->gitlab->checkUserAccess($MR->hostID, 0, $sourceProject, $groupIDList, 'developer'); + + if(isset($gitUsers[$this->app->user->account]) && $isDeveloper) $projectEdit = true; + } + elseif($scm == 'gitea') + { + $projectEdit = (isset($sourceProject->allow_merge_commits) and $sourceProject->allow_merge_commits == true) ? true : false; + } + elseif($scm == 'gogs') + { + $projectEdit = (isset($sourceProject->permissions->push) and $sourceProject->permissions->push) ? true : false; + } + $this->view->sourceProjectName = $sourceProject->name_with_namespace; $this->view->targetProjectName = $targetProject->name_with_namespace; $this->view->sourceProjectURL = isset($sourceBranch->web_url) ? $sourceBranch->web_url : ''; @@ -310,6 +330,7 @@ class mr extends control $this->view->compile = $this->loadModel('compile')->getById($MR->compileID); $this->view->compileJob = $MR->jobID ? $this->job->getById($MR->jobID) : false; $this->view->projectOwner = $projectOwner; + $this->view->projectEdit = $projectEdit; $this->view->title = $this->lang->mr->view; $this->view->MR = $MR; @@ -545,6 +566,7 @@ class mr extends control $this->app->loadModuleConfig('release'); $this->app->loadModuleConfig('task'); + $this->app->loadModuleConfig('repo'); $MR = $this->mr->getByID($MRID); $product = $this->mr->getMRProduct($MR); @@ -650,7 +672,7 @@ class mr extends control $linkedStories = $this->mr->getLinkList($MRID, $product->id, 'story'); if($browseType == 'bySearch') { - $allStories = $this->story->getBySearch($productID, 0, $queryID, 'id', '', 'story', array_keys($linkedStories), $pager); + $allStories = $this->story->getBySearch($productID, 0, $queryID, $orderBy, '', 'story', array_keys($linkedStories), '', $pager); } else { @@ -716,7 +738,7 @@ class mr extends control $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']['execution']['values'] = $this->product->getExecutionPairsByProduct($productID); - $this->config->bug->search['params']['openedBuild']['values'] = $this->loadModel('build')->getBuildPairs(array($productID), 'all', 'releasetag'); + $this->config->bug->search['params']['openedBuild']['values'] = $this->loadModel('build')->getBuildPairs($productID, 'all', 'releasetag'); $this->config->bug->search['params']['resolvedBuild']['values'] = $this->config->bug->search['params']['openedBuild']['values']; unset($this->config->bug->search['fields']['product']); @@ -739,17 +761,13 @@ class mr extends control $linkedBugs = $this->mr->getLinkList($MRID, $product->id, 'bug'); if($browseType == 'bySearch') { - $allBugs = $this->bug->getBySearch($productID, 0, $queryID, 'id_desc', array_keys($linkedBugs), $pager); + $allBugs = $this->bug->getBySearch($productID, 0, $queryID, $orderBy, array_keys($linkedBugs), $pager); } else { - $allBugs = $this->bug->getActiveBugs($productID, 0, '0', array_keys($linkedBugs), $pager); + $allBugs = $this->bug->getActiveBugs($productID, 0, '0', array_keys($linkedBugs), $pager, $orderBy); } - list($order, $sort) = explode('_', $orderBy); - $sortCol = array_column($allBugs, $order); - array_multisort($sortCol, $sort == 'asc' ? SORT_ASC : SORT_DESC, $allBugs); - $this->view->modules = $modules; $this->view->users = $this->loadModel('user')->getPairs('noletter'); $this->view->allBugs = $allBugs; @@ -792,6 +810,7 @@ class mr extends control $this->loadModel('execution'); $this->loadModel('product'); $this->app->loadLang('task'); + $this->app->loadModuleConfig('repo'); /* Set browse type. */ $browseType = strtolower($browseType); diff --git a/module/mr/css/common.ui.css b/module/mr/css/common.ui.css index db027f7627..cf0c538b1e 100644 --- a/module/mr/css/common.ui.css +++ b/module/mr/css/common.ui.css @@ -1,2 +1,3 @@ .mr-linkstory-title {background-color: #e6f0ff; color: #2e7fff; padding: 12px 6px 12px;} -#log .action-btn .caret {display: none; color: red} \ No newline at end of file +#log .action-btn .caret {display: none; color: red} +.dropmenu-btn>.text {max-width: 280px;} \ No newline at end of file diff --git a/module/mr/css/diff.ui.css b/module/mr/css/diff.ui.css index 6a22df286a..03b155291a 100644 --- a/module/mr/css/diff.ui.css +++ b/module/mr/css/diff.ui.css @@ -71,4 +71,5 @@ .panel-body .detail-content{margin-top: 10px;} #log .action-btn .caret {display: none;} #fileTabs .monaco-dropmenu .caret {display: none;} -#monacoTabs .gap-x-5 {-moz-column-gap: 0; column-gap: 0;} \ No newline at end of file +#monacoTabs .gap-x-5 {-moz-column-gap: 0; column-gap: 0;} +#log .action-btn .btn {padding-left: .25rem; padding-right: .25rem;} \ No newline at end of file diff --git a/module/mr/js/browse.ui.js b/module/mr/js/browse.ui.js new file mode 100644 index 0000000000..6403cb11fd --- /dev/null +++ b/module/mr/js/browse.ui.js @@ -0,0 +1,6 @@ +window.createSortLink = function(col) +{ + var sort = col.name + '_asc'; + if(sort == orderBy) sort = col.name + '_desc'; + return sortLink.replace('{orderBy}', sort); +} diff --git a/module/mr/js/create.ui.js b/module/mr/js/create.ui.js index c155d896a8..d3b3c880b9 100644 --- a/module/mr/js/create.ui.js +++ b/module/mr/js/create.ui.js @@ -21,7 +21,8 @@ function urlencode(param) */ function getBranchPriv(project) { - var branchUrl = $.createLink('mr', 'ajaxGetBranchPivs', "hostID=" + hostID + "&project=" + project); + var sourceProject = projectNamespace ? urlencode(projectNamespace) : project; + var branchUrl = $.createLink('mr', 'ajaxGetBranchPivs', "hostID=" + hostID + "&project=" + sourceProject); $.get(branchUrl, function(response) { branchPrivs = eval('(' + response + ')'); @@ -30,7 +31,8 @@ function getBranchPriv(project) function onProjectChange() { - var branchUrl = $.createLink(hostType, 'ajaxGetProjectBranches', hostType + "ID=" + hostID + "&projectID=" + projectID); + var sourceProject = projectNamespace ? urlencode(projectNamespace) : projectID; + var branchUrl = $.createLink(hostType, 'ajaxGetProjectBranches', hostType + "ID=" + hostID + "&projectID=" + sourceProject); $.ajaxSubmit( { url: branchUrl, diff --git a/module/mr/js/diff.js b/module/mr/js/diff.js index 37a53877c1..16e4768f9a 100644 --- a/module/mr/js/diff.js +++ b/module/mr/js/diff.js @@ -70,11 +70,12 @@ function changeEncoding(encoding) * @access public * @return string */ -function htmlspecialchars_decode(str){ +function htmlspecialchars_decode(str) +{ str = str.replace(/&/g, '&'); str = str.replace(/</g, '<'); str = str.replace(/>/g, '>'); - str = str.replace(/"/g, "''"); + str = str.replace(/"/g, '"'); str = str.replace(/'/g, "'"); return str; } @@ -98,27 +99,38 @@ function getDiffs(fileName) { if(diff.fileName == fileName) { - if(typeof diff.contents[0].lines != 'object') return result; - - var lines = diff.contents[0].lines; - $.each(lines, function(l, code) + $.each(diff.contents, function(c, content) { - if(code.type == 'all' || code.type == 'new') - { - result.code.new += htmlspecialchars_decode(code.line.substring(2)) + "\n"; - result.line.new.push(code.newlc); - } + if(typeof content.lines != 'object') return result; - if(code.type == 'all' || code.type == 'old') + var lines = content.lines; + $.each(lines, function(l, code) { - result.code.old += htmlspecialchars_decode(code.line.substring(2)) + "\n"; - result.line.old.push(code.oldlc); - } - }) + var subIndex = code.type == 'all' ? 1 : 2; + var lineCode = htmlspecialchars_decode(code.line.substring(subIndex)) + "\n"; + + if(code.type == 'new') + { + result.code.new += lineCode; + result.line.new.push(code.newlc); + } + else if(code.type == 'old') + { + result.code.old += lineCode; + result.line.old.push(code.oldlc); + } + else + { + result.code.new += lineCode; + result.code.old += lineCode; + result.line.new.push(code.newlc); + result.line.old.push(code.oldlc); + } + }); + }); return result; } }); - return result; } diff --git a/module/mr/js/diff.ui.js b/module/mr/js/diff.ui.js index 88c3680a32..c27a150b4e 100644 --- a/module/mr/js/diff.ui.js +++ b/module/mr/js/diff.ui.js @@ -211,9 +211,7 @@ window.afterPageUpdate = function() /* Select default tree item. */ const currentElement = findItemInTreeItems(tree, fileAsId, 0); - setTimeout(() => { - if(currentElement != undefined) $('#' + currentElement.id).parent().addClass('selected'); - }, 200); + if(currentElement != undefined) $('#' + currentElement.id).parent().addClass('selected'); expandTree(); $('.btn-left').on('click', function() {arrowTabs('monacoTabs', 1);}); diff --git a/module/mr/js/link.ui.js b/module/mr/js/link.ui.js index 0e25f73d28..44c152fc6a 100644 --- a/module/mr/js/link.ui.js +++ b/module/mr/js/link.ui.js @@ -35,16 +35,7 @@ window.createTaskSortLink = function(col) window.showLink = function(obj) { - let link = $(obj).data('url'); - let $tabContent = $(obj); - - if($(obj).hasClass('link')) - { - $tabContent = $(obj).closest('.tab-pane'); - } - else - { - link = $(obj).find('.link').data('url'); - } + const $tabContent = $(obj).closest('.tab-pane'); + const link = $tabContent.find('.link').data('url'); $tabContent.load(link); }; diff --git a/module/mr/js/linkbug.ui.js b/module/mr/js/linkbug.ui.js index f64dd9a1ad..a832c51e5b 100644 --- a/module/mr/js/linkbug.ui.js +++ b/module/mr/js/linkbug.ui.js @@ -3,7 +3,7 @@ window.createSortLink = function(col) var sort = col.name + '_asc'; if(sort == orderBy) sort = col.name + '_desc'; - return sortLink.replace('{orderBy}', sort); + return "javascript:loadTarget('" + sortLink.replace('{orderBy}', sort) + "', 'mr-bug')"; } $(document).off('click','.dtable-footer .batch-btn').on('click', '.dtable-footer .batch-btn', function(e) @@ -20,6 +20,7 @@ $(document).off('click','.dtable-footer .batch-btn').on('click', '.dtable-footer url: $(this).data('url'), data: postData }); + $(this).prop('disabled', true); }); window.onSearchFormResult = function(formName, response) @@ -28,4 +29,4 @@ window.onSearchFormResult = function(formName, response) .then(json => { loadTarget(json.load, 'mr-bug'); }).catch(console.error); -} \ No newline at end of file +} diff --git a/module/mr/js/linkstory.ui.js b/module/mr/js/linkstory.ui.js index 23596b2a6d..b2a50cddf0 100644 --- a/module/mr/js/linkstory.ui.js +++ b/module/mr/js/linkstory.ui.js @@ -3,7 +3,7 @@ window.createSortLink = function(col) var sort = col.name + '_asc'; if(sort == orderBy) sort = col.name + '_desc'; - return sortLink.replace('{orderBy}', sort); + return "javascript:loadTarget('" + sortLink.replace('{orderBy}', sort) + "', 'mr-story')"; } $(document).off('click','.dtable-footer .batch-btn').on('click', '.dtable-footer .batch-btn', function(e) @@ -20,6 +20,7 @@ $(document).off('click','.dtable-footer .batch-btn').on('click', '.dtable-footer url: $(this).data('url'), data: postData }); + $(this).prop('disabled', true); }); window.onSearchFormResult = function(formName, response) diff --git a/module/mr/js/linktask.ui.js b/module/mr/js/linktask.ui.js index 012ec34b27..a06251e3cd 100644 --- a/module/mr/js/linktask.ui.js +++ b/module/mr/js/linktask.ui.js @@ -3,7 +3,7 @@ window.createSortLink = function(col) var sort = col.name + '_asc'; if(sort == orderBy) sort = col.name + '_desc'; - return sortLink.replace('{orderBy}', sort); + return "javascript:loadTarget('" + sortLink.replace('{orderBy}', sort) + "', 'mr-task')"; } $(document).off('click','.dtable-footer .batch-btn').on('click', '.dtable-footer .batch-btn', function(e) @@ -20,6 +20,7 @@ $(document).off('click','.dtable-footer .batch-btn').on('click', '.dtable-footer url: $(this).data('url'), data: postData }); + $(this).prop('disabled', true); }); window.onSearchFormResult = function(formName, response) @@ -28,4 +29,4 @@ window.onSearchFormResult = function(formName, response) .then(json => { loadTarget(json.load, 'mr-task'); }).catch(console.error); -} \ No newline at end of file +} diff --git a/module/mr/lang/de.php b/module/mr/lang/de.php index 817d887729..fb8ded06e0 100644 --- a/module/mr/lang/de.php +++ b/module/mr/lang/de.php @@ -21,6 +21,7 @@ $lang->mr->link = 'Link of stories,Bugs,tasks'; $lang->mr->createAction = '%s, %s submitted a Merge Request.'; $lang->mr->editAction = '%s, %s edited Merge Request。'; $lang->mr->removeAction = '%s, %s deleted Merge Request。'; +$lang->mr->submitType = 'Submit type'; $lang->mr->linkList = 'Link List of stories,Bugs,tasks'; $lang->mr->linkStory = 'Link Stories'; @@ -42,7 +43,7 @@ $lang->mr->commits = 'commits'; $lang->mr->changes = 'changes'; $lang->mr->gitlabID = 'GitLab'; $lang->mr->repoID = 'Repo'; -$lang->mr->jobID = 'Compile job'; +$lang->mr->jobID = 'Pipeline job'; $lang->mr->canMerge = "Can be merged"; $lang->mr->cantMerge = "Can not be merged"; @@ -64,7 +65,7 @@ $lang->mr->approvalResultList['approve'] = 'Approve'; $lang->mr->approvalResultList['reject'] = 'Reject'; $lang->mr->needApproved = 'This MR should be approved before merge'; -$lang->mr->needCI = 'Merge only after passing CI'; +$lang->mr->needCI = 'Merge only after passing pipeline'; $lang->mr->removeSourceBranch = 'Delete source branch after merge'; $lang->mr->squash = 'Squash commits'; @@ -99,11 +100,11 @@ $lang->mr->sourceProject = 'Source repository'; $lang->mr->sourceBranch = 'Source branch'; $lang->mr->targetProject = 'Target repository'; $lang->mr->targetBranch = 'Target branch'; -$lang->mr->noCompileJob = 'No Compile Job'; +$lang->mr->noCompileJob = 'No Pipeline Job'; $lang->mr->compileUnexecuted = 'Compile Unexecuted'; $lang->mr->notFound = "Merge Request does not exist!"; -$lang->mr->toCreatedMessage = "The merge request you submitted:%s, the build task succeeded."; +$lang->mr->toCreatedMessage = "The merge request you submitted:%s, the pipeline task succeeded."; $lang->mr->toReviewerMessage = "You have one merge request %s waiting."; $lang->mr->failMessage = "Your merge request %s failed. Please check its execution result. "; $lang->mr->storySummary = "Total %s {$lang->SRCommon} on this page."; diff --git a/module/mr/lang/en.php b/module/mr/lang/en.php index a6ddb5a34e..fb8ded06e0 100644 --- a/module/mr/lang/en.php +++ b/module/mr/lang/en.php @@ -21,7 +21,7 @@ $lang->mr->link = 'Link of stories,Bugs,tasks'; $lang->mr->createAction = '%s, %s submitted a Merge Request.'; $lang->mr->editAction = '%s, %s edited Merge Request。'; $lang->mr->removeAction = '%s, %s deleted Merge Request。'; -$lang->mr->submitType = 'Submission method'; +$lang->mr->submitType = 'Submit type'; $lang->mr->linkList = 'Link List of stories,Bugs,tasks'; $lang->mr->linkStory = 'Link Stories'; @@ -43,7 +43,7 @@ $lang->mr->commits = 'commits'; $lang->mr->changes = 'changes'; $lang->mr->gitlabID = 'GitLab'; $lang->mr->repoID = 'Repo'; -$lang->mr->jobID = 'Compile job'; +$lang->mr->jobID = 'Pipeline job'; $lang->mr->canMerge = "Can be merged"; $lang->mr->cantMerge = "Can not be merged"; @@ -65,7 +65,7 @@ $lang->mr->approvalResultList['approve'] = 'Approve'; $lang->mr->approvalResultList['reject'] = 'Reject'; $lang->mr->needApproved = 'This MR should be approved before merge'; -$lang->mr->needCI = 'Merge only after passing CI'; +$lang->mr->needCI = 'Merge only after passing pipeline'; $lang->mr->removeSourceBranch = 'Delete source branch after merge'; $lang->mr->squash = 'Squash commits'; @@ -100,11 +100,11 @@ $lang->mr->sourceProject = 'Source repository'; $lang->mr->sourceBranch = 'Source branch'; $lang->mr->targetProject = 'Target repository'; $lang->mr->targetBranch = 'Target branch'; -$lang->mr->noCompileJob = 'No Compile Job'; +$lang->mr->noCompileJob = 'No Pipeline Job'; $lang->mr->compileUnexecuted = 'Compile Unexecuted'; $lang->mr->notFound = "Merge Request does not exist!"; -$lang->mr->toCreatedMessage = "The merge request you submitted:%s, the build task succeeded."; +$lang->mr->toCreatedMessage = "The merge request you submitted:%s, the pipeline task succeeded."; $lang->mr->toReviewerMessage = "You have one merge request %s waiting."; $lang->mr->failMessage = "Your merge request %s failed. Please check its execution result. "; $lang->mr->storySummary = "Total %s {$lang->SRCommon} on this page."; diff --git a/module/mr/lang/fr.php b/module/mr/lang/fr.php index 7268fae084..632b60d0f7 100644 --- a/module/mr/lang/fr.php +++ b/module/mr/lang/fr.php @@ -21,6 +21,7 @@ $lang->mr->link = 'Link of stories,Bugs,tasks'; $lang->mr->createAction = '%s, %s submitted a Merge Request.'; $lang->mr->editAction = '%s, %s edited Merge Request。'; $lang->mr->removeAction = '%s, %s deleted Merge Request。'; +$lang->mr->submitType = 'Submit type'; $lang->mr->linkList = 'Link List of stories,Bugs,tasks'; $lang->mr->linkStory = 'Link Stories'; @@ -42,7 +43,7 @@ $lang->mr->commits = 'commits'; $lang->mr->changes = 'changes'; $lang->mr->gitlabID = 'GitLab'; $lang->mr->repoID = 'Repo'; -$lang->mr->jobID = 'Compile job'; +$lang->mr->jobID = 'Pipeline job'; $lang->mr->canMerge = "Can be merged"; $lang->mr->cantMerge = "Can not be merged"; @@ -64,7 +65,7 @@ $lang->mr->approvalResultList['approve'] = 'Approve'; $lang->mr->approvalResultList['reject'] = 'Reject'; $lang->mr->needApproved = 'This MR should be approved before merge'; -$lang->mr->needCI = 'Merge only after passing CI'; +$lang->mr->needCI = 'Merge only after passing pipeline'; $lang->mr->removeSourceBranch = 'Delete source branch after merge'; $lang->mr->squash = 'Squash commits'; @@ -99,11 +100,11 @@ $lang->mr->sourceProject = 'Source project'; $lang->mr->sourceBranch = 'Source branch'; $lang->mr->targetProject = 'Target project'; $lang->mr->targetBranch = 'Target branch'; -$lang->mr->noCompileJob = 'No Compile Job'; +$lang->mr->noCompileJob = 'No Pipeline Job'; $lang->mr->compileUnexecuted = 'Compile Unexecuted'; $lang->mr->notFound = "Merge Request does not exist!"; -$lang->mr->toCreatedMessage = "The merge request you submitted:%s, the build task succeeded."; +$lang->mr->toCreatedMessage = "The merge request you submitted:%s, the pipeline task succeeded."; $lang->mr->toReviewerMessage = "You have one merge request %s waiting."; $lang->mr->failMessage = "Your merge request %s failed. Please check its execution result. "; $lang->mr->storySummary = "Total %s {$lang->SRCommon} on this page."; diff --git a/module/mr/lang/zh-cn.php b/module/mr/lang/zh-cn.php index 31cde8ee47..92528e4179 100644 --- a/module/mr/lang/zh-cn.php +++ b/module/mr/lang/zh-cn.php @@ -4,7 +4,7 @@ $lang->mr->common = "合并请求"; $lang->mr->server = "服务器"; $lang->mr->view = "概况"; $lang->mr->viewAction = "{$lang->mr->common}详情"; -$lang->mr->create = "提{$lang->mr->common}"; +$lang->mr->create = "创建{$lang->mr->common}"; $lang->mr->apiCreate = "接口:创建{$lang->mr->common}"; $lang->mr->browse = "浏览{$lang->mr->common}"; $lang->mr->browseAction = "{$lang->mr->common}列表"; @@ -43,7 +43,7 @@ $lang->mr->commits = '提交数'; $lang->mr->changes = '更改数'; $lang->mr->gitlabID = 'GitLab'; $lang->mr->repoID = '版本库'; -$lang->mr->jobID = '构建任务'; +$lang->mr->jobID = '流水线任务'; $lang->mr->canMerge = "可合并"; $lang->mr->cantMerge = "不可合并"; @@ -65,7 +65,7 @@ $lang->mr->approvalResultList['approve'] = '通过'; $lang->mr->approvalResultList['reject'] = '拒绝'; $lang->mr->needApproved = '需要通过评审才能合并'; -$lang->mr->needCI = '需要通过构建才能合并'; +$lang->mr->needCI = '需要通过流水线才能合并'; $lang->mr->removeSourceBranch = '合并后删除源分支'; $lang->mr->squash = '合并提交记录'; @@ -100,13 +100,13 @@ $lang->mr->sourceProject = '源仓库'; $lang->mr->sourceBranch = '源分支'; $lang->mr->targetProject = '目标仓库'; $lang->mr->targetBranch = '目标分支'; -$lang->mr->noCompileJob = '没有构建任务'; +$lang->mr->noCompileJob = '没有流水线任务'; $lang->mr->compileUnexecuted = '还未执行'; $lang->mr->notFound = "此{$lang->mr->common}不存在。"; -$lang->mr->toCreatedMessage = "您提交的合并请求:%s 构建任务执行通过。"; +$lang->mr->toCreatedMessage = "您提交的合并请求:%s 流水线任务执行通过。"; $lang->mr->toReviewerMessage = "有一个合并请求:%s 待审核。"; -$lang->mr->failMessage = "您提交的合并请求:%s 构建任务执行失败,查看执行结果。"; +$lang->mr->failMessage = "您提交的合并请求:%s 流水线任务执行失败,查看执行结果。"; $lang->mr->storySummary = "本页共 %s 个" . $lang->SRCommon; $lang->mr->apiError = new stdclass; diff --git a/module/mr/model.php b/module/mr/model.php index 146221cb89..e48f70adf7 100644 --- a/module/mr/model.php +++ b/module/mr/model.php @@ -123,7 +123,7 @@ class mrModel extends model public function getGiteaProjects($hostID = 0) { $projects = $this->loadModel('gitea')->apiGetProjects($hostID); - return array($hostID => array_column($projects, null, 'full_name')); + return array($hostID => helper::arrayColumn($projects, null, 'full_name')); } /** @@ -136,7 +136,7 @@ class mrModel extends model public function getGogsProjects($hostID = 0) { $projects = $this->loadModel('gogs')->apiGetProjects($hostID); - return array($hostID => array_column($projects, null, 'full_name')); + return array($hostID => helper::arrayColumn($projects, null, 'full_name')); } /** @@ -219,6 +219,7 @@ class mrModel extends model ->setDefault('removeSourceBranch','0') ->setDefault('needCI', 0) ->setDefault('squash', 0) + ->setIF($this->post->needCI == 0, 'jobID', 0) ->add('createdBy', $this->app->user->account) ->add('createdDate', helper::now()) ->get(); @@ -427,8 +428,9 @@ class mrModel extends model $MR = $this->getByID($MRID); $this->linkObjects($MR); - - $this->loadModel('action')->create('mr', $MRID, 'edited'); + $changes = common::createChanges($oldMR, $MR); + $actionID = $this->loadModel('action')->create('mr', $MRID, 'edited'); + if(!empty($changes)) $this->action->logHistory($actionID, $changes); $this->createMRLinkedAction($MRID, 'editmr', $MR->editedDate); if(dao::isError()) return array('result' => 'fail', 'message' => dao::getError()); @@ -635,7 +637,7 @@ class mrModel extends model { $todoDesc = $this->dao->select('*') ->from(TABLE_TODO) - ->where('objectID')->eq($rawTodo->id) + ->where('idvalue')->eq($rawTodo->id) ->fetch(); if(empty($todoDesc)) { @@ -651,7 +653,7 @@ class mrModel extends model $todo->begin = '2400'; /* 2400 means begin is 'undefined'. */ $todo->end = '2400'; /* 2400 means end is 'undefined'. */ $todo->type = 'custom'; - $todo->objectID = $rawTodo->id; + $todo->idvalue = $rawTodo->id; $todo->pri = 3; $todo->name = $this->lang->mr->common . ": " . $rawTodo->target->title; $todo->desc = $author . ' ' . $this->lang->mr->at . ' ' . '' . $rawTodo->project->path .'' . ' ' . $this->lang->mr->todomessage . '' . ' ' . $this->lang->mr->common .'' . '。'; @@ -720,7 +722,7 @@ class mrModel extends model $MRObject->head = $MR->sourceBranch; $MRObject->base = $MR->targetBranch; $MRObject->body = $MR->description; - if($MR->assignee) + if(!$MR->assignee) { $assignee = $this->{$host->type}->getUserIDByZentaoAccount($this->post->hostID, $MR->assignee); if($assignee) $MRObject->assignee = $assignee; @@ -761,11 +763,12 @@ class mrModel extends model } $response = json_decode(commonModel::http($url, $data = null, $options = array(), $headers = array(), $dataType = 'data', $method = 'POST', $timeout = 30, $httpCode = false, $log = false)); - if(empty($response)) $response = array(); + if(empty($response) || isset($response->message)) $response = array(); if($scm == 'Gitea') { foreach($response as $MR) { + if(empty($MR)) continue; $MR->iid = $MR->number; $MR->state = $MR->state == 'open' ? 'opened' : $MR->state; if($MR->merged) $MR->state = 'merged'; @@ -842,7 +845,7 @@ class mrModel extends model $host = $this->loadModel('pipeline')->getByID($hostID); if($host->type == 'gitlab') { - $url = sprintf($this->gitlab->getApiRoot($hostID), "/projects/$projectID/merge_requests/$MRID"); + $url = sprintf($this->gitlab->getApiRoot($hostID, false), "/projects/$projectID/merge_requests/$MRID"); $MR = json_decode(commonModel::http($url)); } elseif($host->type == 'gitea') @@ -945,11 +948,11 @@ class mrModel extends model $newMR->squash = $MR->squash == '1' ? 1 : 0; if($MR->assignee) { - $gitlabAssignee = $this->gitlab->getUserIDByZentaoAccount($MR->hostID, $MR->assignee); + $gitlabAssignee = $this->gitlab->getUserIDByZentaoAccount($hostID, $MR->assignee); if($gitlabAssignee) $newMR->assignee_ids = $gitlabAssignee; } $url = sprintf($this->gitlab->getApiRoot($hostID), "/projects/$projectID/merge_requests/$MRID"); - return json_decode(commonModel::http($url, $MR, $options = array(CURLOPT_CUSTOMREQUEST => 'PUT'))); + return json_decode(commonModel::http($url, $newMR, $options = array(CURLOPT_CUSTOMREQUEST => 'PUT'))); } else { @@ -962,7 +965,6 @@ class mrModel extends model $assignee = $this->{$host->type}->getUserIDByZentaoAccount($this->post->hostID, $MR->assignee); if($assignee) $newMR->assignee = $assignee; } - $mergeResult = json_decode(commonModel::http($url, $newMR, array(), array(), 'json', 'PATCH')); if(isset($mergeResult->number)) $mergeResult->iid = $host->type == 'gitea' ? $mergeResult->number : $mergeResult->id; if(isset($mergeResult->mergeable)) @@ -1973,7 +1975,7 @@ class mrModel extends model { $product = array(); - if($MR->repoID) + if(is_object($MR) && $MR->repoID) { $productID = $this->dao->select('product')->from(TABLE_REPO)->where('id')->eq($MR->repoID)->fetch('product'); } diff --git a/module/mr/ui/approval.html.php b/module/mr/ui/approval.html.php index 889def6ae8..a04c44c2b1 100644 --- a/module/mr/ui/approval.html.php +++ b/module/mr/ui/approval.html.php @@ -12,6 +12,7 @@ namespace zin; modalHeader ( + set::title(''), set::entityText($MR->title . ' - ' . zget($lang->mr->approvalResultList, $action)), set::entityID($MR->id), ); @@ -30,6 +31,7 @@ formPanel ) : null, formGroup ( + set::width('1/2'), set::label($lang->mr->assignee), set::name('assignedTo'), set::items($users), diff --git a/module/mr/ui/browse.html.php b/module/mr/ui/browse.html.php index de152a2ce1..5038d3cb58 100644 --- a/module/mr/ui/browse.html.php +++ b/module/mr/ui/browse.html.php @@ -10,6 +10,9 @@ declare(strict_types=1); */ namespace zin; +jsVar('orderBy', $orderBy); +jsVar('sortLink', $sortLink); + dropmenu(set::objectID($repo->id), set::text($repo->name), set::tab('repo')); foreach($MRList as $MR) @@ -72,8 +75,10 @@ toolBar dtable ( + set::userMap($users), set::cols($config->mr->dtable->fieldList), set::data($MRs), + set::sortLink(jsRaw('createSortLink')), set::footPager(usePager()), ); diff --git a/module/mr/ui/create.html.php b/module/mr/ui/create.html.php index a9d1b4099f..1d4e4ba8da 100644 --- a/module/mr/ui/create.html.php +++ b/module/mr/ui/create.html.php @@ -17,9 +17,19 @@ jsVar('repo', $repo); jsVar('projectID', $project->id); jsVar('mrLang', $lang->mr); jsVar('branchPrivs', array()); +jsVar('projectNamespace', in_array($repo->SCM, array('Gitea', 'Gogs')) ? $project->name_with_namespace : ''); dropmenu(set::objectID($repo->id), set::text($repo->name), set::tab('repo')); +if(in_array($repo->SCM, array('Gitea', 'Gogs'))) +{ + $projectItem = array($project->name_with_namespace => $project->name_with_namespace); +} +else +{ + $projectItem = array($project->id => $project->name_with_namespace); +} + formPanel ( set::title($lang->mr->create), @@ -39,7 +49,7 @@ formPanel set::label($lang->mr->sourceProject), set::name('sourceProject'), set::id('sourceProject'), - set::items(array($project->id => $project->name_with_namespace)), + set::items($projectItem), set::disabled(true), ), formGroup @@ -60,7 +70,7 @@ formPanel set::label($lang->mr->targetProject), set::id('targetProject'), set::name('targetProject'), - set::items(array($project->id => $project->name_with_namespace)), + set::items($projectItem), set::disabled(true), ), formGroup @@ -125,7 +135,7 @@ formPanel ( set::name('description'), set::label($lang->mr->description), - set::control('editor'), + set::control('textarea'), ), formRow ( diff --git a/module/mr/ui/diff.html.php b/module/mr/ui/diff.html.php index 02dfd01b34..992314fe49 100644 --- a/module/mr/ui/diff.html.php +++ b/module/mr/ui/diff.html.php @@ -10,6 +10,8 @@ declare(strict_types=1); */ namespace zin; +dropmenu(set::objectID($MR->repoID), set::tab('repo')); + detailHeader ( to::title @@ -34,7 +36,7 @@ $fileInfo = $entry ? pathinfo($entry) : array(); $showBug = isset($showBug) ? $showBug : true; $objectID = isset($objectID) ? $objectID : 0; $tree = $this->repo->getFileTree($repo, '', $diffs); -$diffLink = $this->repo->createLink('diff', "repoID=$repoID&objectID=$objectID&entry=" . $file . "&oldrevision={oldRevision}&newRevision={newRevision}"); +$diffLink = $this->repo->createLink('diff', "repoID=$repoID&objectID=$objectID&entry=&oldrevision={oldRevision}&newRevision={newRevision}"); jsVar('diffs', $diffs); jsVar('tree', $tree); diff --git a/module/mr/ui/link.html.php b/module/mr/ui/link.html.php index c441e7c256..b852b9af06 100644 --- a/module/mr/ui/link.html.php +++ b/module/mr/ui/link.html.php @@ -10,9 +10,14 @@ declare(strict_types=1); */ namespace zin; +$repoName = $this->dao->select('name')->from(TABLE_REPO)->where('id')->eq($MR->repoID)->fetch('name'); +dropmenu(set::objectID($MR->repoID), set::text($repoName), set::tab('repo')); + jsVar('type', $type); jsVar('orderBy', $orderBy); -jsVar('sortLink', createLink('mr', 'link', "MRID={$MR->id}&type={type}&orderBy={orderBy}&recTotal={$pager->recTotal}&recPerPage={$pager->recPerPage}&pageID={$pager->pageID}")); +jsVar('sortLink', createLink('mr', 'link', "MRID={$MR->id}&type={type}&orderBy={orderBy}&recTotal=&recPerPage=&pageID=")); + +dropmenu(set::objectID($MR->repoID), set::tab('repo')); $actionMenu = array(); $actionMenu['title'] = $lang->actions; @@ -23,37 +28,32 @@ $actionMenu['list']['unlink']['hint'] = $lang->productplan->unlinkStory; $actionMenu['list']['unlink']['className'] = 'ajax-submit'; $storyCols = $config->release->dtable->story->fieldList; -$storyCols['actions'] = $actionMenu; +$storyCols['actions'] = $actionMenu; +$storyCols['id']['checkbox'] = false; +$storyCols['title']['data-toggle'] = ''; +$storyCols['title']['nestedToggle'] = false; +$storyCols['title']['link'] = array('module' => 'story', 'method' => 'view', 'params' => 'storyID={id}', 'target' => '_blank'); + $storyCols['actions']['list']['unlink']['data-confirm'] = $lang->productplan->confirmUnlinkStory; $storyCols['actions']['list']['unlink']['url'] = $this->createLink('mr', 'unlink', "MRID=$MR->id&productID=$product->id&type=story&linkID={id}&confirm=yes"); -$storyCols['id']['checkbox'] = false; + $stories = initTableData($stories, $storyCols); $bugCols = $config->release->dtable->bug->fieldList; $bugCols['actions'] = $actionMenu; $bugCols['actions']['list']['unlink']['data-confirm'] = $lang->productplan->confirmUnlinkBug; $bugCols['actions']['list']['unlink']['url'] = $this->createLink('mr', 'unlink', "MRID=$MR->id&productID=$product->id&type=bug&linkID={id}&confirm=yes"); -$bugCols['id']['checkbox'] = false; + +$bugCols['id']['checkbox'] = false; +$bugCols['title']['data-toggle'] = ''; +$bugCols['title']['link'] = array('module' => 'bug', 'method' => 'view', 'params' => 'bugID={id}', 'target' => '_blank'); $bugs = initTableData($bugs, $bugCols); -$taskCols = array(); -$taskCols['id'] = $config->task->dtable->fieldList['id']; -$taskCols['name'] = $config->task->dtable->fieldList['name']; -$taskCols['pri'] = $config->task->dtable->fieldList['pri']; -$taskCols['finishedBy'] = $config->task->dtable->fieldList['finishedBy']; -$taskCols['assignedTo'] = $config->task->dtable->fieldList['assignedTo']; -$taskCols['status'] = $config->task->dtable->fieldList['status']; +$taskCols = $config->mr->taskDtable->fieldList; $taskCols['actions'] = $actionMenu; $taskCols['actions']['list']['unlink']['data-confirm'] = $lang->mr->confirmUnlinkTask; $taskCols['actions']['list']['unlink']['url'] = $this->createLink('mr', 'unlink', "MRID=$MR->id&productID=$product->id&type=task&linkID={id}&confirm=yes"); -$taskCols['id']['checkbox'] = false; -$taskCols['name']['title'] = $lang->task->name; -$taskCols['name']['fixed'] = ''; -$taskCols['assignedTo']['title'] = $lang->task->assignedTo; -foreach($taskCols as $col => $colConfig) -{ - if(isset($colConfig['group'])) unset($taskCols[$col]['group']); -} + $tasks = initTableData($tasks, $taskCols); if(common::hasPriv('mr', 'linkStory')) diff --git a/module/mr/ui/linkbug.html.php b/module/mr/ui/linkbug.html.php index 5c7b28bd9f..ee34512231 100644 --- a/module/mr/ui/linkbug.html.php +++ b/module/mr/ui/linkbug.html.php @@ -33,7 +33,8 @@ div $cols = array(); foreach($config->release->dtable->defaultFields['linkBug'] as $field) $cols[$field] = zget($config->bug->dtable->fieldList, $field, array()); $data = array_values($allBugs); -$cols['title']['link'] = array('module' => 'bug', 'method' => 'view', 'params' => 'bugID={id}', 'target' => '_blank'); +$cols['title']['data-toggle'] = ''; +$cols['title']['link'] = array('module' => 'bug', 'method' => 'view', 'params' => 'bugID={id}', 'target' => '_blank'); dtable ( set::userMap($users), diff --git a/module/mr/ui/linkstory.html.php b/module/mr/ui/linkstory.html.php index ffd983eee5..9c6def03ef 100644 --- a/module/mr/ui/linkstory.html.php +++ b/module/mr/ui/linkstory.html.php @@ -33,9 +33,9 @@ div $cols = array(); foreach($config->release->dtable->defaultFields['linkStory'] as $field) $cols[$field] = zget($config->release->dtable->story->fieldList, $field, array()); $cols = array_map(function($col){$col['show'] = true; return $col;}, $cols); -$cols['title']['link'] = array('module' => 'story', 'method' => 'view', 'params' => 'storyID={id}', 'target' => '_blank'); -$cols['title']['nestedToggle'] = false; $cols['title']['data-toggle'] = ''; +$cols['title']['nestedToggle'] = false; +$cols['title']['link'] = array('module' => 'story', 'method' => 'view', 'params' => 'storyID={id}', 'target' => '_blank'); $data = array_values($allStories); dtable diff --git a/module/mr/ui/view.html.php b/module/mr/ui/view.html.php index 34b443be03..d487e59ec2 100644 --- a/module/mr/ui/view.html.php +++ b/module/mr/ui/view.html.php @@ -10,14 +10,14 @@ declare(strict_types=1); */ namespace zin; -$repoName = $this->dao->select('name')->from(TABLE_REPO)->where('id')->eq($MR->repoID)->fetch('name'); -dropmenu(set::objectID($MR->repoID), set::text($repoName), set::tab('repo')); +dropmenu(set::objectID($MR->repoID), set::tab('repo')); $hasNoConflict = $MR->synced === '1' ? $rawMR->has_conflicts : (bool)$MR->hasNoConflict; $sourceDisabled = ($MR->status == 'merged' && $MR->removeSourceBranch == '1') ? 'disabled' : ''; $compileNotSuccess = !empty($compile->id) && $compile->status != 'success'; -$mainActions = array(); +$mainActions = array(); +$suffixActions = array(); foreach($config->mr->view->operateList as $operate) { if(!common::hasPriv('mr', $operate == 'reject' ? 'approval' : $operate)) continue; @@ -29,7 +29,7 @@ foreach($config->mr->view->operateList as $operate) if(in_array($operate, array('approval', 'reject', 'close', 'edit'))) { if(!$MR->synced || $rawMR->state != 'opened') continue; - if($operate == 'reject' && $MR->approvalStatus == 'rejected') continue; + if($operate == 'reject' && $MR->approvalStatus == 'rejected') $action['disabled'] = true; if($operate == 'approval') { @@ -38,6 +38,14 @@ foreach($config->mr->view->operateList as $operate) } if($operate == 'reopen' && (!$MR->synced || $rawMR->state != 'closed')) continue; + if($operate == 'delete' && !$projectOwner && !$this->app->user->admin) $action['disabled'] = true; + if($operate == 'edit' && !$projectEdit && !$this->app->user->admin) $action['disabled'] = true; + + if($operate === 'edit' || $operate === 'delete') + { + $suffixActions[] = $action; + continue; + } $mainActions[] = $action; } @@ -209,7 +217,7 @@ panel item ( set::name($lang->mr->description), - !empty($MR->description) ? $MR->description : $lang->noData, + !empty($MR->description) ? html(nl2br($MR->description)) : $lang->noData, ), ), ), @@ -235,7 +243,7 @@ panel div ( setClass('article-h1'), - $lang->compile->job, + $lang->mr->jobID, ), $job ), @@ -250,6 +258,7 @@ div set::object($MR), isAjaxRequest('modal') ? null : to::prefix(backBtn(set::icon('back'), $lang->goback)), set::main($mainActions), + set::suffix($suffixActions) ), ); diff --git a/module/mr/view/header.review.html.php b/module/mr/view/header.review.html.php index a674196299..cc8a6db864 100644 --- a/module/mr/view/header.review.html.php +++ b/module/mr/view/header.review.html.php @@ -32,7 +32,7 @@ $taskRepoModule = 0; $taskMembers = array('' => ''); if($repoExecution) { - $taskModules = $this->loadModel('tree')->getTaskOptionMenu($repoExecution); + $taskModules = $this->loadModel('tree')->getTaskOptionMenu($repoExecution, 0, 0, ''); $taskRepoModule = (!empty($lastReview->task) && $lastReview->task->execution == $repoExecution) ? $lastReview->task->module : ''; $taskMembers = $this->loadModel('user')->getTeamMemberPairs($repoExecution, 'execution', 'nodeleted'); } diff --git a/module/mr/view/link.html.php b/module/mr/view/link.html.php index 68fd0575a6..108e66d89f 100644 --- a/module/mr/view/link.html.php +++ b/module/mr/view/link.html.php @@ -156,7 +156,7 @@