resolve conflict master

This commit is contained in:
lanzongjun
2022-12-02 10:28:31 +08:00
103 changed files with 742 additions and 299 deletions
+6 -3
View File
@@ -734,10 +734,13 @@ class baseRouter
$account = $sql->quote($account);
$vision = $this->dbh->query("SELECT * FROM " . TABLE_CONFIG . " WHERE owner = $account AND `key` = 'vision' LIMIT 1")->fetch();
if($vision) $vision = $vision->value;
if(empty($vision))
$user = $this->dbh->query("SELECT * FROM " . TABLE_USER . " WHERE account = $account AND deleted = '0' LIMIT 1")->fetch();
if(!empty($user->visions))
{
$user = $this->dbh->query("SELECT * FROM " . TABLE_USER . " WHERE account = $account AND deleted = '0' LIMIT 1")->fetch();
if(!empty($user->visions)) list($vision) = explode(',', $user->visions);
$userVisions = explode(',', $user->visions);
if(!in_array($vision, $userVisions)) $vision = '';
if(empty($vision)) list($vision) = $userVisions;
}
}
+3 -1
View File
@@ -28,7 +28,9 @@ class GitRepo
if($branch)
{
$branches = $this->branch();
if(isset($branches[$branch])) $branch = "origin/$branch";
$cmd = escapeCmd("$this->client branch -r");
execCmd($cmd . ' 2>&1', 'string', $result);
if(isset($branches[$branch]) and !empty($result)) $branch = "origin/$branch";
}
$this->branch = $branch;
$this->repo = $repo;
+18 -6
View File
@@ -18,10 +18,12 @@ class zfile
* @param string $to
* @param bool $logLevel
* @param string $logFile
* @param array $excludeFiles
* @param bool $toIsLink
* @access public
* @return array copied files, count, size or message.
*/
public function copyDir($from, $to, $logLevel = false, $logFile = '')
public function copyDir($from, $to, $logLevel = false, $logFile = '', $excludeFiles = array(), $toIsLink = false)
{
static $copiedFiles = array();
static $errorFiles = array();
@@ -41,12 +43,21 @@ class zfile
if(!empty($log['message'])) return $log;
$from = realpath($from) . '/';
$to = realpath($to) . '/';
if(is_link($to) || $toIsLink)
{
$to = $to . '/';
$toIsLink = true;
}
else
{
$to = realpath($to) . '/';
}
$entries = scandir($from);
foreach($entries as $entry)
{
if($entry == '.' or $entry == '..' or $entry == '.svn' or $entry == '.git') continue;
if($entry == '.' or $entry == '..' or $entry == '.svn' or $entry == '.git' or in_array($entry, $excludeFiles)) continue;
$fullEntry = $from . $entry;
if(is_file($fullEntry))
@@ -82,7 +93,7 @@ class zfile
{
$nextFrom = $fullEntry;
$nextTo = $to . $entry;
$result = $this->copyDir($nextFrom, $nextTo, $logLevel, $logFile);
$result = $this->copyDir($nextFrom, $nextTo, $logLevel, $logFile, array(), $toIsLink);
$count += $result['count'];
$size += $result['size'];
}
@@ -101,10 +112,11 @@ class zfile
* Get count.
*
* @param string $dir
* @param array $excludeFiles
* @access public
* @return int
*/
public function getCount($dir)
public function getCount($dir, $excludeFiles = array())
{
if(!file_exists($dir)) return 0;
if(is_file($dir)) return 1;
@@ -113,7 +125,7 @@ class zfile
$entries = scandir($dir);
foreach($entries as $entry)
{
if($entry == '.' or $entry == '..' or $entry == '.svn' or $entry == '.git') continue;
if($entry == '.' or $entry == '..' or $entry == '.svn' or $entry == '.git' or in_array($entry, $excludeFiles)) continue;
$fullEntry = $dir . '/' . $entry;
$count += $this->getCount($fullEntry);
+1 -1
View File
@@ -227,7 +227,7 @@ $lang->action->desc->submitreview = '$date, submitted for review by <str
$lang->action->desc->ganttmove = '$date, sort by <strong>$actor</strong> .' . "\n";
$lang->action->desc->relieved = '$date, relieved by <strong>$actor</strong> .' . "\n";
$lang->action->desc->switchtolight = '$date, Switch from ALM mode to light mode by <strong>'. $lang->admin->system .'</strong>.' . "\n";
$lang->action->desc->unlinkproduct = '$date, the project is disassociated from the $extra, synchronization disassociates the sprints of the project from the $extra.' . "\n";
$lang->action->desc->unlinkproduct = '$date, the project is disassociated from the $extra, synchronization disassociates the ' . $lang->executionCommon . 's of the project from the $extra.' . "\n";
/* Used to describe the history of operations related to parent-child tasks. */
$lang->action->desc->createchildren = '$date, <strong>$actor</strong> created a child task <strong>$extra</strong>。' . "\n";
+1 -1
View File
@@ -227,7 +227,7 @@ $lang->action->desc->submitreview = '$date, submitted for review by <str
$lang->action->desc->ganttmove = '$date, sort by <strong>$actor</strong> .' . "\n";
$lang->action->desc->relieved = '$date, relieved by <strong>$actor</strong> .' . "\n";
$lang->action->desc->switchtolight = '$date, Switch from ALM mode to light mode by <strong>'. $lang->admin->system .'</strong>.' . "\n";
$lang->action->desc->unlinkproduct = '$date, the project is disassociated from the $extra, synchronization disassociates the sprints of the project from the $extra.' . "\n";
$lang->action->desc->unlinkproduct = '$date, the project is disassociated from the $extra, synchronization disassociates the ' . $lang->executionCommon . 's of the project from the $extra.' . "\n";
/* Used to describe the history of operations related to parent-child tasks. */
$lang->action->desc->createchildren = '$date, <strong>$actor</strong> created a child task <strong>$extra</strong>。' . "\n";
+1 -1
View File
@@ -227,7 +227,7 @@ $lang->action->desc->submitreview = '$date, submitted for review by <str
$lang->action->desc->ganttmove = '$date, sort by <strong>$actor</strong> .' . "\n";
$lang->action->desc->relieved = '$date, relieved by <strong>$actor</strong> .' . "\n";
$lang->action->desc->switchtolight = '$date, Switch from ALM mode to light mode by <strong>'. $lang->admin->system .'</strong>.' . "\n";
$lang->action->desc->unlinkproduct = '$date, the project is disassociated from the $extra, synchronization disassociates the sprints of the project from the $extra.' . "\n";
$lang->action->desc->unlinkproduct = '$date, the project is disassociated from the $extra, synchronization disassociates the ' . $lang->executionCommon . 's of the project from the $extra.' . "\n";
/* Used to describe the history of operations related to parent-child tasks. */
$lang->action->desc->createchildren = '$date, <strong>$actor</strong> a créé un sous-tâche <strong>$extra</strong>。' . "\n";
+1 -1
View File
@@ -227,7 +227,7 @@ $lang->action->desc->submitreview = '$date, 由 <strong>$actor</strong>
$lang->action->desc->ganttmove = '$date, 由 <strong>$actor</strong> 排序。' . "\n";
$lang->action->desc->relieved = '$date, 由 <strong>$actor</strong> 解除孪生需求关系。' . "\n";
$lang->action->desc->switchtolight = '$date, 由于 <strong>'. $lang->admin->system .'</strong> 从全生命周期管理模式切换为轻量管理模式,项目访问控制由项目集内公开调整为私有。' . "\n";
$lang->action->desc->unlinkproduct = '$date, 系统判断由于迭代所属项目与$extra取消关联,同步将迭代与$extra取消关联。' . "\n";
$lang->action->desc->unlinkproduct = '$date, 系统判断由于' . $lang->executionCommon . '所属项目与$extra取消关联,同步将' . $lang->executionCommon . '与$extra取消关联。' . "\n";
/* 用来描述和父子任务相关的操作历史记录。*/
$lang->action->desc->createchildren = '$date, 由 <strong>$actor</strong> 创建子任务 <strong>$extra</strong>。' . "\n";
+1
View File
@@ -141,3 +141,4 @@ $lang->admin->safe->resetPWDList[0] = 'Off';
$lang->admin->safe->noticeMode = 'The password will be checked when creating and modifying user information, and changing passwords.';
$lang->admin->safe->noticeWeakMode = 'The password will be checked when logging into the system, creating and modifying user information, and changing passwords.';
$lang->admin->safe->noticeStrong = 'The longer the password, the more letters, numbers, or special characters it contains, and the less repetitive the password, the more secure it is!';
$lang->admin->safe->noticeGd = 'Your server does not have GD module installed, you cannot use the Captcha function, Please use it after installation.';
+1
View File
@@ -141,3 +141,4 @@ $lang->admin->safe->resetPWDList[0] = 'Off';
$lang->admin->safe->noticeMode = 'The password will be checked when creating and modifying user information, and changing passwords.';
$lang->admin->safe->noticeWeakMode = 'The password will be checked when logging into the system, creating and modifying user information, and changing passwords.';
$lang->admin->safe->noticeStrong = 'The longer the password, the more letters, numbers, or special characters it contains, and the less repetitive the password, the more secure it is!';
$lang->admin->safe->noticeGd = 'Your server does not have GD module installed, you cannot use the Captcha function, Please use it after installation.';
+1
View File
@@ -141,3 +141,4 @@ $lang->admin->safe->resetPWDList[0] = 'Off';
$lang->admin->safe->noticeMode = "Le mot de passe sera vérifié lors de la création et de la modification des coordonnées de l'utilisateur, et du changement de mot de passe.";
$lang->admin->safe->noticeWeakMode = "Le mot de passe sera vérifié lors de la connexion au système, de la création et de la modification des coordonnées de l'utilisateur, et du changement de mot de passe.";
$lang->admin->safe->noticeStrong = "Le mot de passe est d'autant plus sécurisé qu'il est long, qu'il contient plus de lettres, de chiffres ou de caractères spéciaux, et que les lettres du mot de passe sont peu répétitives !";
$lang->admin->safe->noticeGd = 'Your server does not have GD module installed, you cannot use the Captcha function, Please use it after installation.';
+1
View File
@@ -84,3 +84,4 @@ $lang->admin->safe->loginCaptchaList[0] = 'No';
$lang->admin->safe->noticeMode = 'Mật khẩu sẽ được kiểm tra khi người dùng đăng nhập hoặc người dùng thêm hoặc sửa.';
$lang->admin->safe->noticeStrong = '';
$lang->admin->safe->noticeGd = 'Your server does not have GD module installed, you cannot use the Captcha function, Please use it after installation.';
+1
View File
@@ -141,3 +141,4 @@ $lang->admin->safe->resetPWDList[0] = '关闭';
$lang->admin->safe->noticeMode = '系统会在创建和修改用户、修改密码的时候检查用户口令。';
$lang->admin->safe->noticeWeakMode = '系统会在登录、创建和修改用户、修改密码的时候检查用户口令。';
$lang->admin->safe->noticeStrong = '密码长度越长,含有大写字母或数字或特殊符号越多,密码字母越不重复,安全度越强!';
$lang->admin->safe->noticeGd = '系统检测到您的服务器未安装GD模块,无法使用验证码功能,请安装后使用。';
+4 -2
View File
@@ -82,5 +82,7 @@ $lang->admin->safe->modifyPasswordList[0] = '不強制';
$lang->admin->safe->loginCaptchaList[1] = '是';
$lang->admin->safe->loginCaptchaList[0] = '否';
$lang->admin->safe->noticeMode = '系統會在登錄、創建和修改用戶、修改密碼的時候檢查用戶口令。';
$lang->admin->safe->noticeStrong = '密碼長度越長,含有大寫字母或數字或特殊符號越多,密碼字母越不重複,安全度越強!';
$lang->admin->safe->noticeMode = '系統會在創建和修改用戶、修改密碼的時候檢查用戶口令。';
$lang->admin->safe->noticeWeakMode = '系統會在登錄、創建和修改用戶、修改密碼的時候檢查用戶口令。';
$lang->admin->safe->noticeStrong = '密碼長度越長,含有大寫字母或數字或特殊符號越多,密碼字母越不重複,安全度越強!';
$lang->admin->safe->noticeGd = '系統檢測到您的伺服器未安裝GD模組,無法使用驗證碼功能,請安裝後使用。';
+4 -1
View File
@@ -16,6 +16,7 @@
.notice {color:#2667E3; margin-left: 12px;}
</style>
<?php js::set('adminLang', $lang->admin);?>
<?php js::set('loadedGD', extension_loaded('gd'));?>
<?php include '../../common/view/header.html.php';?>
<div id='mainMenu' class='clearfix'>
<div class='btn-toolbar pull-left'>
@@ -71,7 +72,8 @@
</tr>
<tr>
<th><?php echo $lang->admin->safe->loginCaptcha?></th>
<td colspan='2'><?php echo html::radio('loginCaptcha', $lang->admin->safe->loginCaptchaList, isset($config->safe->loginCaptcha) ? $config->safe->loginCaptcha : 0)?></td>
<td><?php echo html::radio('loginCaptcha', $lang->admin->safe->loginCaptchaList, isset($config->safe->loginCaptcha) ? $config->safe->loginCaptcha : 0)?></td>
<td class='notice'><?php if(!extension_loaded('gd')) echo $lang->admin->safe->noticeGd;?></td>
</tr>
<tr>
<td colspan='3' class='text-center form-actions'>
@@ -89,6 +91,7 @@ $(function()
{
var mode = $("input[name='mode']:checked").val();
showModeRule(mode);
if(!loadedGD) $('#loginCaptcha1').attr('disabled', true);
});
function showModeRule(mode)
{
+4 -4
View File
@@ -33,7 +33,7 @@
<?php $code = $group . ucfirst($feature);?>
<?php if(strpos(",$disabledFeatures,", ",$code,") !== false) continue;?>
<?php $hasData = true;?>
<?php endForeach;?>
<?php endforeach;?>
<?php if($hasData):?>
<tr>
@@ -52,11 +52,11 @@
<?php echo html::checkbox("module[{$code}]", array('1' => $lang->admin->setModule->{$feature}), $value, "data-code='{$code}'", 'inline');?>
<?php echo html::hidden("module[{$code}][]", $value, $value ? 'disabled' : '');?>
</div>
<?php endForeach;?>
<?php endforeach;?>
</td>
</tr>
<?php endif;?>
<?php endForeach;?>
<?php endforeach;?>
<tr>
<td class='text-middle text-right thWidth'>
<div class="checkbox-primary checkbox-inline checkbox-right check-all">
@@ -68,7 +68,7 @@
</tr>
</tbody>
</table>
</form>`
</form>
</div>
</div>
<?php include '../../common/view/footer.html.php';?>
+3 -2
View File
@@ -34,6 +34,7 @@ class backupModel extends model
public function backFile($backupFile)
{
$zfile = $this->app->loadClass('zfile');
$return = new stdclass();
$return->result = true;
$return->error = '';
@@ -42,10 +43,10 @@ class backupModel extends model
$tmpLogFile = $this->getTmpLogFile($backupFile);
$dataDir = $this->app->getAppRoot() . 'www/data/';
$count = $zfile->getCount($dataDir);
$count = $zfile->getCount($dataDir, array('course'));
file_put_contents($tmpLogFile, json_encode(array('allCount' => $count)));
$result = $zfile->copyDir($dataDir, $backupFile, $logLevel = false, $tmpLogFile);
$result = $zfile->copyDir($dataDir, $backupFile, $logLevel = false, $tmpLogFile, array('course'));
$this->processSummary($backupFile, $result['count'], $result['size'], $result['errorFiles'], $count);
unlink($tmpLogFile);
@@ -19,8 +19,9 @@
<?php $isFirstTab = true;?>
<?php $printMore = false;?>
<?php $i = 0;?>
<?php $maxItem = common::checkNotCN() ? 6 : 8;?>
<?php foreach($hasViewPriv as $type => $bool):?>
<?php if(!common::checkNotCN() or $i <= 6):?>
<?php if($i <= $maxItem):?>
<li<?php if($isFirstTab) {echo ' class="active"';}?>>
<a data-tab href='#assigntomeTab-<?php echo $type;?>' onClick="changeLabel('<?php echo $type;?>')">
<?php echo $type == 'review' ? $lang->my->audit : $lang->block->availableBlocks->$type;?>
@@ -36,7 +37,7 @@
<?php endif;?>
<li<?php if($isFirstTab) {echo ' class="active"';}?>>
<a data-tab href='#assigntomeTab-<?php echo $type;?>' class='<?php echo "$type"?>' onClick="changeMoreBtn('<?php echo $type;?>', this);">
<?php echo $lang->block->availableBlocks->$type;?>
<?php echo $type == 'review' ? $lang->my->audit : $lang->block->availableBlocks->$type;?>
<span class='label label-light label-badge label-assignto <?php echo $type . "-count "; echo $isFirstTab ? '' : 'hidden'; $isFirstTab = false ?>'><?php echo $count[$type];?></span>
</a>
</li>
+2
View File
@@ -328,11 +328,13 @@ $config->bug->datatable->fieldList['os']['title'] = 'os';
$config->bug->datatable->fieldList['os']['fixed'] = 'no';
$config->bug->datatable->fieldList['os']['width'] = '80';
$config->bug->datatable->fieldList['os']['required'] = 'no';
$config->bug->datatable->fieldList['os']['control'] = 'multiple';
$config->bug->datatable->fieldList['browser']['title'] = 'browser';
$config->bug->datatable->fieldList['browser']['fixed'] = 'no';
$config->bug->datatable->fieldList['browser']['width'] = '80';
$config->bug->datatable->fieldList['browser']['required'] = 'no';
$config->bug->datatable->fieldList['browser']['control'] = 'multiple';
$config->bug->datatable->fieldList['mailto']['title'] = 'mailto';
$config->bug->datatable->fieldList['mailto']['fixed'] = 'no';
+39 -23
View File
@@ -227,7 +227,8 @@ class bug extends control
$this->view->product = $product;
$this->view->projectProducts = $this->product->getProducts($this->projectID);
$this->view->productName = $productName;
$this->view->builds = $this->loadModel('build')->getBuildPairs($productID, $branch, 'withreleased');
$this->view->builds = $this->loadModel('build')->getBuildPairs($productID, $branch);
$this->view->releasedBuilds = $this->loadModel('release')->getReleasedBuilds($productID, $branch);
$this->view->modules = $this->tree->getOptionMenu($productID, $viewType = 'bug', $startModuleID = 0, $branch);
$this->view->moduleTree = $moduleTree;
$this->view->moduleName = $moduleID ? $this->tree->getById($moduleID)->name : $this->lang->tree->all;
@@ -558,13 +559,13 @@ class bug extends control
/* If executionID is setted, get builds and stories of this execution. */
if($executionID)
{
$builds = $this->loadModel('build')->getBuildPairs($productID, $branch, 'noempty,noterminate,nodone', $executionID, 'execution');
$builds = $this->loadModel('build')->getBuildPairs($productID, $branch, 'noempty,noterminate,nodone,noreleased', $executionID, 'execution');
$stories = $this->story->getExecutionStoryPairs($executionID);
if(!$projectID) $projectID = $this->dao->select('project')->from(TABLE_EXECUTION)->where('id')->eq($executionID)->fetch('project');
}
else
{
$builds = $this->loadModel('build')->getBuildPairs($productID, $branch, 'noempty,noterminate,nodone,withbranch');
$builds = $this->loadModel('build')->getBuildPairs($productID, $branch, 'noempty,noterminate,nodone,withbranch,noreleased');
$stories = $this->story->getProductStoryPairs($productID, $branch, 0, 'all','id_desc', 0, 'full', 'story', false);
}
@@ -655,6 +656,7 @@ class bug extends control
$this->view->projectExecutionPairs = $this->loadModel('project')->getProjectExecutionPairs();
$this->view->executions = defined('TUTORIAL') ? $this->loadModel('tutorial')->getExecutionPairs() : $executions;
$this->view->builds = $builds;
$this->view->releasedBuilds = $this->loadModel('release')->getReleasedBuilds($productID, $branch);
$this->view->moduleID = (int)$moduleID;
$this->view->projectID = $projectID;
$this->view->projectModel = $projectModel;
@@ -765,7 +767,7 @@ class bug extends control
/* If executionID is setted, get builds and stories of this execution. */
if($executionID)
{
$builds = $this->loadModel('build')->getBuildPairs($productID, $branch, 'noempty', $executionID, 'execution');
$builds = $this->loadModel('build')->getBuildPairs($productID, $branch, 'noempty,noreleased', $executionID, 'execution');
$stories = $this->story->getExecutionStoryPairs($executionID);
$execution = $this->loadModel('execution')->getById($executionID);
if($execution->type == 'kanban')
@@ -785,7 +787,7 @@ class bug extends control
}
else
{
$builds = $this->loadModel('build')->getBuildPairs($productID, $branch, 'noempty');
$builds = $this->loadModel('build')->getBuildPairs($productID, $branch, 'noempty,noreleased');
$stories = $this->story->getProductStoryPairs($productID, $branch);
}
@@ -933,7 +935,7 @@ class bug extends control
$this->view->branchName = $product->type == 'normal' ? '' : zget($branches, $bug->branch, '');
$this->view->users = $this->user->getPairs('noletter');
$this->view->actions = $this->action->getList('bug', $bugID);
$this->view->builds = $this->loadModel('build')->getBuildPairs($productID, 'all', 'withreleased');
$this->view->builds = $this->loadModel('build')->getBuildPairs($productID, 'all');
$this->view->preAndNext = $this->loadModel('common')->getPreAndNextObject('bug', $bugID);
$this->view->product = $product;
@@ -1079,18 +1081,18 @@ class bug extends control
$this->view->position[] = $this->lang->bug->edit;
/* Assign. */
$allBuilds = $this->loadModel('build')->getBuildPairs($productID, 'all', 'noempty,withreleased');
$allBuilds = $this->loadModel('build')->getBuildPairs($productID, 'all', 'noempty');
if($executionID)
{
$openedBuilds = $this->build->getBuildPairs($productID, $bug->branch, 'noempty,noterminate,nodone,withbranch', $executionID, 'execution');
$openedBuilds = $this->build->getBuildPairs($productID, $bug->branch, 'noempty,noterminate,nodone,withbranch,noreleased', $executionID, 'execution');
}
elseif($projectID)
{
$openedBuilds = $this->build->getBuildPairs($productID, $bug->branch, 'noempty,noterminate,nodone,withbranch', $projectID, 'project');
$openedBuilds = $this->build->getBuildPairs($productID, $bug->branch, 'noempty,noterminate,nodone,withbranch,noreleased', $projectID, 'project');
}
else
{
$openedBuilds = $this->build->getBuildPairs($productID, $bug->branch, 'noempty,noterminate,nodone,withbranch');
$openedBuilds = $this->build->getBuildPairs($productID, $bug->branch, 'noempty,noterminate,nodone,withbranch,noreleased');
}
/* Set the openedBuilds list. */
@@ -1163,7 +1165,6 @@ class bug extends control
if($product->shadow) $this->view->project = $this->loadModel('project')->getByShadowProduct($bug->product);
$this->view->bug = $bug;
$this->view->productID = $productID;
$this->view->product = $product;
$this->view->execution = $execution;
$this->view->productBugs = $productBugs;
@@ -1828,15 +1829,15 @@ class bug extends control
$this->bug->checkBugExecutionPriv($bug);
$this->qa->setMenu($this->products, $productID, $bug->branch);
$this->view->title = $this->products[$productID] . $this->lang->colon . $this->lang->bug->resolve;
$this->view->bug = $bug;
$this->view->users = $users;
$this->view->assignedTo = $assignedTo;
$this->view->productBugs = $productBugs;
$this->view->executions = $this->loadModel('product')->getExecutionPairsByProduct($productID, $bug->branch ? "0,{$bug->branch}" : 0, 'id_desc', $projectID, 'stagefilter');
$this->view->builds = $this->loadModel('build')->getBuildPairs($productID, $bug->branch, 'withbranch');
$this->view->actions = $this->action->getList('bug', $bugID);
$this->view->execution = isset($execution) ? $execution : '';
$this->view->title = $this->products[$productID] . $this->lang->colon . $this->lang->bug->resolve;
$this->view->bug = $bug;
$this->view->users = $users;
$this->view->assignedTo = $assignedTo;
$this->view->productBugs = $productBugs;
$this->view->executions = $this->loadModel('product')->getExecutionPairsByProduct($productID, $bug->branch ? "0,{$bug->branch}" : 0, 'id_desc', $projectID, 'stagefilter');
$this->view->builds = $this->loadModel('build')->getBuildPairs($productID, $bug->branch, 'withbranch,noreleased');
$this->view->actions = $this->action->getList('bug', $bugID);
$this->view->execution = isset($execution) ? $execution : '';
$this->display();
}
@@ -1933,7 +1934,7 @@ class bug extends control
$this->view->bug = $bug;
$this->view->users = $this->user->getPairs('noclosed', $bug->resolvedBy);
$this->view->builds = $this->loadModel('build')->getBuildPairs($productID, $bug->branch, 'noempty', 0, 'execution', $bug->openedBuild);
$this->view->builds = $this->loadModel('build')->getBuildPairs($productID, $bug->branch, 'noempty,noreleased', 0, 'execution', $bug->openedBuild);
$this->view->actions = $this->action->getList('bug', $bugID);
$this->display();
@@ -2150,7 +2151,7 @@ class bug extends control
$this->view->bugs = $bugs;
$this->view->users = $this->user->getPairs();
$this->view->builds = $this->loadModel('build')->getBuildPairs($productID, $branch, 'noempty');
$this->view->builds = $this->loadModel('build')->getBuildPairs($productID, $branch, 'noempty,noreleased');
$this->display();
}
@@ -2412,7 +2413,7 @@ class bug extends control
public function ajaxGetBugFieldOptions($productID, $executionID = 0)
{
$modules = $this->loadModel('tree')->getOptionMenu($productID, 'bug');
$builds = $this->loadModel('build')->getBuildPairs($productID, 'all', '', $executionID, 'execution');
$builds = $this->loadModel('build')->getBuildPairs($productID, 'all', 'noreleased', $executionID, 'execution');
$type = $this->lang->bug->typeList;
$pri = $this->lang->bug->priList;
$severity = $this->lang->bug->severityList;
@@ -2500,4 +2501,19 @@ class bug extends control
if($project->model == 'kanban') return print($this->lang->bug->kanban);
return print($this->lang->bug->execution);
}
/**
* Ajax get released builds.
*
* @param int $productID
* @param int|string $branch
* @access public
* @return string
*/
public function ajaxGetReleasedBuilds($productID, $branch = 'all')
{
$releasedBuilds = $this->loadModel('release')->getReleasedBuilds($productID, $branch);
return print(helper::jsonEncode($releasedBuilds));
}
}
+2 -2
View File
@@ -38,13 +38,13 @@ function setOpenedBuilds(link, index)
var selected = $('#buildBox' + index).find('select').val();
$('#buildBox' + index).html(builds);
$('#buildBox' + index).find('select').val(selected);
$('#openedBuilds' + index + '_chosen').remove();
$('#pickerDropMenu-pk_openedBuild' + index).remove();
$('#openedBuilds' + index).next('.picker').remove();
$('#buildBox' + index + ' select').removeClass('select-3');
$('#buildBox' + index + ' select').addClass('select-1');
$('#buildBox' + index + ' select').attr('name','openedBuilds[' + index + '][]');
$('#buildBox' + index + ' select').attr('id','openedBuilds' + index);
$('#buildBox' + index + ' select').chosen();
$('#buildBox' + index + ' select').picker({optionRender: markReleasedBuilds, dropWidth: 'auto'});
index++;
if($('#executions' + index).val() != 'ditto') break;
+99 -26
View File
@@ -19,6 +19,27 @@ $(function()
}
});
if($('#openedBuild').length || $('#resolvedBuild').length || $('[name^=openedBuilds]').length)
{
$.get(createLink('bug', 'ajaxGetReleasedBuilds', 'productID=' + productID), function(data){releasedBuilds = data;}, 'json');
$('#openedBuild, #resolvedBuild, [name^=openedBuilds]').picker({optionRender: markReleasedBuilds, dropWidth: 'auto'});
}
function markReleasedBuilds($option)
{
var build = $option.attr('data-value');
if($.inArray(build, releasedBuilds) != -1)
{
if(!$option.find('.label-released').length)
{
var optionText = $option.find('.picker-option-text').html();
$option.find('.picker-option-text').replaceWith("<p class='picker-option-text no-margin'><span class='label label-released label-primary label-outline'>" + releasedBuild + "</span> " + optionText + "</p>");
}
}
}
/**
* Load all fields.
*
@@ -178,6 +199,8 @@ function loadAllExecutionBuilds(executionID, productID, buildBox)
{
branch = $('#branch').val();
if(typeof(branch) == 'undefined') branch = 0;
$.get(createLink('bug', 'ajaxGetReleasedBuilds', 'productID=' + productID), function(data){releasedBuilds = data;}, 'json');
if(page == 'create')
{
oldOpenedBuild = $('#openedBuild').val() ? $('#openedBuild').val() : 0;
@@ -186,10 +209,10 @@ function loadAllExecutionBuilds(executionID, productID, buildBox)
{
if(!data) data = '<select id="openedBuild" name="openedBuild" class="form-control" multiple=multiple></select>';
$('#openedBuild').replaceWith(data);
$('#openedBuild_chosen').remove();
$('#pickerDropMenu-pk_openedBuild').remove();
$('#openedBuild').next('.picker').remove();
$("#openedBuild").chosen();
notice();
$("#openedBuild").picker({optionRender: markReleasedBuilds, dropWidth: 'auto'});
})
}
if(page == 'edit')
@@ -197,12 +220,12 @@ function loadAllExecutionBuilds(executionID, productID, buildBox)
if(buildBox == 'openedBuildBox')
{
link = createLink('build', 'ajaxGetExecutionBuilds', 'executionID=' + executionID + '&productID=' + productID + '&varName=openedBuild&build=' + oldOpenedBuild + '&branch=' + branch + '&index=0&needCreate=true&type=all');
$('#openedBuildBox').load(link, function(){$(this).find('select').chosen()});
$('#openedBuildBox').load(link, function(){$(this).find('select').picker({optionRender: markReleasedBuilds, dropWidth: 'auto'})});
}
if(buildBox == 'resolvedBuildBox')
{
link = createLink('build', 'ajaxGetProductBuilds', 'productID=' + productID + '&varName=resolvedBuild&build=' + oldResolvedBuild + '&branch=' + branch + '&index=0&type=all');
$('#resolvedBuildBox').load(link, function(){$(this).find('select').chosen()});
$('#resolvedBuildBox').load(link, function(){$(this).find('select').picker({optionRender: markReleasedBuilds, dropWidth: 'auto'})});
}
}
}
@@ -219,6 +242,9 @@ function loadAllProductBuilds(productID, buildBox)
{
branch = $('#branch').val();
if(typeof(branch) == 'undefined') branch = 0;
$.get(createLink('bug', 'ajaxGetReleasedBuilds', 'productID=' + productID), function(data){releasedBuilds = data;}, 'json');
if(page == 'create')
{
link = createLink('build', 'ajaxGetProductBuilds', 'productID=' + productID + '&varName=openedBuild&build=' + oldOpenedBuild + '&branch=' + branch + '&index=0&type=all');
@@ -226,10 +252,10 @@ function loadAllProductBuilds(productID, buildBox)
{
if(!data) data = '<select id="openedBuild" name="openedBuild" class="form-control" multiple=multiple></select>';
$('#openedBuild').replaceWith(data);
$('#openedBuild_chosen').remove();
$('#pickerDropMenu-pk_openedBuild').remove();
$('#openedBuild').next('.picker').remove();
$("#openedBuild").chosen();
notice();
$("#openedBuild").picker({optionRender: markReleasedBuilds, dropWidth: 'auto'});
})
}
if(page == 'edit')
@@ -237,12 +263,12 @@ function loadAllProductBuilds(productID, buildBox)
if(buildBox == 'openedBuildBox')
{
link = createLink('build', 'ajaxGetProductBuilds', 'productID=' + productID + '&varName=openedBuild&build=' + oldOpenedBuild + '&branch=' + branch + '&index=0&type=all');
$('#openedBuildBox').load(link, function(){$(this).find('select').chosen()});
$('#openedBuildBox').load(link, function(){$(this).find('select').picker({optionRender: markReleasedBuilds, dropWidth: 'auto'})});
}
if(buildBox == 'resolvedBuildBox')
{
link = createLink('build', 'ajaxGetProductBuilds', 'productID=' + productID + '&varName=resolvedBuild&build=' + oldResolvedBuild + '&branch=' + branch + '&index=0&type=all');
$('#resolvedBuildBox').load(link, function(){$(this).find('select').chosen()});
$('#resolvedBuildBox').load(link, function(){$(this).find('select').picker({optionRender: markReleasedBuilds, dropWidth: 'auto'})});
}
}
}
@@ -294,7 +320,7 @@ function loadProductStories(productID)
function loadProductProjects(productID)
{
required = $('#project_chosen').hasClass('required');
branch = $('#branch').val();
branch = $('#branch').val();
if(typeof(branch) == 'undefined') branch = 0;
link = createLink('product', 'ajaxGetProjects', 'productID=' + productID + '&branch=' + branch + '&projectID=' + oldProjectID);
$('#projectBox').load(link, function()
@@ -437,23 +463,25 @@ function loadProductBuilds(productID)
if(typeof(oldOpenedBuild) == 'undefined') oldOpenedBuild = 0;
link = createLink('build', 'ajaxGetProductBuilds', 'productID=' + productID + '&varName=openedBuild&build=' + oldOpenedBuild + '&branch=' + branch);
$.get(createLink('bug', 'ajaxGetReleasedBuilds', 'productID=' + productID), function(data){releasedBuilds = data;}, 'json');
if(page == 'create')
{
$.get(link, function(data)
{
if(!data) data = '<select id="openedBuild" name="openedBuild" class="form-control" multiple=multiple></select>';
$('#openedBuild').replaceWith(data);
$('#openedBuild_chosen').remove();
$('#pickerDropMenu-pk_openedBuild').remove();
$('#openedBuild').next('.picker').remove();
$("#openedBuild").chosen();
notice();
$("#openedBuild").picker({optionRender: markReleasedBuilds, dropWidth: 'auto'});
})
}
else
{
$('#openedBuildBox').load(link, function(){$(this).find('select').chosen()});
$('#openedBuildBox').load(link, function(){$(this).find('select').picker({optionRender: markReleasedBuilds, dropWidth: 'auto'})});
link = createLink('build', 'ajaxGetProductBuilds', 'productID=' + productID + '&varName=resolvedBuild&build=' + oldResolvedBuild + '&branch=' + branch);
$('#resolvedBuildBox').load(link, function(){$(this).find('select').chosen()});
$('#resolvedBuildBox').load(link, function(){$(this).find('select').picker({optionRender: markReleasedBuilds, dropWidth: 'auto'})});
}
}
@@ -466,9 +494,12 @@ function loadProductBuilds(productID)
*/
function loadExecutionRelated(executionID)
{
executionID = parseInt(executionID);
executionID = parseInt(executionID);
currentProjectID = $('#project').val() == 'undefined' ? 0 : $('#project').val();
if(executionID)
{
if(currentProjectID == 0) loadProjectByExecutionID(executionID);
loadExecutionTasks(executionID);
loadExecutionStories(executionID);
loadExecutionBuilds(executionID);
@@ -477,7 +508,6 @@ function loadExecutionRelated(executionID)
}
else
{
var currentProjectID = $('#project').val() == 'undefined' ? 0 : $('#project').val();
var currentProductID = $('#product').val();
$('#taskIdBox').innerHTML = '<select id="task"></select>'; // Reset the task.
@@ -496,6 +526,43 @@ function loadExecutionRelated(executionID)
}
}
/**
* Load a project by execution id.
*
* @param executionID $executionID
* @access public
* @return void
*/
function loadProjectByExecutionID(executionID)
{
link = createLink('project', 'ajaxGetPairsByExecution', 'executionID=' + executionID, 'json');
required = $('#project_chosen').hasClass('required');
productID = $('#product').val();
$.post(link, function(data)
{
var originProject = $('#project').html();
if($('#project').find('option[value="' + data.id + '"]').length > 0)
{
$('#project').find('option[value="' + data.id + '"]').attr('selected', 'selected');
originProject = $('#project').html();
$('#project').replaceWith('<select id="project" name="project" class="form-control" onchange="loadProductExecutions(' + productID + ', this.value)">' + originProject + '</select>');
}
else
{
var newProject = '<option value="' + data.id + '" data-keys="' + data.namePinyin + '" selected="selected">' + data.name + '</option>';
$('#project').replaceWith('<select id="project" name="project" class="form-control" onchange="loadProductExecutions(' + productID + ', this.value)">' + originProject + newProject+ '</select>');
}
$('#project_chosen').remove();
$('#project').next('.picker').remove();
$('#project').chosen();
if(required) $('#project_chosen').addClass('required');
}, 'json')
}
/**
* Load execution tasks.
*
@@ -552,28 +619,30 @@ function loadProjectBuilds(projectID)
var productID = $('#product').val();
var oldOpenedBuild = $('#openedBuild').val() ? $('#openedBuild').val() : 0;
$.get(createLink('bug', 'ajaxGetReleasedBuilds', 'productID=' + productID), function(data){releasedBuilds = data;}, 'json');
if(page == 'create')
{
var link = createLink('build', 'ajaxGetProjectBuilds', 'projectID=' + projectID + '&productID=' + productID + '&varName=openedBuild&build=&branch=' + branch);
$.get(link, function(data)
{
if(!data) data = '<select id="openedBuild" name="openedBuild" class="form-control" multiple=multiple></select>';
if(!data) data = '<select id="openedBuild" name="openedBuild" class="form-control picker-select" multiple=multiple></select>';
$('#openedBuild').replaceWith(data);
$('#openedBuild').val(oldOpenedBuild);
$('#openedBuild_chosen').remove();
$('#pickerDropMenu-pk_openedBuild').remove();
$('#openedBuild').next('.picker').remove();
$("#openedBuild").chosen();
notice();
$("#openedBuild").picker({optionRender: markReleasedBuilds, dropWidth: 'auto'});
})
}
else
{
var link = createLink('build', 'ajaxGetProjectBuilds', 'projectID=' + projectID + '&productID=' + productID + '&varName=openedBuild&build=' + oldOpenedBuild + '&branch=' + branch);
$('#openedBuildBox').load(link, function(){$(this).find('select').val(oldOpenedBuild).chosen()});
$('#openedBuildBox').load(link, function(){$(this).find('select').val(oldOpenedBuild).picker({optionRender: markReleasedBuilds, dropWidth: 'auto'})});
var oldResolvedBuild = $('#resolvedBuild').val() ? $('#resolvedBuild').val() : 0;
var link = createLink('build', 'ajaxGetProductBuilds', 'productID=' + productID + '&varName=resolvedBuild&build=' + oldResolvedBuild + '&branch=' + branch);
$('#resolvedBuildBox').load(link, function(){$(this).find('select').val(oldResolvedBuild).chosen()});
$('#resolvedBuildBox').load(link, function(){$(this).find('select').val(oldResolvedBuild).picker({optionRender: markReleasedBuilds, dropWidth: 'auto'})});
}
}
@@ -595,28 +664,30 @@ function loadExecutionBuilds(executionID, num)
if(typeof(branch) == 'undefined') var branch = 0;
if(typeof(productID) == 'undefined') var productID = 0;
$.get(createLink('bug', 'ajaxGetReleasedBuilds', 'productID=' + productID), function(data){releasedBuilds = data;}, 'json');
if(page == 'create')
{
link = createLink('build', 'ajaxGetExecutionBuilds', 'executionID=' + executionID + '&productID=' + productID + '&varName=openedBuild&build=' + oldOpenedBuild + "&branch=" + branch + "&index=0&needCreate=true");
$.get(link, function(data)
{
if(!data) data = '<select id="openedBuild" name="openedBuild" class="form-control" multiple=multiple></select>';
if(!data) data = '<select id="openedBuild" name="openedBuild" class="form-control picker-select" multiple=multiple></select>';
$('#openedBuild').replaceWith(data);
$('#openedBuild').val(oldOpenedBuild);
$('#openedBuild_chosen').remove();
$('#pickerDropMenu-pk_openedBuild').remove();
$('#openedBuild').next('.picker').remove();
$("#openedBuild").chosen();
notice();
$("#openedBuild").picker({optionRender: markReleasedBuilds, dropWidth: 'auto'});
})
}
else
{
link = createLink('build', 'ajaxGetExecutionBuilds', 'executionID=' + executionID + '&productID=' + productID + '&varName=openedBuild&build=' + oldOpenedBuild + '&branch=' + branch + '&index=0&needCreate=false&type=normal&number=' + num);
$('#openedBuildBox' + num).load(link, function(){$(this).find('select').val(oldOpenedBuild).chosen()});
$('#openedBuildBox' + num).load(link, function(){$(this).find('select').val(oldOpenedBuild).picker({optionRender: markReleaseBuilds, dropWidth: 'auto'})});
oldResolvedBuild = $('#resolvedBuild').val() ? $('#resolvedBuild').val() : 0;
link = createLink('build', 'ajaxGetProductBuilds', 'productID=' + productID + '&varName=resolvedBuild&build=' + oldResolvedBuild + '&branch=' + branch);
$('#resolvedBuildBox').load(link, function(){$(this).find('select').val(oldResolvedBuild).chosen()});
$('#resolvedBuildBox').load(link, function(){$(this).find('select').val(oldResolvedBuild).picker({optionRender: markReleasedBuilds, dropWidth: 'auto'})});
}
}
@@ -776,7 +847,9 @@ function notice()
if(page == 'edit') return;
$('#buildBoxActions').empty().hide();
if($('#openedBuild').find('option').length <= 1)
var itemCount = $('#openedBuild').find('option').length;
if($('#openedBuild').attr('data-items') != undefined) var itemCount = $('#openedBuild').attr('data-items');
if(itemCount <= 1)
{
var html = '';
if($('#execution').length == 0 || $('#execution').val() == 0)
+2 -1
View File
@@ -124,6 +124,7 @@ $(function()
});
});
$(window).unload(function(){
$(window).unload(function()
{
if(blockID) window.parent.refreshBlock($('#block' + blockID));
});
+1 -5
View File
@@ -81,8 +81,6 @@ class bugModel extends model
->remove('files,labels,uid,oldTaskID,contactListMenu,region,lane,ticket')
->get();
if($bug->execution != 0) $bug->project = $this->dao->select('project')->from(TABLE_EXECUTION)->where('id')->eq($bug->execution)->fetch('project');
/* Check repeat bug. */
$result = $this->loadModel('common')->removeDuplicate('bug', $bug, "product={$bug->product}");
if($result and $result['stop']) return array('status' => 'exists', 'id' => $result['duplicate']);
@@ -219,8 +217,6 @@ class bugModel extends model
if(isset($data->lanes[$i])) $bug->laneID = $data->lanes[$i];
if($bug->execution != 0) $bug->project = $this->dao->select('project')->from(TABLE_EXECUTION)->where('id')->eq($bug->execution)->fetch('project');
/* Assign the bug to the person in charge of the module. */
if(!empty($moduleOwners[$bug->module]))
{
@@ -1623,7 +1619,7 @@ class bugModel extends model
$this->config->bug->search['params']['module']['values'] = $modules;
$this->config->bug->search['params']['execution']['values'] = $this->loadModel('product')->getExecutionPairsByProduct($productID, 0, 'id_desc', $projectID);
$this->config->bug->search['params']['severity']['values'] = array(0 => '') + $this->lang->bug->severityList; //Fix bug #939.
$this->config->bug->search['params']['openedBuild']['values'] = $this->loadModel('build')->getBuildPairs($productID, 'all', 'withbranch');
$this->config->bug->search['params']['openedBuild']['values'] = $this->loadModel('build')->getBuildPairs($productID, 'all', 'withbranch|releasetag');
$this->config->bug->search['params']['resolvedBuild']['values'] = $this->config->bug->search['params']['openedBuild']['values'];
if($this->session->currentProductType == 'normal')
{
+5 -1
View File
@@ -37,7 +37,7 @@
<?php $this->printExtendFields($bug, 'table');?>
<tr>
<th><?php echo $lang->bug->openedBuild;?></th>
<td colspan='2'><?php echo html::select('openedBuild[]', $builds, $bug->openedBuild, 'size=4 multiple=multiple class="form-control chosen"');?></td>
<td colspan='2'><?php echo html::select('openedBuild[]', $builds, $bug->openedBuild, 'size=4 multiple=multiple class="form-control picker-select"');?></td>
</tr>
<tr>
<th><?php echo $lang->comment;?></th>
@@ -56,4 +56,8 @@
<div class='main'><?php include '../../common/view/action.html.php';?></div>
</div>
</div>
<?php
js::set('productID', $bug->product);
js::set('releasedBuild', $lang->build->releasedBuild);
?>
<?php include '../../common/view/footer.html.php';?>
+6 -4
View File
@@ -13,6 +13,8 @@
<?php
include '../../common/view/header.html.php';
js::set('requiredFields', $config->bug->create->requiredFields);
js::set('productID', $productID);
js::set('releasedBuild', $lang->build->releasedBuild);
?>
<?php
$visibleFields = array();
@@ -107,7 +109,7 @@ foreach(explode(',', $config->bug->create->requiredFields) as $field)
<td><?php echo html::select("modules[$i]", $moduleOptionMenu, $moduleID, "class='form-control chosen'");?></td>
<td class='<?php echo zget($visibleFields, 'project', ' hidden')?> projectBox' style='overflow:visible'><?php echo html::select("projects[$i]", $projects, $projectID, "class='form-control chosen' onchange='loadProductExecutionsByProject($productID, this.value, $i)'");?></td>
<td class='<?php echo zget($visibleFields, 'execution', ' hidden')?> executionBox' style='overflow:visible'><?php echo html::select("executions[$i]", $executions, $executionID, "class='form-control chosen' onchange='loadExecutionBuilds($productID, this.value, $i)'");?></td>
<td id='buildBox<?php echo $i;?>'><?php echo html::select("openedBuilds[$i][]", $builds, 'trunk', "class='form-control chosen' multiple");?></td>
<td id='buildBox<?php echo $i;?>'><?php echo html::select("openedBuilds[$i][]", $builds, 'trunk', "class='form-control picker-select' multiple");?></td>
<td>
<div class='input-group'>
<div class="input-control has-icon-right">
@@ -163,7 +165,7 @@ foreach(explode(',', $config->bug->create->requiredFields) as $field)
<td><?php echo html::select("modules[$i]", $moduleOptionMenu, $moduleID, "class='form-control chosen'");?></td>
<td class='<?php echo zget($visibleFields, 'project', ' hidden')?> projectBox' style='overflow:visible'><?php echo html::select("projects[$i]", $projects, $projectID, "class='form-control chosen' onchange = 'loadProductExecutionsByProject($productID, this.value, $i)'");?></td>
<td class='<?php echo zget($visibleFields, 'execution', ' hidden')?> executionBox' style='overflow:visible'><?php echo html::select("executions[$i]", $executions, $executionID, "class='form-control chosen' onchange='loadExecutionBuilds($productID, this.value, $i)'");?></td>
<td id='buildBox<?php echo $i;?>'><?php echo html::select("openedBuilds[$i][]", $builds, '', "class='form-control chosen' multiple");?></td>
<td id='buildBox<?php echo $i;?>'><?php echo html::select("openedBuilds[$i][]", $builds, '', "class='form-control picker-select' multiple");?></td>
<td>
<div class='input-group'>
<div class="input-control has-icon-right">
@@ -224,7 +226,7 @@ foreach(explode(',', $config->bug->create->requiredFields) as $field)
<td><?php echo html::select("modules[%s]", $moduleOptionMenu, $moduleID, "class='form-control chosen'");?></td>
<td class='<?php echo zget($visibleFields, 'project', ' hidden')?> projectBox' style='overflow:visible'><?php echo html::select("projects[%s]", $projects, $projectID, "class='form-control chosen' onchange = 'loadProductExecutionsByProject($productID, this.value, \"%s\")'");?></td>
<td class='<?php echo zget($visibleFields, 'execution', ' hidden')?> executionBox' style='overflow:visible'><?php echo html::select("executions[%s]", $executions, $executionID, "class='form-control chosen' onchange='loadExecutionBuilds($productID, this.value, \"%s\")'");?></td>
<td id='buildBox%s'><?php echo html::select("openedBuilds[%s][]", $builds, '', "class='form-control chosen' multiple");?></td>
<td id='buildBox%s'><?php echo html::select("openedBuilds[%s][]", $builds, '', "class='form-control picker-select' multiple");?></td>
<td>
<div class='input-group'>
<div class="input-control has-icon-right">
@@ -267,7 +269,7 @@ foreach(explode(',', $config->bug->create->requiredFields) as $field)
<td><?php echo html::select("modules[$i]", $moduleOptionMenu, $moduleID, "class='form-control chosen'");?></td>
<td class='<?php echo zget($visibleFields, 'project', ' hidden')?> projectBox' style='overflow:visible'><?php echo html::select("projects[$i]", $projects, $projectID, "class='form-control chosen' onchange = 'loadProductExecutionsByProject($productID, this.value, $i)'");?></td>
<td class='<?php echo zget($visibleFields, 'execution', ' hidden')?> executionBox' style='overflow:visible'><?php echo html::select("executions[$i]", $executions, $executionID, "class='form-control chosen' onchange='loadExecutionBuilds($productID, this.value, $i)'");?></td>
<td id='buildBox<?php echo $i;?>'><?php echo html::select("openedBuilds[$i][]", $builds, '', "class='form-control chosen' multiple");?></td>
<td id='buildBox<?php echo $i;?>'><?php echo html::select("openedBuilds[$i][]", $builds, '', "class='form-control picker-select' multiple");?></td>
<td>
<div class='input-group'>
<div class="input-control has-icon-right">
+1 -1
View File
@@ -328,7 +328,7 @@ $currentBrowseType = isset($lang->bug->mySelects[$browseType]) && in_array($brow
{
$actionLink = $this->createLink('bug', 'batchResolve', "resolution=fixed&resolvedBuild=$key");
echo "<li class='option' data-key='$key'>";
echo html::a('javascript:;', $build, '', "onclick=\"setFormAction('$actionLink', 'hiddenwin', '#bugList')\"");
echo html::a('javascript:;', (in_array($key, $releasedBuilds) ? "<span class='label label-primary label-outline'>{$lang->build->releasedBuild}</span> " : '') . $build, '', "onclick=\"setFormAction('$actionLink', 'hiddenwin', '#bugList')\"");
echo "</li>";
}
echo "</ul>";
+3 -1
View File
@@ -30,6 +30,8 @@ js::set('tab', $this->app->tab);
js::set('requiredFields', $config->bug->create->requiredFields);
js::set('showFields', $showFields);
js::set('projectExecutionPairs', $projectExecutionPairs);
js::set('productID', $productID);
js::set('releasedBuild', $lang->build->releasedBuild);
if($this->app->tab == 'execution') js::set('objectID', zget($execution, 'id', ''));
if($this->app->tab == 'project') js::set('objectID', $projectID);
?>
@@ -128,7 +130,7 @@ if($this->app->tab == 'project') js::set('objectID', $projectID);
<td>
<div class='input-group' id='buildBox'>
<span class="input-group-addon"><?php echo $lang->bug->openedBuild?></span>
<?php echo html::select('openedBuild[]', $builds, empty($buildID) ? '' : $buildID, "multiple=multiple class='chosen form-control'");?>
<?php echo html::select('openedBuild[]', $builds, empty($buildID) ? '' : $buildID, "multiple=multiple class='picker-select form-control' data-items='" . count($builds) . "'");?>
<span class='input-group-addon fix-border' id='buildBoxActions'></span>
<div class='input-group-btn'><?php echo html::commonButton($lang->bug->allBuilds, "class='btn' id='all' data-toggle='tooltip' onclick='loadAllBuilds()'")?></div>
</div>
+7 -5
View File
@@ -30,6 +30,8 @@ js::set('bugID' , $bug->id);
js::set('bugBranch' , $bug->branch);
js::set('isClosedBug' , $bug->status == 'closed');
js::set('projectExecutionPairs' , $projectExecutionPairs);
js::set('productID' , $product->id);
js::set('releasedBuild' , $lang->build->releasedBuild);
if($this->app->tab == 'execution') js::set('objectID', $bug->execution);
if($this->app->tab == 'project') js::set('objectID', $bug->project);
?>
@@ -100,7 +102,7 @@ if($this->app->tab == 'project') js::set('objectID', $bug->project);
<th class='w-80px'><?php echo $lang->bug->product;?></th>
<td>
<div class='input-group'>
<?php echo html::select('product', $products, $productID, "onchange='loadAll(this.value)' class='form-control chosen'");?>
<?php echo html::select('product', $products, $product->id, "onchange='loadAll(this.value)' class='form-control chosen'");?>
<?php if($product->type != 'normal') echo html::select('branch', $branchTagOption, $bug->branch, "onchange='loadBranch();' class='form-control'");?>
</div>
</td>
@@ -114,9 +116,9 @@ if($this->app->tab == 'project') js::set('objectID', $bug->project);
if(count($moduleOptionMenu) == 1)
{
echo "<span class='input-group-addon'>";
echo html::a($this->createLink('tree', 'browse', "rootID=$productID&view=bug&currentModuleID=0&branch=$bug->branch", '', true), $lang->tree->manage, '', "class='text-primary' data-toggle='modal' data-type='iframe' data-width='95%'");
echo html::a($this->createLink('tree', 'browse', "rootID={$product->id}&view=bug&currentModuleID=0&branch=$bug->branch", '', true), $lang->tree->manage, '', "class='text-primary' data-toggle='modal' data-type='iframe' data-width='95%'");
echo '&nbsp; ';
echo html::a("javascript:void(0)", $lang->refreshIcon, '', "class='refresh' title='$lang->refresh' onclick='loadProductModules($productID)'");
echo html::a("javascript:void(0)", $lang->refreshIcon, '', "class='refresh' title='$lang->refresh' onclick='loadProductModules($product->id)'");
echo '</span>';
}
?>
@@ -240,7 +242,7 @@ if($this->app->tab == 'project') js::set('objectID', $bug->project);
<th><?php echo $lang->bug->openedBuild;?></th>
<td>
<div id='openedBuildBox' class='input-group'>
<?php echo html::select('openedBuild[]', $openedBuilds, $bug->openedBuild, 'size=4 multiple=multiple class="chosen form-control"');?>
<?php echo html::select('openedBuild[]', $openedBuilds, $bug->openedBuild, 'size=4 multiple=multiple class="picker-select form-control"');?>
<span class='input-group-btn'><?php echo html::commonButton($lang->bug->allBuilds, "class='btn' onclick='loadAllBuilds(this)'")?></span>
</div>
</td>
@@ -257,7 +259,7 @@ if($this->app->tab == 'project') js::set('objectID', $bug->project);
<th><?php echo $lang->bug->resolvedBuild;?></th>
<td>
<div id='resolvedBuildBox' class='input-group'>
<?php echo html::select('resolvedBuild', $resolvedBuilds, $bug->resolvedBuild, "class='form-control chosen'");?>
<?php echo html::select('resolvedBuild', $resolvedBuilds, $bug->resolvedBuild, "class='form-control picker-select'");?>
<span class='input-group-btn'><?php echo html::commonButton($lang->bug->allBuilds, "class='btn' onclick='loadAllBuilds(this)'")?></span>
</div>
</td>
+4 -3
View File
@@ -14,8 +14,9 @@
<?php include '../../common/view/kindeditor.html.php';?>
<?php include '../../common/view/datepicker.html.php';?>
<?php
js::set('page' , 'resolve');
js::set('productID' , $bug->product);
js::set('page', 'resolve');
js::set('productID', $bug->product);
js::set('releasedBuild', $lang->build->releasedBuild);
?>
<div id='mainContent' class='main-content'>
<div class='center-block'>
@@ -49,7 +50,7 @@ js::set('productID' , $bug->product);
</div>
</td>
<td>
<div id='resolvedBuildBox'><?php echo html::select('resolvedBuild', $builds, '', "class='form-control chosen'");?></div>
<div id='resolvedBuildBox'><?php echo html::select('resolvedBuild', $builds, '', "class='form-control picker-select'");?></div>
<div id='newBuildBox' class='hidden required'><?php echo html::input('buildName', '', "class='form-control' placeholder='{$lang->bug->placeholder->newBuildName}'");?></div>
</td>
<td>
+19 -13
View File
@@ -385,32 +385,38 @@ class build extends control
* @param string|int $branch
* @param int $index the index of batch create bug.
* @param string $type get all builds or some builds belong to normal releases and executions are not done.
* @param string $extra
* @access public
* @return string
*/
public function ajaxGetProductBuilds($productID, $varName, $build = '', $branch = 'all', $index = 0, $type = 'normal')
public function ajaxGetProductBuilds($productID, $varName, $build = '', $branch = 'all', $index = 0, $type = 'normal', $extra = '')
{
$isJsonView = $this->app->getViewType() == 'json';
if($varName == 'openedBuild' )
{
$params = ($type == 'all') ? 'noempty,withbranch' : 'noempty,noterminate,nodone,withbranch';
$params = ($type == 'all') ? 'noempty,withbranch,noreleased' : 'noempty,noterminate,nodone,withbranch,noreleased';
$builds = $this->build->getBuildPairs($productID, $branch, $params, 0, 'project', $build);
if($isJsonView) return print(json_encode($builds));
return print(html::select($varName . '[]', $builds, $build, 'size=4 class=form-control multiple'));
}
if($varName == 'openedBuilds' )
{
$builds = $this->build->getBuildPairs($productID, $branch, 'noempty', 0, 'project', $build);
$builds = $this->build->getBuildPairs($productID, $branch, 'noempty,noreleased', 0, 'project', $build);
if($isJsonView) return print(json_encode($builds));
return print(html::select($varName . "[$index][]", $builds, $build, 'size=4 class=form-control multiple'));
}
if($varName == 'resolvedBuild')
{
$params = ($type == 'all') ? 'withbranch' : 'noterminate,nodone,withbranch';
$params = ($type == 'all') ? 'withbranch,noreleased' : 'noterminate,nodone,withbranch,noreleased';
$builds = $this->build->getBuildPairs($productID, $branch, $params, 0, 'project', $build);
if($isJsonView) return print(json_encode($builds));
return print(html::select($varName, $builds, $build, "class='form-control'"));
}
$builds = $this->build->getBuildPairs($productID, $branch, $type, 0, 'project', $build);
if(strpos($extra, 'multiple') !== false) $varName .= '[]';
if($isJsonView) return print(json_encode($builds));
return print(html::select($varName, $builds, $build, "class='form-control chosen' $extra"));
}
/**
@@ -434,7 +440,7 @@ class build extends control
{
if(empty($projectID)) return $this->ajaxGetProductBuilds($productID, $varName, $build, $branch, $index, $type);
$params = ($type == 'all') ? 'noempty,withbranch' : 'noempty,noterminate,nodone,withbranch';
$params = ($type == 'all') ? 'noempty,withbranch,noreleased' : 'noempty,noterminate,nodone,withbranch,noreleased';
$builds = $this->build->getBuildPairs($productID, $branch, $params, $projectID, 'project', $build);
if($isJsonView) return print(json_encode($builds));
return print(html::select($varName . '[]', $builds , '', 'size=4 class=form-control multiple'));
@@ -443,13 +449,13 @@ class build extends control
{
if(empty($projectID)) return $this->ajaxGetProductBuilds($productID, $varName, $build, $branch, $index, $type);
$params = ($type == 'all') ? 'withbranch' : 'noterminate,nodone,withbranch';
$params = ($type == 'all') ? 'withbranch,noreleased' : 'noterminate,nodone,withbranch,noreleased';
$builds = $this->build->getBuildPairs($productID, $branch, $params, $projectID, 'project', $build);
if($isJsonView) return print(json_encode($builds));
return print(html::select($varName, $builds, $build, "class='form-control'"));
}
if(empty($projectID)) return $this->ajaxGetProductBuilds($productID, $varName, $build, $branch, $index, $type);
if(empty($projectID)) return $this->ajaxGetProductBuilds($productID, $varName, $build, $branch, $index, $type, $extra);
$builds = $this->build->getBuildPairs($productID, $branch, $type, $projectID, 'project', $build, false);
if(strpos($extra, 'multiple') !== false) $varName .= '[]';
if($isJsonView) return print(json_encode($builds));
@@ -478,7 +484,7 @@ class build extends control
{
if(empty($executionID)) return $this->ajaxGetProductBuilds($productID, $varName, $build, $branch, $index, $type);
$params = ($type == 'all') ? 'noempty' : 'noempty,noterminate,nodone';
$params = ($type == 'all') ? 'noempty,noreleased' : 'noempty,noterminate,nodone,noreleased';
$builds = $this->build->getBuildPairs($productID, $branch, $params, $executionID, 'execution', $build);
if($isJsonView) return print(json_encode($builds));
@@ -489,7 +495,7 @@ class build extends control
{
if(empty($executionID)) return $this->ajaxGetProductBuilds($productID, $varName, $build, $branch, $index, $type);
$builds = $this->build->getBuildPairs($productID, $branch, 'noempty', $executionID, 'execution', $build);
$builds = $this->build->getBuildPairs($productID, $branch, 'noempty,noreleased', $executionID, 'execution', $build);
if($isJsonView) return print(json_encode($builds));
return print(html::select($varName . "[$index][]", $builds , $build, 'size=4 class=form-control multiple'));
}
@@ -497,14 +503,14 @@ class build extends control
{
if(empty($executionID)) return $this->ajaxGetProductBuilds($productID, $varName, $build, $branch, $index, $type);
$params = ($type == 'all') ? '' : 'noterminate,nodone';
$params = ($type == 'all') ? ',noreleased' : 'noterminate,nodone,noreleased';
$builds = $this->build->getBuildPairs($productID, $branch, $params, $executionID, 'execution', $build);
if($isJsonView) return print(json_encode($builds));
return print(html::select($varName, $builds, $build, "class='form-control'"));
}
if($varName == 'testTaskBuild')
{
$builds = $this->build->getBuildPairs($productID, $branch, 'noempty,notrunk', $executionID, 'execution');
$builds = $this->build->getBuildPairs($productID, $branch, 'noempty,notrunk', $executionID, 'execution', '', false);
if($isJsonView) return print(json_encode($builds));
if(empty($builds))
@@ -543,7 +549,7 @@ class build extends control
{
$lastBuild = $this->build->getLast($executionID, $projectID);
if($lastBuild)
{
{
echo "<div class='help-block'> &nbsp; " . $this->lang->build->last . ": <a class='code label label-badge label-light' id='lastBuildBtn'>" . $lastBuild->name . "</a></div>";
}
else
@@ -714,7 +720,7 @@ class build extends control
$this->config->bug->search['params']['plan']['values'] = $this->loadModel('productplan')->getPairsForStory($build->product, $build->branch, 'skipParent');
$this->config->bug->search['params']['module']['values'] = $this->loadModel('tree')->getOptionMenu($build->product, 'bug', 0, $build->branch);
$this->config->bug->search['params']['execution']['values'] = $this->loadModel('product')->getExecutionPairsByProduct($build->product, $build->branch, 'id_desc', $this->session->project);
$this->config->bug->search['params']['openedBuild']['values'] = $this->build->getBuildPairs($build->product, $branch = 'all', $params = '');
$this->config->bug->search['params']['openedBuild']['values'] = $this->build->getBuildPairs($build->product, $branch = 'all', $params = 'releasetag');
$this->config->bug->search['params']['resolvedBuild']['values'] = $this->config->bug->search['params']['openedBuild']['values'];
unset($this->config->bug->search['fields']['product']);
+2
View File
@@ -36,6 +36,7 @@ $lang->build->execution = $lang->executionCommon;
$lang->build->integrated = 'Integrated';
$lang->build->singled = 'Singled';
$lang->build->builds = 'Included Builds';
$lang->build->releasedBuild = 'Released Build';
$lang->build->name = 'Name';
$lang->build->date = 'Datum';
$lang->build->builder = 'Builder';
@@ -60,6 +61,7 @@ $lang->build->notice->changeProduct = "The {$lang->SRCommon}, bug, or the vers
$lang->build->notice->changeExecution = "The version of the submitted test order cannot be modified {$lang->executionCommon}";
$lang->build->notice->changeBuilds = "The version of the submitted test order cannot be modified builds";
$lang->build->notice->autoRelation = "The completed requirements, resolved bugs, and generated bugs under the relevant version will be automatically associated with the project version";
$lang->build->notice->createTest = "The execution of this version has been deleted, and the test cannot be submitted";
$lang->build->finishStories = " %s {$lang->SRCommon} sind abgeschlossen.";
$lang->build->resolvedBugs = ' %s Bugs sind gelöst.';
+2
View File
@@ -36,6 +36,7 @@ $lang->build->execution = $lang->executionCommon;
$lang->build->integrated = 'Integrated';
$lang->build->singled = 'Singled';
$lang->build->builds = 'Included Builds';
$lang->build->releasedBuild = 'Released Build';
$lang->build->name = 'Name';
$lang->build->date = 'Date';
$lang->build->builder = 'Builder';
@@ -60,6 +61,7 @@ $lang->build->notice->changeProduct = "The {$lang->SRCommon}, bug, or the vers
$lang->build->notice->changeExecution = "The version of the submitted test order cannot be modified {$lang->executionCommon}";
$lang->build->notice->changeBuilds = "The version of the submitted test order cannot be modified builds";
$lang->build->notice->autoRelation = "The completed requirements, resolved bugs, and generated bugs under the relevant version will be automatically associated with the project version";
$lang->build->notice->createTest = "The execution of this version has been deleted, and the test cannot be submitted";
$lang->build->finishStories = " Finished {$lang->SRCommon} %s";
$lang->build->resolvedBugs = ' Resolved Bug %s';
+2
View File
@@ -36,6 +36,7 @@ $lang->build->execution = $lang->executionCommon;
$lang->build->integrated = 'Integrated';
$lang->build->singled = 'Singled';
$lang->build->builds = 'Included Builds';
$lang->build->releasedBuild = 'Released Build';
$lang->build->name = 'Nom';
$lang->build->date = 'Date';
$lang->build->builder = 'Builder';
@@ -60,6 +61,7 @@ $lang->build->notice->changeProduct = "The {$lang->SRCommon}, bug, or the vers
$lang->build->notice->changeExecution = "The version of the submitted test order cannot be modified {$lang->executionCommon}";
$lang->build->notice->changeBuilds = "The version of the submitted test order cannot be modified builds";
$lang->build->notice->autoRelation = "The completed requirements, resolved bugs, and generated bugs under the relevant version will be automatically associated with the project version";
$lang->build->notice->createTest = "The execution of this version has been deleted, and the test cannot be submitted";
$lang->build->finishStories = " {$lang->SRCommon} Terminées %s";
$lang->build->resolvedBugs = ' Bugs Résolus %s';
+1
View File
@@ -54,6 +54,7 @@ $lang->build->notice->changeProduct = "The {$lang->SRCommon}, bug, or the vers
$lang->build->notice->changeExecution = "The version of the submitted test order cannot be modified {$lang->executionCommon}";
$lang->build->notice->changeBuilds = "The version of the submitted test order cannot be modified builds";
$lang->build->notice->autoRelation = "The completed requirements, resolved bugs, and generated bugs under the relevant version will be automatically associated with the project version";
$lang->build->notice->createTest = "The execution of this version has been deleted, and the test cannot be submitted";
$lang->build->finishStories = " {$lang->SRCommon} đã kết thúc %s";
$lang->build->resolvedBugs = ' Bug đã giải quyết %s';
+3 -1
View File
@@ -28,7 +28,7 @@ $lang->build->confirmUnlinkBug = "您确认移除该Bug吗?";
$lang->build->basicInfo = '基本信息';
$lang->build->id = 'ID';
$lang->build->product = $lang->productCommon;
$lang->build->product = '所属' . $lang->productCommon;
$lang->build->project = '所属项目';
$lang->build->branch = '平台/分支';
$lang->build->branchName = '所属%s';
@@ -36,6 +36,7 @@ $lang->build->execution = '所属' . $lang->executionCommon;
$lang->build->integrated = '集成版本';
$lang->build->singled = '单一版本';
$lang->build->builds = '包含版本';
$lang->build->releasedBuild = '发布版本';
$lang->build->name = '名称编号';
$lang->build->date = '打包日期';
$lang->build->builder = '构建者';
@@ -60,6 +61,7 @@ $lang->build->notice->changeProduct = "已经关联{$lang->SRCommon}、Bug或
$lang->build->notice->changeExecution = "提交测试单的版本,不能修改其所属{$lang->executionCommon}";
$lang->build->notice->changeBuilds = "提交测试单的版本,不能修改关联版本";
$lang->build->notice->autoRelation = "相关版本下完成的需求、解决的Bug、产生的Bug将会自动关联到项目版本中";
$lang->build->notice->createTest = "该版本所属执行已删除,不能提交测试";
$lang->build->finishStories = " 本次共完成 %s 个{$lang->SRCommon}";
$lang->build->resolvedBugs = ' 本次共解决 %s 个Bug';
+44 -5
View File
@@ -181,6 +181,38 @@ class buildModel extends model
return $this->getExecutionBuilds($executionID, 'bysearch', $buildQuery);
}
/**
* Filter linked stories or bugs builds.
*
* @param array $buildIdList
* @access public
* @return array
*/
public function filterLinked($buildIdList)
{
$linkeds = array();
$buildList = $this->getByList($buildIdList);
foreach($buildList as $build)
{
if(!$build->execution && !empty($build->builds))
{
$childBuilds = $this->getByList($build->builds);
foreach($childBuilds as $childBuild)
{
$childBuild->stories = trim($childBuild->stories, ',');
$childBuild->bugs = trim($childBuild->bugs, ',');
if($childBuild->stories) $build->stories .= ',' . $childBuild->stories;
if($childBuild->bugs) $build->bugs .= ',' . $childBuild->bugs;
}
}
if(!empty($build->stories) or !empty($build->bugs)) $linkeds[$build->id] = $build->id;
}
return $linkeds;
}
/**
* Get story builds.
*
@@ -202,7 +234,7 @@ class buildModel extends model
*
* @param int|array $products
* @param string|int $branch
* @param string $params noempty|notrunk|noterminate|withbranch|hasproject|noDeleted|singled|withreleased, can be a set of them
* @param string $params noempty|notrunk|noterminate|withbranch|hasproject|noDeleted|singled|noreleased|releasedtag, can be a set of them
* @param string|int $objectID
* @param string $objectType
* @param int|array $buildIdList
@@ -227,7 +259,7 @@ class buildModel extends model
}
$branchs = strpos($params, 'separate') === false ? "0,$branch" : $branch;
$allBuilds = $this->dao->select('t1.id, t1.name, t1.date, t1.deleted, t2.status as objectStatus, t3.id as releaseID, t3.status as releaseStatus, t4.name as branchName, t5.type as productType')->from(TABLE_BUILD)->alias('t1')
$allBuilds = $this->dao->select('t1.id, t1.name, t1.execution, t1.date, t1.deleted, t2.status as objectStatus, t3.id as releaseID, t3.status as releaseStatus, t4.name as branchName, t5.type as productType')->from(TABLE_BUILD)->alias('t1')
->beginIF($objectType === 'execution')->leftJoin(TABLE_EXECUTION)->alias('t2')->on('t1.execution = t2.id')->fi()
->beginIF($objectType === 'project')->leftJoin(TABLE_PROJECT)->alias('t2')->on('t1.project = t2.id')->fi()
->leftJoin(TABLE_RELEASE)->alias('t3')->on("FIND_IN_SET(t1.id,t3.build)")
@@ -243,6 +275,8 @@ class buildModel extends model
->beginIF($branch !== 'all')->andWhere('t1.branch')->in("$branchs")->fi()
->orderBy('t1.date desc, t1.id desc')->fetchAll('id');
$deletedExecutions = $this->dao->select('id, deleted')->from(TABLE_EXECUTION)->where('type')->eq('sprint')->andWhere('deleted')->eq('1')->fetchPairs();
/* Set builds and filter done executions and terminate releases. */
$builds = array();
$buildIdList = array();
@@ -251,6 +285,7 @@ class buildModel extends model
{
if(empty($build->releaseID) and (strpos($params, 'nodone') !== false) and ($build->objectStatus === 'done')) continue;
if((strpos($params, 'noterminate') !== false) and ($build->releaseStatus === 'terminate')) continue;
if((strpos($params, 'withexecution') !== false) and $build->execution and isset($executions[$build->execution])) continue;
if($build->deleted == 1) $build->name .= ' (' . $this->lang->build->deleted . ')';
$branchName = $build->branchName ? $build->branchName : $this->lang->branch->main;
@@ -292,12 +327,13 @@ class buildModel extends model
$releaseName = $release->name;
$branchName = $release->branchName ? $release->branchName : $this->lang->branch->main;
if($release->productType != 'normal') $releaseName = (strpos($params, 'withbranch') !== false ? $branchName . '/' : '') . $releaseName;
if(strpos($params, 'releasetag') !== false) $releaseName = "[{$this->lang->build->releasedBuild}] " . $releaseName;
$builds[$release->date][$release->shadow] = $releaseName;
foreach(explode(',', trim($release->build, ',')) as $buildID)
{
if(!isset($allBuilds[$buildID])) continue;
$build = $allBuilds[$buildID];
if(strpos($params, 'withreleased') === false) unset($builds[$build->date][$buildID]);
if(strpos($params, 'noreleased') !== false) unset($builds[$build->date][$buildID]);
}
}
}
@@ -621,7 +657,7 @@ class buildModel extends model
{
$action = strtolower($action);
if($module == 'testtask' && $action == 'create') return !!$object->execution;
if($module == 'testtask' and $action == 'create') return !$object->executionDeleted;
return true;
}
@@ -651,11 +687,14 @@ class buildModel extends model
{
$executionID = $tab == 'execution' ? $extraParams['executionID'] : $build->execution;
$execution = $this->loadModel('execution')->getByID($executionID);
$build->executionDeleted = $execution ? $execution->deleted : 0;
$testtaskApp = (!empty($execution->type) and $execution->type == 'kanban') ? 'data-app="qa"' : "data-app='{$tab}'";
if(common::hasPriv($module, 'linkstory') and common::canBeChanged('build', $build)) $menu .= $this->buildMenu($module, 'view', "{$params}&type=story&link=true", $build, $type, 'link', '', '', '', "data-app={$tab}", $this->lang->build->linkStory);
$menu .= $this->buildMenu('testtask', 'create', "product=$build->product&execution={$executionID}&build=$build->id&projectID=$build->project", $build, $type, 'bullhorn', '', '', '', $testtaskApp);
$title = ($execution and $execution->deleted === '1') ? $this->lang->build->notice->createTest : '';
$menu .= $this->buildMenu('testtask', 'create', "product=$build->product&execution={$executionID}&build=$build->id&projectID=$build->project", $build, $type, 'bullhorn', '', '', '', $testtaskApp, $title);
if($tab == 'execution' and !empty($execution->type) and $execution->type != 'kanban') $menu .= $this->buildMenu('execution', 'bug', "execution={$extraParams['executionID']}&productID={$extraParams['productID']}&branchID=all&orderBy=status&build=$build->id", $build, $type, '', '', '', '', $this->lang->execution->viewBug);
if($tab == 'project' or empty($execution->type) or $execution->type == 'kanban') $menu .= $this->buildMenu($module, 'view', "{$params}&type=generatedBug", $build, $type, 'bug', '', '', '', "data-app='$tab'", $this->lang->project->bug);
+5 -1
View File
@@ -26,7 +26,11 @@ tbody tr td:first-child input {display: none;}
<div id='mainMenu' class='clearfix'>
<div class='btn-toolbar pull-left'>
<?php $browseLink = $this->session->buildList ? $this->session->buildList : $this->createLink('execution', 'build', "executionID=$build->execution");?>
<?php common::printBack($browseLink, 'btn btn-secondary');?>
<?php
$dataApp = strpos($browseLink, 'release') !== false ? 'data-app=product' : '';
if(strpos($browseLink, 'projectrelease') !== false) $dataApp = 'data-app=project';
?>
<?php common::printBack($browseLink, 'btn btn-secondary', $dataApp);?>
<div class='divider'></div>
<div class='page-title'>
<span title='<?php echo $build->name;?>'>
+2
View File
@@ -2365,6 +2365,8 @@ EOD;
*/
public function checkSafeFile()
{
if($this->app->isContainer()) return false;
if($this->app->getModuleName() == 'upgrade' and $this->session->upgrading) return false;
$statusFile = $this->app->getAppRoot() . 'www' . DIRECTORY_SEPARATOR . 'data' . DIRECTORY_SEPARATOR . 'ok.txt';
+1
View File
@@ -249,6 +249,7 @@ $lang->doc->errorEmptyLib = 'No data in document library.';
$lang->doc->confirmUpdateContent = 'You have a document that is not saved from last time. Do you want to continue editing it?';
$lang->doc->selectLibType = 'Please select a type of doc library.';
$lang->doc->noLibreOffice = 'You does not have access to office conversion settings!';
$lang->doc->errorParentChapter = 'The parent chapter cannot be its own chapter or sub chapter!';
$lang->doc->noticeAcl['lib']['product']['default'] = 'Users who can access the selected product can access it.';
$lang->doc->noticeAcl['lib']['product']['custom'] = 'Users who can access the selected product or users in the whiltelist can access it.';
+1
View File
@@ -249,6 +249,7 @@ $lang->doc->errorEmptyLib = 'No data in document library.';
$lang->doc->confirmUpdateContent = 'You have a document that is not saved from last time. Do you want to continue editing it?';
$lang->doc->selectLibType = 'Please select a type of doc library.';
$lang->doc->noLibreOffice = 'You does not have access to office conversion settings!';
$lang->doc->errorParentChapter = 'The parent chapter cannot be its own chapter or sub chapter!';
$lang->doc->noticeAcl['lib']['product']['default'] = 'Users who can access the selected product can access it.';
$lang->doc->noticeAcl['lib']['product']['custom'] = 'Users who can access the selected product or users in the whiltelist can access it.';
+1
View File
@@ -249,6 +249,7 @@ $lang->doc->errorEmptyLib = 'No data in document library.';
$lang->doc->confirmUpdateContent = 'You have a document that is not saved from last time. Do you want to continue editing it?';
$lang->doc->selectLibType = 'Please select a type of doc library.';
$lang->doc->noLibreOffice = 'You does not have access to office conversion settings!';
$lang->doc->errorParentChapter = 'The parent chapter cannot be its own chapter or sub chapter!';
$lang->doc->noticeAcl['lib']['product']['default'] = 'Les utilisateurs qui ont accès au Product peuvent y accéder.';
$lang->doc->noticeAcl['lib']['product']['custom'] = 'Les utilisateurs qui ont accès au Product ou les utilisateurs de la Liste Blanche peuvent y accéder.';
+1
View File
@@ -249,6 +249,7 @@ $lang->doc->errorEmptyLib = '文档库暂无数据。';
$lang->doc->confirmUpdateContent = '检查到您有未保存的文档内容,是否继续编辑?';
$lang->doc->selectLibType = '请选择文档库类型';
$lang->doc->noLibreOffice = '您还没有office转换设置访问权限!';
$lang->doc->errorParentChapter = '父章节不能是自身章节及子章节!';
$lang->doc->noticeAcl['lib']['product']['default'] = '有所选产品访问权限的用户可以访问。';
$lang->doc->noticeAcl['lib']['product']['custom'] = '有所选产品访问权限或白名单里的用户可以访问。';
+10
View File
@@ -821,6 +821,16 @@ class docModel extends model
->remove('comment,files,labels,uid,contactListMenu')
->get();
if($doc->type == 'chapter' and $doc->parent)
{
$parentDoc = $this->dao->select('*')->from(TABLE_DOC)->where('id')->eq((int)$doc->parent)->fetch();
if(strpos($parentDoc->path, ",$docID,") !== false)
{
dao::$errors['parent'] = $this->lang->doc->errorParentChapter;
return false;
}
}
if(!empty($doc->acl) and $doc->acl == 'private') $doc->users = $oldDoc->addedBy;
$oldDocContent = $this->dao->select('*')->from(TABLE_DOCCONTENT)->where('doc')->eq($docID)->andWhere('version')->eq($oldDoc->version)->fetch();
+2 -2
View File
@@ -1097,7 +1097,7 @@ class execution extends control
$modules = $this->tree->getAllModulePairs('bug');
/* Get module tree.*/
$extra = array('executionID' => $executionID, 'orderBy' => $orderBy, 'type' => $type, 'build' => $build, 'branchID' => $branch);
$extra = array('projectID' => $executionID, 'orderBy' => $orderBy, 'type' => $type, 'build' => $build, 'branchID' => $branch);
if($executionID and empty($productID) and count($products) > 1)
{
$moduleTree = $this->tree->getBugTreeMenu($executionID, $productID, 0, array('treeModel', 'createBugLink'), $extra);
@@ -1205,7 +1205,7 @@ class execution extends control
}
else
{
$moduleTree = $this->tree->getTreeMenu($productID, 'case', 0, array('treeModel', 'createCaseLink'), array('executionID' => $executionID, 'productID' => $productID), $branchID);
$moduleTree = $this->tree->getTreeMenu($productID, 'case', 0, array('treeModel', 'createCaseLink'), array('projectID' => $executionID, 'productID' => $productID), $branchID);
}
$tree = $moduleID ? $this->tree->getByID($moduleID) : '';
+5 -3
View File
@@ -67,7 +67,8 @@ function renderUserAvatar(user, objectType, objectID, size, objectStatus)
if(objectType == 'bug' && !priv.canAssignBug) return $noPrivAvatar;
var realname = user.realname ? user.realname : user.account;
return objectStatus == 'closed' ? '' : $('<a class="avatar has-text ' + avatarSizeClass + ' avatar-circle iframe" title="' + realname + '" href="' + link + '"/>').avatar({user: user});
var title = user.title ? user.title : realname;
return objectStatus == 'closed' ? '' : $('<a class="avatar has-text ' + avatarSizeClass + ' avatar-circle iframe" title="' + title + '" href="' + link + '"/>').avatar({user: user});
}
/**
@@ -286,8 +287,9 @@ function renderTaskItem(item, $item, col)
{
var priHtml = '<span class="info info-pri' + (item.pri ? ' label-pri label-pri-' + item.pri : '') + '" title="' + item.pri + '">' + item.pri + '</span>';
var hoursHtml = scaleSize <= 1 && item.status != 'wait' ? ('<span class="info info-estimate text-muted">' + taskLang.leftAB + ' ' + item.left + 'h</span>') : ('<span class="info info-estimate text-muted">' + taskLang.estimateAB + ' ' + item.estimate + 'h</span>');
var avatarHtml = renderUserAvatar(item.assignedTo, 'task', item.id, '', col.type);
var avatarHtml = '';
if(item.assignedTo == '' && item.mode == 'multi') avatarHtml = renderUserAvatar({title: item.teamMembers, realname: teamWords}, 'task', item.id, '', col.type);
else avatarHtml = renderUserAvatar(item.assignedTo, 'task', item.id, '', col.type);
var $infos = $item.find('.infos');
if(!$infos.length) $infos = $('<div class="infos"></div>');
$infos.html([priHtml, hoursHtml].join(''));
+3 -1
View File
@@ -347,7 +347,7 @@ $lang->execution->timeSummary = '<div class="table-col"><div class="cle
$lang->execution->groupSummaryAB = "<div>Aufgaben <strong>%s</strong></div><div><span class='text-muted'>Wartend</span> %s &nbsp; <span class='text-muted'>In Arbeit</span> %s</div><div>Geplant <strong>%s</strong></div><div><span class='text-muted'>Genutzt</span> %s &nbsp; <span class='text-muted'>Rest</span> %s</div>";
$lang->execution->wbs = "Aufgaben aufteilen";
$lang->execution->batchWBS = "Mehrere aufteilen";
$lang->execution->howToUpdateBurn = "<a href='http://api.zentao.net/goto.php?item=burndown&lang=zh-cn' target='_blank' title='Wie wird der Burndown Chart aktualisiert?' class='btn btn-link'>Hilfe <i class='icon icon-help'></i></a>";
$lang->execution->howToUpdateBurn = "<a href='https://api.zentao.pm/goto.php?item=burndown' target='_blank' title='Wie wird der Burndown Chart aktualisiert?' class='btn btn-link'>Hilfe <i class='icon icon-help'></i></a>";
$lang->execution->whyNoStories = "Keine Story kann verknüpft werden. Bitte prüfen Sie ob ein Story mit {$lang->executionCommon} verknüpft ist {$lang->productCommon} und stellen Sie sicher das diese geprüft ist.";
$lang->execution->projectNoStories = "No story can be linked. Please check whether there is any story in project and make sure it has been reviewed.";
$lang->execution->productStories = "{$lang->executionCommon} verknüpfte Story ist ein Subset von {$lang->productCommon}, welche nur nach überprüfung verknüpft werden kann. Bitte <a href='%s'> Story verknüpfen</a>。";
@@ -480,6 +480,8 @@ $lang->execution->kanbanViewList['story'] = "{$lang->SRCommon}";
$lang->execution->kanbanViewList['bug'] = 'Bug';
$lang->execution->kanbanViewList['task'] = 'Task';
$lang->execution->teamWords = 'Team';
$lang->kanbanSetting = new stdclass();
$lang->kanbanSetting->noticeReset = 'Möchten Sie die Einstellungen des Kanbans zurücksetzen?';
$lang->kanbanSetting->optionList['0'] = 'Verstecken';
+2
View File
@@ -480,6 +480,8 @@ $lang->execution->kanbanViewList['story'] = "{$lang->SRCommon}";
$lang->execution->kanbanViewList['bug'] = 'Bug';
$lang->execution->kanbanViewList['task'] = 'Task';
$lang->execution->teamWords = 'Team';
$lang->kanbanSetting = new stdclass();
$lang->kanbanSetting->noticeReset = 'Do you want to reset Kanban?';
$lang->kanbanSetting->optionList['0'] = 'Hide';
+2
View File
@@ -480,6 +480,8 @@ $lang->execution->kanbanViewList['story'] = "{$lang->SRCommon}";
$lang->execution->kanbanViewList['bug'] = 'Bug';
$lang->execution->kanbanViewList['task'] = 'Task';
$lang->execution->teamWords = 'Team';
$lang->kanbanSetting = new stdclass();
$lang->kanbanSetting->noticeReset = 'Voulez-vous réinitialiser le tableau Kanban ?';
$lang->kanbanSetting->optionList['0'] = 'Masquer';
+2
View File
@@ -436,4 +436,6 @@ $lang->execution->statusColorList['doing'] = '#0BD986';
$lang->execution->statusColorList['suspended'] = '#fdc137';
$lang->execution->statusColorList['closed'] = '#838A9D';
$lang->execution->teamWords = 'đội';
$lang->execution->boardColorList = array('#32C5FF', '#006AF1', '#9D28B2', '#FF8F26', '#7FBB00', '#424BAC', '#66c5f8', '#EC2761');
+2
View File
@@ -480,6 +480,8 @@ $lang->execution->kanbanViewList['story'] = "{$lang->SRCommon}看板";
$lang->execution->kanbanViewList['bug'] = 'Bug看板';
$lang->execution->kanbanViewList['task'] = '任务看板';
$lang->execution->teamWords = '团队';
$lang->kanbanSetting = new stdclass();
$lang->kanbanSetting->noticeReset = '是否恢复看板默认设置?';
$lang->kanbanSetting->optionList['0'] = '隐藏';
+2
View File
@@ -453,4 +453,6 @@ $lang->execution->statusColorList['doing'] = '#0BD986';
$lang->execution->statusColorList['suspended'] = '#fdc137';
$lang->execution->statusColorList['closed'] = '#838A9D';
$lang->execution->teamWords = '團隊';
$lang->execution->boardColorList = array('#32C5FF', '#006AF1', '#9D28B2', '#FF8F26', '#7FBB00', '#424BAC', '#66c5f8', '#EC2761');
+2 -1
View File
@@ -161,7 +161,8 @@
</div>
</td>
</tr>
<?php if(isset($project->model) and $project->model == 'scrum') $hidden = '';?>
<?php $hidden = 'hide'?>
<?php if(isset($project->model) and !empty($project->hasProduct) and $project->model == 'scrum') $hidden = '';?>
<tr class="<?php echo $hidden?>">
<th><?php echo $lang->execution->linkPlan;?></th>
<td colspan="3" id="plansBox">
@@ -231,4 +231,5 @@ js::set('priv',
<?php js::set('orderBy', $storyOrder);?>
<?php js::set('defaultMinColWidth', $this->config->minColWidth);?>
<?php js::set('defaultMaxColWidth', $this->config->maxColWidth);?>
<?php js::set('teamWords', $lang->execution->teamWords);?>
<?php include '../../common/view/footer.html.php';?>
+3 -4
View File
@@ -780,11 +780,10 @@ class extensionModel extends model
/**
* Update an extension.
*
* @param string $extension
* @param string $status
* @param array $files
* @param string $extension
* @param array|object $data
* @access public
* @return void
* @return int
*/
public function updateExtension($extension, $data)
{
+9 -23
View File
@@ -221,34 +221,20 @@ class file extends control
$this->view->fields = $this->post->fields;
$this->view->rows = $this->post->rows;
$this->host = common::getSysURL();
$kind = $this->post->kind;
switch($this->post->kind)
foreach($this->view->rows as $row)
{
case 'task':
foreach($this->view->rows as $row)
foreach($row as &$field)
{
$row->name = html::a($this->host . $this->createLink('task', 'view', "taskID=$row->id"), $row->name);
if(empty($field)) continue;
$field = preg_replace('/ src="{([0-9]+)(\.(\w+))?}" /', ' src="' . $this->host . helper::createLink('file', 'read', "fileID=$1", "$3") . '" ', $field);
}
break;
case 'story':
foreach($this->view->rows as $row)
{
$row->title= html::a($this->host . $this->createLink('story', 'view', "storyID=$row->id"), $row->title);
}
break;
case 'bug':
foreach($this->view->rows as $row)
{
$row->title= html::a($this->host . $this->createLink('bug', 'view', "bugID=$row->id"), $row->title);
}
break;
case 'testcase':
foreach($this->view->rows as $row)
{
$row->title= html::a($this->host . $this->createLink('testcase', 'view', "caseID=$row->id"), $row->title);
}
break;
if(in_array($kind, array('story', 'bug', 'testcase'))) $row->title = html::a($this->host . $this->createLink($kind, 'view', "{$kind}ID=$row->id"), $row->title);
if($kind == 'task') $row->name = html::a($this->host . $this->createLink('task', 'view', "taskID=$row->id"), $row->name);
}
$this->view->fileName = $this->post->fileName;
$output = $this->parse('file', 'export2Html');
+2 -2
View File
@@ -667,7 +667,6 @@ class fileModel extends model
public function pasteImage($data, $uid = '', $safe = false)
{
if(empty($data)) return '';
$data = str_replace('\"', '"', $data);
$dataLength = strlen($data);
if(ini_get('pcre.backtrack_limit') < $dataLength) ini_set('pcre.backtrack_limit', $dataLength);
@@ -676,7 +675,8 @@ class fileModel extends model
{
foreach($out[3] as $key => $base64Image)
{
$extension = strtolower($out[2][$key]);
$base64Image = str_replace('\"', '"', $base64Image);
$extension = strtolower($out[2][$key]);
if(!in_array($extension, $this->config->file->imageExtensions)) helper::end();
$imageData = base64_decode($base64Image);
+4 -1
View File
@@ -266,7 +266,10 @@ class install extends control
$this->setting->setItem('system.common.safe.changeWeak', '1');
$this->setting->setItem('system.common.global.cron', 1);
if(strpos($this->app->getClientLang(), 'zh') === 0) $this->loadModel('api')->createDemoData($this->lang->api->zentaoAPI, 'http://' . $_SERVER['HTTP_HOST'] . $this->app->config->webRoot . 'api.php/v1', '16.0');
$httpType = (isset($_SERVER["HTTPS"]) && $_SERVER["HTTPS"] == 'on') ? 'https' : 'http';
if(isset($_SERVER['HTTP_X_FORWARDED_PROTO']) and strtolower($_SERVER['HTTP_X_FORWARDED_PROTO']) == 'https') $httpType = 'https';
if(isset($_SERVER['REQUEST_SCHEME']) and strtolower($_SERVER['REQUEST_SCHEME']) == 'https') $httpType = 'https';
if(strpos($this->app->getClientLang(), 'zh') === 0) $this->loadModel('api')->createDemoData($this->lang->api->zentaoAPI, "{$httpType}://{$_SERVER['HTTP_HOST']}" . $this->app->config->webRoot . 'api.php/v1', '16.0');
return print(js::locate(inlink('step6'), 'parent'));
}
+2
View File
@@ -1514,6 +1514,8 @@ class kanbanModel extends model
$cardData['status'] = $object->status;
$cardData['left'] = $object->left;
$cardData['estStarted'] = $object->estStarted;
$cardData['mode'] = $object->mode;
if($object->mode == 'multi') $cardData['teamMembers'] = $object->teamMembers;
}
else
{
+8 -1
View File
@@ -114,7 +114,6 @@ class messageModel extends model
$this->loadModel('webhook')->send($objectType, $objectID, $actionType, $actionID, $actor);
}
}
if(isset($messageSetting['message']))
{
$actions = $messageSetting['message']['setting'];
@@ -201,6 +200,14 @@ class messageModel extends model
if(!empty($notifyPersons)) $toList = implode(',', $notifyPersons);
}
if(empty($toList) and $objectType == 'task' and $object->mode == 'multi')
{
$teamMembers = $this->loadModel('task')->getTeamMembers($object->id);
$toList = array_filter($teamMembers, function($account){
return $account != $this->app->user->account;
});
$toList = implode(',', $toList);
}
if($toList == 'closed') $toList = '';
if($objectType == 'feedback' and $object->status == 'replied') $toList = ',' . $object->openedBy . ',';
+2 -2
View File
@@ -697,8 +697,8 @@ 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($productID, $branch = 'all', $params = '');
$this->config->bug->search['params']['resolvedBuild']['values'] = $this->loadModel('build')->getBuildPairs($productID, $branch = 'all', $params = '');
$this->config->bug->search['params']['openedBuild']['values'] = $this->loadModel('build')->getBuildPairs($productID, $branch = 'all', $params = 'releasetag');
$this->config->bug->search['params']['resolvedBuild']['values'] = $this->config->bug->search['params']['openedBuild']['values'];
unset($this->config->bug->search['fields']['product']);
if($product->type == 'normal')
+2
View File
@@ -1 +1,3 @@
.tip {margin-top: 10px;}
.table-form>tbody>tr>th {white-space: nowrap; !important}
.table-form>tbody>tr>td {width: 75%; !important}
+2 -2
View File
@@ -640,7 +640,7 @@ class myModel extends model
$this->config->bug->search['params']['plan']['values'] = $this->loadModel('productplan')->getPairs();
$this->config->bug->search['params']['module']['values'] = $this->loadModel('tree')->getAllModulePairs();
$this->config->bug->search['params']['severity']['values'] = array(0 => '') + $this->lang->bug->severityList;
$this->config->bug->search['params']['openedBuild']['values'] = $this->loadModel('build')->getBuildPairs($products);
$this->config->bug->search['params']['openedBuild']['values'] = $this->loadModel('build')->getBuildPairs($products, 'all', 'releasetag');
$this->config->bug->search['params']['resolvedBuild']['values'] = $this->config->bug->search['params']['openedBuild']['values'];
$this->loadModel('search')->setSearchParams($this->config->bug->search);
@@ -911,7 +911,7 @@ class myModel extends model
$this->config->ticket->search['params']['module']['values'] = array('' => '') + $this->loadModel('tree')->getAllModulePairs();
$grantProducts = $this->loadModel('feedback')->getGrantProducts();
$productIDlist = array_keys($grantProducts);
$this->config->ticket->search['params']['openedBuild']['values'] = $this->loadModel('build')->getBuildPairs($productIDlist);
$this->config->ticket->search['params']['openedBuild']['values'] = $this->loadModel('build')->getBuildPairs($productIDlist, 'all', 'releasetag');
$this->loadModel('search')->setSearchParams($this->config->ticket->search);
}
+23 -6
View File
@@ -271,13 +271,30 @@ class product extends control
/* Display status of branch. */
$branchOption = array();
$branchTagOption = array();
if($product and $product->type != 'normal')
if(!$product and $isProjectStory)
{
$branches = $this->loadModel('branch')->getList($productID, $projectID, 'all');
foreach($branches as $branchInfo)
/* Get branch display under multiple products. */
foreach($projectProducts as $projectProduct)
{
$branchOption[$branchInfo->id] = $branchInfo->name;
$branchTagOption[$branchInfo->id] = $branchInfo->name . ($branchInfo->status == 'closed' ? ' (' . $this->lang->branch->statusList['closed'] . ')' : '');
if($projectProduct and $projectProduct->type != 'normal')
{
$branches = $this->loadModel('branch')->getList($projectProduct->id, $projectID, 'all');
foreach($branches as $branchInfo) $branchOptions[$projectProduct->id][$branchInfo->id] = $branchInfo->name;
}
}
$this->view->branchOptions = $branchOptions;
}
else
{
if($product and $product->type != 'normal')
{
$branches = $this->loadModel('branch')->getList($productID, $projectID, 'all');
foreach($branches as $branchInfo)
{
$branchOption[$branchInfo->id] = $branchInfo->name;
$branchTagOption[$branchInfo->id] = $branchInfo->name . ($branchInfo->status == 'closed' ? ' (' . $this->lang->branch->statusList['closed'] . ')' : '');
}
}
}
@@ -1374,7 +1391,7 @@ class product extends control
$this->view->title = $this->lang->product->line;
$this->view->position[] = $this->lang->product->line;
$this->view->programs = array('') + $this->loadModel('program')->getTopPairs();
$this->view->programs = array('') + $this->loadModel('program')->getTopPairs('', 'withDeleted');
$this->view->lines = $this->product->getLines();
$this->display();
}
+1
View File
@@ -357,6 +357,7 @@ js::set('vision', $this->config->vision);
<?php foreach($stories as $story):?>
<tr data-id='<?php echo $story->id?>' data-estimate='<?php echo $story->estimate?>' <?php if(!empty($story->children)) echo "data-children=" . count($story->children);?> data-cases='<?php echo zget($storyCases, $story->id, 0);?>'>
<?php $story->from = $from;?>
<?php if(!empty($branchOptions) and isset($branchOptions[$story->product])) $branchOption = $branchOptions[$story->product];?>
<?php if($this->app->getViewType() == 'xhtml'):?>
<?php
foreach($setting as $key => $value)
+3
View File
@@ -820,6 +820,9 @@ class productplan extends control
$this->config->bug->search['params']['openedBuild']['values'] = $this->loadModel('build')->getBuildPairs($productID, $branch = 'all', $params = '');
$this->config->bug->search['params']['resolvedBuild']['values'] = $this->build->getBuildPairs($productID, $branch = 'all', $params = '');
$this->config->bug->search['params']['module']['values'] = $this->loadModel('tree')->getOptionMenu($plan->product, 'bug', 0, 'all');
$this->config->bug->search['params']['openedBuild']['values'] = $this->loadModel('build')->getBuildPairs($productID, $branch = 'all', $params = 'releasetag');
$this->config->bug->search['params']['resolvedBuild']['values'] = $this->config->bug->search['params']['openedBuild']['values'];
$this->config->bug->search['params']['module']['values'] = $this->loadModel('tree')->getOptionMenu($plan->product, 'bug', 0, 'all');
$this->config->bug->search['params']['project']['values'] = $this->product->getProjectPairsByProduct($productID, $plan->branch);
unset($this->config->bug->search['fields']['product']);
+18 -2
View File
@@ -1031,15 +1031,31 @@ class programModel extends model
*/
public function getTopPairs($model = '', $mode = '', $isQueryAll = false)
{
return $this->dao->select('id,name')->from(TABLE_PROGRAM)
$topPairs = $this->dao->select('id,name')->from(TABLE_PROGRAM)
->where('type')->eq('program')
->andWhere('grade')->eq(1)
->beginIF(strpos($mode, 'noclosed') !== false)->andWhere('status')->ne('closed')->fi()
->beginIF(!$isQueryAll)->andWhere('id')->in($this->app->user->view->programs)->fi()
->andWhere('deleted')->eq(0)
->beginIF(strpos($mode, 'withDeleted') === false)->andWhere('deleted')->eq(0)->fi()
->beginIF($model)->andWhere('model')->eq($model)->fi()
->orderBy('`order` asc')
->fetchPairs();
if(strpos($mode, 'withDeleted') !== false)
{
$deletedTopPairs = $this->dao->select('id, name')->from(TABLE_PROGRAM)
->where('type')->eq('program')
->andWhere('grade')->eq(1)
->andWhere('deleted')->eq(1)
->fetchPairs();
foreach($topPairs as $id => $name)
{
if(isset($deletedTopPairs[$id])) $topPairs[$id] .= ' (' . $this->lang->program->deleted . ')';
}
}
return $topPairs;
}
/**
+42 -3
View File
@@ -1456,6 +1456,7 @@ class project extends control
{
foreach($builds as $build)
{
$build->builds = $this->build->getByList($build->builds);
/* If product is normal, unset branch name. */
if(isset($productList[$build->product]) and $productList[$build->product]->type == 'normal')
{
@@ -1483,6 +1484,7 @@ class project extends control
$this->view->products = $products;
$this->view->allExecutions = $allExecutions;
$this->view->executions = $executions;
$this->view->buildPairs = $this->loadModel('build')->getBuildPairs(0);
$this->view->type = $type;
$this->display();
@@ -2161,6 +2163,11 @@ class project extends control
}
$oldProducts = $this->product->getProducts($projectID);
if($project->multiple and $project->model != 'waterfall')
{
$executions = $this->dao->select('id')->from(TABLE_EXECUTION)->where('project')->eq($projectID)->fetchPairs('id');
$oldExecutionProducts = $this->dao->select('project,product')->from(TABLE_PROJECTPRODUCT)->where('project')->in($executions)->fetchGroup('project', 'product');
}
$this->project->updateProducts($projectID);
if(dao::isError()) return $this->send(array('result' => 'fail', 'message' => dao::getError()));
@@ -2177,7 +2184,7 @@ class project extends control
$diffProducts = array_merge(array_diff($oldProductIDs, $newProductIDs), array_diff($newProductIDs, $oldProductIDs));
if($diffProducts) $this->loadModel('action')->create('project', $projectID, 'Managed', '', !empty($_POST['products']) ? join(',', $_POST['products']) : '');
if($project->multiple)
if($project->multiple and $project->model != 'waterfall')
{
$unlinkedProducts = array_diff($oldProductIDs, $newProductIDs);
if(!empty($unlinkedProducts))
@@ -2185,8 +2192,14 @@ class project extends control
$unlinkedProductPairs = array();
foreach($unlinkedProducts as $unlinkedProduct) $unlinkedProductPairs[$unlinkedProduct] = $oldProducts[$unlinkedProduct]->name;
$executionIDList = $this->execution->getIdList($projectID);
foreach($executionIDList as $executionID) $this->action->create('execution', $executionID, 'unlinkproduct', '', implode(',', $unlinkedProductPairs));
$unlinkExecutions = array();
foreach($oldExecutionProducts as $executionID => $executionProducts)
{
$unlinkExecutionProducts = array_intersect_key($unlinkedProductPairs, $executionProducts);
if($unlinkExecutionProducts) $unlinkExecutions[$executionID] = $unlinkExecutionProducts;
}
foreach($unlinkExecutions as $executionID => $unlinkExecutionProducts) $this->action->create('execution', $executionID, 'unlinkproduct', '', implode(',', $unlinkExecutionProducts));
}
}
@@ -2307,6 +2320,32 @@ class project extends control
return print(html::select('execution', $executions, $executionID, "class='form-control'"));
}
/**
* AJAX: get a project by execution id.
*
* @param string $executionID
* @access public
* @return string
*/
public function ajaxGetPairsByExecution($executionID)
{
$execution = $this->loadModel('execution')->getByID($executionID);
$projectPairs = $this->loadModel('project')->getPairsByIdList($execution->project);
if($this->app->getViewType() == 'json')
{
$project = array('id' => key($projectPairs), 'name' => reset($projectPairs));
$pinyin = common::convert2Pinyin(array(reset($projectPairs)));
$project['namePinyin'] = zget($pinyin, $project['name']);
return print(json_encode($project));
}
else
{
return print(html::select('project', $projectPairs, $execution->project, "class='form-control' onchange='loadProductExecutions({$execution->project}, this.value)'"));
}
}
/**
* Link projects and code repositories.
*
+5 -5
View File
@@ -377,8 +377,8 @@ $lang->project->action->managed = '$date, managed by <strong>$actor</strong>. $e
$lang->project->multiple = "Multi {$lang->executionCommon}";
$lang->project->copyproject = new stdClass();
$lang->project->copyproject->nameTips = '『Project Name』Cannot be repeated.';
$lang->project->copyproject->codeTips = '『Project Code』Cannot be repeated.';
$lang->project->copyproject->endTips = '『Schedule End』Cannot be empty.';
$lang->project->copyproject->daysTips = '『Available working days』Should be numerical.';
$lang->project->copyProject = new stdClass();
$lang->project->copyProject->nameTips = '『Project Name』Cannot be repeated.';
$lang->project->copyProject->codeTips = '『Project Code』Cannot be repeated.';
$lang->project->copyProject->endTips = '『Schedule End』Cannot be empty.';
$lang->project->copyProject->daysTips = '『Available working days』Should be numerical.';
+5 -5
View File
@@ -377,8 +377,8 @@ $lang->project->action->managed = '$date, managed by <strong>$actor</strong>. $e
$lang->project->multiple = "Multi {$lang->executionCommon}";
$lang->project->copyproject = new stdClass();
$lang->project->copyproject->nameTips = '『Project Name』Cannot be repeated.';
$lang->project->copyproject->codeTips = '『Project Code』Cannot be repeated.';
$lang->project->copyproject->endTips = '『Schedule End』Cannot be empty.';
$lang->project->copyproject->daysTips = '『Available working days』Should be numerical.';
$lang->project->copyProject = new stdClass();
$lang->project->copyProject->nameTips = '『Project Name』Cannot be repeated.';
$lang->project->copyProject->codeTips = '『Project Code』Cannot be repeated.';
$lang->project->copyProject->endTips = '『Schedule End』Cannot be empty.';
$lang->project->copyProject->daysTips = '『Available working days』Should be numerical.';
+5 -5
View File
@@ -377,8 +377,8 @@ $lang->project->action->managed = '$date, managed by <strong>$actor</strong>. $e
$lang->project->multiple = "Multi {$lang->executionCommon}";
$lang->project->copyproject = new stdClass();
$lang->project->copyproject->nameTips = '『Project Name』Cannot be repeated.';
$lang->project->copyproject->codeTips = '『Project Code』Cannot be repeated.';
$lang->project->copyproject->endTips = '『Schedule End』Cannot be empty.';
$lang->project->copyproject->daysTips = '『Available working days』Should be numerical.';
$lang->project->copyProject = new stdClass();
$lang->project->copyProject->nameTips = '『Project Name』Cannot be repeated.';
$lang->project->copyProject->codeTips = '『Project Code』Cannot be repeated.';
$lang->project->copyProject->endTips = '『Schedule End』Cannot be empty.';
$lang->project->copyProject->daysTips = '『Available working days』Should be numerical.';
+5 -5
View File
@@ -377,8 +377,8 @@ $lang->project->action->managed = '$date, 由 <strong>$actor</strong> 维护。$
$lang->project->multiple = "启用{$lang->executionCommon}";
$lang->project->copyproject = new stdClass();
$lang->project->copyproject->nameTips = '『项目名称』不可重复需要修改。';
$lang->project->copyproject->codeTips = '『项目代号』不可重复需要修改。';
$lang->project->copyproject->endTips = '『计划完成』不能为空。';
$lang->project->copyproject->daysTips = '『可用工作日』应当是数字。';
$lang->project->copyProject = new stdClass();
$lang->project->copyProject->nameTips = '『项目名称』不可重复需要修改。';
$lang->project->copyProject->codeTips = '『项目代号』不可重复需要修改。';
$lang->project->copyProject->endTips = '『计划完成』不能为空。';
$lang->project->copyProject->daysTips = '『可用工作日』应当是数字。';
+3 -2
View File
@@ -2459,9 +2459,10 @@ class projectModel extends model
}
/* Delete the execution linked products that is not linked with the execution. */
if((int)$projectID > 0)
$projectID = (int)$projectID;
if($projectID > 0)
{
$executions = $this->dao->select('id')->from(TABLE_EXECUTION)->where('project')->eq((int)$projectID)->fetchPairs('id');
$executions = $this->dao->select('id')->from(TABLE_EXECUTION)->where('project')->eq($projectID)->fetchPairs('id');
$this->dao->delete()->from(TABLE_PROJECTPRODUCT)->where('project')->in($executions)->andWhere('product')->notin($products)->exec();
if(!empty($_POST['division']))
+16
View File
@@ -81,7 +81,23 @@
<td class="c-name text-left" title='<?php echo $build->productName;?>'><?php echo $build->productName;?></td>
<?php endif;?>
<?php if($project->multiple):?>
<?php if($build->execution):?>
<td class="c-name text-left" title='<?php echo $build->executionName;?>'><?php echo $build->executionName;?></td>
<?php else:?>
<td class="c-name text-left">
<?php $childExecutions = array();?>
<?php foreach($build->builds as $childBuild):?>
<?php $childExecutions[$childBuild->execution] = $childBuild->execution;?>
<?php endforeach;?>
<?php foreach($childExecutions as $execution):?>
<?php $executionName = zget($allExecutions, $execution, '');?>
<?php if($executionName):?>
<span title="<?php echo $executionName;?>"><?php echo $executionName;?></span></br>
<?php endif;?>
<?php endforeach;?>
</td>
<?php endif;?>
<?php endif;?>
<td class="c-url" title="<?php echo $build->scmPath?>"><?php echo strpos($build->scmPath, 'http') === 0 ? html::a($build->scmPath) : $build->scmPath;?></td>
<td class="c-url" title="<?php echo $build->filePath?>"><?php echo strpos($build->filePath, 'http') === 0 ? html::a($build->filePath) : $build->filePath;?></td>
+4 -4
View File
@@ -36,10 +36,10 @@
<?php $requiredFields = $config->project->create->requiredFields;?>
<?php js::set('requiredFields', $requiredFields);?>
<?php js::set('copyType', '');?>
<?php js::set('nameTips', $lang->project->copyproject->nameTips);?>
<?php js::set('codeTips', $lang->project->copyproject->codeTips);?>
<?php js::set('endTips', $lang->project->copyproject->endTips);?>
<?php js::set('daysTips', $lang->project->copyproject->daysTips);?>
<?php js::set('nameTips', $lang->project->copyProject->nameTips);?>
<?php js::set('codeTips', $lang->project->copyProject->codeTips);?>
<?php js::set('endTips', $lang->project->copyProject->endTips);?>
<?php js::set('daysTips', $lang->project->copyProject->daysTips);?>
<div id='mainContent' class='main-content'>
<div class='center-block'>
<div class='main-header'>
+23 -17
View File
@@ -69,7 +69,10 @@ class projectrelease extends control
*/
public function browse($projectID = 0, $executionID = 0, $type = 'all', $orderBy = 't1.date_desc', $recTotal = 0, $recPerPage = 15, $pageID = 1)
{
$this->session->set('releaseList', $this->app->getURI(true), 'project');
$uri = $this->app->getURI(true);
$this->session->set('releaseList', $uri, 'project');
$this->session->set('buildList', $uri);
$project = $this->project->getById($projectID);
$execution = $this->loadModel('execution')->getById($executionID);
@@ -130,17 +133,17 @@ class projectrelease extends control
$this->commonAction($projectID);
/* Get the builds that can select. */
$builds = $this->build->getBuildPairs($this->view->product->id, $this->view->branch, 'notrunk,withbranch|hasproject', $projectID, 'project');
$builds = $this->build->getBuildPairs($this->view->product->id, $this->view->branch, 'notrunk|withbranch|hasproject', $projectID, 'project', '', false);
$releasedBuilds = $this->projectrelease->getReleasedBuilds($projectID);
foreach($releasedBuilds as $build) unset($builds[$build]);
unset($builds['trunk']);
$this->view->title = $this->view->project->name . $this->lang->colon . $this->lang->release->create;
$this->view->projectID = $projectID;
$this->view->builds = $builds;
$this->view->lastRelease = $this->projectrelease->getLast($projectID);
$this->view->users = $this->loadModel('user')->getPairs('noclosed');
$this->view->confirmLink = $this->lang->release->confirmLink;
$this->view->title = $this->view->project->name . $this->lang->colon . $this->lang->release->create;
$this->view->projectID = $projectID;
$this->view->builds = $builds;
$this->view->lastRelease = $this->projectrelease->getLast($projectID);
$this->view->users = $this->loadModel('user')->getPairs('noclosed');
$this->view->confirmLink = $this->lang->release->confirmLink;
$this->view->notEmptyBuilds = $this->build->filterLinked(array_keys($builds));
$this->display();
}
@@ -187,7 +190,7 @@ class projectrelease extends control
$bindBuilds = $this->build->getByList($release->build);
/* Get the builds that can select. */
$builds = $this->build->getBuildPairs($release->product, $release->branch, 'notrunk|withbranch|hasproject', $this->session->project, 'project', '', false);
$builds = $this->build->getBuildPairs($release->product, $release->branch, 'notrunk|withbranch|hasproject', $this->session->project, 'project', $release->build, false);
$releasedBuilds = $this->projectrelease->getReleasedBuilds($this->session->project);
foreach($releasedBuilds as $releasedBuild)
{
@@ -196,7 +199,6 @@ class projectrelease extends control
if(!isset($bindBuilds[$bindBuildID])) unset($builds[$bindBuildID]);
}
}
unset($builds['trunk']);
/* Set project menu. */
$this->project->setMenu($this->session->project);
@@ -226,9 +228,6 @@ class projectrelease extends control
*/
public function view($releaseID, $type = 'story', $link = 'false', $param = '', $orderBy = 'id_desc', $recTotal = 0, $recPerPage = 100, $pageID = 1)
{
$this->session->set('buildList', $this->app->getURI(true), 'execution');
$this->session->set('storyList', $this->app->getURI(true), $this->app->tab);
$this->loadModel('story');
$this->loadModel('bug');
@@ -243,6 +242,11 @@ class projectrelease extends control
return print(js::error($this->lang->notFound) . js::locate('back'));
}
$uri = $this->app->getURI(true);
if($release->build) $this->session->set('buildList', $uri);
if($type == 'story') $this->session->set('storyList', $uri, $this->app->tab);
if($type == 'bug' or $type == 'leftBug') $this->session->set('bugList', $uri, $this->app->tab);
$sort = common::appendOrder($orderBy);
if(strpos($sort, 'pri_') !== false) $sort = str_replace('pri_', 'priOrder_', $sort);
@@ -683,7 +687,7 @@ class projectrelease extends control
$this->config->bug->search['style'] = 'simple';
$this->config->bug->search['params']['plan']['values'] = $this->loadModel('productplan')->getPairsForStory($release->product, $release->branch, 'skipParent|withMainPlan');
$this->config->bug->search['params']['execution']['values'] = $this->loadModel('product')->getExecutionPairsByProduct($release->product, $release->branch, 'id_desc', $release->project);
$this->config->bug->search['params']['openedBuild']['values'] = $this->loadModel('build')->getBuildPairs($release->product, $branch = 0, $params = '');
$this->config->bug->search['params']['openedBuild']['values'] = $this->loadModel('build')->getBuildPairs($release->product, $branch = 0);
$this->config->bug->search['params']['resolvedBuild']['values'] = $this->config->bug->search['params']['openedBuild']['values'];
$searchModules = array();
@@ -811,8 +815,10 @@ class projectrelease extends control
$builds = $this->loadModel('build')->getBuildPairs($productID, $branch, 'notrunk,withbranch,hasproject', $projectID, 'project', '', false);
$releasedBuilds = $this->projectrelease->getReleasedBuilds($projectID);
foreach($releasedBuilds as $build) unset($builds[$build]);
unset($builds['trunk']);
return print(html::select('build[]', $builds, '', "class='form-control chosen' multiple"));
/* Get the builds of the linked stories or bugs. */
$notEmptyBuilds = $this->build->filterLinked(array_keys($builds));
return print(html::select('build[]', $builds, '', "class='form-control chosen' multiple data-notemptybuilds='" . join(',', $notEmptyBuilds) . "'"));
}
}
+20 -7
View File
@@ -1,18 +1,27 @@
$('#submit').click(function()
{
var dateFormat = new RegExp(/^\d{4}\-\d{2}\-\d{2}$/);
var name = $('#name').val();
var date = $('#date').val();
var build = $('#build').val();
if(name && build && dateFormat.test(date))
var dateFormat = new RegExp(/^\d{4}\-\d{2}\-\d{2}$/);
var name = $('#name').val();
var date = $('#date').val();
var build = $('#build').val();
var notEmptyBuild = false;
$.each(build, function(index, value)
{
if(typeof(notEmptyBuilds[value]) != 'undefined')
{
notEmptyBuild = true;
return false;
}
})
if(name && build && notEmptyBuild && dateFormat.test(date))
{
var result = confirm(confirmLink) ? true : false;
$('#sync').val(result);
}
});
$('[data-toggle="popover"]').popover();
/**
* Ajax load unlinked builds with project and product.
*
@@ -26,6 +35,10 @@ function loadBuilds()
$('#buildBox').load(createLink('projectrelease', 'ajaxLoadBuilds', "projectID=" + projectID + "&productID=" + productID + "&branch=" + branch), function()
{
$('#build').attr('data-placeholder', multipleSelect).chosen();
$.each($('#build').attr('data-notemptybuilds').split(','), function(index, value)
{
notEmptyBuilds[value] = value;
});
});
}
@@ -13,6 +13,7 @@
<?php include '../../common/view/header.html.php';?>
<?php include '../../common/view/kindeditor.html.php';?>
<?php js::set('confirmLink', $confirmLink);?>
<?php js::set('notEmptyBuilds', $notEmptyBuilds);?>
<?php js::set('projectID', $projectID);?>
<div id='mainContent' class='main-content'>
<div class='center-block'>
+1 -1
View File
@@ -335,7 +335,7 @@
<table class='table table-data'>
<?php if($project->hasProduct):?>
<tr>
<th class='w-90px'><?php echo $lang->release->product;?></th>
<th class='w-100px'><?php echo $lang->release->product;?></th>
<td><?php echo $release->productName;?></td>
</tr>
<?php if($release->productType != 'normal'):?>
+10 -26
View File
@@ -46,7 +46,10 @@ class release extends control
$this->app->loadClass('pager', $static = true);
$pager = new pager($recTotal, $recPerPage, $pageID);
$this->commonAction($productID, $branch);
$this->session->set('releaseList', $this->app->getURI(true), 'product');
$uri = $this->app->getURI(true);
$this->session->set('releaseList', $uri, 'product');
$this->session->set('buildList', $uri);
$this->view->title = $this->view->product->name . $this->lang->colon . $this->lang->release->browse;
$this->view->position[] = $this->lang->release->browse;
@@ -86,27 +89,6 @@ class release extends control
$releasedBuilds = $this->release->getReleasedBuilds($productID, $branch);
foreach($releasedBuilds as $build) unset($builds[$build]);
/* Get the builds of the linked stories or bugs. */
$notEmptyBuilds = array();
$buildList = $this->build->getByList(array_keys($builds));
foreach($buildList as $build)
{
if(!$build->execution && !empty($build->builds))
{
$childBuilds = $this->build->getByList($build->builds);
foreach($childBuilds as $childBuild)
{
$childBuild->stories = trim($childBuild->stories, ',');
$childBuild->bugs = trim($childBuild->bugs, ',');
if($childBuild->stories) $build->stories .= ',' . $childBuild->stories;
if($childBuild->bugs) $build->bugs .= ',' . $childBuild->bugs;
}
}
if(!empty($build->stories) or !empty($build->bugs)) $notEmptyBuilds[$build->id] = $build->id;
}
$this->commonAction($productID, $branch);
$this->view->title = $this->view->product->name . $this->lang->colon . $this->lang->release->create;
$this->view->position[] = $this->lang->release->create;
@@ -114,7 +96,7 @@ class release extends control
$this->view->builds = $builds;
$this->view->users = $this->loadModel('user')->getPairs('noclosed');
$this->view->lastRelease = $this->release->getLast($productID, $branch);
$this->view->notEmptyBuilds = $notEmptyBuilds;
$this->view->notEmptyBuilds = $this->build->filterLinked(array_keys($builds));
$this->display();
}
@@ -188,8 +170,10 @@ class release extends control
$release = $this->release->getByID($releaseID, true);
if(!$release) return print(js::error($this->lang->notFound) . js::locate($this->createLink('product', 'index')));
if($type == 'story') $this->session->set('storyList', $this->app->getURI(true), 'product');
if($type == 'bug' or $type == 'leftBug') $this->session->set('bugList', $this->app->getURI(true), 'qa');
$uri = $this->app->getURI(true);
if(!empty($release->build)) $this->session->set('buildList', $uri);
if($type == 'story') $this->session->set('storyList', $uri, 'product');
if($type == 'bug' or $type == 'leftBug') $this->session->set('bugList', $uri, 'qa');
$this->loadModel('story');
$this->loadModel('bug');
@@ -639,7 +623,7 @@ class release extends control
$this->config->bug->search['params']['plan']['values'] = $this->loadModel('productplan')->getPairsForStory($release->product, $release->branch, 'skipParent|withMainPlan');
$this->config->bug->search['params']['execution']['values'] = $this->loadModel('product')->getExecutionPairsByProduct($release->product, $release->branch);
$this->config->bug->search['params']['openedBuild']['values'] = $this->loadModel('build')->getBuildPairs($release->product, $branch = 'all', $params = '');
$this->config->bug->search['params']['openedBuild']['values'] = $this->loadModel('build')->getBuildPairs($release->product, $branch = 'all', 'releasetag');
$this->config->bug->search['params']['resolvedBuild']['values'] = $this->config->bug->search['params']['openedBuild']['values'];
$searchModules = array();
-2
View File
@@ -21,5 +21,3 @@ $('#submit').click(function()
$('#sync').val(result);
}
});
$('[data-toggle="popover"]').popover();
+3 -2
View File
@@ -123,12 +123,13 @@ class releaseModel extends model
$buildIdList = array();
foreach($releases as $release)
{
if($branch != 'all')
if($branch != 'all' and $branch !== '')
{
$inBranch = false;
foreach(explode(',', trim($release->branch, ',')) as $branchID)
{
if(empty($branchID)) continue;
if($branchID === '') continue;
if(strpos(",{$branch},", ",{$branchID},") !== false) $inBranch = true;
}
if(!$inBranch) continue;
+1 -1
View File
@@ -336,7 +336,7 @@
<div class='detail-content'>
<table class='table table-data'>
<tr>
<th class='w-90px'><?php echo $lang->release->product;?></th>
<th class='w-100px'><?php echo $lang->release->product;?></th>
<td><?php echo $release->productName;?></td>
</tr>
<?php if($release->productType != 'normal'):?>
+7 -6
View File
@@ -5425,9 +5425,9 @@ class storyModel extends model
foreach($requirements as $requirement)
{
$stories = $this->getRelation($requirement->id, 'requirement');
$stories = $this->getRelation($requirement->id, 'requirement', array('id', 'title', 'parent'));
$stories = empty($stories) ? array() : $stories;
foreach($stories as $id => $title)
foreach($stories as $id => $story)
{
if($projectStories and !isset($projectStories[$id]))
{
@@ -5436,10 +5436,11 @@ class storyModel extends model
}
$stories[$id] = new stdclass();
$stories[$id]->title = $title;
$stories[$id]->cases = $this->loadModel('testcase')->getStoryCases($id);
$stories[$id]->bugs = $this->loadModel('bug')->getStoryBugs($id);
$stories[$id]->tasks = $this->loadModel('task')->getStoryTasks($id);
$stories[$id]->parent = $story->parent;
$stories[$id]->title = $story->title;
$stories[$id]->cases = $this->loadModel('testcase')->getStoryCases($id);
$stories[$id]->bugs = $this->loadModel('bug')->getStoryBugs($id);
$stories[$id]->tasks = $this->loadModel('task')->getStoryTasks($id);
if($this->config->edition == 'max')
{
$stories[$id]->designs = $this->dao->select('id, name')->from(TABLE_DESIGN)
+1
View File
@@ -241,6 +241,7 @@ $lang->task->confirmRecord = '"Reststunden " sind 0. Möchten Sie de
$lang->task->confirmTransfer = '"Left Hour" is 0,Do you want to assign to <strong>%s</strong> task?';
$lang->task->noticeTaskStart = '"Cost Hour" and "Left Hour" cannot be 0 at the same time.';
$lang->task->noticeLinkStory = "Es wurde keine Story verknüpft. Sie können %s für dieses Projekt, anschließend %s.";
$lang->task->noticeLinkStoryNoProduct = "No story has been linked.";
$lang->task->noticeSaveRecord = 'Ihre Stunden wurden nicht gespeichrt. Bitte erst speichern.';
$lang->task->noticeManageTeam = 'Task status is %s, can not manage team.';
$lang->task->commentActions = '%s. %s, kommentiert von <strong>%s</strong>.';
+1
View File
@@ -241,6 +241,7 @@ $lang->task->confirmRecord = '"Left Hour" is 0. Do you want to set t
$lang->task->confirmTransfer = '"Left Hour" is 0,Do you want to assign to <strong>%s</strong> task?';
$lang->task->noticeTaskStart = '"Cost Hour" and "Left Hour" cannot be 0 at the same time.';
$lang->task->noticeLinkStory = "No story has been linked. You can %s for this project, then %s.";
$lang->task->noticeLinkStoryNoProduct = "No story has been linked.";
$lang->task->noticeSaveRecord = 'Your Hour is not saved. Please save it first.';
$lang->task->noticeManageTeam = 'Task status is %s, can not manage team.';
$lang->task->commentActions = '%s. %s, commented by <strong>%s</strong>.';
+1
View File
@@ -241,6 +241,7 @@ $lang->task->confirmRecord = '"Heures Restantes" à 0. Voulez-vous p
$lang->task->confirmTransfer = '"Left Hour" is 0,Do you want to assign to <strong>%s</strong> task?';
$lang->task->noticeTaskStart = '"Cost Hour" and "Left Hour" cannot be 0 at the same time.';
$lang->task->noticeLinkStory = "Aucune Story n'est associée. Vous pouvez %s pour ce projet, alors %s.";
$lang->task->noticeLinkStoryNoProduct = "No story has been linked.";
$lang->task->noticeSaveRecord = "Votre temps n'a pas été sauvé. Enregistrez-le d'abord.";
$lang->task->noticeManageTeam = 'Task status is %s, can not manage team.';
$lang->task->commentActions = '%s. %s, commenté par <strong>%s</strong>.';
+1
View File
@@ -241,6 +241,7 @@ $lang->task->confirmRecord = '"剩余"为0,任务将标记为"已
$lang->task->confirmTransfer = '剩余工时为0,当前成员已完成任务,任务指派给:<strong>%s</strong>。';
$lang->task->noticeTaskStart = '"总计消耗"和"预计剩余"不能同时为0';
$lang->task->noticeLinkStory = "没有可关联的相关{$lang->SRCommon},您可以为当前项目%s,然后%s";
$lang->task->noticeLinkStoryNoProduct = "没有可关联的相关{$lang->SRCommon}";
$lang->task->noticeSaveRecord = '您有尚未保存的工时记录,请先将其保存。';
$lang->task->noticeManageTeam = '任务状态是%s,不能维护团队';
$lang->task->commentActions = '%s. %s, 由 <strong>%s</strong> 添加备注。';
+34 -2
View File
@@ -3206,6 +3206,16 @@ class taskModel extends model
$task->progress = round($task->consumed / ($task->consumed + $task->left), 2) * 100;
}
if($task->mode == 'multi')
{
$teamMembers = $this->dao->select('t1.realname')->from(TABLE_USER)->alias('t1')
->leftJoin(TABLE_TASKTEAM)->alias('t2')
->on('t1.account = t2.account')
->where('t2.task')->eq($task->id)
->fetchPairs();
$task->teamMembers= join(',', array_keys($teamMembers));
}
return $task;
}
@@ -3921,8 +3931,15 @@ class taskModel extends model
public function getToAndCcList($task)
{
/* Set toList and ccList. */
$toList = $task->assignedTo;
$ccList = trim($task->mailto, ',');
$toList = $task->assignedTo;
$ccList = trim($task->mailto, ',');
$toTeamTaskList = '';
if($task->mode == 'multi')
{
$toTeamTaskList = $this->getTeamMembers($task->id);
$toTeamTaskList = implode(',', $toTeamTaskList);
$toList = $toTeamTaskList;
}
if(empty($toList))
{
@@ -4339,4 +4356,19 @@ class taskModel extends model
$order ++;
}
}
/**
* Get teamTask members.
*
* @param int $taskID
* @access public
* @return array
*/
public function getTeamMembers($taskID)
{
$taskType = $this->dao->select('mode')->from(TABLE_TASK)->where('id')->eq($taskID)->fetch('mode');
if($taskType != 'multi') return array();
$teamMembers = $this->dao->select('account')->from(TABLE_TASKTEAM)->where('task')->eq($taskID)->fetchPairs();
return empty($teamMembers) ? $teamMembers : array_keys($teamMembers);
}
}
+7 -1
View File
@@ -108,7 +108,13 @@ foreach(explode(',', $config->task->create->requiredFields) as $field)
<tr class="<?php echo $hiddenStory?> storyBox">
<th><?php echo $lang->task->story;?></th>
<td colspan='3'>
<span id='storyBox' class="<?php if(!empty($stories)) echo 'hidden';?> "><?php printf($lang->task->noticeLinkStory, html::a($this->createLink('execution', 'linkStory', "executionID=$execution->id"), $lang->execution->linkStory, '', 'class="text-primary"'), html::a("javascript:loadStories($execution->id)", $lang->refresh, '', 'class="text-primary"'));?></span>
<span id='storyBox' class="<?php if(!empty($stories)) echo 'hidden';?> ">
<?php
$noticeLinkStory = sprintf($lang->task->noticeLinkStory, html::a($this->createLink('execution', 'linkStory', "executionID=$execution->id"), $lang->execution->linkStory, '', 'class="text-primary"'), html::a("javascript:loadStories($execution->id)", $lang->refresh, '', 'class="text-primary"'));
if(empty($execution->hasProduct)) $noticeLinkStory = $lang->task->noticeLinkStoryNoProduct;
echo $noticeLinkStory;
?>
</span>
<div class='input-group <?php if(empty($stories)) echo "hidden";?>'>
<?php echo html::select('story', $stories, $task->story, "class='form-control chosen' onchange='setStoryRelated();'");?>
<?php if(common::hasPriv('execution', 'storyView')):?>
+2 -2
View File
@@ -2,8 +2,8 @@
$config->testtask = new stdclass();
$config->testtask->create = new stdclass();
$config->testtask->edit = new stdclass();
$config->testtask->create->requiredFields = 'execution,build,begin,end,name';
$config->testtask->edit->requiredFields = 'execution,build,begin,end,name';
$config->testtask->create->requiredFields = 'build,begin,end,name';
$config->testtask->edit->requiredFields = 'build,begin,end,name';
$config->testtask->importUnit = new stdclass();
$config->testtask->importUnit->requiredFields = 'execution,build,begin,end,name,resultFile';
+11 -5
View File
@@ -250,7 +250,7 @@ class testtask extends control
/* Create testtask from testtask of test.*/
$productID = $productID ? $productID : key($this->products);
$executions = empty($productID) ? array() : $this->loadModel('product')->getExecutionPairsByProduct($productID, '', 'id_desc', $projectID, 'stagefilter');
$builds = empty($productID) ? array() : $this->loadModel('build')->getBuildPairs($productID, 'all', 'notrunk');
$builds = empty($productID) ? array() : $this->loadModel('build')->getBuildPairs($productID, 'all', 'notrunk,withexecution', $projectID, 'project');
$execution = $this->loadModel('execution')->getByID($executionID);
if(!empty($execution) and $execution->type == 'kanban') $this->lang->testtask->execution = str_replace($this->lang->execution->common, $this->lang->kanban->common, $this->lang->testtask->execution);
@@ -517,7 +517,7 @@ class testtask extends control
/* Get execution type and set assignedToList. */
$execution = $this->execution->getById($task->execution);
if($execution->acl == 'private')
if($execution and $execution->acl == 'private')
{
$assignedToList = $this->loadModel('user')->getTeamMemberPairs($execution->id, 'execution', 'nodeleted');
}
@@ -816,13 +816,18 @@ class testtask extends control
$executions[$executionID] = $project->name . "({$this->lang->project->disableExecution})";
}
}
$builds = $this->loadModel('build')->getBuildPairs($productID, 'all', 'noempty,notrunk,withexecution', $executionID, 'execution');
}
else
{
$builds = $this->loadModel('build')->getBuildPairs($productID, 'all', 'noempty,notrunk,withexecution', $task->project, 'project');
}
$this->view->title = $this->products[$productID] . $this->lang->colon . $this->lang->testtask->edit;
$this->view->task = $task;
$this->view->project = $this->project->getByID($projectID);
$this->view->executions = $executions;
$this->view->builds = empty($productID) ? array() : $this->loadModel('build')->getBuildPairs($productID, 'all', 'noempty,notrunk', $executionID, 'execution');
$this->view->builds = empty($productID) ? array() : $builds;
$this->view->testreports = $this->loadModel('testreport')->getPairs($task->product, $task->testreport);
$this->view->users = $this->loadModel('user')->getPairs('nodeleted|noclosed', $task->owner);
$this->view->contactLists = $this->user->getContactLists($this->app->user->account, 'withnote');
@@ -1421,7 +1426,7 @@ class testtask extends control
$this->view->case = $case;
$this->view->runID = $runID;
$this->view->results = $results;
$this->view->builds = $this->loadModel('build')->getBuildPairs($case->product, $case->branch, $params = '');
$this->view->builds = $this->loadModel('build')->getBuildPairs($case->product, $case->branch);
$this->view->users = $this->loadModel('user')->getPairs('noclosed, noletter');
$this->display();
@@ -1491,7 +1496,7 @@ class testtask extends control
$projectID = $this->app->tab == 'qa' ? 0 : $this->session->project;
$executions = empty($productID) ? array() : $this->loadModel('product')->getExecutionPairsByProduct($productID, '', 'id_desc', $projectID);
$builds = empty($productID) ? array() : $this->loadModel('build')->getBuildPairs($productID, 'all', 'notrunk');
$builds = empty($productID) ? array() : $this->loadModel('build')->getBuildPairs($productID, 'all', 'notrunk', 0, 'execution', '', false);
$this->view->title = $this->products[$productID] . $this->lang->colon . $this->lang->testtask->importUnitResult;
$this->view->position[] = html::a($this->createLink('testtask', 'browse', "productID=$productID"), $this->products[$productID]);
@@ -1501,6 +1506,7 @@ class testtask extends control
$this->view->builds = $builds;
$this->view->users = $this->loadModel('user')->getPairs('noletter|nodeleted|noclosed');
$this->view->productID = $productID;
$this->view->projectID = $projectID;
$this->display();
}
+2 -5
View File
@@ -90,21 +90,18 @@ function loadExecutionRelated(executionID)
* Load execution builds.
*
* @param int $executionID
* @param int $selected
* @access public
* @return void
*/
function loadExecutionBuilds(executionID, selected)
function loadExecutionBuilds(executionID)
{
var selectedBuild = $('#build').val();
if(!selectedBuild) selectedBuild = 0;
var link = createLink('build', 'ajaxGetExecutionBuilds', 'executionID=' + executionID + '&productID=' + $('#product').val() + '&varName=testTaskBuild&build=' + selectedBuild);
if(executionID == 0) link = createLink('build', 'ajaxGetProductBuilds', 'productID=' + $('#product').val() + '&varName=resolvedBuild&build=' + selectedBuild);
if(executionID == 0) link = createLink('build', 'ajaxGetProjectBuilds', 'projectID=' + projectID + '&productID=' + $('#product').val() + '&varName=build&build=' + selectedBuild + '&branch=&index=&needCreate=&type=noempty,notrunk,withexecution');
$('#buildBox').load(link, function()
{
$('#resolvedBuild').attr('id', 'build').attr('name', 'build').find('option[value=trunk]').remove();
if(selected) $('#build').val(selected);
$('#build').chosen();
});
}
+3 -5
View File
@@ -8,11 +8,7 @@ function loadProductRelated()
{
loadExecutions($('#product').val());
loadTestReports($('#product').val());
buildData = '<select id="build" name="build" class="form-control"></select>';
$('#build').replaceWith(buildData);
$('#build_chosen').remove();
$("#build").chosen();
$('#build').trigger("chosen:updated");
loadExecutionBuilds($('#execution').val())
}
/**
@@ -24,12 +20,14 @@ function loadProductRelated()
*/
function loadExecutions(productID)
{
var executionID = $('#execution').val();
link = createLink('product', 'ajaxGetExecutions', 'productID=' + productID + '&projectID=' + projectID + '&branch=');
$.get(link, function(data)
{
if(!data) data = '<select id="execution" name="execution" class="form-control"></select>';
$('#execution').replaceWith(data);
$('#execution_chosen').remove();
$("#execution").val(executionID);
$("#execution").chosen();
});
}
+1 -3
View File
@@ -38,12 +38,11 @@
<?php if(isset($noMultipleExecutionID)):?>
<?php echo html::hidden('execution', $noMultipleExecutionID);?>
<?php else:?>
<tr>
<tr class='<?php echo ($app->tab == 'execution' and $executionID) ? 'hide' : '';?>'>
<th class='w-100px'><?php echo $lang->testtask->execution;?></th>
<td class='w-p35-f'><?php echo html::select('execution', $executions, $executionID, "class='form-control chosen' onchange='loadExecutionRelated(this.value)'");?></td><td></td>
</tr>
<?php endif;?>
<tr>
<th><?php echo $lang->testtask->build;?></th>
<td>
@@ -58,7 +57,6 @@
</td>
<td></td>
</tr>
<tr>
<th><?php echo $lang->testtask->type;?></th>
<td><?php echo html::select('type[]', $lang->testtask->typeList, '', "class='form-control picker-select' multiple");?></td>
+8 -5
View File
@@ -13,6 +13,7 @@
<?php include '../../common/view/header.html.php';?>
<?php include '../../common/view/datepicker.html.php';?>
<?php include '../../common/view/kindeditor.html.php';?>
<?php js::set('projectID', $task->project);?>
<div id='mainContent' class='main-content'>
<div class='center-block'>
<div class='main-header'>
@@ -24,16 +25,18 @@
</div>
<form method='post' class="main-form form-ajax" enctype="multipart/form-data" id='dataform'>
<table class='table table-form'>
<tr class="<?php if(isset($project) and !$project->multiple) echo 'hide';?>">
<?php echo html::hidden('product', $task->product);?>
<?php if(!empty($project) and !$project->multiple):?>
<?php echo html::hidden('execution', $task->execution);?>
<?php else:?>
<tr class='<?php echo ($app->tab == 'execution' and $task->execution) ? 'hide' : '';?>'>
<th class='w-100px'><?php echo $lang->testtask->execution;?></th>
<td class='w-p35-f'>
<?php
echo html::select('execution', $executions, $task->execution, "class='form-control chosen' onchange='loadExecutionRelated(this.value)'");
echo html::hidden('product', $task->product);
?>
<?php echo html::select('execution', $executions, $task->execution, "class='form-control chosen' onchange='loadExecutionRelated(this.value)'");?>
</td>
<td></td>
</tr>
<?php endif;?>
<tr>
<th class='w-100px'><?php echo $lang->testtask->build;?></th>
<td class='w-p35-f'><span id='buildBox'><?php echo html::select('build', $builds, $task->build, "class='form-control chosen'");?></span></td>
@@ -107,4 +107,5 @@ $(function()
$('#subNavbar li[data-id="case"]').addClass('active');
})
</script>
<?php js::set('projectID', $projectID);?>
<?php include '../../common/view/footer.html.php';?>
+7 -8
View File
@@ -425,10 +425,9 @@ class treeModel extends model
$this->loadModel('branch');
$projectID = zget($extra, 'projectID', 0);
$executionID = zget($extra, 'executionID', 0);
$branches = array($branch => '');
$executionModules = array();
if($branch and empty($projectID) and empty($executionID))
if($branch and empty($projectID))
{
$branchName = $this->branch->getById($branch);
$branches = array($branch => $branchName);
@@ -438,15 +437,15 @@ class treeModel extends model
$manage = $userFunc[1] == 'createManageLink' ? true : false;
$product = $this->loadModel('product')->getById($rootID);
$onlyGetLinked = (($projectID or $executionID) and $this->config->vision != 'lite');
if(strpos('story|bug|case', $type) !== false and $branch === 'all' and empty($projectID) and empty($executionID))
$onlyGetLinked = ($projectID and $this->config->vision != 'lite');
if(strpos('story|bug|case', $type) !== false and $branch === 'all' and empty($projectID))
{
if($product->type != 'normal') $branches = array(BRANCH_MAIN => $this->lang->branch->main) + $this->loadModel('branch')->getPairs($rootID, 'noempty');
}
elseif(strpos(',case,bug,', ",$type,") !== false and $this->app->tab == 'execution')
{
if($product->type != 'normal' and $executionID) $branches += $this->branch->getPairs($product->id, 'noempty', $executionID);
if($onlyGetLinked) $executionModules = $this->getTaskTreeModules($executionID, true, $type, array('branchID' => $branch));
if($product->type != 'normal' and $projectID) $branches += $this->branch->getPairs($product->id, 'noempty', $projectID);
if($onlyGetLinked) $executionModules = $this->getTaskTreeModules($projectID, true, $type, array('branchID' => $branch));
}
elseif(($type == 'story' and $this->app->rawModule == 'projectstory') or (strpos(',case,bug,', ",$type,") !== false and $this->app->tab == 'project'))
{
@@ -1259,7 +1258,7 @@ class treeModel extends model
$param = "root={$module->root}&branch=&type=byModule&param={$module->id}";
$extra['type'] = (isset($extra['type']) and $extra['type'] != 'bysearch') ? $extra['type'] : 'all';
if($this->app->tab == 'execution') $param = "execuitonID={$extra['executionID']}&productID={$module->root}&branch={$extra['branchID']}&orderBy={$extra['orderBy']}&build={$extra['build']}&type={$extra['type']}&param={$module->id}";
if($this->app->tab == 'execution') $param = "execuitonID={$extra['projectID']}&productID={$module->root}&branch={$extra['branchID']}&orderBy={$extra['orderBy']}&build={$extra['build']}&type={$extra['type']}&param={$module->id}";
if($this->app->tab == 'project') $param = "projectID={$extra['projectID']}&productID={$module->root}&branch={$extra['branchID']}&orderBy={$extra['orderBy']}&build={$extra['build']}&type={$extra['type']}&param={$module->id}";
return html::a(helper::createLink($moduleName, $methodName, $param), $module->name, '_self', "id='module{$module->id}' title='{$module->name}'");
}
@@ -1278,7 +1277,7 @@ class treeModel extends model
$moduleName = strpos(',project,execution,', ",{$this->app->tab},") !== false ? $this->app->tab : 'testcase';
$methodName = strpos(',project,execution,', ",{$this->app->tab},") !== false ? 'testcase' : 'browse';
$param = $this->app->tab == 'project' ? "projectID={$this->session->project}&" : "";
$param = $this->app->tab == 'execution' ? "executionID={$extra['executionID']}&" : $param;
$param = $this->app->tab == 'execution' ? "executionID={$extra['projectID']}&" : $param;
return html::a(helper::createLink($moduleName, $methodName, $param . "root={$module->root}&branch={$extra['branchID']}&type=byModule&param={$module->id}"), $module->name, '_self', "id='module{$module->id}' data-app='{$this->app->tab}' title='{$module->name}'");
}
+2 -2
View File
@@ -452,7 +452,7 @@ class upgradeModel extends model
$this->updateProjectLinkedBranch();
break;
case '16_0_beta1':
$this->loadModel('api')->createDemoData($this->lang->api->zentaoAPI, 'http://' . $_SERVER['HTTP_HOST'] . $this->app->config->webRoot . 'api.php/v1', '16.0');
$this->loadModel('api')->createDemoData($this->lang->api->zentaoAPI, commonModel::getSysURL() . $this->app->config->webRoot . 'api.php/v1', '16.0');
break;
case '16_1':
$this->moveKanbanData();
@@ -4287,7 +4287,7 @@ class upgradeModel extends model
$moduleRoot = $this->app->getModuleRoot();
$editorDir = $moduleRoot . 'editor';
if(is_dir($editor)) $zfile->removeDir($editorDir);
if(is_dir($editorDir)) $zfile->removeDir($editorDir);
$translateDir = $moduleRoot . 'translate';
if(is_dir($translateDir)) $zfile->removeDir($translateDir);
+1 -1
View File
@@ -36,7 +36,7 @@
<?php endif;?>
</label>
</div>
<?php endForeach;?>
<?php endforeach;?>
</td>
</tr>
</tbody>
+1
View File
@@ -341,6 +341,7 @@ class weeklyModel extends model
->from(TABLE_TASK)
->where('execution')->in($executionIdList)
->andWhere('deleted')->eq(0)
->andWhere('parent')->ge(0)
->groupBy('type')
->fetchPairs();
}

Some files were not shown because too many files have changed in this diff Show More