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

This commit is contained in:
lanzongjun
2022-06-17 09:06:39 +08:00
69 changed files with 4385 additions and 221 deletions
+1 -1
View File
@@ -1 +1 @@
17.0
17.1
+33
View File
@@ -0,0 +1,33 @@
<?php
/**
* The mr entry point of ZenTaoPMS.
*
* @copyright Copyright 2009-2022 青岛易软天创网络科技有限公司(QingDao Nature Easy Soft Network Technology Co,LTD, www.cnezsoft.com)
* @license ZPL(http://zpl.pub/page/zplv12.html) or AGPL(https://www.gnu.org/licenses/agpl-3.0.en.html)
* @author liyuchun <liyuchun@easysoft.ltd>
* @package repo
* @version 1
* @link http://www.zentao.net
*/
class mrEntry extends baseEntry
{
/**
* Create mr.
*
* @access public
* @return void
*/
public function post()
{
$fields = 'repoID,jobID,sourceBranch,targetBranch,diffs,mergeStatus';
$this->batchSetPost($fields);
$postData = fixer::input('post')->get();
$this->loadController('mr', 'create');
$MRID = $this->loadModel('mr')->apiCreate();
if(dao::isError()) $this->sendError(400, dao::getError());
$MR = $this->mr->getByID($MRID);
$this->send(201, $MR);
}
}
+1 -1
View File
@@ -16,7 +16,7 @@ if(!class_exists('config')){class config{}}
if(!function_exists('getWebRoot')){function getWebRoot(){}}
/* 基本设置。Basic settings. */
$config->version = '17.0'; // ZenTaoPHP的版本。 The version of ZenTaoPHP. Don't change it.
$config->version = '17.1'; // ZenTaoPHP的版本。 The version of ZenTaoPHP. Don't change it.
$config->liteVersion = '1.0'; // 迅捷版版本。 The version of Lite.
$config->charset = 'UTF-8'; // ZenTaoPHP的编码。 The encoding of ZenTaoPHP.
$config->cookieLife = time() + 2592000; // Cookie的生存时间。The cookie life time.
+1
View File
@@ -154,6 +154,7 @@ $routes['/docs/:id'] = 'doc';
$routes['/repos'] = 'repos';
$routes['/repos/rules'] = 'reporules';
$routes['/jobs'] = 'jobs';
$routes['/mr'] = 'mr';
$routes['/modules'] = 'modules';
File diff suppressed because it is too large Load Diff
+2
View File
@@ -11,3 +11,5 @@ DELETE FROM `zt_workflowaction` WHERE `module`='task' AND `action`='browse';
DELETE FROM `zt_workflowaction` WHERE `module`='build' AND `action`='browse';
ALTER TABLE `zt_projectproduct` MODIFY COLUMN `plan` varchar(255) NOT NULL;
UPDATE `zt_project` SET status = 'closed' WHERE status='done';
+88
View File
@@ -1,3 +1,89 @@
2022-06-16 17.1
完成的需求
33060 Scrum看板中增加搜索功能
32812 需求检索条件中增加类别字段
32710 地盘贡献的文档列表增加搜索功能
32707 地盘贡献的用例列表增加搜索功能
32706 地盘贡献的Bug列表增加搜索功能
32705 地盘贡献的软件需求列表增加搜索功能
32704 地盘贡献的用户需求列表增加搜索功能
32703 地盘贡献的任务列表增加搜索功能
31315 地盘待处理的任务列表增加搜索功能
31314 地盘待处理的会议列表增加搜索功能
31311 地盘待处理的用例列表增加搜索功能
31310 地盘待处理的Bug列表增加搜索功能
31309 地盘待处理的软件需求列表增加搜索功能
31308 地盘待处理的用户需求列表增加搜索功能
30964 产品计划列表增加搜索功能
29722 专业研发看板中增加搜索功能
25835 回收站增加搜索功能
33296 创建和编辑执行保存成功后提示用户是否导入计划关联的相关需求
33177 创建和编辑项目时允许关联同一个产品的多个计划
33099 执行需求列表中提需求不受启用评审流程的限制
33098 指定人提交的软件需求必须评审时由谁评审为必填项
32574 执行列表中增加自定义列和高级表格功能
31670 执行概况中增加所属项目集和项目信息
31669 项目概况中增加所属项目集信息
30711 专业研发看板中需求、任务、Bug支持在当前泳道列中上下拖拽排序
30682 产品列表中可以显示所有产品线名称
29852 Scrum看板中需求、任务、Bug支持在列中上下拖拽排序
27150 创建和编辑执行时允许关联同一个产品的多个计划
57190 地盘待处理的反馈列表增加搜索功能
57189 地盘待处理列表增加指派给我的反馈功能
57188 导入Excel功能支持xls格式
57181 执行甘特图增加显示设置功能
57180 组织下的日志列表支持点击查看详情
57179 导入任务的模板中日期格式支持xxxx/xx/xx
57178 Bug导入导出字段中增加反馈者和通知邮箱字段
57177 项目导出后所属项目集显示完整层级
57176 执行甘特图增加按照指派给、进度、开始日期、结束日期、持续天数排序功能
57174 模版文件中的必填字段提示根据后台自定义设置的必填项进行提示
57175 反馈检索标签后面增加上数字显示
33536 批量编辑项目页面增加代号字段
33470 更新日志页面优化
33262 需求描述模块右上角打印最终判定结果
33261 需求描述模块右上角打印评分展开、收起按钮
33260 实现MSCWA评分模块功能
33259 没有最终评定结果时评分展开、收起按钮显示规则
33184 测试单的用例列表中搜索条件增加套件的检索字段
33104 将MSCWA评分功能打包成插件在官网发布
33102 需求列表中增加最终分数和MSCWA字段
33101 需求列表搜索中增加最终分数和MSCWA检索条件
33100 MSCWA评分功能增加权限控制
32676 执行失败的用例可以关联一个已有的Bug
33129 专业研发看板支持转入Bug
33025 更新接口库中禅道API文档
32106 完善产品投入统计表的统计维度
30765 专业研发看板支持转入任务
28469 组织日志中增加所属项目筛选条件
9206 自定义必填项中增加反馈的必填设置功能
30075 反馈的相关操作增加通知功能
28471 日志统计表按部门搜索时可以统计到子部门
30532 瀑布项目创建评审可以选择项目库中的文档
32709 地盘贡献的风险列表增加搜索功能
32708 地盘贡献的问题列表增加搜索功能
31313 地盘待处理的风险列表增加搜索功能
31312 地盘待处理的问题列表增加搜索功能
解决的Bug
23586 导入任务的相关需求字段显示不全
23568 评审的动态缺少语言项
23538 需求优先级下拉菜单显示异常
23410 scrum看板和专业研发看板中按指派人分组查看任务时,指派给无中数据有误
23298 创建版本库后没有关闭项目中的创建页面
23253 创建项目集,提示连接超时
23251 PHP8.0点击登录后,页面无响应
23184 用例库导入用例变更后点击更新同步时前置条件没有更新
23026 专业研发看板不关联产品时需求和Bug泳道没有提示
23419 通用看板,设置和创建看板没有对齐
23427 进入通用看板,默认显示“我参与的”标签页下的空间
23432 专业研发看板中创建任务页面抄送给提示信息显示不完整
23434 设置按钮下拉列表文案加上“空间”二字
23540 设置空间页面团队处样式建议优化
23543 迅捷界面项目看板没有对任务开始截止日期显示进行优化
23554 用户有泳道设置的权限升级后默认也应该有设置背景色和修改泳道名的权限
23558 进入执行Bug详情页会进入测试Bug中
23560 项目-测试用例列表有报错
2022-06-02 17.0
修复的bug
22948 执行需求列表中列名称显示遮挡
@@ -40,6 +126,7 @@
32972 实现导出用户模板功能
32440 实现导出用户功能
15620 实现导入用户功能
2022-05-26 17.0.beta2
修复的bug
22755 导入用例确认页面相关研发需求没有必填项标识
@@ -134,6 +221,7 @@
29765 已关闭的看板可以进行激活操作
28566 一级导航中项目集、产品、项目、执行菜单根据个性化设置中的选项权限依次判断
14741 用例导出增加执行人和执行时间字段
2022-05-06 17.0.beta1
修复的bug
11398 批量移除需求的权限无法单独设置
+1 -1
View File
@@ -429,13 +429,13 @@ $lang->bug->featureBar['browse']['openedbyme'] = $lang->bug->openedByMe;
$lang->bug->featureBar['browse']['assigntome'] = $lang->bug->assignToMe;
$lang->bug->featureBar['browse']['resolvedbyme'] = $lang->bug->resolvedByMe;
$lang->bug->featureBar['browse']['assignedbyme'] = $lang->bug->assignedByMe;
$lang->bug->featureBar['browse']['unresolved'] = $lang->bug->unResolved;
$lang->bug->featureBar['browse']['more'] = $lang->more;
$lang->bug->moreSelects['unconfirmed'] = $lang->bug->unconfirmed;
$lang->bug->moreSelects['assigntonull'] = $lang->bug->assignToNull;
$lang->bug->moreSelects['longlifebugs'] = $lang->bug->longLifeBugs;
$lang->bug->moreSelects['toclosed'] = $lang->bug->toClosed;
$lang->bug->moreSelects['postponedbugs'] = $lang->bug->postponedBugs;
$lang->bug->moreSelects['overduebugs'] = $lang->bug->overdueBugs;
$lang->bug->moreSelects['needconfirm'] = $lang->bug->needConfirm;
+2 -2
View File
@@ -3087,7 +3087,7 @@ class bugModel extends model
case 'id':
if($canBatchAction)
{
echo html::checkbox('bugIDList', array($bug->id => '')) . html::a(helper::createLink('bug', 'view', "bugID=$bug->id"), sprintf('%03d', $bug->id));
echo html::checkbox('bugIDList', array($bug->id => '')) . html::a(helper::createLink('bug', 'view', "bugID=$bug->id"), sprintf('%03d', $bug->id), '', "data-app='{$this->app->tab}'");
}
else
{
@@ -3389,7 +3389,7 @@ class bugModel extends model
if($type == 'view' && $this->app->tab != 'product')
{
$menu .= $this->buildMenu('bug', 'toStory', $toStoryParams, $bug, $type, $this->lang->icons['story'], '', '', '', "data-app='product' id='tostory'", $this->lang->bug->toStory);
if(common::hasPriv('task', 'create')) $menu .= html::a('#toTask', "<i class='icon icon-check'></i><span class='text'>{$this->lang->bug->toTask}</span>", '', "data-app='qa' data-toggle='modal' class='btn btn-link'");
if(common::hasPriv('task', 'create') and !isonlybody()) $menu .= html::a('#toTask', "<i class='icon icon-check'></i><span class='text'>{$this->lang->bug->toTask}</span>", '', "data-app='qa' data-toggle='modal' class='btn btn-link'");
$menu .= $this->buildMenu('bug', 'createCase', $convertParams, $bug, $type, 'sitemap');
}
if($type == 'view')
+5 -5
View File
@@ -97,17 +97,17 @@
<?php if($branchProduct):?>
<td style='overflow:visible'>
<?php $disabled = (isset($productList) and $productList[$bug->product]->type == 'normal') ? "disabled='disabled'" : '';?>
<?php echo html::select("branches[$bugID]", !empty($disabled) ? array() : $branchTagOption[$bug->product], $bug->branch, "class='form-control picker-select' $disabled onchange='setBranchRelated(this.value, $bug->product, $bug->id)'");?>
<?php echo html::select("branches[$bugID]", !empty($disabled) ? array() : $branchTagOption[$bug->product], $bug->branch, "class='form-control picker-select' data-drop-width='auto' $disabled onchange='setBranchRelated(this.value, $bug->product, $bug->id)'");?>
</td>
<?php endif;?>
<td><?php echo html::select("modules[$bugID]", isset($modules[$bug->product][$bug->branch]) ? $modules[$bug->product][$bug->branch] : array(0 => '/'), $bug->module, "class='form-control picker-select'");?></td>
<td class='<?php echo zget($visibleFields, 'productplan', ' hidden')?>' style='overflow:visible'><?php echo html::select("plans[$bugID]", $plans, $bug->plan, "class='form-control picker-select'");?></td>
<td class='<?php echo zget($visibleFields, 'assignedTo', ' hidden')?>' style='overflow:visible'><?php echo html::select("assignedTos[$bugID]", $users, $bug->assignedTo, "class='form-control picker-select'");?></td>
<td><?php echo html::select("modules[$bugID]", isset($modules[$bug->product][$bug->branch]) ? $modules[$bug->product][$bug->branch] : array(0 => '/'), $bug->module, "class='form-control picker-select' data-drop-width='auto'");?></td>
<td class='<?php echo zget($visibleFields, 'productplan', ' hidden')?>' style='overflow:visible'><?php echo html::select("plans[$bugID]", $plans, $bug->plan, "class='form-control picker-select' data-drop-width='auto'");?></td>
<td class='<?php echo zget($visibleFields, 'assignedTo', ' hidden')?>' style='overflow:visible'><?php echo html::select("assignedTos[$bugID]", $users, $bug->assignedTo, "class='form-control picker-select' data-drop-width='auto'");?></td>
<td class='<?php echo zget($visibleFields, 'deadline', ' hidden')?>' style='overflow:visible'><?php echo html::input("deadlines[$bugID]", $bug->deadline, "class='form-control form-date'");?></td>
<td <?php echo zget($visibleFields, 'os', "class='hidden'")?>><?php echo html::select("os[$bugID]", $osList, $bug->os, 'class=form-control');?></td>
<td <?php echo zget($visibleFields, 'browser', "class='hidden'")?>><?php echo html::select("browsers[$bugID]", $browserList, $bug->browser, 'class=form-control');?></td>
<td <?php echo zget($visibleFields, 'keywords', "class='hidden'")?>><?php echo html::input("keywords[$bugID]", $bug->keywords, 'class=form-control');?></td>
<td class='<?php echo zget($visibleFields, 'resolvedBy', ' hidden')?>' style='overflow:visible'><?php echo html::select("resolvedBys[$bugID]", $users, $bug->resolvedBy, "class='form-control picker-select'");?></td>
<td class='<?php echo zget($visibleFields, 'resolvedBy', ' hidden')?>' style='overflow:visible'><?php echo html::select("resolvedBys[$bugID]", $users, $bug->resolvedBy, "class='form-control picker-select' data-drop-width='auto'");?></td>
<td <?php echo zget($visibleFields, 'resolution', "class='hidden'")?>>
<table class='table-borderless table no-margin'>
<tr>
+10 -3
View File
@@ -55,7 +55,7 @@ class commonModel extends model
if($this->config->systemMode == 'new')
{
if($thisModule == 'task')
if($thisModule == 'task' or $thisModule == 'effort')
{
$taskID = $objectID;
$execution = $this->syncExecutionStatus($taskID);
@@ -2356,7 +2356,8 @@ EOD;
($module == 'user' && strpos('|login|deny|logout|reset|', "|{$method}|") !== false) ||
($module == 'my' && strpos('|changepassword|preference|', "|{$method}|") !== false) ||
($module == 'file' && strpos('|read|download|uploadimages|ajaxwopifiles|', "|{$method}|") !== false) ||
($module == 'sso' && $method == 'login'))
($module == 'sso' && $method == 'login') ||
($module == 'traincourse' && $method == 'ajaxuploadlargefile'))
{
return;
}
@@ -3103,7 +3104,7 @@ EOD;
return;
}
if($currentModule == $tab && $currentMethod== 'create')
if($currentModule == $tab && $currentMethod == 'create')
{
$lang->menu = $lang->$tab->homeMenu;
return;
@@ -3127,6 +3128,12 @@ EOD;
$lang->menu = $lang->$tab->homeMenu;
return;
}
if(isset($menu['subModule']) and strpos(",{$menu['subModule']},", ",$currentModule,") !== false)
{
$lang->menu = $lang->$tab->homeMenu;
return;
}
}
/* Default, display menu. */
+3 -1
View File
@@ -7,7 +7,9 @@
<style>
.histories-list > li {word-break: break-word; word-wrap: break-word;}
.history-changes del {padding-left: 3px;}
#actionbox > .detail-content {width:100%; max-height: 800px; overflow: scroll;}
#actionbox {margin: unset;}
#actionbox .detail-title {padding-left: 10px;}
#actionbox > .detail-content {padding-left: 10px; width:100%; max-height: 800px; overflow: scroll;}
</style>
<script>
$(function()
+3 -3
View File
@@ -26,9 +26,9 @@ $(function()
}
else if(typeof(from) != 'undefined')
{
<?php $from = isset($from) ? $from : '';?>
<?php $from = ($from == 'project' and isset($isStage) and $isStage) ? 'stage' : $from;?>
$dropmenu.append("<li><a href='<?php echo $this->createLink('datatable', 'ajaxCustom', 'id=' . $this->moduleName . '&method=' . $this->methodName . "&extra=$from")?>' data-toggle='modal' data-type='ajax'><?php echo $lang->datatable->custom?></a></li>");
<?php $fromPage = isset($fromPage) ? $fromPage : '';?>
<?php $fromPage = ($fromPage == 'project' and isset($isStage) and $isStage) ? 'stage' : $fromPage;?>
$dropmenu.append("<li><a href='<?php echo $this->createLink('datatable', 'ajaxCustom', 'id=' . $this->moduleName . '&method=' . $this->methodName . "&extra=$fromPage")?>' data-toggle='modal' data-type='ajax'><?php echo $lang->datatable->custom?></a></li>");
}
else
{
+42 -5
View File
@@ -827,19 +827,56 @@ class doc extends control
}
/**
* Ajax get doclib whitelist.
* Ajax get whitelist.
*
* @param int $doclibID
* @param string $acl open|custom|private
* @param string $control user|group
* @access public
* @return string
*/
public function ajaxGetWhitelist($doclibID, $acl)
public function ajaxGetWhitelist($doclibID, $acl = '', $control = '')
{
$doclib = $this->doc->getLibById($doclibID);
$users = $this->user->getPairs('noletter|noempty|noclosed');
$doclib = $this->doc->getLibById($doclibID);
$users = $this->user->getPairs('noletter|noempty|noclosed');
$selectedUser = $doclib->users;
if($control == 'group')
{
$groups = $this->loadModel('group')->getPairs();
$selectedGroup = $doclib->groups;
if($doclib->acl == 'custom')
{
foreach($groups as $groupID => $group)
{
if(strpos($doclib->groups, (string)$groupID) === false) unset($groups[$groupID]);
}
return print(html::select('groups[]', $groups, $selectedGroup, "class='form-control chosen' multiple"));
}
if($doclib->acl == 'open') return print(html::select('groups[]', $groups, $selectedGroup, "class='form-control chosen' multiple"));
if($doclib->acl == 'private') echo 'private';
if($doclib->acl == 'default') echo 'default';
return false;
}
if($control == 'user')
{
foreach($users as $account => $user)
{
if(($doclib->acl == 'custom' or $doclib->acl == 'private') and strpos($doclib->users, (string)$account) === false ) unset($users[$account]);
}
if($doclib->acl == 'custom')
{
return print(html::select('users[]', $users, $selectedUser, "multiple class='form-control"));
}
if($doclib->acl == 'open') return print(html::select('users[]', $users, $selectedUser, "multiple class='form-control"));
if($doclib->acl == 'private') echo 'private';
if($doclib->acl == 'default') echo 'default';
return false;
}
/* Sync whitelist when doclib permissions changed. */
if($doclib->acl != 'custom' and !empty($doclib->project) and $acl == 'custom')
{
$project = $this->loadModel('project')->getById($doclib->project);
+58
View File
@@ -21,15 +21,18 @@ function loadModules(libID)
*/
function toggleAcl(acl, type)
{
var libID = $('#lib').val();
if(acl == 'custom')
{
$('#whiteListBox').removeClass('hidden');
$('#groupBox').removeClass('hidden');
if(type == 'doc') loadWhitelist(libID);
}
else if(acl == 'private')
{
$('#whiteListBox').removeClass('hidden');
$('#groupBox').addClass('hidden');
if(type == 'doc') loadWhitelist(libID);
}
else
{
@@ -78,6 +81,61 @@ function loadDocModule(libID)
$('#module_chosen').remove();
$('#module').chosen();
});
loadWhitelist(libID);
}
/**
* Load whitelist by libID.
*
* @param int $libID
* @access public
* @return void
*/
function loadWhitelist(libID)
{
var groupLink = createLink('doc', 'ajaxGetWhitelist', 'libID=' + libID + '&acl=&control=group');
var userLink = createLink('doc', 'ajaxGetWhitelist', 'libID=' + libID + '&acl=&control=user');
$.post(groupLink, function(groups)
{
if(!(groups == 'default' || groups == 'private'))
{
$('#groups').replaceWith(groups);
$('#groups_chosen').remove();
$('#groups').chosen();
}
});
$.post(userLink, function(users)
{
if(users != 'default')
{
if(users == 'private')
{
$('#aclopen').parent('.radio-inline').addClass('hidden');
$('#aclcustom').parent('.radio-inline').addClass('hidden');
$('#aclprivate').prop('checked', true);
}
else
{
$('#aclopen').parent('.radio-inline').removeClass('hidden');
$('#aclcustom').parent('.radio-inline').removeClass('hidden');
$('#aclprivate').prop('checked', false);
$('#users').replaceWith(users);
$('#users_chosen').remove();
$('#whiteListBox .picker').remove();
if($('#users option').length < maxCount)
{
$('#users').chosen();
}
else
{
$('#users').picker();
}
}
}
});
}
/**
+2 -2
View File
@@ -1084,7 +1084,7 @@ class docModel extends model
if(strpos(",{$object->users},", $account) !== false) return true;
}
if(strpos($extra, 'notdoc') === false)
if(strpos($extra, 'notdoc') !== false)
{
static $extraDocLibs;
if($extraDocLibs === null) $extraDocLibs = $this->getPrivLibsByDoc();
@@ -1118,7 +1118,7 @@ class docModel extends model
if($extraDocLibs === null) $extraDocLibs = $this->getPrivLibsByDoc();
static $libs;
if($libs === null) $libs = $this->getLibs('all', 'notdoc');
if($libs === null) $libs = $this->getLibs('all');
if(isset($libs[$object->lib]) and isset($extraDocLibs[$object->lib])) unset($extraDocLibs[$object->lib]);
if($object->acl == 'open' and !isset($extraDocLibs[$object->lib])) return true;
+1
View File
@@ -10,6 +10,7 @@
* @link http://www.zentao.net
*/
?>
<?php js::set('maxCount', $this->config->maxCount);?>
<?php if($docType != '' and strpos($config->doc->officeTypes, $docType) !== false):?>
<?php include '../../common/view/header.lite.html.php';?>
<div id="mainContent" class="main-content">
+1
View File
@@ -17,6 +17,7 @@
<?php js::set('confirmUpdateContent', $lang->doc->confirmUpdateContent);?>
<?php js::set('docID', $doc->id);?>
<?php js::set('draft', $doc->draft);?>
<?php js::set('maxCount', $this->config->maxCount);?>
<div id='mainContent' class='main-content'>
<div class='center-block'>
<div class='main-header'>
+8 -8
View File
@@ -139,7 +139,7 @@ $config->execution->gantt->linkType['end']['end'] = 2;
$config->execution->gantt->linkType['begin']['end'] = 3;
$config->execution->datatable = new stdclass();
$config->execution->datatable->defaultField = array('id', 'name', 'code', 'project', 'PM', 'status', 'progress', 'begin', 'end', 'estimate', 'consumed', 'left', 'burn');
$config->execution->datatable->defaultField = array('id', 'name', 'code', 'project', 'PM', 'status', 'progress', 'percent', 'attribute', 'begin', 'end', 'estimate', 'consumed', 'left', 'burn', 'actions');
$config->execution->datatable->fieldList['id']['title'] = 'idAB';
$config->execution->datatable->fieldList['id']['fixed'] = 'left';
@@ -153,7 +153,7 @@ $config->execution->datatable->fieldList['name']['required'] = 'yes';
$config->execution->datatable->fieldList['code']['title'] = 'code';
$config->execution->datatable->fieldList['code']['fixed'] = 'no';
$config->execution->datatable->fieldList['code']['width'] = '90';
$config->execution->datatable->fieldList['code']['width'] = '95';
$config->execution->datatable->fieldList['code']['required'] = 'no';
$config->execution->datatable->fieldList['project']['title'] = 'project';
@@ -168,18 +168,18 @@ $config->execution->datatable->fieldList['PM']['required'] = 'no';
$config->execution->datatable->fieldList['status']['title'] = 'status';
$config->execution->datatable->fieldList['status']['fixed'] = 'no';
$config->execution->datatable->fieldList['status']['width'] = '80';
$config->execution->datatable->fieldList['status']['width'] = '100';
$config->execution->datatable->fieldList['status']['required'] = 'no';
$config->execution->datatable->fieldList['progress']['title'] = 'progress';
$config->execution->datatable->fieldList['progress']['fixed'] = 'no';
$config->execution->datatable->fieldList['progress']['width'] = '40';
$config->execution->datatable->fieldList['progress']['width'] = '70';
$config->execution->datatable->fieldList['progress']['required'] = 'no';
$config->execution->datatable->fieldList['progress']['sort'] = 'no';
$config->execution->datatable->fieldList['percent']['title'] = 'percent';
$config->execution->datatable->fieldList['percent']['fixed'] = 'no';
$config->execution->datatable->fieldList['percent']['width'] = '80';
$config->execution->datatable->fieldList['percent']['width'] = '85';
$config->execution->datatable->fieldList['percent']['required'] = 'no';
$config->execution->datatable->fieldList['percent']['sort'] = 'no';
@@ -196,12 +196,12 @@ $config->execution->datatable->fieldList['openedDate']['required'] = 'no';
$config->execution->datatable->fieldList['begin']['title'] = 'begin';
$config->execution->datatable->fieldList['begin']['fixed'] = 'no';
$config->execution->datatable->fieldList['begin']['width'] = '85';
$config->execution->datatable->fieldList['begin']['width'] = '100';
$config->execution->datatable->fieldList['begin']['required'] = 'no';
$config->execution->datatable->fieldList['end']['title'] = 'end';
$config->execution->datatable->fieldList['end']['fixed'] = 'no';
$config->execution->datatable->fieldList['end']['width'] = '85';
$config->execution->datatable->fieldList['end']['width'] = '90';
$config->execution->datatable->fieldList['end']['required'] = 'no';
$config->execution->datatable->fieldList['realBegan']['title'] = 'realBegan';
@@ -224,7 +224,7 @@ $config->execution->datatable->fieldList['estimate']['sort'] = 'no';
$config->execution->datatable->fieldList['consumed']['title'] = 'consumed';
$config->execution->datatable->fieldList['consumed']['fixed'] = 'no';
$config->execution->datatable->fieldList['consumed']['width'] = '70';
$config->execution->datatable->fieldList['consumed']['width'] = '75';
$config->execution->datatable->fieldList['consumed']['required'] = 'no';
$config->execution->datatable->fieldList['consumed']['sort'] = 'no';
+33 -14
View File
@@ -740,6 +740,7 @@ class execution extends control
else
{
$this->session->set('executionStoryBrowseType', $type);
$this->session->set('storyBrowseType', $type, 'execution');
}
/* Save session. */
@@ -1026,6 +1027,7 @@ class execution extends control
$this->loadModel('common')->saveQueryCondition($this->dao->get(), 'testcase', false);
$cases = $this->testcase->appendData($cases, 'case');
$cases = $this->loadModel('story')->checkNeedConfirm($cases);
$this->view->title = $this->lang->execution->testcase;
$this->view->executionID = $executionID;
@@ -1574,6 +1576,9 @@ class execution extends control
return print(js::confirm($this->lang->execution->importEditPlanStory, inlink('edit', "executionID=$executionID&action=edit&extra=&newPlans=$newPlans&confirm=yes"), inlink('view', "executionID=$executionID")));
}
/* Set menu. */
$this->execution->setMenu($executionID);
if(!empty($_POST))
{
$oldPlans = $this->dao->select('plan')->from(TABLE_PROJECTPRODUCT)->where('project')->eq($executionID)->andWhere('plan')->ne(0)->fetchPairs('plan');
@@ -1636,9 +1641,6 @@ class execution extends control
return $this->send(array('result' => 'success', 'message' => $this->lang->saveSuccess, 'locate' => inlink('view', "executionID=$executionID")));
}
/* Set menu. */
$this->execution->setMenu($executionID);
$executions = array('' => '') + $this->executions;
$managers = $this->execution->getDefaultManagers($executionID);
@@ -3476,16 +3478,6 @@ class execution extends control
$parents = array();
if($parentIdList) $parents = $this->execution->getByIdList($parentIdList);
$isStage = (isset($project->model) and $project->model == 'waterfall') ? true : false;
if($isStage)
{
$this->config->execution->datatable->defaultField = array('id', 'name', 'PM', 'status', 'progress', 'percent', 'attribute', 'begin', 'end', 'realBegan', 'realEnd', 'actions');
}
elseif($this->app->tab == 'project')
{
$this->config->execution->datatable->defaultField = array('id', 'name', 'code', 'PM', 'status', 'progress', 'begin', 'end', 'estimate', 'consumed', 'left', 'burn');
}
$this->view->executionStats = $executionStats;
$this->view->productList = $this->loadModel('product')->getProductPairsByProject($projectID);
$this->view->productID = $productID;
@@ -3497,7 +3489,8 @@ class execution extends control
$this->view->users = $this->loadModel('user')->getPairs('noletter');
$this->view->status = $status;
$this->view->from = $from;
$this->view->isStage = $isStage;
$this->view->isStage = (isset($project->model) and $project->model == 'waterfall') ? true : false;
$this->display();
}
@@ -3909,4 +3902,30 @@ class execution extends control
echo true;
}
/**
* AJAX: Gets the start date of the project to which the execution belongs.
*
* @param int $executionID
* @access public
* @return string
*/
public function ajaxGetProjectStartDate($executionID = 0)
{
if($this->config->systemMode == 'new')
{
$execution = $this->dao->select('id,project')->from(TABLE_EXECUTION)->where('id')->eq($executionID)->fetch();
$project = $this->dao->select('begin,end')->from(TABLE_PROJECT)->where('id')->eq($execution->project)->fetch();
if(empty($project))
{
echo '';
return false;
}
$date = array();
$date['begin'] = $project->begin;
$date['end'] = $project->end;
echo json_encode($date);
}
}
}
+4 -2
View File
@@ -1,4 +1,5 @@
body {margin-bottom: 25px;}
.table-responsive {overflow-y: hidden !important;}
#product_chosen .chosen-single {width: 180px;}
.table-children {border-left: 2px solid #cbd0db; border-right: 2px solid #cbd0db;}
@@ -14,6 +15,7 @@ body {margin-bottom: 25px;}
.main-table tbody > tr.table-children > td:first-child::before {width: 3px;}
td.hours {text-align: right; overflow: hidden; text-overflow: ellipsis; white-space: nowrap;}
td.flex {display: flex; flex-flow: row nowrap; justify-content: flex-start; align-items: center; margin-bottom: -1px;}
td.datatable-cell.flex {margin-bottom: -2px;}
td.flex span.label-badge {margin-left: 5px; min-width: 50px;}
td.flex span.label-badge.label-light {min-width: 22px;}
td.flex span.project-type-label {margin-left: 5px; min-width: 36px;}
@@ -30,5 +32,5 @@ td.flex span.project-type-label {min-width: 40px;}
.c-project{text-overflow: unset !important;}
canvas {height: 28px;}
.parent.has-child.c-name.flex, .table-child-bottom > .c-name.flex {border-bottom: 1px solid #cbd0db;}
.parent.has-child.c-name.flex {margin-bottom: -2px;}
.parent.has-child.c-name.flex, .table-child-bottom > .c-name.flex {border-bottom: 1px solid #cbd0db !important;}
.parent.has-child.c-name.flex {margin-bottom: -2px !important;}
+2 -1
View File
@@ -8,7 +8,8 @@ $(function()
});
var nameWidth = $('#executionsForm thead th.c-name').width();
if(nameWidth < 150 && !useDatatable) $('#executionsForm thead th.c-name').css('width', '150px');
if(isCNLang && nameWidth < 150 && !useDatatable) $('#executionsForm thead th.c-name').css('width', '150px');
if(!isCNLang && nameWidth < 200 && !useDatatable) $('#executionsForm thead th.c-name').css('width', '200px');
toggleFold('#executionsForm', unfoldExecutions, projectID, 'execution');
+7 -5
View File
@@ -236,7 +236,8 @@ function createLaneMenu(options)
if(!privs.length) return [];
var items = [];
if(privs.includes('setLane')) items.push({label: kanbanLang.setLane, icon: 'edit', url: createLink('kanban', 'setLane', 'laneID=' + lane.id + '&executionID=0&from=kanban'), className: 'iframe', attrs: {'data-toggle': 'modal', 'data-width': '635px'}});
if(privs.includes('editLaneName')) items.push({label: kanbanLang.editLaneName, icon: 'edit', url: createLink('kanban', 'editLaneName', 'laneID=' + lane.id + '&executionID=0&from=kanban'), className: 'iframe', attrs: {'data-toggle': 'modal', 'data-width': '635px'}});
if(privs.includes('editLaneColor')) items.push({label: kanbanLang.editLaneColor, icon: 'color', url: createLink('kanban', 'editLaneColor', 'laneID=' + lane.id + '&executionID=0&from=kanban'), className: 'iframe', attrs: {'data-toggle': 'modal', 'data-width': '635px'}});
if(privs.includes('deleteLane')) items.push({label: kanbanLang.deleteLane, icon: 'trash', url: createLink('kanban', 'deleteLane', 'lane=' + lane.id), attrs: {'target': 'hiddenwin'}});
var bounds = options.$trigger[0].getBoundingClientRect();
@@ -794,13 +795,14 @@ function renderHeaderCol($column, column, $header, kanbanData)
function renderLaneName($lane, lane, $kanban, columns, kanban)
{
if(groupBy != 'default') return;
var canSet = lane.actions.includes('setLane');
var canSort = lane.actions.includes('sortLane') && kanban.lanes.length > 1;
var canDelete = lane.actions.includes('deleteLane');
var canEditLaneColor = lane.actions.includes('editLaneColor');
var canEditLaneName = lane.actions.includes('editLaneName');
var canSort = lane.actions.includes('sortLane') && kanban.lanes.length > 1;
var canDelete = lane.actions.includes('deleteLane');
$lane.parent().toggleClass('sort', canSort);
if(!$lane.children('.actions').length && (canSet || canDelete))
if(!$lane.children('.actions').length && (canEditLaneColor || canEditLaneName || canDelete))
{
$([
'<div class="actions" title="' + kanbanLang.more + '">',
+2 -2
View File
@@ -270,8 +270,8 @@ $lang->execution->treeOnlyTask = 'Show Task Only';
$lang->execution->treeOnlyStory = 'Show Story Only';
$lang->execution->storyKanban = 'Story Kanban';
$lang->execution->storySort = 'Rank Story';
$lang->execution->importPlanStory = $lang->executionCommon . ' is created!\nDo you want to import stories that have been linked to the plan?';
$lang->execution->importEditPlanStory = $lang->executionCommon . ' is edited!\nDo you want to import stories that have been linked to the plan?';
$lang->execution->importPlanStory = $lang->executionCommon . ' is created!\nDo you want to import stories that have been linked to the plan? The stories in the draft will be automatically filtered out when imported.';
$lang->execution->importEditPlanStory = $lang->executionCommon . ' is edited!\nDo you want to import stories that have been linked to the plan? The stories in the draft will be automatically filtered out when imported.';
$lang->execution->needLinkProducts = 'The execution has not been linked with any product, and the related functions cannot be used. Please link the product first and try again.';
$lang->execution->iteration = 'Iterations';
$lang->execution->iterationInfo = '%s Iterations';
+2 -2
View File
@@ -270,8 +270,8 @@ $lang->execution->treeOnlyTask = '树状图只看任务';
$lang->execution->treeOnlyStory = "树状图只看{$lang->SRCommon}";
$lang->execution->storyKanban = "{$lang->SRCommon}看板";
$lang->execution->storySort = "{$lang->SRCommon}排序";
$lang->execution->importPlanStory = '创建' . $lang->executionCommon . '成功!\n是否导入计划关联的相关' . $lang->SRCommon . '';
$lang->execution->importEditPlanStory = '编辑' . $lang->executionCommon . '成功!\n是否导入计划关联的相关' . $lang->SRCommon . '';
$lang->execution->importPlanStory = '创建' . $lang->executionCommon . '成功!\n是否导入计划关联的相关' . $lang->SRCommon . '导入时将自动过滤掉草稿状态的' . $lang->SRCommon . '。';
$lang->execution->importEditPlanStory = '编辑' . $lang->executionCommon . '成功!\n是否导入计划关联的相关' . $lang->SRCommon . '导入时将自动过滤掉草稿状态的' . $lang->SRCommon . '。';
$lang->execution->needLinkProducts = '该执行还未关联任何产品,相关功能无法使用,请先关联产品后再试。';
$lang->execution->iteration = '版本迭代';
$lang->execution->iterationInfo = '迭代%s次';
+4 -6
View File
@@ -2024,6 +2024,8 @@ class executionModel extends model
$data->product = $productID;
$data->branch = $branch;
$data->plan = isset($plans[$productID][$branch]) ? implode(',', $plans[$productID][$branch]) : $oldPlan;
$data->plan = trim($data->plan, ',');
$data->plan = empty($data->plan) ? 0 : ",$data->plan,";
$this->dao->insert(TABLE_PROJECTPRODUCT)->data($data)->exec();
$existedProducts[$productID][$branch] = true;
}
@@ -2535,7 +2537,6 @@ class executionModel extends model
$planStories = array();
$planProducts = array();
$count = 0;
$this->loadModel('story');
if(!empty($plans))
{
@@ -2552,7 +2553,6 @@ class executionModel extends model
{
if($story->status == 'draft')
{
$count++;
unset($planStory[$id]);
continue;
}
@@ -2567,7 +2567,6 @@ class executionModel extends model
$projectID = $this->dao->select('project')->from(TABLE_EXECUTION)->where('id')->eq($executionID)->fetch('project');
$this->linkStory($executionID, $planStories, $planProducts);
if($this->config->systemMode == 'new') $this->linkStory($projectID, $planStories, $planProducts);
if($count != 0) echo js::alert(sprintf($this->lang->execution->haveDraft, $count)) . js::locate(helper::createLink('execution', 'create', "projectID=$projectID&executionID=$executionID"));
}
/**
@@ -3103,7 +3102,6 @@ class executionModel extends model
if($currentTime > time() and !$todayTag)
{
$todayTag = $i + 1;
break;
}
if(!isset($sets[$current]) and $mode == 'noempty')
@@ -4167,7 +4165,7 @@ class executionModel extends model
$id = $col->id;
$onlyChildStage = ($execution->grade == 2 and $execution->project != $execution->parent);
if(!$isStage and $col->id == 'actions') return;
if(!$isStage and in_array($col->id, array('percent', 'attribute', 'actions'))) return;
if(($this->config->systemMode == 'classic' or ($this->config->systemMode == 'new' and $this->app->tab != 'execution')) and $col->id == 'project') return;
if($col->show)
@@ -4221,7 +4219,7 @@ class executionModel extends model
{
echo "<div class='checkbox-primary'><input type='checkbox' name='executionIDList[$execution->id]' value='$execution->id' autocomplete='off'/><label></label></div>";
}
echo printf('%03d', $execution->id);
echo sprintf('%03d', $execution->id);
break;
case 'name':
$label = $execution->type == 'stage' ? 'label-warning' : 'label-info';
+8 -3
View File
@@ -26,6 +26,7 @@ $unfoldExecutions = zget($unfoldExecutions, $projectID, array());
js::set('unfoldExecutions', $unfoldExecutions);
js::set('unfoldAll', $lang->execution->treeLevel['all']);
js::set('foldAll', $lang->execution->treeLevel['root']);
js::set('isCNLang', !$this->loadModel('common')->checkNotCN())
?>
<div id='mainMenu' class='clearfix'>
<div class='btn-toolbar pull-left'>
@@ -106,7 +107,11 @@ js::set('foldAll', $lang->execution->treeLevel['root']);
$hasActions = false;
foreach($setting as $key => $value)
{
if($value->id == 'actions') $hasActions = true;
if($value->id == 'actions')
{
$hasActions = true;
$value->show = true;
}
}
if(!$hasActions)
@@ -126,9 +131,9 @@ js::set('foldAll', $lang->execution->treeLevel['root']);
foreach($setting as $key => $value)
{
if($value->show || $value->id == 'actions')
if($value->show)
{
if($isStage and $value->id == 'actions') $value->show = true;
if(!$isStage and in_array($value->id, array('percent', 'attribute', 'actions'))) continue;
if(($config->systemMode == 'classic' or ($config->systemMode == 'new' and $this->app->tab != 'execution')) and $value->id == 'project') continue;
$this->datatable->printHead($value, $orderBy, $vars, $canBatchEdit);
+27 -5
View File
@@ -144,8 +144,6 @@ js::set('emptyEnd', $lang->programplan->emptyEnd);
js::set('planFinishSmall', $lang->programplan->error->planFinishSmall);
js::set('errorBegin', $lang->execution->errorLetterProject);
js::set('errorEnd', $lang->execution->errorGreaterProject);
js::set('projectBeginDate', $project->begin);
js::set('projectEndDate', $project->end);
?>
<script>
@@ -157,8 +155,9 @@ $('#executionForm').submit(function()
var beginDate = $(this).val();
var beginDateID = $(this).attr('id');
var nameID = beginDateID.replace('begins', 'names');
var endDateID = beginDateID.replace('begins', 'ends');
var nameID = beginDateID.replace('begins', 'names');
var endDateID = beginDateID.replace('begins', 'ends');
var executionID = beginDateID.replace('begins', '');
$('#help' + beginDateID).remove();
$('#help' + endDateID).remove();
@@ -166,6 +165,25 @@ $('#executionForm').submit(function()
var nameVal = $('#' + nameID).val()
if(!nameVal) return;
var projectBeginDate = '0000-00-00';
var projectEndDate = '2059-12-31';
$.ajax(
{
url: createLink('execution', 'ajaxGetProjectStartDate', "executionID=" + executionID),
dataType: 'json',
method: 'post',
async: false,
success: function(data)
{
if(data)
{
projectBeginDate = data.begin;
projectEndDate = data.end;
}
}
});
// Check if the begin date is empty.
if(!beginDate)
{
@@ -216,7 +234,11 @@ $('#executionForm').submit(function()
}
});
if(!submitForm) return false;
if(!submitForm)
{
setTimeout(function(){$('#submit').removeAttr('disabled')}, 500);
return false;
}
});
</script>
<?php include '../../common/view/footer.html.php';?>
+1 -1
View File
@@ -71,7 +71,7 @@
{
if(common::hasPriv('story', 'view'))
{
echo html::a($this->createLink('story', 'view', "storyid=$task->storyID"), $task->storyTitle);
echo html::a($this->createLink('story', 'view', "storyid=$task->storyID"), $task->storyTitle, '', "class='preview'", true, isonlybody());
}
else
{
+19 -12
View File
@@ -32,7 +32,7 @@
<th class='c-date'> <?php common::printOrderLink('lastRunDate', $orderBy, $vars, $lang->testtask->lastRunTime);?></th>
<th class='c-result'><?php common::printOrderLink('lastRunResult', $orderBy, $vars, $lang->testtask->lastRunResult);?></th>
<th class='c-status'><?php common::printOrderLink('status', $orderBy, $vars, $lang->statusAB);?></th>
<th class='c-actions-5 text-center'> <?php echo $lang->actions;?></th>
<th class='c-actions-6 text-center'><?php echo $lang->actions;?></th>
</tr>
</thead>
<tbody>
@@ -40,7 +40,6 @@
<?php
$caseID = $type == 'assigntome' ? $case->case : $case->id;
$runID = $type == 'assigntome' ? $case->id : 0;
$canBeChanged = common::canBeChanged('testcase', $case);
?>
<tr>
<td class="c-id">
@@ -55,18 +54,26 @@
<td><?php echo zget($users, $case->lastRunner);?></td>
<td><?php if(!helper::isZeroDate($case->lastRunDate)) echo date(DT_MONTHTIME1, strtotime($case->lastRunDate));?></td>
<td class='<?php echo $case->lastRunResult;?>'><?php if($case->lastRunResult) echo $lang->testcase->resultList[$case->lastRunResult];?></td>
<td class='<?php if(isset($run)) echo $run->status;?>'><?php echo $this->processStatus('testcase', $case);?></td>
<td>
<?php
if($case->needconfirm)
{
echo "<span class='status-story status-changed' title='{$this->lang->story->changed}'>{$this->lang->story->changed}</span>";
}
elseif(isset($case->fromCaseVersion) and $case->fromCaseVersion > $case->version and !$case->needconfirm)
{
echo "<span class='status-story status-changed' title='{$this->lang->testcase->changed}'>{$this->lang->testcase->changed}</span>";
}
else
{
echo "<span class='status-testcase status-{$case->status}'>" . $this->processStatus('testcase', $case) . "</span>";
}
?>
</td>
<td class='c-actions'>
<?php
if($canBeChanged)
{
$disabled = $case->status == 'wait' ? 'disabled' : '';
common::printIcon('testcase', 'createBug', "product=$case->product&branch=$case->branch&extra=caseID=$caseID,version=$case->version,runID=$runID,executionID=$executionID", $case, 'list', 'bug', '', 'iframe', '', "data-width='90%'", '', $case->project);
common::printIcon('testcase', 'create', "productID=$case->product&branch=$case->branch&moduleID=$case->module&from=testcase&param=$caseID", $case, 'list', 'copy', '', '', '', '', '', $case->project);
common::printIcon('testtask', 'runCase', "runID=$runID&caseID=$caseID&version=$case->version", '', 'list', 'play', '', "iframe $disabled", true, "data-width='95%'", '', $case->project);
common::printIcon('testtask', 'results', "runID=$runID&caseID=$caseID", '', 'list', 'list-alt', '', 'iframe', true, "data-width='95%'", '', $case->project);
common::printIcon('testcase', 'edit', "caseID=$caseID&comment=false&executionID=$executionID", $case, 'list', 'edit', '', '', '', '', '', $case->project);
}
$case->browseType = $type;
echo $this->testcase->buildOperateMenu($case, 'browse');
?>
</td>
</tr>
+1 -1
View File
@@ -252,7 +252,7 @@
$planIDList = explode(',', $planIDList);
foreach($planIDList as $planID)
{
if(isset($planGroups[$productID][$planID])) echo '<div class="col-xs-12">' . html::a($this->createLink('productplan', 'view', "planID={$planID}"), $product->name . '/' . $planGroups[$productID][$planID]) . '</div>';
if(isset($planGroups[$productID][$planID])) echo '<div class="col-xs-12">' . "<i class='icon icon-calendar text-muted'></i> " . html::a($this->createLink('productplan', 'view', "planID={$planID}"), $product->name . '/' . $planGroups[$productID][$planID]) . '</div>';
}
}
}
-1
View File
@@ -1404,7 +1404,6 @@ $lang->sonarqube->methodOrder[50] = 'browseIssue';
/* merge request. */
$lang->resource->mr = new stdclass();
$lang->resource->mr->create = 'create';
$lang->resource->mr->apiCreate = 'apiCreate';
$lang->resource->mr->browse = 'browse';
$lang->resource->mr->edit = 'edit';
$lang->resource->mr->delete = 'delete';
+1
View File
@@ -615,6 +615,7 @@ class kanban extends control
}
$kanban = $from == 'execution' ? $this->loadModel('execution')->getByID($kanbanID) : $this->kanban->getByID($kanbanID);
if($from == 'execution') $this->lang->kanbanlane->heightTypeList['auto'] = $this->lang->kanbanlane->heightByCard;
$this->view->heightType = $kanban->displayCards > 2 ? 'custom' : 'auto';
$this->view->displayCards = $kanban->displayCards ? $kanban->displayCards : '';
+2 -2
View File
@@ -1,3 +1,3 @@
#mainContent {padding-left: 0px; height: 500px;}
#contactListMenu_chosen {float: left;}
#teamBox .input-group .input-group-btn {vertical-align: unset;}
#contactListMenu_chosen {vertical-align: unset;}
#teamBox .input-group .input-group-btn {vertical-align: top;}
+2 -1
View File
@@ -102,7 +102,8 @@
.cardcolor {width:40px; height: 14px; float: left; margin-left: 5px; margin-right: 5px; margin-top: 2px; border-radius: 2px;}
#cardcolormenu {padding:2px 2px; width: 100px;}
.position {margin-top: -6px;}
.region-header {margin-top: -6px;}
.region-header > .icon{padding: 6px; margin-left:2px;}
.kanban-col[data-type=ADD] {display: none;}
.kanban-col[data-type=EMPTY] {display: none;}
.kanban-col {padding-right: 0px !important;}
+2 -1
View File
@@ -1387,7 +1387,7 @@ $(function()
$(this).toggleClass('icon-angle-top icon-angle-down');
$(this).parents('.region').find('.kanban').toggle();
hideKanbanAction();
resetRegionHeight($(this).hasClass('icon-chevron-double-up') ? 'open' : 'close');
resetRegionHeight($(this).hasClass('icon-angle-top') ? 'open' : 'close');
});
$('.region-header').on('click', '.action', hideKanbanAction);
@@ -1700,6 +1700,7 @@ function resetRegionHeight(fold)
{
$('.region').css('height', regionHeaderHeight);
}
}
$(document).on('click', '.dropdown-menu', function()
+8 -7
View File
@@ -308,13 +308,14 @@ $lang->kanbancolumn->confirmDeleteChild = 'Are you sure to delete this column? A
$lang->kanbancolumn->confirmRestore = 'Are you sure you want to restore this Kanban column? After restoring the Kanban column, the Kanban column and all tasks in the Kanban column will be restored to the previous position at the same time.';
$lang->kanbanlane = new stdclass();
$lang->kanbanlane->name = $lang->kanban->laneName;
$lang->kanbanlane->common = 'Lane';
$lang->kanbanlane->default = 'Default Lane';
$lang->kanbanlane->column = 'Lane Kanban Column';
$lang->kanbanlane->otherlane = 'Select Existed Lane';
$lang->kanbanlane->color = 'Lane Color';
$lang->kanbanlane->WIPType = 'Lane WIP Type';
$lang->kanbanlane->name = $lang->kanban->laneName;
$lang->kanbanlane->common = 'Lane';
$lang->kanbanlane->default = 'Default Lane';
$lang->kanbanlane->column = 'Lane Kanban Column';
$lang->kanbanlane->otherlane = 'Select Existed Lane';
$lang->kanbanlane->color = 'Lane Color';
$lang->kanbanlane->WIPType = 'Lane WIP Type';
$lang->kanbanlane->heightByCard = 'Adaptive (Adaptive to card height)';
$lang->kanbanlane->confirmDelete = 'Are you sure to delete this lane? After deleting the lane, all data (columns and cards) in the lane will also be deleted.';
$lang->kanbanlane->confirmDeleteTip = 'Are you sure to delete this lane? After deleting the lane, all %s in the lane will be hidden.';
+8 -7
View File
@@ -308,13 +308,14 @@ $lang->kanbancolumn->confirmDeleteChild = '您确认删除该列吗?删除列
$lang->kanbancolumn->confirmRestore = '您确定要还原该看板列吗?还原后,该看板列将回到之前的位置。';
$lang->kanbanlane = new stdclass();
$lang->kanbanlane->name = $lang->kanban->laneName;
$lang->kanbanlane->common = '泳道';
$lang->kanbanlane->default = '默认泳道';
$lang->kanbanlane->column = '泳道看板列';
$lang->kanbanlane->otherlane = '选择共享看板列的泳道';
$lang->kanbanlane->color = '泳道颜色';
$lang->kanbanlane->WIPType = '泳道在制品类型';
$lang->kanbanlane->name = $lang->kanban->laneName;
$lang->kanbanlane->common = '泳道';
$lang->kanbanlane->default = '默认泳道';
$lang->kanbanlane->column = '泳道看板列';
$lang->kanbanlane->otherlane = '选择共享看板列的泳道';
$lang->kanbanlane->color = '泳道颜色';
$lang->kanbanlane->WIPType = '泳道在制品类型';
$lang->kanbanlane->heightByCard = '自适应(根据卡片高度自适应)';
$lang->kanbanlane->confirmDelete = '您确认删除该泳道吗?删除泳道后,该泳道中所有数据(列、卡片)也会被删除。';
$lang->kanbanlane->confirmDeleteTip = '您确认删除该泳道吗?删除泳道后,该泳道中所有的%s将被隐藏。';
+1 -1
View File
@@ -57,7 +57,7 @@ $canCreateLane = commonModel::hasPriv('kanban', 'createLane');
<div class="region<?php if($canSortRegion) echo ' sort';?>" data-id="<?php echo $region->id;?>">
<div class="region-header dropdown">
<strong><?php echo $region->name;?></strong>
<button class="btn btn-link action position"><i class="icon icon-angle-top" data-id="<?php echo $region->id;?>"></i></button>
<i class="icon icon-angle-top btn-link" data-id="<?php echo $region->id;?>"></i>
<div class='region-actions'>
<?php if(($canEditRegion || $canCreateLane || $canDeleteRegion) and !(isset($this->config->CRKanban) and $this->config->CRKanban == '0' and $kanban->status == 'closed')):?>
<button class="btn btn-link action" type="button" data-toggle="dropdown"><i class="icon icon-ellipsis-v"></i></button>
+1 -1
View File
@@ -142,7 +142,7 @@ class message extends control
else
{
echo <<<EOT
<div class='alert alert-info with-icon alert-dismissable' style='width:380px; position:fixed; bottom:25px; right:15px; z-index: 9999;'>
<div class='alert alert-info with-icon alert-dismissable' style='width:380px; position:fixed; margin-bottom:0px; bottom:0px; right:15px; z-index: 9999;'>
<i class='icon icon-envelope-o'> </i>
<div class='content'>{$messages}</div>
<button type="button" class="close" data-dismiss="alert">×</button>
+2
View File
@@ -103,6 +103,7 @@ $lang->misc->feature->themeDesc = '<p>ZenTao 15.0+ a new "Youth Blue" theme
$lang->misc->feature->visionsDesc = "<p>The concept of interface has been added since 16.5. Users can deal with R & D affairs in <span style='color: #0c60e1'>[R&D]</span> and daily office affairs in <span style='color: #0c60e1'>[Lite]</span>.</p><p>You can view the current interface on the avatar, and click the name of the interface to view and switch other interfaces.</p>";
$lang->misc->feature->visionsImage = 'theme/default/images/main/visions_en.png';
$lang->misc->releaseDate['17.1'] = '2022-06-16';
$lang->misc->releaseDate['17.0'] = '2022-06-02';
$lang->misc->releaseDate['17.0.beta2'] = '2022-05-26';
$lang->misc->releaseDate['17.0.beta1'] = '2022-05-06';
@@ -182,6 +183,7 @@ $lang->misc->releaseDate['7.2.stable'] = '2015-05-22';
$lang->misc->releaseDate['7.1.stable'] = '2015-03-07';
$lang->misc->releaseDate['6.3.stable'] = '2014-11-07';
$lang->misc->feature->all['17.1'][] = array('title' => "Modify the interaction problem of execution, project module. Complete customer's high priority requirements. The detail experience is optimized, fix bugs.", 'desc' => '');
$lang->misc->feature->all['17.0'][] = array('title' => 'The detail experience is optimized, fix bugs.', 'desc' => '');
$lang->misc->feature->all['17.0.beta2'][] = array('title' => 'The detail experience is optimized, fix bugs.', 'desc' => '');
$lang->misc->feature->all['17.0.beta1'][] = array('title' => "Complete customer's high priority requirements", 'desc' => '');
+2
View File
@@ -103,6 +103,7 @@ $lang->misc->feature->themeDesc = "<p>禅道15系列上线了全新的“
$lang->misc->feature->visionsDesc = "<p>从16.5开始增加了界面概念,用户可以在<span style='color:#0c60e1'>[研发综合界面]</span>中处理研发事务、在<span style='color:#0c60e1'>[迅捷界面]</span>处理日常办公事务。</p><p>在头像右侧即可查看当前所处界面,点击当前界面名称可查看和切换其他的界面。</p>";
$lang->misc->feature->visionsImage = 'theme/default/images/main/visions.png';
$lang->misc->releaseDate['17.1'] = '2022-06-16';
$lang->misc->releaseDate['17.0'] = '2022-06-02';
$lang->misc->releaseDate['17.0.beta2'] = '2022-05-26';
$lang->misc->releaseDate['17.0.beta1'] = '2022-05-06';
@@ -182,6 +183,7 @@ $lang->misc->releaseDate['7.2.stable'] = '2015-05-22';
$lang->misc->releaseDate['7.1.stable'] = '2015-03-07';
$lang->misc->releaseDate['6.3.stable'] = '2014-11-07';
$lang->misc->feature->all['17.1'][] = array('title' => '修改执行、项目模块的交互问题,完成客户巴高优先级需求,细节体验优化。修复Bug。', 'desc' => '');
$lang->misc->feature->all['17.0'][] = array('title' => '细节体验优化。修复Bug。', 'desc' => '');
$lang->misc->feature->all['17.0.beta2'][] = array('title' => '细节体验优化。修复Bug。', 'desc' => '');
$lang->misc->feature->all['17.0.beta1'][] = array('title' => '完成客户巴高优先级需求。修复Bug。', 'desc' => '');
-24
View File
@@ -99,30 +99,6 @@ class mr extends control
$this->display();
}
/**
* Create MR function by api.
*
* @access public
* @return void
*/
public function apiCreate()
{
if($_POST)
{
$this->mr->apiCreate();
$response['result'] = 'success';
$response['message'] = $this->lang->saveSuccess;
if(dao::isError())
{
$response['result'] = 'fail';
$response['message'] = join("\n", dao::getError());
}
return $this->send($response);
}
}
/**
* Edit MR function.
*
+14 -18
View File
@@ -249,32 +249,30 @@ class mrModel extends model
public function apiCreate()
{
$postData = fixer::input('post')->get();
$postData = (object)$postData->data;
$repo = $this->loadModel('repo')->getRepoByUrl($postData->RepoUrl);
if(empty($repo['data']))
$repo = $this->dao->findByID($postData->repoID)->from(TABLE_REPO)->fetch();
if(empty($repo))
{
dao::$errors[] = $repo['message'];
dao::$errors[] = 'No matched gitlab.';
return false;
}
$repo = $repo['data'];
/* Process and insert mr data. */
$MR = new stdClass();
$MR->gitlabID = $repo->client;
$MR->sourceProject = $repo->path;
$MR->sourceBranch = $postData->RepoSrcBranch;
$MR->sourceBranch = $postData->sourceBranch;
$MR->targetProject = $repo->path;
$MR->targetBranch = $postData->RepoDistBranch;
$MR->diffs = $this->post->data['DiffMsg'];
$MR->title = $this->lang->mr->common . ' ' . $postData->RepoSrcBranch . $this->lang->mr->to . $postData->RepoDistBranch ;
$MR->targetBranch = $postData->targetBranch;
$MR->diffs = $postData->diffs;
$MR->title = $this->lang->mr->common . ' ' . $postData->sourceBranch . $this->lang->mr->to . $postData->targetBranch ;
$MR->repoID = $repo->id;
$MR->jobID = isset($repo->job->id) ? $repo->job->id : 0;
$MR->jobID = $postData->jobID;
$MR->status = 'opened';
$MR->synced = '0';
$MR->needCI = '1';
$MR->hasNoConflict = $postData->MergeStatus ? '0' : '1';
$MR->mergeStatus = $postData->MergeStatus ? 'can_be_merged' : 'cannot_be_merged';
$MR->hasNoConflict = $postData->mergeStatus ? '0' : '1';
$MR->mergeStatus = $postData->mergeStatus ? 'can_be_merged' : 'cannot_be_merged';
$MR->createdBy = $this->app->user->account;
$MR->createdDate = date('Y-m-d H:i:s');
@@ -303,11 +301,9 @@ class mrModel extends model
/* Exec Job */
if($MR->hasNoConflict == '0' && $MR->mergeStatus == 'can_be_merged' && $MR->jobID)
{
$extraParam = array();
if(!empty($repo->fileServerUrl)) $extraParam = array('ZENTAO_REPOPATH' => $repo->fileServerUrl);
$pipeline = $this->loadModel('job')->exec($MR->jobID, $extraParam);
$newMR = new stdClass();
$extraParam = array('sourceBranch' => $MR->sourceBranch, 'targetBranch' => $MR->targetBranch);
$pipeline = $this->loadModel('job')->exec($MR->jobID, $extraParam);
$newMR = new stdClass();
if(!empty($pipeline->queue))
{
$compile = $this->loadModel('compile')->getByQueue($pipeline->queue);
@@ -325,7 +321,7 @@ class mrModel extends model
$this->dao->update(TABLE_MR)->data($newMR)->where('id')->eq($MRID)->autoCheck()->exec();
if(dao::isError()) return false;
}
return true;
return $MRID;
}
/**
+13 -10
View File
@@ -462,33 +462,35 @@ class product extends control
if(!empty($unmodifiableProjects)) $canChangeProgram = false;
/* Get the projects linked with this product. */
$projectPairs = $this->dao->select('t2.id,t2.name')->from(TABLE_PROJECTPRODUCT)->alias('t1')
$projects = $this->dao->select('t2.id,t2.name,t2.path')->from(TABLE_PROJECTPRODUCT)->alias('t1')
->leftJoin(TABLE_PROJECT)->alias('t2')->on('t1.project = t2.id')
->where('t1.product')->eq($productID)
->andWhere('t2.type')->eq('project')
->andWhere('t2.deleted')->eq('0')
->fetchPairs();
->fetchAll('id');
if(!empty($projectPairs))
$projectPathList = array();
if(!empty($projects))
{
foreach($projectPairs as $projectID => $projectName)
foreach($projects as $projectID => $project)
{
$projectPathList[$projectID] = $project->path;
if($canChangeProgram)
{
$products = $this->dao->select('product')->from(TABLE_PROJECTPRODUCT)->where('project')->eq($projectID)->fetchPairs();
if(count($products) == 1)
{
$singleLinkProjects[$projectID] = $projectName;
$singleLinkProjects[$projectID] = $project->name;
}
if(count($products) > 1)
{
$multipleLinkProjects[$projectID] = $projectName;
$multipleLinkProjects[$projectID] = $project->name;
}
}
else
{
if(isset($unmodifiableProjects[$projectID])) $linkStoriesProjects[$projectID] = $projectName;
if(isset($unmodifiableProjects[$projectID])) $linkStoriesProjects[$projectID] = $project->name;
}
}
}
@@ -579,6 +581,7 @@ class product extends control
$this->view->singleLinkProjects = $singleLinkProjects;
$this->view->multipleLinkProjects = $multipleLinkProjects;
$this->view->linkStoriesProjects = $linkStoriesProjects;
$this->view->projectPathList = $projectPathList;
unset($this->lang->product->typeList['']);
$this->display();
@@ -1255,10 +1258,10 @@ class product extends control
$pager = new pager($recTotal, $recPerPage, $pageID);
/* Process product structure. */
if($this->config->systemMode == 'classic' and $orderBy == 'program_asc') $orderBy = 'order_desc';
$productStats = $this->product->getStats($orderBy, $pager, $browseType, '', 'story', '', $queryID);
$productStructure = $this->product->statisticProgram($productStats);
$productLines = $this->dao->select('*')->from(TABLE_MODULE)->where('type')->eq('line')->andWhere('deleted')->eq(0)->orderBy('`order`')->fetchAll();
array_multisort(array_column($productLines, 'order'), SORT_ASC, $productLines);
$productLines = $this->dao->select('*')->from(TABLE_MODULE)->where('type')->eq('line')->andWhere('deleted')->eq(0)->orderBy('`order` asc')->fetchAll();
$programLines = array();
foreach($productLines as $index => $productLine)
@@ -1267,7 +1270,7 @@ class product extends control
$programLines[$productLine->root][$productLine->id] = $productLine->name;
}
$actionURL = $this->createLink('product', 'all', "browseType=bySearch&orderBy=order_asc&queryID=myQueryID");
$actionURL = $this->createLink('product', 'all', "browseType=bySearch&orderBy=order_desc&queryID=myQueryID");
$this->product->buildProductSearchForm($param, $actionURL);
$this->view->title = $this->lang->product->common;
+1 -1
View File
@@ -43,7 +43,7 @@ th.c-story {width: 290px;}
th.c-bug {width: 200px;}
th.c-plan {width: 45px;}
th.c-release {width: 50px;}
th.c-actions {width: 60px;}
th.c-actions {width: 50px;}
[lang='en'] .en-wrap-text {white-space: normal; height: 24px; line-height: 1; font-size: 12px;}
+9 -1
View File
@@ -3,7 +3,15 @@ $(function()
$('#program').change(function()
{
var programID = $(this).val();
if(!canChangeProgram || singleLinkProjects.length !== 0 || multipleLinkProjects.length !== 0)
var canChange = true;
for(var i = 0; i < linkStoriesProjectIDList.length; i ++)
{
var projectID = linkStoriesProjectIDList[i];
var path = projectPathList[projectID];
if(path.indexOf(',' + programID + ',') < 0) canChange = false;
}
if(!canChange && (!canChangeProgram || singleLinkProjects.length !== 0 || multipleLinkProjects.length !== 0))
{
$('#changeProgram').modal({show: true});
if(!canChangeProgram)
+1 -1
View File
@@ -89,7 +89,7 @@ $lang->product->programChangeTip = "如下项目只关联了该{$lang->produ
$lang->product->notChangeProgramTip = "{$lang->productCommon}{$lang->SRCommon}已经关联到如下项目,请取消关联后再操作";
$lang->product->confirmChangeProgram = "如下项目既关联了该{$lang->productCommon}又关联了其他{$lang->productCommon},请确认是否继续关联该{$lang->productCommon},勾选后将取消与其他{$lang->productCommon}的关联关系,同时转移至新项目集下。";
$lang->product->changeProgramError = "{$lang->productCommon}{$lang->SRCommon}已经关联到项目,请取消关联后再操作";
$lang->product->changeLineError = "产品线下已有产品,不可修改所属项目集";
$lang->product->changeLineError = "产品线下已有产品不可修改所属项目集";
$lang->product->programEmpty = '项目集不能为空';
$lang->product->nameIsDuplicate = "『%s』产品线已经存在,请重新设置!";
$lang->product->nameIsDuplicated = "产品线已经有『%s』这条记录了。如果您确定该记录已删除,请到后台-系统-数据-回收站还原。";
+8 -25
View File
@@ -760,25 +760,6 @@ class productModel extends model
->remove('uid,changeProjects,contactListMenu')
->get();
if($this->config->systemMode == 'new')
{
if($product->program != $oldProduct->program)
{
/* Link the projects stories under this product. */
$unmodifiableProjects = $this->dao->select('t1.*')->from(TABLE_PROJECTSTORY)->alias('t1')
->leftJoin(TABLE_PROJECT)->alias('t2')->on('t1.project = t2.id')
->where('t1.product')->eq($productID)
->andWhere('t2.type')->eq('project')
->andWhere('t2.deleted')->eq('0')
->fetchPairs('project', 'product');
if(!empty($unmodifiableProjects))
{
dao::$errors[] = $this->lang->product->changeProgramError;
return false;
}
}
}
$product = $this->loadModel('file')->processImgURL($product, $this->config->product->editor->edit['id'], $this->post->uid);
$programID = isset($product->program) ? $product->program : '';
$this->dao->update(TABLE_PRODUCT)->data($product)->autoCheck()
@@ -917,13 +898,16 @@ class productModel extends model
$data = fixer::input('post')->get();
/* When there are products under the line, the program cannot be modified */
foreach($oldLines as $oldLine)
if($this->config->systemMode == 'new')
{
$oldLineID = 'id' . $oldLine->id;
if($data->programs[$oldLineID] != $oldLine->root)
foreach($oldLines as $oldLine)
{
$product = $this->dao->select('*')->from(TABLE_PRODUCT)->where('line')->eq($oldLine->id)->fetch();
if(!empty($product)) return print(js::error($this->lang->product->changeLineError));
$oldLineID = 'id' . $oldLine->id;
if($data->programs[$oldLineID] != $oldLine->root)
{
$product = $this->dao->select('*')->from(TABLE_PRODUCT)->where('line')->eq($oldLine->id)->fetch();
if(!empty($product)) return print(js::error($this->lang->product->changeLineError));
}
}
}
@@ -2157,7 +2141,6 @@ class productModel extends model
$menu .= $this->buildMenu('product', 'edit', $params, $product, $type);
if($type == 'view') $menu .= $this->buildMenu('product', 'delete', $params, $product, $type, 'trash', 'hiddenwin');
if($type == 'browse' && common::hasPriv('product', 'updateOrder')) $menu .= "<i class='icon icon-move text-blue'></i>";
return $menu;
}
+2 -2
View File
@@ -207,7 +207,7 @@
<?php if($canBatchEdit):?>
<td class='c-checkbox'><?php echo html::checkbox('productIDList', array($product->id => ''));?></td>
<?php endif;?>
<td class="c-name text-left table-nest-title" title='<?php echo $product->name?>'>
<td class="c-name text-left sort-handler table-nest-title" title='<?php echo $product->name?>'>
<?php
$productLink = html::a($this->createLink('product', 'browse', 'productID=' . $product->id), $product->name);
echo "<span class='table-nest-icon icon icon-product'></span>" . $productLink;
@@ -229,7 +229,7 @@
<td><?php echo $product->plans;?></td>
<td><?php echo $product->releases;?></td>
<?php foreach($extendFields as $extendField) echo "<td>" . $this->loadModel('flow')->getFieldValue($extendField, $product) . "</td>";?>
<td class='c-actions sort-handler'><?php echo $this->product->buildOperateMenu($product, 'browse');?></td>
<td class='c-actions'><?php echo $this->product->buildOperateMenu($product, 'browse');?></td>
</tr>
<?php endforeach;?>
<?php endif;?>
+2
View File
@@ -17,6 +17,8 @@
<?php js::set('canChangeProgram', $canChangeProgram);?>
<?php js::set('singleLinkProjects', $singleLinkProjects);?>
<?php js::set('multipleLinkProjects', $multipleLinkProjects);?>
<?php js::set('linkStoriesProjectIDList', array_keys($linkStoriesProjects));?>
<?php js::set('projectPathList', $projectPathList);?>
<style>
#changeProgram .icon-project {padding-right: 5px;}
</style>
+2 -1
View File
@@ -4,7 +4,6 @@
tbody.sortable > tr > td.sort-handler .table-nest-toggle:before {cursor: pointer !important;}
.table .avatar {display: inline-block; top: 6px;}
label[for^="projectIdList"]:before {top: 1px; width:14px; height:14px;}
label[for^="projectIdList"]:after {width: 14px; height:14px;}
tbody.sortable > tr > td.sort-handler {color: #3c4353 !important;}
@@ -13,3 +12,5 @@ tbody.sortable > tr > td.sort-handler {color: #3c4353 !important;}
.has-prefix > a {padding-left: 5px;}
.has-suffix > a {max-width: calc(100% - 100px); padding-right: 5px; color: #0c60e1; display: inline-block; max-width: calc(100% - 50px);}
div.checkbox-primary + span.table-nest-icon {margin-left:0px !important;}
+3 -3
View File
@@ -47,16 +47,16 @@ $(function()
function showEditCheckbox(show)
{
$('.icon-project,.icon-waterfall,.icon-scrum').each(function()
$('.icon-project,.icon-waterfall,.icon-scrum,.icon-kanban').each(function()
{
$this = $(this);
$tr = $(this).closest('tr');
projectID = $tr.attr('data-id');
if(show)
{
$tr.find('td:first').prepend("<div class='checkbox-primary'><input type='checkbox' name='projectIdList[]' value='" + projectID + "' id='projectIdList" + projectID + "'/><label for='projectIdList" + projectID + "'></lable></div>");
var marginLeft = $tr.find('td:first').find('span.table-nest-icon').css('margin-left');
$tr.find('td:first').prepend("<div class='checkbox-primary'><input type='checkbox' name='projectIdList[]' value='" + projectID + "' id='projectIdList" + projectID + "'/><label for='projectIdList" + projectID + "'></lable></div>");
$tr.find('td:first').find('.checkbox-primary').css('margin-left', marginLeft).css('width', '14');
$tr.find('td:first').find('span.table-nest-icon').css('margin-left', '0');
}
+7 -4
View File
@@ -1326,7 +1326,7 @@ class programModel extends model
{
$parent = $this->dao->select('id,parent,path,grade')->from(TABLE_PROGRAM)->where('id')->eq($parentID)->fetch();
$childNodes = $this->dao->select('id,parent,path,grade')->from(TABLE_PROGRAM)
$childNodes = $this->dao->select('id,parent,path,grade,type')->from(TABLE_PROGRAM)
->where('path')->like("{$oldPath}%")
->andWhere('deleted')->eq(0)
->orderBy('grade')
@@ -1335,13 +1335,16 @@ class programModel extends model
/* Process child node path and grade field. */
foreach($childNodes as $childNode)
{
$path = substr($childNode->path, strpos($childNode->path, ",{$programID},"));
$grade = $childNode->grade - $oldGrade + 1;
$path = substr($childNode->path, strpos($childNode->path, ",{$programID},"));
/* Only program and project sets update grade. */
$grade = in_array($childNode->type, array('program', 'project')) ? $childNode->grade - $oldGrade + 1 : $childNode->grade;
if($parent)
{
$path = rtrim($parent->path, ',') . $path;
$grade = $parent->grade + $grade;
$grade = in_array($childNode->type, array('program', 'project'))? $parent->grade + $grade : $grade;
}
$this->dao->update(TABLE_PROGRAM)->set('path')->eq($path)->set('grade')->eq($grade)->where('id')->eq($childNode->id)->exec();
}
+5 -1
View File
@@ -285,7 +285,11 @@ $('#planForm').submit(function()
}
});
if(!submitForm) return false;
if(!submitForm)
{
setTimeout(function(){$('#submit').removeAttr('disabled')}, 500);
return false;
}
});
</script>
<?php include '../../common/view/footer.html.php';?>
+1 -3
View File
@@ -78,7 +78,7 @@ class project extends control
if($this->config->edition != 'open') list($fields, $projects) = $this->loadModel('workflowfield')->appendDataFromFlow($fields, $projects);
$this->post->set('fields', $fields);
$this->post->set('rows', $projects);
$this->post->set('kind', 'project');
$this->post->set('kind', $this->lang->project->common);
$this->fetch('file', 'export2' . $this->post->fileType, $_POST);
}
@@ -710,8 +710,6 @@ class project extends control
return print(js::locate($this->session->projectList, 'parent'));
}
if($this->app->tab == 'program') $this->loadModel('program')->setMenu(0);
if(!$this->post->projectIdList) return print(js::locate($this->session->projectList, 'parent'));
$projectIdList = $this->post->projectIdList;
$projects = $this->dao->select('*')->from(TABLE_PROJECT)->where('id')->in($projectIdList)->fetchAll('id');
+1 -1
View File
@@ -16,7 +16,7 @@
#productsBox a {border-radius: 2px !important;}
#productsBox .col-sm-4 {padding-right: 5px;}
#productsBox .addProduct {padding-left: 0px !important;}
#productsBox > .required:after{right: -6px !important;}
#productsBox .required:after{right: -6px !important;}
#productsBox .input-group-addon > div {display: inline-block !important;}
#plansBox .row {display: inline-table; width: 102%;}
#plansBox .col-sm-4 {float: none; display: inline-block; padding-right: 5px;}
+3
View File
@@ -2130,6 +2130,9 @@ class projectModel extends model
$data->product = $productID;
$data->branch = $branch;
$data->plan = isset($plans[$productID][$branch]) ? implode(',', $plans[$productID][$branch]) : $oldPlan;
$data->plan = trim($data->plan, ',');
$data->plan = empty($data->plan) ? 0 : ",$data->plan,";
$this->dao->insert(TABLE_PROJECTPRODUCT)->data($data)->exec();
$existedProducts[$productID][$branch] = true;
}
+1 -1
View File
@@ -181,7 +181,7 @@
<?php $planIDList = explode(',', $planIDList);?>
<?php foreach($planIDList as $planID):?>
<?php if(isset($planGroup[$productID][$planID])):?>
<div class="col-xs-12"><?php echo html::a($this->createLink('productplan', 'view', "planID={$planID}"), $product->name . '/' . $planGroup[$productID][$planID]);?></div>
<div class="col-xs-12"><?php echo html::a($this->createLink('productplan', 'view', "planID={$planID}"), "<i class='icon icon-calendar text-muted'></i> " . $product->name . '/' . $planGroup[$productID][$planID]);?></div>
<?php endif;?>
<?php endforeach;?>
<?php endforeach;?>
+4
View File
@@ -552,6 +552,10 @@ class repoModel extends model
->andWhere('deleted')->eq('0')
->orderBy('id_desc')
->fetchAll();
foreach($matchedRepos as $key => $repo)
{
if(!$this->checkPriv($repo)) unset($matchedRepos[$key]);
}
if(empty($matchedRepos)) return array('status' => 'fail', 'message' => 'No matched gitlab.');
return array('status' => 'success', 'repos' => $matchedRepos);
+1 -1
View File
@@ -2902,7 +2902,7 @@ class storyModel extends model
$storyIdList = $this->dao->select('story')->from(TABLE_PROJECTSTORY)->where('project')->in(array_keys($executions))->fetchPairs();
}
$type = ($type == 'bymodule' and $this->session->storyBrowseType) ? $this->session->storyBrowseType : $type;
$type = (strpos('bymodule|byproduct', $type) !== false and $this->session->storyBrowseType) ? $this->session->storyBrowseType : $type;
$stories = $this->dao->select('distinct t1.*, t2.*,t3.type as productType,t2.version as version')->from(TABLE_PROJECTSTORY)->alias('t1')
->leftJoin(TABLE_STORY)->alias('t2')->on('t1.story = t2.id')
+8 -8
View File
@@ -73,14 +73,14 @@ foreach(explode(',', $showFields) as $field)
<td class='text-left<?php echo zget($visibleFields, 'branch', ' hidden')?>'>
<?php $disabled = $products[$story->product]->type == 'normal' ? "disabled='disabled'" : '';?>
<?php if($products[$story->product]->type == 'normal') $branchTagOption[$story->product] = array();?>
<?php echo html::select("branches[$storyID]", $branchTagOption[$story->product], $story->branch, "class='form-control picker-select' onchange='loadBranches($story->product, this.value, $storyID);' $disabled");?>
<?php echo html::select("branches[$storyID]", $branchTagOption[$story->product], $story->branch, "class='form-control picker-select' data-drop-width='auto' onchange='loadBranches($story->product, this.value, $storyID);' $disabled");?>
</td>
<?php endif;?>
<td class='text-left<?php echo zget($visibleFields, 'module')?>'>
<?php echo html::select("modules[$storyID]", zget($moduleList, $story->id, array(0 => '/')), $story->module, "class='form-control picker-select'");?>
<?php echo html::select("modules[$storyID]", zget($moduleList, $story->id, array(0 => '/')), $story->module, "class='form-control picker-select' data-drop-width='auto'");?>
</td>
<td class='text-left<?php echo zget($visibleFields, 'plan', ' hidden')?>'>
<?php echo html::select("plans[$storyID]", isset($plans[$story->product][$story->branch]) ? array('' => '') + $plans[$story->product][$story->branch] : '', $story->plan, "class='form-control picker-select'");?>
<?php echo html::select("plans[$storyID]", isset($plans[$story->product][$story->branch]) ? array('' => '') + $plans[$story->product][$story->branch] : '', $story->plan, "class='form-control picker-select' data-drop-width='auto'");?>
</td>
<td title='<?php echo $story->title?>'>
<div class="input-group">
@@ -100,15 +100,15 @@ foreach(explode(',', $showFields) as $field)
</td>
<td <?php echo zget($visibleFields, 'estimate', "class='hidden'")?>><?php echo html::input("estimates[$storyID]", $story->estimate, "class='form-control'"); ?></td>
<td><?php echo html::select("category[$storyID]", $lang->story->categoryList, $story->category, 'class=form-control picker-select');?></td>
<td><?php echo html::select("category[$storyID]", $lang->story->categoryList, $story->category, 'class="form-control picker-select" data-drop-width="auto"');?></td>
<td <?php echo zget($visibleFields, 'pri', "class='hidden'")?>><?php echo html::select("pris[$storyID]", $priList, $story->pri, 'class=form-control');?></td>
<td class='text-left<?php echo zget($visibleFields, 'assignedTo', ' hidden')?>'><?php echo html::select("assignedTo[$storyID]", $users, $story->assignedTo, "class='form-control picker-select'");?></td>
<td <?php echo zget($visibleFields, 'source', "class='hidden'")?>><?php echo html::select("sources[$storyID]", $sourceList, $story->source, "class='form-control picker-select' id='source_$storyID'");?></td>
<td class='text-left<?php echo zget($visibleFields, 'assignedTo', ' hidden')?>'><?php echo html::select("assignedTo[$storyID]", $users, $story->assignedTo, "class='form-control picker-select' data-drop-width='auto'");?></td>
<td <?php echo zget($visibleFields, 'source', "class='hidden'")?>><?php echo html::select("sources[$storyID]", $sourceList, $story->source, "class='form-control picker-select' data-drop-width='auto' id='source_$storyID'");?></td>
<?php
if($story->source == 'meeting' or $story->source == 'researchreport')
{
$objects = $story->source == 'meeting' ? $meetings : $researchReports;
$html = html::select("sourceNote[$storyID]", $objects, $story->sourceNote, "class='form-control picker-select' id='sourceNote_$storyID'");
$html = html::select("sourceNote[$storyID]", $objects, $story->sourceNote, "class='form-control picker-select' data-drop-width='auto' id='sourceNote_$storyID'");
}
else
{
@@ -118,7 +118,7 @@ foreach(explode(',', $showFields) as $field)
<td class='<?php echo zget($visibleFields, 'source', 'hidden')?>' data-id="<?php echo $story->sourceNote;?>"><?php echo $html;?></td>
<td class='story-<?php echo $story->status;?>'><?php echo $this->processStatus('story', $story);?></td>
<td <?php echo zget($visibleFields, 'stage', "class='hidden'")?>><?php echo html::select("stages[$storyID]", $stageList, $story->stage, 'class="form-control"' . ($story->status == 'draft' ? ' disabled="disabled"' : ''));?></td>
<td class='text-left<?php echo zget($visibleFields, 'closedBy', ' hidden')?>'><?php echo html::select("closedBys[$storyID]", $users, $story->closedBy, "class='form-control" . ($story->status == 'closed' ? " picker-select'" : "' disabled='disabled'"));?></td>
<td class='text-left<?php echo zget($visibleFields, 'closedBy', ' hidden')?>'><?php echo html::select("closedBys[$storyID]", $users, $story->closedBy, "class='form-control" . ($story->status == 'closed' ? " picker-select' data-drop-width='auto'" : "' disabled='disabled'"));?></td>
<?php if($story->status == 'closed'):?>
<td <?php echo zget($visibleFields, 'closedReason', "class='hidden'")?>>
+1 -1
View File
@@ -26,7 +26,7 @@
<th class='w-80px'><?php echo $lang->story->reviewedBy;?></th>
<td colspan="2">
<div class="input-group">
<?php echo html::select('reviewer[]', $productReviewers, $reviewer, 'class="form-control chosen" multiple');?>
<?php echo html::select('reviewer[]', $productReviewers, $reviewer, "class='form-control chosen' multiple" . ($this->story->checkForceReview() ? ' required' : ''));?>
<?php if(!$this->story->checkForceReview()):?>
<span class="input-group-addon">
<?php echo html::checkbox('needNotReview', $lang->story->needNotReview, '', "id='needNotReview' {$needReview}");?>
+5 -5
View File
@@ -124,8 +124,8 @@ js::set('dittoNotice', $dittoNotice);
</div>
</div>
</td>
<td class='text-left<?php echo zget($visibleFields, 'module', ' hidden')?>' style='overflow:visible'><?php echo html::select("modules[$taskID]", $modules, $tasks[$taskID]->module, "class='form-control picker-select'")?></td>
<td class='text-left<?php echo zget($visibleFields, 'assignedTo', ' hidden')?>' style='overflow:visible'><?php echo html::select("assignedTos[$taskID]", $taskMembers, $tasks[$taskID]->assignedTo, "class='form-control picker-select' {$disableAssignedTo}");?></td>
<td class='text-left<?php echo zget($visibleFields, 'module', ' hidden')?>' style='overflow:visible'><?php echo html::select("modules[$taskID]", $modules, $tasks[$taskID]->module, "class='form-control picker-select' data-drop-width='auto'")?></td>
<td class='text-left<?php echo zget($visibleFields, 'assignedTo', ' hidden')?>' style='overflow:visible'><?php echo html::select("assignedTos[$taskID]", $taskMembers, $tasks[$taskID]->assignedTo, "class='form-control picker-select' data-drop-width='auto' {$disableAssignedTo}");?></td>
<td><?php echo html::select("types[$taskID]", $typeList, $tasks[$taskID]->type, "class='form-control'");?></td>
<td <?php echo zget($visibleFields, 'status', "class='hidden'")?>><?php echo html::select("statuses[$taskID]", $statusList, $tasks[$taskID]->status, "class='form-control' {$disableHour}");?></td>
<td <?php echo zget($visibleFields, 'estStarted', "class='hidden'")?>><?php echo html::input("estStarteds[$taskID]", helper::isZeroDate($tasks[$taskID]->estStarted) ? '' : $tasks[$taskID]->estStarted, "class='form-control text-center form-date'");?></td>
@@ -134,9 +134,9 @@ js::set('dittoNotice', $dittoNotice);
<td <?php echo zget($visibleFields, 'estimate', "class='hidden'")?>><?php echo html::input("estimates[$taskID]", $tasks[$taskID]->estimate, "class='form-control text-center' {$disableHour}");?></td>
<td <?php echo zget($visibleFields, 'record', "class='hidden'")?>><?php echo html::input("consumeds[$taskID]", 0, "class='form-control text-center' {$disableHour}");?></td>
<td <?php echo zget($visibleFields, 'left', "class='hidden'")?>><?php echo html::input("lefts[$taskID]", $tasks[$taskID]->left, "class='form-control text-center' {$disableHour}");?></td>
<td class='text-left<?php echo zget($visibleFields, 'finishedBy', ' hidden')?>' style='overflow:visible'><?php echo html::select("finishedBys[$taskID]", $members, $tasks[$taskID]->finishedBy, "class='form-control picker-select'");?></td>
<td class='text-left<?php echo zget($visibleFields, 'canceledBy', ' hidden')?>' style='overflow:visible'><?php echo html::select("canceledBys[$taskID]", $members, $tasks[$taskID]->canceledBy, "class='form-control picker-select'");?></td>
<td class='text-left<?php echo zget($visibleFields, 'closedBy', ' hidden')?>' style='overflow:visible'><?php echo html::select("closedBys[$taskID]", $members, $tasks[$taskID]->closedBy, "class='form-control picker-select'");?></td>
<td class='text-left<?php echo zget($visibleFields, 'finishedBy', ' hidden')?>' style='overflow:visible'><?php echo html::select("finishedBys[$taskID]", $members, $tasks[$taskID]->finishedBy, "class='form-control picker-select' data-drop-width='auto'");?></td>
<td class='text-left<?php echo zget($visibleFields, 'canceledBy', ' hidden')?>' style='overflow:visible'><?php echo html::select("canceledBys[$taskID]", $members, $tasks[$taskID]->canceledBy, "class='form-control picker-select' data-drop-width='auto'");?></td>
<td class='text-left<?php echo zget($visibleFields, 'closedBy', ' hidden')?>' style='overflow:visible'><?php echo html::select("closedBys[$taskID]", $members, $tasks[$taskID]->closedBy, "class='form-control picker-select' data-drop-width='auto'");?></td>
<td <?php echo zget($visibleFields, 'closedReason', "class='hidden'")?>>
<?php
$reasonList[''] = '';
+1 -3
View File
@@ -285,18 +285,16 @@
<table class='table table-data'>
<?php if($case->fromBug):?>
<tr>
<th class='thWidth'><?php echo $lang->testcase->fromBug;?></th>
<td><?php echo html::a($this->createLink('bug', 'view', "bugID=$case->fromBug", '', true), $case->fromBugTitle, '', "class='iframe' data-width='80%'");?></td>
</tr>
<?php endif;?>
<?php if($case->toBugs):?>
<tr>
<th class='thWidth' valign="top"><?php echo $lang->testcase->toBug;?></th>
<td>
<?php
foreach($case->toBugs as $bugID => $bugTitle)
{
echo '<p style="margin-bottom:0;">' . html::a($this->createLink('bug', 'view', "bugID=$bugID", '', true), $bugTitle, '', "class='iframe' data-width='80%'") . '</p>';
echo '<p style="margin-bottom:0;">' . html::a($this->createLink('bug', 'view', "bugID=$bugID", '', true), "#$bugID " . $bugTitle, '', "class='iframe' data-width='80%'") . '</p>';
}
?>
</td>
+2
View File
@@ -18,6 +18,7 @@ $config->upgrade->maxVersion['max3_0'] = '16_5';
$config->upgrade->maxVersion['max3_1_beta1'] = '17_0_beta1';
$config->upgrade->maxVersion['max3_1_beta2'] = '17_0_beta2';
$config->upgrade->maxVersion['max3_1'] = '17_0';
$config->upgrade->maxVersion['max3_2'] = '17_1';
$config->upgrade->bizVersion = array();
$config->upgrade->bizVersion['biz1_0'] = '9_5_1';
@@ -74,6 +75,7 @@ $config->upgrade->bizVersion['biz6_5'] = '16_5';
$config->upgrade->bizVersion['biz7_0_beta1'] = '17_0_beta1';
$config->upgrade->bizVersion['biz7_0_beta2'] = '17_0_beta2';
$config->upgrade->bizVersion['biz7_0'] = '17_0';
$config->upgrade->bizVersion['biz7_1'] = '17_1';
$config->upgrade->proVersion = array();
$config->upgrade->proVersion['pro1_0'] = '3_1';
+3
View File
@@ -159,6 +159,7 @@ $lang->upgrade->fromVersions['16_5'] = '16.5';
$lang->upgrade->fromVersions['17_0_beta1'] = '17.0.beta1';
$lang->upgrade->fromVersions['17_0_beta2'] = '17.0.beta2';
$lang->upgrade->fromVersions['17_0'] = '17.0';
$lang->upgrade->fromVersions['17_1'] = '17.1';
/* Lite. */
$lang->upgrade->fromVersions['lite1_0'] = 'Lite1.0';
@@ -320,6 +321,7 @@ $lang->upgrade->fromVersions['biz6_5'] = 'Biz6.5';
$lang->upgrade->fromVersions['biz7_0_beta1'] = 'Biz7.0.beta1';
$lang->upgrade->fromVersions['biz7_0_beta2'] = 'Biz7.0.beta2';
$lang->upgrade->fromVersions['biz7_0'] = 'Biz7.0';
$lang->upgrade->fromVersions['biz7_1'] = 'Biz7.1';
/* Max. */
$lang->upgrade->fromVersions['max2_0_beta4'] = 'Max2.0.beta4';
@@ -339,3 +341,4 @@ $lang->upgrade->fromVersions['max3_0_beta1'] = 'Max3.0.beta1';
$lang->upgrade->fromVersions['max3_0'] = 'Max3.0';
$lang->upgrade->fromVersions['max3_1_beta1'] = 'Max3.1.beta1';
$lang->upgrade->fromVersions['max3_1_beta2'] = 'Max3.1.beta2';
$lang->upgrade->fromVersions['max3_1'] = 'Max3.1';
+79
View File
@@ -513,6 +513,7 @@ class upgradeModel extends model
break;
case '17_0':
$this->replaceSetLanePriv();
$this->updateProjectData();
break;
}
@@ -6358,4 +6359,82 @@ class upgradeModel extends model
return true;
}
/**
* Update path and grade of program, project and execution.
*
* @access public
* @return bool
*/
public function updateProjectData()
{
/* Process programs. */
$programs = $this->dao->select('id,parent,grade,path')->from(TABLE_PROJECT)->where('type')->eq('program')->orderBy('parent_asc')->fetchAll('id');
foreach($programs as $program)
{
if(!$program->parent)
{
$program->grade = 1;
$program->path = ",$program->id,";
}
else
{
$program->grade = $programs[$program->parent]->grade + 1;
$program->path = $programs[$program->parent]->path . "$program->id,";
}
$this->dao->update(TABLE_PROGRAM)
->set('path')->eq($program->path)
->set('grade')->eq($program->grade)
->where('id')->eq($program->id)->exec();
}
/* Process projects. */
$projects = $this->dao->select('id,project,parent,grade,path')->from(TABLE_PROJECT)->where('type')->eq('project')->orderBy('parent_asc')->fetchAll('id');
foreach($projects as $project)
{
if(!$project->parent)
{
$project->grade = 1;
$project->path = ",$project->id,";
}
else
{
$project->grade = $programs[$project->parent]->grade + 1;
$project->path = $programs[$project->parent]->path . "$project->id,";
}
$this->dao->update(TABLE_PROJECT)
->set('path')->eq($project->path)
->set('grade')->eq($project->grade)
->where('id')->eq($project->id)->exec();
}
/* Process executions. */
$sprints = $this->dao->select('id,project,parent,grade,path')->from(TABLE_PROJECT)
->where('type')->ne('project')
->andWhere('type')->ne('program')
->orderBy('parent_asc')->fetchAll('id');
foreach($sprints as $sprint)
{
if($sprint->parent == $sprint->project)
{
$sprint->grade = 1;
$sprint->path = ",$sprint->project,$sprint->id,";
}
else
{
$sprint->grade = 2;
$sprint->path = $sprints[$sprint->parent]->path . "$sprint->id,";
}
$this->dao->update(TABLE_EXECUTION)
->set('path')->eq($sprint->path)
->set('grade')->eq($sprint->grade)
->where('id')->eq($sprint->id)->exec();
}
return true;
}
}
+1
View File
@@ -1490,6 +1490,7 @@ class userModel extends model
}
$this->dao->insert(TABLE_USERCONTACT)->data($data)
->check('listName', 'unique', "account = '{$data->account}'")
->autoCheck()
->exec();
if(dao::isError()) return false;