Merge branch 'master' into zenops_46

This commit is contained in:
liyuchun
2022-09-29 09:25:12 +08:00
194 changed files with 5548 additions and 736 deletions
+41 -30
View File
@@ -1,11 +1,13 @@
stages:
- sonar
- unit_test
- uitest
- cleanup_packages
- sonarqube
- unit-test
- ui-test
- package
sonarqube:
stage: sonar
- cleanup-packages
- notify
program-static-analysis:
stage: sonarqube
variables:
SONAR_USER_HOME: "${CI_PROJECT_DIR}/.sonar" # Defines the location of the analysis task cache
GIT_DEPTH: "0" # Tells git to fetch all the branches of the project, required by the analysis task
@@ -18,6 +20,25 @@ sonarqube:
allow_failure: true
only:
- master # or the name of your main branch
unit-test:
stage: unit-test
script:
- "/home/gitlab-runner/bin/zentao-unittest.sh ${CI_PROJECT_DIR}"
allow_failure: true
only:
- master
- merge_requests
ui-test:
stage: ui-test
script:
- "/home/gitlab-runner/bin/zentao-uitest.sh ${CI_PROJECT_DIR}"
allow_failure: true
only:
- master
- merge_requests
package:
stage: package
script:
@@ -25,30 +46,20 @@ package:
allow_failure: true
only:
- master
unit_test:
stage: unit_test
script:
- "/home/gitlab-runner/bin/zentao-unittest.sh ${CI_PROJECT_DIR}"
allow_failure: true
only:
- master
- merge_requests
uitest:
stage: uitest
script:
- "/home/gitlab-runner/bin/zentao-uitest.sh ${CI_PROJECT_DIR}"
allow_failure: true
only:
- master
- merge_requests
#notify:
# script:
# - 'curl --location --request POST ''http://api.lf.oop.cc/api/v1/xuan/chatMessage'' --header ''Content-Type: application/json'' --data-raw ''{"gid": "84be4c6e-02e3-4fdc-b081-318c0c1eca02", "title": "开源包下载地址", "content": "点击查看详情链接", "url": "http://10.0.7.242:8080/allpacks/"}'''
# when: on_success
# only:
# - master
cleanup_packages:
stage: cleanup_packages
cleanup-packages:
stage: cleanup-packages
script:
- make clean
when: on_failure
only:
- master
notify:
stage: notify
script:
- "/home/gitlab-runner/bin/ci-notify.php"
when: on_success
only:
- master
- merge_requests
+5
View File
@@ -102,6 +102,11 @@ zentaoxx:
mkdir zentaoxx/db/
cp zentaoxx/db_bak/upgradexuanxuan*.sql zentaoxx/db_bak/xuanxuan.sql zentaoxx/db/
rm -rf zentaoxx/db_bak/
sed -i "s/\$$accountAdmin = \$$this->dao->select('account, admin')->from(TABLE_USER)->where('id')->eq(\$$userID)->fetch();/\$$accountAdmin = \$$this->dao->select('account')->from(TABLE_USER)->where('id')->eq(\$$userID)->fetch();\n\$$admins = \$$this->dao->select('admins')->from(TABLE_COMPANY)->where('id')->eq(\$$this->app->company->id)->fetch('admins');\n\$$adminArray = explode(',', \$$admins);\n\$$accountAdmin->admin = in_array(\$$accountAdmin->account, \$$adminArray) ? 'super' : '';\n/" zentaoxx/extension/xuan/im/model/chat.php
sed -i "/->on('tc.ownedBy=tu.account')/{ N ; s/type/tc.type/}" zentaoxx/extension/xuan/im/model/chat.php
sed -i "s/\$$super = \$$this->dao->select('admin')->from(TABLE_USER)->where('id')->eq(\$$userID)->fetch('admin');/\$$account = \$$this->dao->select('account')->from(TABLE_USER)->where('id')->eq(\$$userID)->fetch('account');\n\$$admins = \$$this->dao->select('admins')->from(TABLE_COMPANY)->where('id')->eq(\$$this->app->company->id)->fetch('admins');\n\$$adminArray = explode(',', \$$admins);\n\$$super = in_array(\$$account, \$$adminArray) ? 'super' : '';/g" zentaoxx/extension/xuan/im/control.php
sed -i "/foreach(\$$users as \$$user)/i \$$admins = \$$this->dao->select('admins')->from(TABLE_COMPANY)->where('id')->eq(\$$this->app->company->id)->fetch('admins');\$$adminArray = explode(',', \$$admins);" zentaoxx/extension/xuan/im/model/user.php
sed -i "/if(\!isset(\$$user->signed)) \$$user->signed = 0;/a \$$user->admin = in_array(\$$user->account, \$$adminArray) ? 'super' : '';" zentaoxx/extension/xuan/im/model/user.php
sed -i 's/XXBVERSION/$(XVERSION)/g' zentaoxx/config/ext/_0_xuanxuan.php
sed -i "/\$$config->xuanxuan->backend /c\\\$$config->xuanxuan->backend = 'zentao';" zentaoxx/config/ext/_0_xuanxuan.php
sed -i 's/site,//' zentaoxx/extension/xuan/im/model/user.php
+1 -1
View File
@@ -1 +1 @@
17.6.1
17.6.2
+1 -1
View File
@@ -53,7 +53,7 @@ class buildsEntry extends entry
$project = $this->loadModel('project')->getByID($projectID);
if(!$project) return $this->send404();
$fields = 'execution,product,name,builder,date,scmPath,filePath,desc';
$fields = 'execution,product,name,builder,date,scmPath,filePath,desc,branch';
$this->batchSetPost($fields);
$control = $this->loadController('build', 'create');
+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.6.1'; // ZenTaoPHP的版本。 The version of ZenTaoPHP. Don't change it.
$config->version = '17.6.2'; // ZenTaoPHP的版本。 The version of ZenTaoPHP. Don't change it.
$config->liteVersion = '1.2'; // 迅捷版版本。 The version of Lite.
$config->charset = 'UTF-8'; // ZenTaoPHP的编码。 The encoding of ZenTaoPHP.
$config->cookieLife = time() + 2592000; // Cookie的生存时间。The cookie life time.
+15 -7
View File
@@ -97,6 +97,7 @@ $filter->mail->batchdelete = new stdclass();
$filter->misc->checkupdate = new stdclass();
$filter->file->download = new stdclass();
$filter->product->browse = new stdclass();
$filter->product->all = new stdclass();
$filter->product->default = new stdclass();
$filter->product->index = new stdclass();
$filter->product->export = new stdclass();
@@ -108,6 +109,7 @@ $filter->program->default = new stdclass();
$filter->program->pgmproject = new stdclass();
$filter->program->prjbrowse = new stdclass();
$filter->program->project = new stdclass();
$filter->program->product = new stdclass();
$filter->program->browse = new stdclass();
$filter->program->export = new stdclass();
$filter->program->pgmbrowse = new stdclass();
@@ -169,6 +171,7 @@ $filter->execution->export = new stdclass();
$filter->tree->browse = new stdclass();
$filter->productplan->browse = new stdclass();
$filter->kanban->space = new stdclass();
$filter->execution->kanban = new stdclass();
$filter->index->index->get['open'] = 'reg::base64';
@@ -235,6 +238,7 @@ $filter->product->browse->cookie['productStoryOrder'] = 'reg::orderBy';
$filter->product->browse->cookie['storyModule'] = 'int';
$filter->product->browse->cookie['storyBranch'] = 'int';
$filter->product->browse->cookie['treeBranch'] = 'reg::word';
$filter->product->all->cookie['showProductBatchEdit'] = 'int';
$filter->product->default->cookie['lastProduct'] = 'int';
$filter->product->default->cookie['preProductID'] = 'int';
$filter->product->index->cookie['preBranch'] = 'reg::word';
@@ -246,19 +250,22 @@ $filter->product->dynamic->cookie['preBranch'] = 'reg::word';
$filter->branch->default->cookie['preBranch'] = 'reg::word';
$filter->program->default->cookie['lastPGM'] = 'int';
$filter->program->default->cookie['lastPRJ'] = 'int';
$filter->program->prjbrowse->cookie['programType'] = 'code';
$filter->program->project->cookie['involved'] = 'code';
$filter->program->browse->cookie['showClosed'] = 'code';
$filter->program->export->cookie['checkedItem'] = 'reg::checked';
$filter->program->ajaxgetdropmenu->cookie['showClosed'] = 'code';
$filter->program->default->cookie['lastPGM'] = 'int';
$filter->program->default->cookie['lastPRJ'] = 'int';
$filter->program->prjbrowse->cookie['programType'] = 'code';
$filter->program->project->cookie['involved'] = 'code';
$filter->program->project->cookie['showProjectBatchEdit'] = 'int';
$filter->program->product->cookie['showProductBatchEdit'] = 'int';
$filter->program->browse->cookie['showClosed'] = 'code';
$filter->program->export->cookie['checkedItem'] = 'reg::checked';
$filter->program->ajaxgetdropmenu->cookie['showClosed'] = 'code';
$filter->project->default->cookie['lastProject'] = 'int';
$filter->project->default->cookie['lastPRJ'] = 'int';
$filter->project->default->cookie['projectMode'] = 'code';
$filter->project->default->cookie['kanbanview'] = 'code';
$filter->project->browse->cookie['involved'] = 'code';
$filter->project->browse->cookie['showProjectBatchEdit'] = 'int';
$filter->project->export->cookie['involved'] = 'code';
$filter->project->browse->cookie['projectType'] = 'code';
$filter->project->story->cookie['storyModuleParam'] = 'int';
@@ -300,6 +307,7 @@ $filter->execution->story->cookie['storyProductParam'] = 'int';
$filter->execution->story->cookie['storyBranchParam'] = 'int';
$filter->execution->story->cookie['executionStoryOrder'] = 'code';
$filter->execution->export->cookie['checkedItem'] = 'reg::checked';
$filter->execution->kanban->cookie['taskToOpen'] = 'int';
$filter->testcase->browse->cookie['caseModule'] = 'int';
$filter->testcase->browse->cookie['caseSuite'] = 'int';
File diff suppressed because it is too large Load Diff
+2
View File
@@ -11,3 +11,5 @@ ALTER TABLE `zt_vmtemplate` ADD `createdDate` datetime NOT NULL;
ALTER TABLE `zt_vmtemplate` ADD `editedBy` varchar(30) NOT NULL;
ALTER TABLE `zt_vmtemplate` ADD `editedDate` datetime NOT NULL;
ALTER TABLE `zt_vm` ADD `osVersion` varchar(50) NOT NULL DEFAULT '' AFTER `osCategory`;
UPDATE `zt_workflowlabel` SET `label` = '全部' where `label` = '所有' AND `action` = 'browse';
+44
View File
@@ -1,3 +1,47 @@
2022-09-23 17.6.2
完成的需求
开源版:
37324 敏捷项目下的迭代列表没有任务时中,隐藏名称前的展开、收起按钮
36946 私有产品的访问权限增加项目集负责人(反馈)
32322 Bug批量导入页面中先校验必填字段再校验重复数据
36977 增加全局头像下拉菜单的点击热区面积
67327 实现禅道中文件上传组件支持选择一次性多个文件(反馈)
37262 列表中“所有”标签修改为“全部”
37866 项目集列表中名称字段样式优化
37869 删除项目集列表中项目的图标
37862 项目集列表删除“显示已关闭”的勾选按钮
37868 项目集列表操作列的更多按钮调整
37861 用例列表操作列交换开始和结果按钮的位置
37854 bug列表确认字段的内容颜色调整
37864 项目集列表中延期标签位置调整
37833 叶兰绿主题风格更新
37842 禅道蓝主题风格更新
37813 列表中优先级颜色调整
37816 列表检索标签选中样式优化
38002 多人串行任务中,团队日志页去掉操作区域
38006 多人串行任务开始任务的弹窗,总计消耗改名为我的总消耗
37997 多人串行任务,用户打开工时填写页,默认打开我的日志页
37993 工时记录页,日期、工作内容、消耗、剩余增加必填项校验(开源版不校验工作内容)
37218 调整看板区域标题栏名称的对齐方式
37207 去掉看板中选中单个产品规划的背景
37206 调整看板区域检索标签组件样式
37132 将指派他人的待办列表中“由谁指派”字段修改为“指派给”
37831 项目统计报表增加权限判断,过滤掉没有访问权限的项目
32626 产品统计报表增加权限判断,过滤掉没有访问权限的产品
37064 长期项目的概况上计划完成显示“长期”
企业版:
37221 组织日志列表增加项目字段
35025 需求导入模板增加由谁评审字段
旗舰版:
35042 旗舰版周报3个工作项列表能显示总数
修复的Bug
27875 工时记录页面日期控件展开后显示遮挡
27778 创建项目和编辑项目的所属项目集字段显示不一致
27690 创建项目页面提示信息窗口建议向右展开
27632 复制bug时希望可以同步反馈者和通知邮箱两个字段的信息
27561 提需求页面所属产品右侧边框线缺失
27547 编辑项目集预算,点击保存,提示有未提交表单
2022-09-08 17.6.1
完成的需求
开源版:
+24 -4
View File
@@ -35,8 +35,15 @@
</div>
<?php else:?>
<form id='myTaskForm' class="main-table table-task skip-iframe-modal" method="post">
<?php $canBatchEdit = (common::hasPriv('task', 'batchEdit') and $type == 'assignedTo');?>
<?php $canBatchClose = (common::hasPriv('task', 'batchClose') and $type != 'closedBy');?>
<?php
$canBatchEdit = (common::hasPriv('task', 'batchEdit') and $type == 'assignedTo');
$canBatchClose = (common::hasPriv('task', 'batchClose') and $type != 'closedBy');
$canFinish = common::hasPriv('task', 'finish');
$canClose = common::hasPriv('task', 'close');
$canRecordEstimate = common::hasPriv('task', 'recordEstimate');
$canEdit = common::hasPriv('task', 'edit');
$canBatchCreate = common::hasPriv('task', 'batchCreate');
?>
<table class="table has-sort-head table-fixed" id='taskTable'>
<?php $vars = "mode=$mode&type=$type&orderBy=%s&recTotal=$recTotal&recPerPage=$recPerPage&pageID=$pageID"; ?>
<thead>
@@ -134,10 +141,16 @@
}
else
{
$canStart = ($task->status != 'pause' and common::hasPriv('task', 'start'));
$canRestart = ($task->status == 'pause' and common::hasPriv('task', 'restart'));
if($task->status != 'pause') common::printIcon('task', 'start', "taskID=$task->id", $task, 'list', '', '', 'iframe', true, '', '', $task->project);
if($task->status == 'pause') common::printIcon('task', 'restart', "taskID=$task->id", $task, 'list', '', '', 'iframe', true, '', '', $task->project);
common::printIcon('task', 'close', "taskID=$task->id", $task, 'list', '', '', 'iframe', true, '', '', $task->project);
common::printIcon('task', 'finish', "taskID=$task->id", $task, 'list', '', '', 'iframe', true, '', '', $task->project);
common::printIcon('task', 'close', "taskID=$task->id", $task, 'list', '', '', 'iframe', true, '', '', $task->project);
if(($canStart or $canRestart or $canFinish or $canClose) and ($canRecordEstimate or $canEdit or $canBatchCreate))
{
echo "<div class='dividing-line'></div>";
}
common::printIcon('task', 'recordEstimate', "taskID=$task->id", $task, 'list', 'time', '', 'iframe', true, '', '', $task->project);
common::printIcon('task', 'edit', "taskID=$task->id", $task, 'list', '', '', 'iframe', true, "data-width='95%'", '', $task->project);
@@ -198,10 +211,17 @@
}
else
{
$canStart = ($child->status != 'pause' and common::hasPriv('task', 'start'));
$canRestart = ($child->status == 'pause' and common::hasPriv('task', 'restart'));
if($child->status != 'pause') common::printIcon('task', 'start', "taskID=$child->id", $child, 'list', '', '', 'iframe', true, '', '', $child->project);
if($child->status == 'pause') common::printIcon('task', 'restart', "taskID=$child->id", $child, 'list', '', '', 'iframe', true, '', '', $child->project);
common::printIcon('task', 'close', "taskID=$child->id", $child, 'list', '', '', 'iframe', true, '', '', $child->project);
common::printIcon('task', 'finish', "taskID=$child->id", $child, 'list', '', '', 'iframe', true, '', '', $child->project);
common::printIcon('task', 'close', "taskID=$child->id", $child, 'list', '', '', 'iframe', true, '', '', $child->project);
if(($canStart or $canRestart or $canFinish or $canClose) and ($canRecordEstimate or $canEdit or $canBatchCreate))
{
echo "<div class='dividing-line'></div>";
}
common::printIcon('task', 'recordEstimate', "taskID=$child->id", $child, 'list', 'time', '', 'iframe', true, '', '', $child->project);
common::printIcon('task', 'edit', "taskID=$child->id", $child, 'list', '', '', '', '', '', '', $child->project);
@@ -18,6 +18,7 @@ body {margin-bottom: 25px;}
#mainMenu .btn-toolbar .btn-group .dropdown-menu .btn-active-text:hover .text:after {border-bottom: unset;}
.body-modal #mainMenu>.btn-toolbar {width: auto;}
.assignedTo{border-radius: 4px !important;}
#productStoryForm table tbody tr td.c-actions .dividing-line {width: 1px; height: 16px; display: inline-block; vertical-align: middle; background: #F4F5F7; margin: 0 4px 0 0;}
</style>
<?php js::set('browseType', $browseType);?>
<?php js::set('productID', $productID);?>
@@ -19,6 +19,7 @@
<?php js::set('projectID', $projectID);?>
<?php js::set('productID', $productID);?>
<?php js::set('teamMemberError', $lang->task->error->teamMember);?>
<?php js::set('estimateNotEmpty', sprintf($lang->error->gt, $lang->task->estimate, '0'))?>
<?php if(!empty($storyID)):?>
<style> .title-group.required > .required:after {right: 110px;}</style>
<?php endif;?>
+1 -1
View File
@@ -82,7 +82,7 @@ $lang->action->dynamic->all = '所有';
$lang->action->dynamic->hidden = '已隐藏';
$lang->action->dynamic->search = '搜索';
$lang->action->periods['all'] = $lang->action->dynamic->all;
$lang->action->periods['all'] = '全部';
$lang->action->periods['today'] = $lang->action->dynamic->today;
$lang->action->periods['yesterday'] = $lang->action->dynamic->yesterday;
$lang->action->periods['thisweek'] = $lang->action->dynamic->thisWeek;
+7 -3
View File
@@ -376,10 +376,10 @@ class actionModel extends model
elseif($actionName == 'linked2execution' or $actionName == 'linked2kanban')
{
$execution = $this->dao->select('name,type')->from(TABLE_PROJECT)->where('id')->eq($action->extra)->fetch();
$name = $execution->name;
$method = $execution->type == 'kanban' ? 'kanban' : 'view';
if($name)
if(!empty($execution))
{
$name = $execution->name;
$method = $execution->type == 'kanban' ? 'kanban' : 'view';
$action->extra = (!common::hasPriv('execution', $method) or ($method == 'kanban' and isonlybody())) ? $name : html::a(helper::createLink('execution', $method, "executionID=$action->execution"), $name);
}
}
@@ -1071,6 +1071,9 @@ class actionModel extends model
$programCondition = empty($this->app->user->view->programs) ? '0' : $this->app->user->view->programs;
$efforts = $this->dao->select('id')->from(TABLE_EFFORT)->where($condition)->fetchPairs();
$efforts = !empty($efforts) ? implode(',', $efforts) : 0;
/* Get actions. */
$actions = $this->dao->select('*')->from(TABLE_ACTION)
->where('objectType')->notIN($this->config->action->ignoreObjectType4Dynamic)
@@ -1098,6 +1101,7 @@ class actionModel extends model
/* Filter out client login/logout actions. */
->andWhere('action')->notin('disconnectxuanxuan,reconnectxuanxuan,loginxuanxuan,logoutxuanxuan')
->andWhere("IF((objectType = 'program'), (objectID in ($programCondition)), '1=1')")
->andWhere("IF((objectType = 'effort'), (objectID in ($efforts)), '1=1')")
->orderBy($orderBy)
->page($pager)
->fetchAll();
+1 -1
View File
@@ -14,7 +14,7 @@
<div id='mainMenu' class='clearfix'>
<div class='btn-toolbar pull-left'>
<?php $activeClass = $currentObjectType == 'all' ? 'btn-active-text' : '';?>
<?php echo html::a($this->createLink('action', 'trash', "objectType=all&type=$type"), "<span class='text'>" . $lang->all . "</span>", '', "class='btn btn-link $activeClass'");?>
<?php echo html::a($this->createLink('action', 'trash', "objectType=all&type=$type"), "<span class='text'>" . $lang->action->periods['all'] . "</span>", '', "class='btn btn-link $activeClass'");?>
<?php
/* Output the objectType order by preferredTypeConfig. */
foreach($preferredTypeConfig as $objectType)
+1 -1
View File
@@ -57,6 +57,6 @@ $lang->branch->statusList = array();
$lang->branch->statusList['active'] = '激活';
$lang->branch->statusList['closed'] = '已关闭';
$lang->branch->featureBar['manage']['all'] = '所有';
$lang->branch->featureBar['manage']['all'] = '全部';
$lang->branch->featureBar['manage']['active'] = '激活';
$lang->branch->featureBar['manage']['closed'] = '已关闭';
+6 -6
View File
@@ -188,7 +188,7 @@ $config->bug->datatable->fieldList['pri']['name'] = $lang->bug->pri;
$config->bug->datatable->fieldList['confirmed']['title'] = 'confirmedAB';
$config->bug->datatable->fieldList['confirmed']['fixed'] = 'left';
$config->bug->datatable->fieldList['confirmed']['width'] = '50';
$config->bug->datatable->fieldList['confirmed']['width'] = '100';
$config->bug->datatable->fieldList['confirmed']['required'] = 'no';
$config->bug->datatable->fieldList['title']['title'] = 'title';
@@ -300,11 +300,11 @@ $config->bug->datatable->fieldList['openedBuild']['required'] = 'no';
$config->bug->datatable->fieldList['openedBuild']['control'] = 'multiple';
$config->bug->datatable->fieldList['openedBuild']['dataSource'] = array('module' => 'build', 'method' =>'getBuildPairs', 'params' => '$productID&$branch&noempty,noterminate,nodone,withbranch');
$config->bug->datatable->fieldList['assignedTo']['title'] = 'assignedToAB';
$config->bug->datatable->fieldList['assignedTo']['fixed'] = 'no';
$config->bug->datatable->fieldList['assignedTo']['width'] = '120';
$config->bug->datatable->fieldList['assignedTo']['required'] = 'no';
$config->bug->datatable->fieldList['assignedTo']['dataSource'] = array('module' => 'bug', 'method' =>'getProductMemberPairs', 'params' => '$productID&$branch');
$config->bug->datatable->fieldList['assignedTo']['title'] = 'assignedToAB';
$config->bug->datatable->fieldList['assignedTo']['fixed'] = 'no';
$config->bug->datatable->fieldList['assignedTo']['width'] = '120';
$config->bug->datatable->fieldList['assignedTo']['required'] = 'no';
$config->bug->datatable->fieldList['assignedTo']['dataSource'] = array('module' => 'user', 'method' =>'getPairs', 'params' => 'noclosed|noletter');
$config->bug->datatable->fieldList['assignedDate']['title'] = 'assignedDate';
$config->bug->datatable->fieldList['assignedDate']['fixed'] = 'no';
+15
View File
@@ -503,6 +503,8 @@ class bug extends control
$type = 'codeerror';
$pri = 3;
$color = '';
$feedbackBy = '';
$notifyEmail = '';
/* Parse the extras. extract fix php7.2. */
$extras = str_replace(array(',', ' '), array('&', ''), $extras);
@@ -528,6 +530,8 @@ class bug extends control
$deadline = helper::isZeroDate($bug->deadline) ? '' : $bug->deadline;
$color = $bug->color;
$testtask = $bug->testtask;
$feedbackBy = $bug->feedbackBy;
$notifyEmail = $bug->notifyEmail;
if($pri == 0) $pri = '3';
}
@@ -688,6 +692,8 @@ class bug extends control
$this->view->stepsRequired = strpos($this->config->bug->create->requiredFields, 'steps');
$this->view->isStepsTemplate = $steps == $this->lang->bug->tplStep . $this->lang->bug->tplResult . $this->lang->bug->tplExpect ? true : false;
$this->view->issueKey = $from == 'sonarqube' ? $output['sonarqubeID'] . ':' . $output['issueKey'] : '';
$this->view->feedbackBy = $feedbackBy;
$this->view->notifyEmail = $notifyEmail;
$this->display();
}
@@ -2314,6 +2320,15 @@ class bug extends control
{
$this->loadModel('port');
$this->session->set('bugPortParams', array('productID' => $productID, 'executionID' => $executionID, 'branch' => 'all'));
if(!$productID)
{
$this->config->bug->datatable->fieldList['module']['dataSource']['method'] = 'getAllModulePairs';
$this->config->bug->datatable->fieldList['module']['dataSource']['params'] = 'bug';
$this->config->bug->datatable->fieldList['project']['dataSource'] = array('module' => 'project', 'method' => 'getPairsByIdList', 'params' => $executionID);
$this->config->bug->datatable->fieldList['execution']['dataSource'] = array('module' => 'execution', 'method' => 'getPairs', 'params' => $executionID);
}
$this->port->export('bug');
$this->fetch('file', 'export2' . $_POST['fileType'], $_POST);
}
-2
View File
@@ -2,8 +2,6 @@
.closed, .closed a {color: gray; text-decoration:line-through;}
.resolved, .resolved a {color: #8EC21F; text-decoration: none;}
.tree .closed, .tree .closed a {color: #003366; text-decoration: none;}
.confirm0 {color: gray;}
.confirm1 {color: green;}
td.delayed {color: #fff; background: #e84e0f !important;}
#bugForm .setting {height: 25px;}
+2 -2
View File
@@ -1,2 +1,2 @@
.confirm0 {color:gray; font-size:9px}
.confirm1 {color:green; font-size:9px}
.confirm0 {font-size:9px}
.confirm1 {font-size:9px}
+2 -2
View File
@@ -286,8 +286,8 @@ $lang->bug->statusList['resolved'] = 'Resolved';
$lang->bug->statusList['closed'] = 'Closed';
$lang->bug->confirmedList[''] = '';
$lang->bug->confirmedList[1] = 'Yes';
$lang->bug->confirmedList[0] = 'No';
$lang->bug->confirmedList[1] = 'confirmed';
$lang->bug->confirmedList[0] = 'unconfirmed';
$lang->bug->resolutionList[''] = '';
$lang->bug->resolutionList['bydesign'] = 'As Designed';
+2 -2
View File
@@ -286,8 +286,8 @@ $lang->bug->statusList['resolved'] = 'Résolu';
$lang->bug->statusList['closed'] = 'Fermé';
$lang->bug->confirmedList[''] = '';
$lang->bug->confirmedList[1] = 'Oui';
$lang->bug->confirmedList[0] = 'Non';
$lang->bug->confirmedList[1] = 'confirmé';
$lang->bug->confirmedList[0] = 'non confirmé';
$lang->bug->resolutionList[''] = '';
$lang->bug->resolutionList['bydesign'] = 'Du Design';
+2 -2
View File
@@ -267,8 +267,8 @@ $lang->bug->statusList['active'] = 'Kích hoạt';
$lang->bug->statusList['resolved'] = 'Đã giải quyết';
$lang->bug->statusList['closed'] = 'Đã đóng';
$lang->bug->confirmedList[1] = 'Có';
$lang->bug->confirmedList[0] = 'Không';
$lang->bug->confirmedList[1] = 'đã xác nhận';
$lang->bug->confirmedList[0] = 'chưa được xác nhận';
$lang->bug->resolutionList[''] = '';
$lang->bug->resolutionList['bydesign'] = 'Như thiết kế';
+3 -3
View File
@@ -286,8 +286,8 @@ $lang->bug->statusList['resolved'] = '已解决';
$lang->bug->statusList['closed'] = '已关闭';
$lang->bug->confirmedList[''] = '';
$lang->bug->confirmedList[1] = '是';
$lang->bug->confirmedList[0] = '否';
$lang->bug->confirmedList[1] = '已确认';
$lang->bug->confirmedList[0] = '未确认';
$lang->bug->resolutionList[''] = '';
$lang->bug->resolutionList['bydesign'] = '设计如此';
@@ -415,7 +415,7 @@ $lang->bug->placeholder = new stdclass();
$lang->bug->placeholder->chooseBuilds = '选择相关版本...';
$lang->bug->placeholder->newBuildName = '新版本名称';
$lang->bug->featureBar['browse']['all'] = $lang->bug->allBugs;
$lang->bug->featureBar['browse']['all'] = '全部';
$lang->bug->featureBar['browse']['unclosed'] = $lang->bug->unclosed;
$lang->bug->featureBar['browse']['openedbyme'] = $lang->bug->openedByMe;
$lang->bug->featureBar['browse']['assigntome'] = $lang->bug->assignToMe;
+2 -2
View File
@@ -283,8 +283,8 @@ $lang->bug->statusList['resolved'] = '已解決';
$lang->bug->statusList['closed'] = '已關閉';
$lang->bug->confirmedList[''] = '';
$lang->bug->confirmedList[1] = '是';
$lang->bug->confirmedList[0] = '否';
$lang->bug->confirmedList[1] = '已確認';
$lang->bug->confirmedList[0] = '未確認';
$lang->bug->resolutionList[''] = '';
$lang->bug->resolutionList['bydesign'] = '設計如此';
+8 -6
View File
@@ -704,7 +704,7 @@ class bugModel extends model
->setDefault('browser', '')
->setDefault('plan', 0)
->setDefault('deadline', '0000-00-00')
->setDefault('resolvedDate', '0000-00-00 00:00:00')
->setDefault('resolvedDate', '')
->setDefault('lastEditedBy', $this->app->user->account)
->setDefault('mailto', '')
->setDefault('deleteFiles', array())
@@ -3485,15 +3485,17 @@ class bugModel extends model
public function printAssignedHtml($bug, $users)
{
$btnTextClass = '';
$btnClass = '';
$assignedToText = !empty($bug->assignedTo) ? zget($users, $bug->assignedTo) : $this->lang->bug->noAssigned;
$btnTextClass = 'text-primary';
if($bug->assignedTo == $this->app->user->account) $btnTextClass = 'text-red';
if(empty($bug->assignedTo)) $btnClass = $btnTextClass = 'assigned-none';
if($bug->assignedTo == $this->app->user->account) $btnClass = $btnTextClass = 'assigned-current';
if(!empty($bug->assignedTo) and $bug->assignedTo != $this->app->user->account) $btnClass = $btnTextClass = 'assigned-other';
$btnClass = $bug->assignedTo == 'closed' ? ' disabled' : '';
$btnClass = "iframe btn btn-icon-left btn-sm {$btnClass}";
$btnClass .= $bug->assignedTo == 'closed' ? ' disabled' : '';
$btnClass .= ' iframe btn btn-icon-left btn-sm';
$assignToLink = helper::createLink('bug', 'assignTo', "bugID=$bug->id", '', true);
$assignToHtml = html::a($assignToLink, "<i class='icon icon-hand-right'></i> <span title='" . zget($users, $bug->assignedTo) . "' class='{$btnTextClass}'>{$assignedToText}</span>", '', "class='$btnClass'");
$assignToHtml = html::a($assignToLink, "<i class='icon icon-hand-right'></i> <span title='" . zget($users, $bug->assignedTo) . "'>{$assignedToText}</span>", '', "class='$btnClass'");
echo !common::hasPriv('bug', 'assignTo', $bug) ? "<span style='padding-left: 21px' class='{$btnTextClass}'>{$assignedToText}</span>" : $assignToHtml;
}
+2 -2
View File
@@ -17,7 +17,7 @@ foreach($products as $product)
}
$productsPinYin = common::convert2Pinyin($productNames);
$linkHtml = $this->product->setParamsForLink($module, $link, $projectID, 0);
$productsHtml = count($products) > 1 ? html::a($linkHtml, $this->lang->bug->allProduct, '', "class='text-important' title='{$this->lang->bug->allProduct}' data-key='" . zget($productsPinYin, $this->lang->bug->allProduct, '') . "' data-app='{$this->app->tab}'") : '';
$productsHtml = count($products) > 1 ? html::a($linkHtml, $this->lang->bug->allProduct, '', "class='text-primary' title='{$this->lang->bug->allProduct}' data-key='" . zget($productsPinYin, $this->lang->bug->allProduct, '') . "' data-app='{$this->app->tab}'") : '';
foreach($products as $product)
{
@@ -26,7 +26,7 @@ foreach($products as $product)
$productName .= $product->line ? zget($lines, $product->line, '') . '/' . $product->name : $product->name;
$objectID = ($product->type != 'platform' && $module == 'branch' && $method == 'manage') ? $productID : $product->id;
$linkHtml = $this->product->setParamsForLink($module, $link, $projectID, $product->id);
$productsHtml .= html::a($linkHtml, $productName, '', "class='text-important $selected' title='{$productName}' data-key='" . zget($productsPinYin, $product->name, '') . "' data-app='{$this->app->tab}'");
$productsHtml .= html::a($linkHtml, $productName, '', "class='text-primary $selected' title='{$productName}' data-key='" . zget($productsPinYin, $product->name, '') . "' data-app='{$this->app->tab}'");
}
?>
<div class="table-row">
+4 -4
View File
@@ -160,11 +160,11 @@ if($this->app->tab == 'project') js::set('objectID', $projectID);
<?php if($showNoticefeedbackBy):?>
<tr>
<th><nobr><?php echo $lang->bug->feedbackBy;?></nobr></th>
<td><?php echo html::input('feedbackBy', '', "class='form-control'");?></td>
<td><?php echo html::input('feedbackBy', $feedbackBy, "class='form-control'");?></td>
<td id='notifyEmailTd'>
<div class='input-group'>
<span class='input-group-addon'><?php echo $lang->bug->notifyEmail?></span>
<span><?php echo html::input('notifyEmail', '', "class='form-control'");?></span>
<span><?php echo html::input('notifyEmail', $notifyEmail, "class='form-control'");?></span>
</div>
</td>
</tr>
@@ -173,9 +173,9 @@ if($this->app->tab == 'project') js::set('objectID', $projectID);
<td>
<div class='input-group' id='feedback'>
<span class="input-group-addon"><?php echo $lang->bug->feedbackBy?></span>
<?php echo html::input('feedbackBy', '', "class='form-control'");?>
<?php echo html::input('feedbackBy', $feedbackBy, "class='form-control'");?>
<span class="input-group-addon"><?php echo $lang->bug->notifyEmail?></span>
<?php echo html::input('notifyEmail', '', "class='form-control'");?>
<?php echo html::input('notifyEmail', $notifyEmail, "class='form-control'");?>
</div>
</td>
</tr>
+1 -1
View File
@@ -393,7 +393,7 @@
<?php if($bug->case):?>
<tr>
<th><?php echo $lang->bug->fromCase;?></th>
<td><?php echo html::a($this->createLink('testcase', 'view', "caseID=$bug->case&caseVersion=" . ($bug->testtask ? "&from=testtask&taskID={$bug->testtask}" : ''), '', true), "#$bug->case $bug->caseTitle", '', "class='iframe' data-width='80%'");?></td>
<td><?php echo html::a($this->createLink('testcase', 'view', "caseID=$bug->case&caseVersion=$bug->caseVersion", '', true), "#$bug->case $bug->caseTitle", '', "class='iframe' data-width='80%'");?></td>
</tr>
<?php endif;?>
<?php if($bug->toCases):?>
+3 -2
View File
@@ -20,6 +20,7 @@
#stories .action {display: none;}
#bugs .action {display: none;}
tbody tr td:first-child input {display: none;}
.page-title .dropdown-menu {top: 40px; left: 70px;}
</style>
<?php endif;?>
<div id='mainMenu' class='clearfix'>
@@ -28,8 +29,8 @@ tbody tr td:first-child input {display: none;}
<?php common::printBack($browseLink, 'btn btn-secondary');?>
<div class='divider'></div>
<div class='page-title'>
<span class='text' title='<?php echo $build->name;?>'>
<?php echo html::a('javascript:void(0)', "<span class='label label-id'>{$build->id}</span> " . $build->name . " <span class='caret'></span>", '', "data-toggle='dropdown' class='btn btn-link btn-active-text'");?>
<span title='<?php echo $build->name;?>'>
<?php echo html::a('javascript:void(0)', "<span class='label label-id'>{$build->id}</span> " . $build->name . " <span class='caret'></span>", '', "data-toggle='dropdown' class='text btn btn-link btn-active-text'");?>
<?php
echo "<ul class='dropdown-menu'>";
foreach($buildPairs as $id => $name)
+1 -1
View File
@@ -45,5 +45,5 @@ $lang->caselib->legendDesc = '描述';
$lang->caselib->libraryDelete = '您确认要删除该用例库吗?';
$lang->caselib->noModule = '<div>您现在还没有模块信息</div><div>请维护用例库模块</div>';
$lang->caselib->featureBar['browse']['all'] = '所有';
$lang->caselib->featureBar['browse']['all'] = '全部';
$lang->caselib->featureBar['browse']['wait'] = '待评审';
+12 -2
View File
@@ -1460,9 +1460,17 @@ class commonModel extends model
echo '<li>' . html::a(helper::createLink('misc', 'downloadClient', '', '', true), $lang->downloadClient, '', "title='$lang->downloadClient' class='iframe text-ellipsis' data-width='600'") . '</li>';
echo "<li class='dropdown-submenu' id='downloadMobile'><a href='javascript:;'>" . $lang->downloadMobile . "</a><ul class='dropdown-menu pull-left''>";
$appqrcode = self::http('https://www.zentao.net/page/appqrcode.json');
/* Intranet users use local pictures. */
if(!empty($appqrcode))
$curl = curl_init();
curl_setopt($curl, CURLOPT_URL, 'https://www.zentao.net/page/appqrcode.json');
curl_setopt($curl, CURLOPT_TIMEOUT_MS, 200);
curl_setopt($curl, CURLOPT_CONNECTTIMEOUT_MS, 200);
curl_setopt($curl, CURLOPT_RETURNTRANSFER, TRUE);
curl_setopt($curl, CURLOPT_SSL_VERIFYPEER, FALSE);
curl_setopt($curl, CURLOPT_SSL_VERIFYHOST, FALSE);
$connected = curl_exec($curl);
curl_close($curl);
if($connected)
{
echo "<li><div class='mobile-qrcode'><iframe src='https://www.zentao.net/page/appqrcode.html?v={$config->version}' frameborder='0' scrolling='no' seamless></iframe></div></li>";
}
@@ -2141,6 +2149,8 @@ EOD;
{
if(strpos($orderBy, 'priOrder') !== false) $select .= ", IF(`pri` = 0, {$this->config->maxPriValue}, `pri`) as priOrder";
if(strpos($orderBy, 'severityOrder') !== false) $select .= ", IF(`severity` = 0, {$this->config->maxPriValue}, `severity`) as severityOrder";
$queryCondition = str_replace('t4.status', 'status', $queryCondition);
$sql = $this->dao->select("*$select")->from($table)
->where($queryCondition)
->beginIF($orderBy != false)->orderBy($orderBy)->fi()
+1
View File
@@ -30,6 +30,7 @@ $lang->dept->noDepartment = "No Department";
$lang->dept->confirmDelete = " Möchten Sie diese Abteilung löschen?";
$lang->dept->successSave = " Gespeichert!";
$lang->dept->repeatDepart = " Es gibt einen doppelten Abteilungsnamen, möchten Sie ihn wirklich hinzufügen?";
$lang->dept->error = new stdclass();
$lang->dept->error->hasSons = 'Diese Abteilung hat Unterabteilungen und kann daher nicht gelöscht werden!';
+1
View File
@@ -30,6 +30,7 @@ $lang->dept->noDepartment = "No Department";
$lang->dept->confirmDelete = " Do you want to delete this department?";
$lang->dept->successSave = " Saved!";
$lang->dept->repeatDepart = " There is a duplicate department name, are you sure to add it?";
$lang->dept->error = new stdclass();
$lang->dept->error->hasSons = 'This Department has child departments. You cannot delete it!';
+1
View File
@@ -30,6 +30,7 @@ $lang->dept->noDepartment = "No Department";
$lang->dept->confirmDelete = " Confirmez que vous voulez bien supprimer ce Compartiment ?";
$lang->dept->successSave = " Sauvé !";
$lang->dept->repeatDepart = " Il y a un nom de département en double, êtes-vous sûr de l'ajouter ?";
$lang->dept->error = new stdclass();
$lang->dept->error->hasSons = 'Ce Compartiment possède des domaines. Vous ne pouvez pas le supprimer !';
+1
View File
@@ -26,6 +26,7 @@ $lang->dept->dragAndSort = "Drag để sắp xếp";
$lang->dept->confirmDelete = " Bạn có muốn xóa this department?";
$lang->dept->successSave = " Saved!";
$lang->dept->repeatDepart = " Có một tên bộ phận trùng lặp, bạn có chắc chắn thêm nó không?";
$lang->dept->error = new stdclass();
$lang->dept->error->hasSons = 'This Department has child departments. You cannot xóa it!';
+1
View File
@@ -30,6 +30,7 @@ $lang->dept->noDepartment = "无部门";
$lang->dept->confirmDelete = " 您确定删除该部门吗?";
$lang->dept->successSave = " 修改成功。";
$lang->dept->repeatDepart = " 存在部门名称重复,您确认添加吗?";
$lang->dept->error = new stdclass();
$lang->dept->error->hasSons = '该部门有子部门,不能删除!';
+1
View File
@@ -29,6 +29,7 @@ $lang->dept->dragAndSort = "拖動排序";
$lang->dept->confirmDelete = " 您確定刪除該部門嗎?";
$lang->dept->successSave = " 修改成功。";
$lang->dept->repeatDepart = " 存在部門名稱重複,您確認添加嗎?";
$lang->dept->error = new stdclass();
$lang->dept->error->hasSons = '該部門有子部門,不能刪除!';
+39 -4
View File
@@ -11,6 +11,7 @@
*/
?>
<?php include '../../common/view/header.html.php';?>
<?php js::set('repeatDepart', $lang->dept->repeatDepart);?>
<div id='mainMenu' class='clearfix'>
<div class='btn-toolbar pull-left'>
<span class='btn btn-link btn-active-text'><span class='text'><?php echo $lang->dept->common;?></span></span>
@@ -33,7 +34,7 @@
<div class='panel-title'><?php echo $lang->dept->manageChild;?></div>
</div>
<div class='panel-body'>
<form method='post' target='hiddenwin' action='<?php echo $this->createLink('dept', 'manageChild');?>'>
<form method='post' target='hiddenwin' action='<?php echo $this->createLink('dept', 'manageChild');?>' id="dataForm">
<table class='table table-form'>
<tr>
<td>
@@ -49,7 +50,7 @@
?>
</nobr>
</td>
<td class='w-300px'>
<td class='w-500px'>
<?php
$maxOrder = 0;
foreach($sons as $sonDept)
@@ -85,7 +86,7 @@ $(function()
name: 'deptTree',
initialState: 'preserve',
data: data,
sortable:
sortable:
{
lazy: true,
nested: true,
@@ -105,7 +106,7 @@ $(function()
$li.append($toggle);
return true;
},
actions:
actions:
{
sort:
{
@@ -172,6 +173,40 @@ $(function()
$(this).addClass('hover');
e.stopPropagation();
});
$("input[name*='depts']").change(function ()
{
var depts = new Array();
var modifyData = $(this).val();
var changedInput = $(this);
changedInput.wrap('<span>');
changedInput.closest('span').addClass('dataField');
$('input[name^="depts"]').not($(this)).each(function()
{
if($(this).val()) depts.push($(this).val());
});
if(depts.indexOf(modifyData) > -1)
{
$('.dataField #depts\\[\\]').addClass('intro');
$('.intro').css({"margin" : "5px 0px 5px 0px", "display" : "inline", "width" : "50%"});
changedInput.after('<span style="padding-left: 15px;color: #1183fb" class="tips">' + repeatDepart + '</span>');
}
});
$("input[name*='depts']").focus(function ()
{
if($('.dataField').length)
{
$('.intro').removeAttr('style');
$('.intro').unwrap();
$('#depts\\[\\]').removeClass('intro');
$('.tips').remove();
}
});
});
</script>
<?php include '../../common/view/footer.html.php';?>
+7 -5
View File
@@ -467,19 +467,21 @@ class designModel extends model
public function printAssignedHtml($design = '', $users = '')
{
$btnTextClass = '';
$btnClass = '';
$assignedToText = zget($users, $design->assignedTo);
if(empty($design->assignedTo))
{
$btnTextClass = 'text-primary';
$btnClass = $btnTextClass = 'assigned-none';
$assignedToText = $this->lang->design->noAssigned;
}
if($design->assignedTo == $this->app->user->account) $btnTextClass = 'text-red';
if($design->assignedTo == $this->app->user->account) $btnClass = $btnTextClass = 'assigned-current';
if(!empty($design->assignedTo) and $design->assignedTo != $this->app->user->account) $btnClass = $btnTextClass = 'assigned-other';
$btnClass = $design->assignedTo == 'closed' ? ' disabled' : '';
$btnClass = "iframe btn btn-icon-left btn-sm {$btnClass}";
$btnClass .= $design->assignedTo == 'closed' ? ' disabled' : '';
$btnClass .= ' iframe btn btn-icon-left btn-sm';
$assignToLink = helper::createLink('design', 'assignTo', "designID=$design->id", '', true);
$assignToHtml = html::a($assignToLink, "<i class='icon icon-hand-right'></i> <span title='" . zget($users, $design->assignedTo) . "' class='{$btnTextClass}'>{$assignedToText}</span>", '', "class='$btnClass'");
$assignToHtml = html::a($assignToLink, "<i class='icon icon-hand-right'></i> <span title='" . zget($users, $design->assignedTo) . "'>{$assignedToText}</span>", '', "class='$btnClass'");
echo !common::hasPriv('design', 'assignTo', $design) ? "<span style='padding-left: 21px' class='{$btnTextClass}'>{$assignedToText}</span>" : $assignToHtml;
}
+1 -1
View File
@@ -25,7 +25,7 @@ foreach($products as $product)
$linkHtml = sprintf($link, $product->id);
if($product->status == 'normal' and $product->PO == $this->app->user->account)
{
$myProductsHtml .= html::a($linkHtml, $productName, '', "class='text-important $selected' title='{$productName}' data-key='" . zget($productsPinYin, $product->name, '') . "' data-app='$tab'");
$myProductsHtml .= html::a($linkHtml, $productName, '', "class='text-primary $selected' title='{$productName}' data-key='" . zget($productsPinYin, $product->name, '') . "' data-app='$tab'");
}
else if($product->status == 'normal' and !($product->PO == $this->app->user->account))
{
+12
View File
@@ -629,6 +629,18 @@ class doc extends control
if($this->config->systemMode == 'classic' and $objectType == 'project') $objectType = 'execution';
$this->doc->delete(TABLE_DOC, $docID);
/* Delete doc files. */
$this->loadModel('file');
foreach($doc->files as $fileID => $file)
{
$file = $this->file->getById($fileID);
$this->dao->delete()->from(TABLE_FILE)->where('id')->eq($fileID)->exec();
$this->loadModel('action')->create($file->objectType, $file->objectID, 'deletedFile', '', $extra=$file->title);
$fileRecord = $this->dao->select('id')->from(TABLE_FILE)->where('pathname')->eq($file->pathname)->fetch();
if(empty($fileRecord)) @unlink($file->realPath);
}
/* if ajax request, send result. */
if($this->server->ajax)
{
+1 -1
View File
@@ -62,7 +62,7 @@ $(function()
if($(".createCustomLib").length == 1) $(".createCustomLib").click(); // Fix bug #15139.
if(!fromGlobal && textType.indexOf(docType) != -1)
if(!fromGlobal && textType.indexOf(docType) != -1 && from == 'doc')
{
var basicInfo = JSON.parse(sessionStorage.getItem('docBasicInfo'));
+1
View File
@@ -10,6 +10,7 @@
* @link http://www.zentao.net
*/
?>
<?php js::set('from', $from);?>
<?php if(strpos($config->doc->textTypes, $docType) !== false and $from == 'doc'):?>
<?php include 'createtexttype.html.php';?>
<?php else:?>
+9 -6
View File
@@ -2365,10 +2365,10 @@ class execution extends control
/**
* Kanban.
*
* @param int $executionID
* @param string $browseType
* @param string $orderBy
* @param string $groupBy
* @param int $executionID
* @param string $browseType
* @param string $orderBy
* @param string $groupBy
* @access public
* @return void
*/
@@ -2422,7 +2422,6 @@ class execution extends control
}
foreach($products as $product) $productNames[$product->id] = $product->name;
$plans = $this->execution->getPlans($products, 'skipParent', $executionID);
$allPlans = array('' => '');
if(!empty($plans))
@@ -2430,6 +2429,9 @@ class execution extends control
foreach($plans as $plan) $allPlans += $plan;
}
$taskToOpen = !empty($_COOKIE['taskToOpen']) ? $_COOKIE['taskToOpen'] : 0;
setcookie('taskToOpen', 0, time() - 3600, $this->config->webRoot, '', $this->config->cookieSecure, true);
$this->view->title = $this->lang->kanban->view;
$this->view->users = $users;
$this->view->regions = $kanbanData;
@@ -2448,6 +2450,7 @@ class execution extends control
$this->view->kanbanData = $kanbanData;
$this->view->executionActions = $executionActions;
$this->view->kanban = $this->lang->execution->kanban;
$this->view->taskToOpen = $taskToOpen;
$this->display();
}
@@ -2495,7 +2498,7 @@ class execution extends control
$kanbanGroup = $this->kanban->getExecutionKanban($executionID, $browseType, $groupBy, '', $orderBy);
if(empty($kanbanGroup))
{
$this->kanban->createExecutionLane($executionID, $browseType, $groupBy);
$this->kanban->createExecutionLane($executionID, $browseType);
$kanbanGroup = $this->kanban->getExecutionKanban($executionID, $browseType, $groupBy, '', $orderBy);
}
+1
View File
@@ -20,3 +20,4 @@ th.c-pri{width:50px;}
.switchBtn {background-color: #fff !important;}
.switchBtn > i {padding-left: 7px;}
#main>.container {padding: 0 20px 20px 23px;}
#executionStoryForm table tbody tr td.c-actions .dividing-line {width: 1px; height: 16px; display: inline-block; vertical-align: middle; background: #F4F5F7; margin: 0 4px 0 0;}
+1
View File
@@ -11,3 +11,4 @@ td.delayed {background: #e84e0f !important; color: white;}
#taskList .c-progress{padding-right: 8px; text-align: right;}
#datatable-taskList .c-progress{padding-right: 8px; text-align: right;}
.c-finishedBy, .c-lastEditedBy {overflow: hidden; text-overflow: ellipsis; white-space: nowrap;}
#executionTaskForm table tbody tr td.c-actions .dividing-line {width: 1px; height: 16px; display: inline-block; vertical-align: middle; background: #F4F5F7; margin: 0 4px 0 0;}
+2 -2
View File
@@ -467,7 +467,7 @@ $lang->execution->kanban = "Kanban";
$lang->execution->kanbanSetting = "Kanban Einstellung";
$lang->execution->setKanban = "Kanban Einstellung";
$lang->execution->resetKanban = "Einstellungen zurücksetzen";
$lang->execution->printKanban = "Kanban drucken";
$lang->execution->printKanban = "drucken Kanban";
$lang->execution->fullScreen = "Full Screen";
$lang->execution->bugList = "Bugs";
@@ -487,7 +487,7 @@ $lang->kanbanSetting->optionList['0'] = 'Verstecken';
$lang->kanbanSetting->optionList['1'] = 'Anzeigen';
$lang->printKanban = new stdclass();
$lang->printKanban->common = 'Kanban drucken';
$lang->printKanban->common = 'drucken Kanban';
$lang->printKanban->content = 'Inhanlt';
$lang->printKanban->print = 'Drucken';
+1 -1
View File
@@ -467,7 +467,7 @@ $lang->execution->kanban = "Kanban";
$lang->execution->kanbanSetting = "Settings";
$lang->execution->setKanban = "Set Kanban";
$lang->execution->resetKanban = "Reset";
$lang->execution->printKanban = "Print";
$lang->execution->printKanban = "Print Kanban";
$lang->execution->fullScreen = "Full Screen";
$lang->execution->bugList = "Bugs";
+1 -1
View File
@@ -467,7 +467,7 @@ $lang->execution->kanban = "Kanban";
$lang->execution->kanbanSetting = "Paramétrage";
$lang->execution->setKanban = "Paramétrage";
$lang->execution->resetKanban = "Réinitialiser";
$lang->execution->printKanban = "Impression";
$lang->execution->printKanban = "Imprimer Kanban";
$lang->execution->fullScreen = "Full Screen";
$lang->execution->bugList = "Bugs";
+8 -8
View File
@@ -317,12 +317,12 @@ $lang->execution->groups['finishedBy'] = '完成者分组';
$lang->execution->groups['closedBy'] = '关闭者分组';
$lang->execution->groups['type'] = '类型分组';
$lang->execution->groupFilter['story']['all'] = '所有';
$lang->execution->groupFilter['story']['all'] = '全部';
$lang->execution->groupFilter['story']['linked'] = "已关联{$lang->SRCommon}的任务";
$lang->execution->groupFilter['pri']['all'] = '所有';
$lang->execution->groupFilter['pri']['all'] = '全部';
$lang->execution->groupFilter['pri']['noset'] = '未设置';
$lang->execution->groupFilter['assignedTo']['undone'] = '未完成';
$lang->execution->groupFilter['assignedTo']['all'] = '所有';
$lang->execution->groupFilter['assignedTo']['all'] = '全部';
$lang->execution->byQuery = '搜索';
@@ -487,7 +487,7 @@ $lang->kanbanSetting->optionList['0'] = '隐藏';
$lang->kanbanSetting->optionList['1'] = '显示';
$lang->printKanban = new stdclass();
$lang->printKanban->common = '看板打印';
$lang->printKanban->common = '打印看板';
$lang->printKanban->content = '内容';
$lang->printKanban->print = '打印';
@@ -501,7 +501,7 @@ $lang->execution->typeList['stage'] = '阶段';
$lang->execution->typeList['sprint'] = $lang->executionCommon;
$lang->execution->typeList['kanban'] = '看板';
$lang->execution->featureBar['task']['all'] = $lang->execution->allTasks;
$lang->execution->featureBar['task']['all'] = '全部';
$lang->execution->featureBar['task']['unclosed'] = $lang->execution->unclosed;
$lang->execution->featureBar['task']['assignedtome'] = $lang->execution->assignedToMe;
$lang->execution->featureBar['task']['myinvolved'] = $lang->execution->myInvolved;
@@ -509,17 +509,17 @@ $lang->execution->featureBar['task']['assignedbyme'] = $lang->execution->assigne
$lang->execution->featureBar['task']['needconfirm'] = "{$lang->SRCommon}变更";
$lang->execution->featureBar['task']['status'] = $lang->execution->statusSelects[''];
$lang->execution->featureBar['all']['all'] = $lang->execution->all;
$lang->execution->featureBar['all']['all'] = '全部';
$lang->execution->featureBar['all']['undone'] = $lang->execution->undone;
$lang->execution->featureBar['all']['wait'] = $lang->execution->statusList['wait'];
$lang->execution->featureBar['all']['doing'] = $lang->execution->statusList['doing'];
$lang->execution->featureBar['all']['suspended'] = $lang->execution->statusList['suspended'];
$lang->execution->featureBar['all']['closed'] = $lang->execution->statusList['closed'];
$lang->execution->featureBar['bug']['all'] = '所有';
$lang->execution->featureBar['bug']['all'] = '全部';
$lang->execution->featureBar['bug']['unresolved'] = '未解决';
$lang->execution->featureBar['build']['all'] = '所有版本';
$lang->execution->featureBar['build']['all'] = '全部版本';
$lang->execution->myExecutions = '我参与的';
$lang->execution->doingProject = '进行中的项目';
+1 -1
View File
@@ -410,7 +410,7 @@ $lang->kanbanSetting->optionList['0'] = '隱藏';
$lang->kanbanSetting->optionList['1'] = '顯示';
$lang->printKanban = new stdclass();
$lang->printKanban->common = '看板打印';
$lang->printKanban->common = '打印看板';
$lang->printKanban->content = '內容';
$lang->printKanban->print = '打印';
+2 -2
View File
@@ -706,7 +706,7 @@ class executionModel extends model
/* Check unique code for edited executions. */
if($projectModel == 'scrum' and isset($executionCode) and empty($executionCode))
{
dao::$errors['code'][] = 'execution#' . $executionID . sprintf($this->lang->error->notempty, $this->lang->project->code);
dao::$errors['code'][] = 'execution#' . $executionID . sprintf($this->lang->error->notempty, $this->lang->execution->execCode);
return false;
}
elseif(!empty($executionCode))
@@ -714,7 +714,7 @@ class executionModel extends model
/* Check unique code for edited executions. */
if(isset($codeList[$executionCode]))
{
dao::$errors['code'][] = 'execution#' . $executionID . sprintf($this->lang->error->unique, $this->lang->project->code, $executionCode);
dao::$errors['code'][] = 'execution#' . $executionID . sprintf($this->lang->error->unique, $this->lang->execution->execCode, $executionCode);
return false;
}
$codeList[$executionCode] = $executionCode;
+1 -1
View File
@@ -33,7 +33,7 @@
<?php echo html::a(inlink('grouptask', "executionID=$executionID&groupBy=$groupBy&filter=$filterKey"), $name, '', "class='btn btn-link $active'");?>
<?php endforeach;?>
<?php else:?>
<?php echo html::a(inlink('grouptask', "executionID=$executionID&groupBy=$groupBy"), "<span class='text'>{$lang->execution->allTasks}</span> <span class='label label-light label-badge'>{$allCount}</span>", '', "class='btn btn-link btn-active-text'");?>
<?php echo html::a(inlink('grouptask', "executionID=$executionID&groupBy=$groupBy"), "<span class='text'>{$lang->execution->featureBar['task']['all']}</span> <span class='label label-light label-badge'>{$allCount}</span>", '', "class='btn btn-link btn-active-text'");?>
<?php endif;?>
</div>
<div class="btn-toolbar pull-right">
+1 -1
View File
@@ -73,7 +73,7 @@
<div class='table-footer'>
<div class="checkbox-primary check-all"><label><?php echo $lang->selectAll?></label></div>
<div class="table-actions btn-toolbar show-always">
<?php echo html::submitButton('<i class="icon icon-import icon-sm"></i> ' . $lang->import, '', 'btn');?>
<?php echo html::submitButton('<i class="icon icon-import icon-sm"></i> ' . $lang->import, '', 'btn btn-primary');?>
</div>
<div class='btn-toolbar'>
<?php if(isonlybody()):?>
+29
View File
@@ -304,4 +304,33 @@ js::set('priv',
</div>
</div>
</div>
<?php js::set('taskToOpen', $taskToOpen);?>
<script>
$(function()
{
/* Open the task details popup from dynamic. */
if(taskToOpen)
{
var kanban = document.querySelector('#kanban');
var observer = new MutationObserver(function (mutationsList, observer)
{
for(var mutation of mutationsList)
{
var target = mutation.target;
if(mutation.type == 'childList' && target.tagName.toLowerCase() == 'a' && target.classList.contains('title') && target.parentElement.parentElement.dataset.id == taskToOpen && target.parentElement.className.includes('kanban-item-task'))
{
var a = document.querySelector('[data-id="' + taskToOpen +'"] a.title');
if(a)
{
observer.disconnect();
a.click();
break;
}
}
}
});
observer.observe(kanban, {subtree: true, childList: true});
}
})
</script>
<?php include '../../common/view/footer.html.php';?>
+1 -1
View File
@@ -13,7 +13,7 @@
</div>
</div>
<div class="btn-toolbar pull-left">
<?php echo html::a(inlink('testcase', "executionID=$executionID&productID=$productID&branchID=$branchID&type=$type&moduleID=$moduleID&orderBy=$orderBy"), "<span class='text'>{$lang->execution->all}</span>", '', "class='btn btn-link btn-active-text'");?>
<?php echo html::a(inlink('testcase', "executionID=$executionID&productID=$productID&branchID=$branchID&type=$type&moduleID=$moduleID&orderBy=$orderBy"), "<span class='text'>{$lang->execution->featureBar['all']['all']}</span>", '', "class='btn btn-link btn-active-text'");?>
</div>
<div class="btn-toolbar pull-right">
<?php if(common::canModify('execution', $execution)) echo html::a(helper::createLink('testcase', 'create', "productID=$productID&branch=0&moduleID=0&from=execution&param=$execution->id", '', '', '', true), "<i class='icon icon-plus'></i> " . $lang->testcase->create, '', "class='btn btn-primary' data-app='{$this->app->tab}'");?>
+9 -6
View File
@@ -12,14 +12,17 @@
?>
<?php
echo '"'. implode('","', $fields) . '"' . "\n";
foreach($rows as $row)
if($rows)
{
echo '"';
foreach($fields as $fieldName => $fieldLabel)
foreach($rows as $row)
{
isset($row->$fieldName) ? print(str_replace(array('"', '&nbsp;'), array('“', ' '), htmlspecialchars_decode(strip_tags($row->$fieldName, '<img>')))) : print('');
echo '","';
echo '"';
foreach($fields as $fieldName => $fieldLabel)
{
isset($row->$fieldName) ? print(str_replace(array('"', '&nbsp;'), array('“', ' '), htmlspecialchars_decode(strip_tags($row->$fieldName, '<img>')))) : print('');
echo '","';
}
echo '"' . "\n";
}
echo '"' . "\n";
}
if($this->post->kind == 'task' && $config->vision != 'lite') echo $this->lang->file->childTaskTips;
+2 -2
View File
@@ -206,8 +206,8 @@ $lang->gitlab->branch->create = 'Create';
$lang->gitlab->branch->lastCommitter = 'Last Committer';
$lang->gitlab->branch->lastCommittedDate = 'Last Committed Date';
$lang->gitlab->branch->accessLevel = "Branch protection list";
$lang->gitlab->branch->mergeAllowed = "Merge Allowed";
$lang->gitlab->branch->pushAllowed = "Push Allowed";
$lang->gitlab->branch->mergeAllowed = "Allowed to merge";
$lang->gitlab->branch->pushAllowed = "Allowed to push";
$lang->gitlab->branch->placeholderSearch = "Branch name";
$lang->gitlab->branch->placeholderSelect = "Branch name";
$lang->gitlab->branch->confirmDelete = 'Branch will be writable for developers. Are you sure?';
+2 -2
View File
@@ -206,8 +206,8 @@ $lang->gitlab->branch->create = 'Create';
$lang->gitlab->branch->lastCommitter = 'Last Committer';
$lang->gitlab->branch->lastCommittedDate = 'Last Committed Date';
$lang->gitlab->branch->accessLevel = "Branch protection list";
$lang->gitlab->branch->mergeAllowed = "Merge Allowed";
$lang->gitlab->branch->pushAllowed = "Push Allowed";
$lang->gitlab->branch->mergeAllowed = "Allowed to merge";
$lang->gitlab->branch->pushAllowed = "Allowed to push";
$lang->gitlab->branch->placeholderSearch = "Branch name";
$lang->gitlab->branch->placeholderSelect = "Branch name";
$lang->gitlab->branch->confirmDelete = 'Branch will be writable for developers. Are you sure?';
+2 -2
View File
@@ -206,8 +206,8 @@ $lang->gitlab->branch->create = 'Create';
$lang->gitlab->branch->lastCommitter = 'Last Committer';
$lang->gitlab->branch->lastCommittedDate = 'Last Committed Date';
$lang->gitlab->branch->accessLevel = "Branch protection list";
$lang->gitlab->branch->mergeAllowed = "Merge Allowed";
$lang->gitlab->branch->pushAllowed = "Push Allowed";
$lang->gitlab->branch->mergeAllowed = "Allowed to merge";
$lang->gitlab->branch->pushAllowed = "Allowed to push";
$lang->gitlab->branch->placeholderSearch = "Branch name";
$lang->gitlab->branch->placeholderSelect = "Branch name";
$lang->gitlab->branch->confirmDelete = 'Branch will be writable for developers. Are you sure?';
+2 -2
View File
@@ -206,8 +206,8 @@ $lang->gitlab->branch->create = '创建';
$lang->gitlab->branch->lastCommitter = '最后提交';
$lang->gitlab->branch->lastCommittedDate = '最后修改时间';
$lang->gitlab->branch->accessLevel = "分支保护列表";
$lang->gitlab->branch->mergeAllowed = "允许合并到";
$lang->gitlab->branch->pushAllowed = "允许推送到";
$lang->gitlab->branch->mergeAllowed = "允许合并";
$lang->gitlab->branch->pushAllowed = "允许推送";
$lang->gitlab->branch->placeholderSearch = "请输入分支名称";
$lang->gitlab->branch->placeholderSelect = "请选择分支";
$lang->gitlab->branch->confirmDelete = '确定删除分支保护?';
+1
View File
@@ -1711,6 +1711,7 @@ $lang->resource->report->bugCreate = 'bugCreate';
$lang->resource->report->bugAssign = 'bugAssign';
$lang->resource->report->workload = 'workload';
$lang->resource->report->annualData = 'annual';
$lang->resource->report->allAnnualData = 'viewEveryoneAnnual';
$lang->report->methodOrder[0] = 'index';
$lang->report->methodOrder[5] = 'projectDeviation';
+2 -3
View File
@@ -1,13 +1,12 @@
body {padding-left: 96px;}
#menu {position: fixed; left: 0; top: 0; bottom: 0; background-color: #3C495C; width: 96px; z-index: 1015;}
#menu {position: fixed; left: 0; top: 0; bottom: 0; width: 96px; z-index: 1015;}
.menu-show .menu-tip {display: none!important;}
#menuNav {position: absolute; top: 5px; bottom: 40px; width: 100%;}
#menu .nav > li {float: none; padding: 2px 8px;}
#menu .nav > li > a {color: #fff; line-height: 24px; padding: 6px; border-radius: 2px; white-space: nowrap; height: 36px;}
#menu .nav > li > a > .icon {display: inline-block; font-size: 16px; position: relative; top: -1px}
#menu .nav > li > a > .icon + .text {margin-left: 4px; position: relative; top: -1px}
#menu .nav > li.active > a, #menu .nav > li > a:hover, #menu .nav > li > a:focus {background-color: #0c64eb;}
#menu .nav > li.active > a, #menu .nav > li > a:hover, #menu .nav > li > a:focus {background-color: #3785ff;}
#menu .nav > li.divider {margin: 8px; background-color: #fff; opacity: 0.24; height: 1px; padding: 0 !important;}
#menuFooter {position: absolute; bottom: 0; left: 0; right: 0;}
#menu .nav > li.has-avatar {padding: 1px 6px;}
+17 -11
View File
@@ -157,26 +157,32 @@
.executionName .delayed {margin-right: 10px;}
#kanbanBox {position: relative;}
#regionTabs {background-color: #efefef; z-index: 100; display: flex;}
#regionTabs {background-color: #efefef; z-index: 100; display: flex; align-items: center; gap: 1.5rem; justify-content: space-between;}
#regionTabs .leftBtn.disabled i, #regionTabs .rightBtn.disabled i{color: #c2c2c2;}
#regionTabs .leftBtn i, #regionTabs .rightBtn i{vertical-align: 1px;}
#regionTabs .icon-angle-left, #regionTabs .icon-angle-right {font-size: 20px; vertical-align: -webkit-baseline-middle;}
#regionNavTabs {display: inline-flex; overflow: hidden; width: 100%; padding-left: 10px;}
#regionNavTabs > ul {display: inline-flex; border-bottom: unset;}
#regionNavTabs > ul > li {padding: 6px 15px; margin-bottom: 6px; border-radius: 4px 4px 0px 0px;}
#regionNavTabs > ul > li.active {background-color: #fff;}
#regionNavTabs > ul > li.active::before {content: ''; width: 10px; height: 10px; position: absolute; left: -10px; top: 21px; background: radial-gradient(circle at 0% 0%,transparent 10px,#fff 0);}
#regionNavTabs > ul > li.active::after {content: ''; width: 10px; height: 10px; position: absolute; left: calc(100%); top: 21px; background: radial-gradient(circle at 100% 0%,transparent 10px,#fff 0);}
#regionNavTabs > ul > li > a {max-width: 195px; overflow: hidden; white-space: nowrap; padding: 0; background-color: transparent;}
#regionNavTabs > ul > li.active > a:before {background: unset;}
#regionNavTabs {display: inline-flex; overflow: hidden;}
.leftBtn.hidden + #regionNavTabs {padding-left: 10px;}
#regionNavTabs > ul {display: inline-flex; border-bottom: none; margin-bottom: -3px;}
#regionNavTabs > ul > li {padding: 0; text-align: center;}
#regionNavTabs > ul > li > a {min-width: 134px; overflow: hidden; white-space: nowrap; z-index: 0; position: relative; padding: 1.7rem; margin-left: -20px; background: none; outline: 0; cursor: pointer !important;}
#regionNavTabs > ul > li:first-child > a {margin-left: 0;}
#regionNavTabs > ul > li.active > a {z-index: 1;}
#regionNavTabs > ul > li.active > a::before {background-color: #fff;}
#regionNavTabs > ul > li > a:before {content: ""; position: absolute; top: -1rem; left: 0; background: #f8f8f8; height: 100%; width: 100%; z-index: -1; border-top-left-radius: 1rem; border-top-right-radius: 1rem; transform: perspective(0.5rem) rotateX(2deg); transform-origin: bottom;}
#regionNavTabs > ul > li > a > span {vertical-align: bottom; overflow: hidden; max-width: 6em; white-space: nowrap; display: inline-block;}
#regionNavTabs > ul > li.active > a > span {color: #2b80ff!important;}
#regionTabs.affixed {margin-bottom: 5px; position: fixed; top: 0px;}
#regionTabs.affixed + #kanbanContainer .kanban-board.kanban-affixed > .kanban-header {margin-top: 30px;}
#regionTabs.affixed + #kanbanContainer .kanban-board.kanban-affixed > .kanban-header {margin-top: 43px;}
#regionTabs.affixed + #kanbanContainer .kanban-board.kanban-affixed > .kanban-header + .kanban-lane {margin-top: 38px;}
#regionTabs.affixed ul {margin-bottom: -10px;}
#regionTabs.affixed ul > li {margin-bottom: 0px !important;}
#regionTabs .region-actions .dropdown-menu {top: 25px;}
#region-tab-actions {display: none;}
#region-tab-actions.active {display: flex; position: relative; right: 0px; top: -2px;}
#region-tab-actions.active {display: flex;}
.region {display: none;}
.region.active {display: block;}
.region.active.notAll {margin-top: -5px;}
.region.active.notAll .region-header {display: none;}
.region.active.notAll .kanban, .region.active.notAll .kanban .kanban-header {background-color: #efefef;}
.kanban-card a[disabled] {color: #313c52;}
+13 -3
View File
@@ -1457,7 +1457,7 @@ $(function()
resetRegionHeight($(this).hasClass('icon-angle-top') ? 'open' : 'close');
});
$('.region-header').on('click', '.action', hideKanbanAction);
$('#regionTabs, .region-header').on('click', '.action', hideKanbanAction);
$('#TRAction').on('click', '.btn', hideKanbanAction);
/* Hide action box when user click document */
@@ -1507,6 +1507,7 @@ $(function()
$(window).on('resize', function(a)
{
adjustAddBtnPosition();
initRegionTabs();
});
resetLaneHeight();
@@ -1558,8 +1559,6 @@ $(function()
distance = 0;
radiusWidth = 10;
$(window).on('resize', initRegionTabs);
initRegionTabs();
$('.leftBtn').click(function()
{
@@ -1865,6 +1864,8 @@ function swipeRegionNavTabs($object, direction)
{
/* If you swipe left, the distance is equal to the item's left. */
distance = - itemLeft + radius - ($item.prev().hasClass('active') ? radiusWidth : 0);
/* tab overlap width */
distance += 20;
if($item.prev().length == 0)
{
distance = 0;
@@ -1882,6 +1883,7 @@ function swipeRegionNavTabs($object, direction)
{
/* If you swipe right, the distance is equal to the left distance of item plus the width of item minus the width of the regionNavTabs. */
distance = offsetWidth - itemOffset - radius + nextRadius - radiusWidth * 2;
distance += 20;
if($item.next().length == 0)
{
distance = - objectWidth + offsetWidth - radiusWidth * 2;
@@ -1922,6 +1924,7 @@ function initRegionTabs()
if(acitiveItemLeft + distance < 0)
{
distance = - acitiveItemLeft;
distance += 20;
if($acitiveItem.prev().length == 0)
{
distance = 0;
@@ -1932,6 +1935,7 @@ function initRegionTabs()
else if(acitiveItemWidth + acitiveItemLeft + distance + radiusWidth * 2 > regionTabsWidth && acitiveItemLeft != 0 && acitiveItemWidth != 0)
{
distance = regionTabsWidth - acitiveItemWidth - acitiveItemLeft + (distance != 0 ? - radiusWidth * 2 : radiusWidth);
distance += 20;
if($acitiveItem.next().length == 0)
{
distance = regionTabsWidth - acitiveItemWidth - acitiveItemLeft - radiusWidth * 2;
@@ -1967,6 +1971,11 @@ $('[data-tab]').on('shown.zui.tab', function(e)
{
$regions.addClass('active').removeClass('notAll');
if(hasActions) $regionActions.removeClass('active');
$regions.each(function()
{
var isFold = $(this).find('.region-header i').hasClass('icon-angle-down');
if(isFold) $(this).find('.kanban').css('display', 'none');
});
}
else
{
@@ -1986,6 +1995,7 @@ $('[data-tab]').on('shown.zui.tab', function(e)
if($(this).hasClass('archivedColumn')) $(this).find('a').attr('href', "javascript:loadMore(\"Column\", " + regionID + ')');
});
}
window.scrollTo(0, 0);
/* To manually refresh stay under the current tab, save the ID of the current region. */
var url = createLink('kanban', 'ajaxSaveRegionID', 'regionID=' + regionID);
+15 -65
View File
@@ -1554,7 +1554,7 @@ class kanbanModel extends model
$teamPairs = array();
foreach($taskTeams[$taskID] as $account => $team) $teamPairs[$account] = $team->realname;
$task->team = $teamPairs;
$task->teamMember = $teamPairs;
}
/* Get objects cards menus. */
@@ -1610,6 +1610,7 @@ class kanbanModel extends model
$laneData['order'] = $lane->order;
$laneData['type'] = $browseType;
$laneData['defaultCardType'] = $browseType;
if(empty($laneID) and !in_array($groupBy, array('module', 'story', 'pri', 'severity'))) $laneID = '';
if($browseType == 'task' and $groupBy == 'story')
{
@@ -1675,8 +1676,9 @@ class kanbanModel extends model
if($groupBy == 'assignedTo')
{
$laneID = (string)$laneID;
if(empty($object->team) and $object->$groupBy !== $laneID) continue;
if(!empty($object->team) and !in_array($laneID, array_keys($object->team), true)) continue;
if(empty($object->$groupBy)) $object->$groupBy = '';
if(empty($object->teamMember) and (string)$object->$groupBy !== $laneID) continue;
if(!empty($object->teamMember) and !in_array($laneID, array_keys($object->teamMember), true)) continue;
if($object->$groupBy !== $laneID) $cardData['assignedTo'] = $laneID;
}
@@ -1745,9 +1747,9 @@ class kanbanModel extends model
{
if(!isset($groupByList[$item->$groupBy])) $groupByList[$item->$groupBy] = $item->$groupBy;
if($groupBy == 'assignedTo' and !empty($item->team))
if($groupBy == 'assignedTo' and !empty($item->teamMember))
{
foreach($item->team as $account => $name)
foreach($item->teamMember as $account => $name)
{
if(!isset($groupByList[$account])) $groupByList[$account] = $account;
}
@@ -1796,6 +1798,7 @@ class kanbanModel extends model
if(in_array($groupBy, array('module', 'story', 'pri', 'severity'))) $objectPairs[0] = $this->lang->$browseType->$groupBy . ': ' . $this->lang->kanban->noGroup;
if(in_array($groupBy, array('assignedTo', 'source'))) $objectPairs[] = $this->lang->$browseType->$groupBy . ': ' . $this->lang->kanban->noGroup;
if($browseType == 'bug' and $groupBy == 'type') $objectPairs[0] = $this->lang->$browseType->$groupBy . ': ' . $this->lang->kanban->noGroup;
$laneColor = 0;
$order = 1;
@@ -2420,72 +2423,19 @@ class kanbanModel extends model
*
* @param int $executionID
* @param string $type all|story|bug|task
* @param string $groupBy default
* @access public
* @return void
*/
public function createExecutionLane($executionID, $type = 'all', $groupBy = 'default')
public function createExecutionLane($executionID, $type = 'all')
{
if($groupBy == 'default' or $type == 'all')
foreach($this->config->kanban->default as $type => $lane)
{
foreach($this->config->kanban->default as $type => $lane)
{
$lane->type = $type;
$lane->execution = $executionID;
$this->dao->insert(TABLE_KANBANLANE)->data($lane)->exec();
$lane->type = $type;
$lane->execution = $executionID;
$this->dao->insert(TABLE_KANBANLANE)->data($lane)->exec();
$laneID = $this->dao->lastInsertId();
$this->createExecutionColumns($laneID, $type, $executionID);
}
}
else
{
$this->loadModel($type);
$groupList = $this->getObjectGroup($executionID, $type, $groupBy);
$objectPairs = array();
if($groupBy == 'module') $objectPairs = $this->dao->select('id,name')->from(TABLE_MODULE)->where('type')->in('story,bug,task')->andWhere('deleted')->eq('0')->fetchPairs();
if($groupBy == 'story') $objectPairs = $this->dao->select('id,title')->from(TABLE_STORY)->where('deleted')->eq(0)->fetchPairs();
if($groupBy == 'assignedTo') $objectPairs = $this->loadModel('user')->getPairs('noletter');
$laneName = '';
$laneOrder = 5;
$colorIndex = 0;
foreach($groupList as $groupKey)
{
if($groupKey)
{
if(strpos('module,story,assignedTo', $groupBy) !== false)
{
$laneName = zget($objectPairs, $groupKey);
}
else
{
$laneName = zget($this->lang->$type->{$groupBy . 'List'}, $groupKey);
}
}
else
{
$laneName = $this->lang->kanban->noGroup;
}
$lane = new stdClass();
$lane->execution = $executionID;
$lane->type = $type;
$lane->groupby = $groupBy;
$lane->extra = $groupKey;
$lane->name = $laneName;
$lane->color = $this->config->kanban->laneColorList[$colorIndex];
$lane->order = $laneOrder;
$laneOrder += 5;
$colorIndex += 1;
if($colorIndex == count($this->config->kanban->laneColorList) + 1) $colorIndex = 0;
$this->dao->insert(TABLE_KANBANLANE)->data($lane)->exec();
$laneID = $this->dao->lastInsertId();
$this->createExecutionColumns($laneID, $type, $executionID, $groupBy, $groupKey);
}
$laneID = $this->dao->lastInsertId();
$this->createExecutionColumns($laneID, $type, $executionID);
}
}
+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.6.2'] = '2022-09-23';
$lang->misc->releaseDate['17.6.1'] = '2022-09-08';
$lang->misc->releaseDate['17.6'] = '2022-08-26';
$lang->misc->releaseDate['17.5'] = '2022-08-11';
@@ -189,6 +190,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.6.2'][] = array('title' => "3 themes in ZenTao including Green, ZenTao Blue, and Young Blue are updated. At the same time, the attachments could be uploaded in bulk in ZenTao. Fix bugs.", 'desc' => '');
$lang->misc->feature->all['17.6.1'][] = array('title' => "Optimized the processing logic of multi-member tasks. Fix bugs.", 'desc' => '');
$lang->misc->feature->all['17.6'][] = array('title' => "The processing logic of requirements is optimized, and the permissions of user requirements and soft requirements are split. Gantt chart supports manual drag and drop to manage task relationship. Fix bugs.", 'desc' => '');
$lang->misc->feature->all['17.5'][] = array('title' => "Provide efficient visual statistical tools. Optimize ZenTao performance, the database engine is adjusted from MyISAM to InnoDB. Gantt chart is optimized and upgraded, and the Copy items of the Max version can replicate more information. Fix bugs.", 'desc' => '');
+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.6.2'] = '2022-09-23';
$lang->misc->releaseDate['17.6.1'] = '2022-09-08';
$lang->misc->releaseDate['17.6'] = '2022-08-26';
$lang->misc->releaseDate['17.5'] = '2022-08-11';
@@ -189,6 +190,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.6.2'][] = array('title' => "3 themes in ZenTao including Green, ZenTao Blue, and Young Blue are updated. At the same time, the attachments could be uploaded in bulk in ZenTao. Fix bugs.", 'desc' => '');
$lang->misc->feature->all['17.6.1'][] = array('title' => "Optimized the processing logic of multi-member tasks. Fix bugs.", 'desc' => '');
$lang->misc->feature->all['17.6'][] = array('title' => "The processing logic of requirements is optimized, and the permissions of user requirements and soft requirements are split. Gantt chart supports manual drag and drop to manage task relationship. Fix bugs.", 'desc' => '');
$lang->misc->feature->all['17.5'][] = array('title' => "Provide efficient visual statistical tools. Optimize ZenTao performance, the database engine is adjusted from MyISAM to InnoDB. Gantt chart is optimized and upgraded, and the Copy items of the Max version can replicate more information. Fix bugs.", 'desc' => '');
+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.6.2'] = '2022-09-23';
$lang->misc->releaseDate['17.6.1'] = '2022-09-08';
$lang->misc->releaseDate['17.6'] = '2022-08-26';
$lang->misc->releaseDate['17.5'] = '2022-08-11';
@@ -189,6 +190,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.6.2'][] = array('title' => "3 themes in ZenTao including Green, ZenTao Blue, and Young Blue are updated. At the same time, the attachments could be uploaded in bulk in ZenTao. Fix bugs.", 'desc' => '');
$lang->misc->feature->all['17.6.1'][] = array('title' => "Optimized the processing logic of multi-member tasks. Fix bugs.", 'desc' => '');
$lang->misc->feature->all['17.6'][] = array('title' => "The processing logic of requirements is optimized, and the permissions of user requirements and soft requirements are split. Gantt chart supports manual drag and drop to manage task relationship. Fix bugs.", 'desc' => '');
$lang->misc->feature->all['17.5'][] = array('title' => "Provide efficient visual statistical tools. Optimize ZenTao performance, the database engine is adjusted from MyISAM to InnoDB. Gantt chart is optimized and upgraded, and the Copy items of the Max version can replicate more information. Fix bugs.", '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.6.2'] = '2022-09-23';
$lang->misc->releaseDate['17.6.1'] = '2022-09-08';
$lang->misc->releaseDate['17.6'] = '2022-08-26';
$lang->misc->releaseDate['17.5'] = '2022-08-11';
@@ -189,6 +190,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.6.2'][] = array('title' => '禅道更新叶兰绿、禅道蓝、青春蓝三大主题。实现附件批量上传功能。修复Bug。', 'desc' => '');
$lang->misc->feature->all['17.6.1'][] = array('title' => '优化了多人任务的处理逻辑,修复Bug。', 'desc' => '');
$lang->misc->feature->all['17.6'][] = array('title' => '优化了需求的处理逻辑,拆分了用需和软需的权限。甘特图支持手动拖拽维护任务关系。修复Bug。', 'desc' => '');
$lang->misc->feature->all['17.5'][] = array('title' => '提供高效的可视化统计工具。优化禅道性能,数据库引擎从MyISAM调整为InnoDB。甘特图优化升级,旗舰版的复制项目可以复制任务等更多信息。修复Bug。', 'desc' => '');
+1 -1
View File
@@ -77,7 +77,7 @@ $lang->mr->assignedToMe = '指派给我';
$lang->mr->createdByMe = '由我创建';
$lang->mr->statusList = array();
$lang->mr->statusList['all'] = '所有';
$lang->mr->statusList['all'] = '全部';
$lang->mr->statusList['opened'] = '开放中';
$lang->mr->statusList['merged'] = '已合并';
$lang->mr->statusList['closed'] = '已关闭';
+13 -2
View File
@@ -686,7 +686,7 @@ class mrModel extends model
}
$mergeResult = json_decode(commonModel::http($url, $MRObject));
if(isset($mergeResult->number)) $mergeResult->iid = $host->type == 'gitea' ? $mergeResult->number : $mergeResult->id;
if(isset($mergeResult->number)) $mergeResult->iid = $mergeResult->number;
if(isset($mergeResult->mergeable))
{
if($mergeResult->mergeable) $mergeResult->merge_status = 'can_be_merged';
@@ -867,7 +867,16 @@ class mrModel extends model
*/
public function apiGetMRCommits($hostID, $projectID, $MRID)
{
$url = sprintf($this->gitlab->getApiRoot($hostID), "/projects/$projectID/merge_requests/$MRID/commits");
$host = $this->loadModel('pipeline')->getByID($hostID);
if($host->type == 'gitlab')
{
$url = sprintf($this->gitlab->getApiRoot($hostID), "/projects/$projectID/merge_requests/$MRID/commits");
}
else
{
$url = sprintf($this->loadModel($host->type)->getApiRoot($hostID), "/repos/$projectID/pulls/$MRID/commits");
}
return json_decode(commonModel::http($url));
}
@@ -1797,6 +1806,8 @@ class mrModel extends model
/* Get commits by MR. */
$commits = $this->apiGetMRCommits($MR->hostID, $MR->targetProject, $MR->mriid);
if(empty($commits)) return true;
foreach($commits as $commit)
{
$objects = $this->repo->parseComment($commit->message);
+12 -11
View File
@@ -809,17 +809,18 @@ EOF;
}
$PMList = $this->user->getListByAccounts($accounts, 'account');
$this->view->title = $this->lang->my->common . $this->lang->colon . $this->lang->my->project;
$this->view->position[] = $this->lang->my->project;
$this->view->users = $this->loadModel('user')->getPairs('noletter');
$this->view->projects = $projects;
$this->view->PMList = $PMList;
$this->view->pager = $pager;
$this->view->status = $status;
$this->view->recTotal = $recTotal;
$this->view->recPerPage = $recPerPage;
$this->view->pageID = $pageID;
$this->view->orderBy = $orderBy;
$this->view->title = $this->lang->my->common . $this->lang->colon . $this->lang->my->project;
$this->view->position[] = $this->lang->my->project;
$this->view->users = $this->loadModel('user')->getPairs('noletter');
$this->view->projects = $projects;
$this->view->PMList = $PMList;
$this->view->pager = $pager;
$this->view->status = $status;
$this->view->recTotal = $recTotal;
$this->view->recPerPage = $recPerPage;
$this->view->pageID = $pageID;
$this->view->orderBy = $orderBy;
$this->view->usersAvatar = $this->user->getAvatarPairs('');
$this->display();
}
+2 -3
View File
@@ -1,4 +1,3 @@
td.delayed {color: #fff; background: #e84e0f !important;}
.confirmed {color: #008000;}
.unconfirmed {color: #808080;}
.c-confirm {width:50px;}
.c-confirm {width:60px;}
+1
View File
@@ -8,3 +8,4 @@
.dropdown-list > li > a:focus {color: #1a4f85; text-decoration: none; background-color: #ddd;}
.btn-toolbar .nav-title {float: left; display: inline-block; padding: 6px 12px; margin-bottom: 0; font-size: 13px; font-weight: bolder; line-height: 18px; text-align: center; white-space: nowrap; vertical-align: middle;}
#myStoryForm table tbody tr td.c-actions .dividing-line {width: 1px; height: 16px; display: inline-block; vertical-align: middle; background: #F4F5F7; margin: 0 4px 0 0;}
+1
View File
@@ -10,3 +10,4 @@
.table td.c-hours {padding-right: 12px;}
.main-table tbody > tr.table-children > td:first-child::before {width: 3px;}
@-moz-document url-prefix() {.main-table tbody > tr.table-children > td:first-child::before {width: 4px;};}
.c-actions-6 {width: 185px;}
+1
View File
@@ -36,3 +36,4 @@ html[lang="en"] .c-user-short {width: 88px;}
[lang^=fr] #taskTable .assigned-title {width: 130px !important;}
[lang^=fr] #taskTable .c-user-short {width: 75px;}
[lang^=fr] #taskTable .c-status {width: 71px;}
#myTaskForm table tbody tr td.c-actions .dividing-line {width: 1px; height: 16px; display: inline-block; vertical-align: middle; background: #F4F5F7; margin: 0 4px 0 0;}
+9 -10
View File
@@ -51,12 +51,7 @@
<tr>
<td class='c-id'><?php printf('%03d', $project->id);?></td>
<td class='c-name text-left' title='<?php echo $project->name?>'>
<?php
if($project->model === 'waterfall') echo "<span class='project-type-label label label-outline label-warning'>{$lang->project->waterfall}</span> ";
if($project->model === 'scrum') echo "<span class='project-type-label label label-outline label-info'>{$lang->project->scrum}</span> ";
if($project->model === 'kanban') echo "<span class='project-type-label label label-outline label-info'>{$lang->project->kanban}</span> ";
echo html::a($this->createLink('project', 'index', "projectID=$project->id", '', '', $project->id), $project->name, '', "data-group='project'");
?>
<?php echo html::a($this->createLink('project', 'index', "projectID=$project->id", '', '', $project->id), $project->name, '', "data-group='project' title='{$project->name} ({$this->lang->project->{$project->model}})'");?>
</td>
<?php if($status == 'openedbyme'):?>
<td class='c-status'><span class="status-project status-<?php echo $project->status?>"><?php echo zget($lang->project->statusList, $project->status, '');?></span></td>
@@ -65,9 +60,13 @@
<td class='text-left'><?php echo $project->end == LONG_TIME ? $this->lang->project->longTime : $project->end;?></td>
<?php $projectBudget = in_array($this->app->getClientLang(), array('zh-cn','zh-tw')) ? round((float)$project->budget / 10000, 2) . $this->lang->project->tenThousand : round((float)$project->budget, 2);?>
<td class='text-right c-budget'><?php echo $project->budget != 0 ? zget($lang->project->currencySymbol, $project->budgetUnit) . ' ' . $projectBudget : $lang->project->future;?></td>
<td>
<?php $userID = isset($PMList[$project->PM]) ? $PMList[$project->PM]->id : ''?>
<?php if(!empty($project->PM)) echo html::a($this->createLink('user', 'profile', "userID=$userID", '', true), zget($users, $project->PM), '', "data-toggle='modal' data-type='iframe' data-width='600'");?>
<td class='c-manager'>
<?php if(!empty($project->PM)):?>
<?php $userName = zget($users, $project->PM);?>
<?php echo html::smallAvatar(array('avatar' => $usersAvatar[$project->PM], 'account' => $project->PM, 'name' => $userName), "avatar-circle avatar-top avatar-{$project->PM}"); ?>
<?php $userID = isset($PMList[$project->PM]) ? $PMList[$project->PM]->id : '';?>
<?php echo html::a($this->createLink('user', 'profile', "userID=$userID", '', true), $userName, '', "title='{$userName}' data-toggle='modal' data-type='iframe' data-width='600'");?>
<?php endif;?>
</td>
<td class='c-actions'>
<?php if($project->status == 'wait' || $project->status == 'suspended') common::printIcon('project', 'start', "projectID=$project->id", $project, 'list', 'play', '', 'iframe', true);?>
@@ -88,7 +87,7 @@
<?php common::printIcon('project', 'group', "projectID=$project->id", $project, 'list', 'lock', '', '', false, "data-group='project'", '', $project->id);?>
<?php if(common::hasPriv('project','manageProducts') || common::hasPriv('project','whitelist') || common::hasPriv('project','delete')):?>
<div class='btn-group'>
<button type='button' class='btn dropdown-toggle' data-toggle='dropdown' title="<?php echo $this->lang->more;?>"><i class='icon-more-alt'></i></button>
<button type='button' class='btn dropdown-toggle' data-toggle='dropdown' title="<?php echo $this->lang->more;?>"><i class='icon-ellipsis-v'></i></button>
<ul class='dropdown-menu pull-right text-center' role='menu'>
<?php common::printIcon('project', 'manageProducts', "projectID=$project->id", $project, 'list', 'link', '', '', false, "data-group='project'", '', $project->id);?>
<?php common::printIcon('project', 'whitelist', "projectID=$project->id&module=project", $project, 'list', 'shield-check', '', '', false, "data-group='project'", '', $project->id);?>
+26 -2
View File
@@ -114,8 +114,21 @@
echo common::buildIconButton('story', 'review', "$vars&from=product&storyType=requirement", $story, 'list', 'search', '', 'iframe', true);
}
echo common::buildIconButton('story', 'recall', "$vars&from=list&storyType=requirement", $story, 'list', 'undo', 'hiddenwin', '', '', '', $lang->story->recall);
echo common::buildIconButton('story', 'close', "$vars&from=&storyType=requirement", $story, 'list', '', '', 'iframe', true);
echo common::buildIconButton('story', 'edit', "$vars&from=default&storyType=requirement", $story, 'list', '', '', 'iframe', true, "data-width='95%'");
$storyType = 'storyType=requirement';
$canChange = common::hasPriv('story', 'change', '', $storyType);
$canSubmitReview = (strpos('draft,changing', $story->status) !== false and common::hasPriv('story', 'submitReview', '', $storyType));
$canReview = (strpos('draft,changing', $story->status) === false and common::hasPriv('story', 'review', '', $storyType));
$canRecall = common::hasPriv('story', 'recall', '', $storyType);
$canEdit = common::hasPriv('story', 'edit', '', $storyType);
$canClose = common::hasPriv('story', 'close', '', $storyType);
if(($canChange or $canSubmitReview or $canReview or $canRecall or $canEdit) and $canClose)
{
echo "<div class='dividing-line'></div>";
}
echo common::buildIconButton('story', 'close', "$vars&from=&storyType=requirement", $story, 'list', '', '', 'iframe', true);
}
?>
</td>
@@ -163,8 +176,19 @@
}
common::printIcon('story', 'recall', "$vars&from=list&storyType=story", $child, 'list', 'undo', 'hiddenwin', '', '', '', $lang->story->recall);
common::printIcon('story', 'close', "$vars&from=&storyType=story", $child, 'list', '', '', 'iframe', true);
common::printIcon('story', 'edit', "$vars&from=default&storyType=story", $child, 'list');
$storyType = 'storyType=story';
$canChange = common::hasPriv('story', 'change', '', $storyType);
$canSubmitReview = (strpos('draft,changing', $child->status) !== false and common::hasPriv('story', 'submitReview', '', $storyType));
$canReview = (strpos('draft,draft', $child->status) === false and common::hasPriv('story', 'review', '', $storyType));
$canRecall = common::hasPriv('story', 'recall', '', $storyType);
$canEdit = common::hasPriv('story', 'edit', '', $storyType);
$canClose = common::hasPriv('story', 'close', '', $storyType);
if(($canChange or $canSubmitReview or $canReview or $canRecall or $canEdit) and $canClose)
{
echo "<div class='dividing-line'></div>";
}
common::printIcon('story', 'close', "$vars&from=&storyType=story", $child, 'list', '', '', 'iframe', true);
}
}
?>
+33 -4
View File
@@ -50,6 +50,11 @@
$canBatchReview = common::hasPriv('story', 'batchReview');
$canBatchAssignTo = common::hasPriv('story', 'batchAssignTo');
$canBatchAction = ($canBatchEdit or $canBatchClose or $canBatchReview or $canBatchAssignTo);
$canChange = common::hasPriv('story', 'change');
$canRecall = common::hasPriv('story', 'recall');
$canEdit = common::hasPriv('story', 'edit');
$canCreateCase = common::hasPriv('testcase', 'create');
$canClose = common::hasPriv('story', 'close');
?>
<thead>
<tr>
@@ -116,9 +121,21 @@
}
echo common::buildIconButton('story', 'recall', $vars, $story, 'list', 'undo', 'hiddenwin', '', '', '', $lang->story->recall);
echo common::buildIconButton('story', 'close', $vars, $story, 'list', '', '', 'iframe', true);
echo common::buildIconButton('story', 'edit', $vars, $story, 'list', '', '', 'iframe', true, "data-width='95%'");
echo common::buildIconButton('story', 'createCase', "productID=$story->product&branch=$story->branch&module=0&from=&param=0&$vars", $story, 'list', 'sitemap', '', 'iframe', true, "data-width='95%'");
$canSubmitReview = (strpos('draft,changing', $story->status) !== false and common::hasPriv('story', 'submitReview'));
$canReview = (strpos('draft,changing', $story->status) === false and common::hasPriv('story', 'review'));
if(($canChange or $canSubmitReview or $canReview or $canRecall or $canEdit) and ($canCreateCase or $canClose))
{
echo "<div class='dividing-line'></div>";
}
echo common::buildIconButton('testcase', 'create', "productID=$story->product&branch=$story->branch&module=0&from=&param=0&$vars", $story, 'list', 'sitemap', '', 'iframe', true, "data-width='95%'");
if($canCreateCase and $canClose) echo "<div class='dividing-line'></div>";
echo common::buildIconButton('story', 'close', $vars, $story, 'list', '', '', 'iframe', true);
}
?>
</td>
@@ -165,9 +182,21 @@
common::printIcon('story', 'review', $vars, $child, 'list', 'search', '', 'iframe', true);
}
common::printIcon('story', 'recall', $vars, $child, 'list', 'undo', 'hiddenwin', '', '', '', $lang->story->recall);
common::printIcon('story', 'close', $vars, $child, 'list', '', '', 'iframe', true);
common::printIcon('story', 'edit', $vars, $child, 'list', '', '', 'iframe', true, "data-width='95%'");
common::printIcon('story', 'createCase', "productID=$child->product&branch=$child->branch&module=0&from=&param=0&$vars", $child, 'list', 'sitemap', '', 'iframe', true, "data-width='95%'");
$canSubmitReview = (strpos('draft,changing', $child->status) !== false and common::hasPriv('story', 'submitReview'));
$canReview = (strpos('draft,changing', $child->status) === false and common::hasPriv('story', 'review'));
if(($canChange or $canSubmitReview or $canReview or $canRecall or $canEdit) and ($canCreateCase or $canClose))
{
echo "<div class='dividing-line'></div>";
}
common::printIcon('testcase', 'create', "productID=$child->product&branch=$child->branch&module=0&from=&param=0&$vars", $child, 'list', 'sitemap', '', 'iframe', true, "data-width='95%'");
if($canCreateCase and $canClose) echo "<div class='dividing-line'></div>";
common::printIcon('story', 'close', $vars, $child, 'list', '', '', 'iframe', true);
}
?>
</td>
+26 -5
View File
@@ -44,8 +44,15 @@
</div>
<?php else:?>
<form id='myTaskForm' class="main-table table-task skip-iframe-modal" method="post">
<?php $canBatchEdit = (common::hasPriv('task', 'batchEdit') and $type == 'assignedTo');?>
<?php $canBatchClose = (common::hasPriv('task', 'batchClose') and $type != 'closedBy');?>
<?php
$canBatchEdit = (common::hasPriv('task', 'batchEdit') and $type == 'assignedTo');
$canBatchClose = (common::hasPriv('task', 'batchClose') and $type != 'closedBy');
$canFinish = common::hasPriv('task', 'finish');
$canClose = common::hasPriv('task', 'close');
$canRecordEstimate = common::hasPriv('task', 'recordEstimate');
$canEdit = common::hasPriv('task', 'edit');
$canBatchCreate = common::hasPriv('task', 'batchCreate');
?>
<div class="table-responsive">
<table class="table has-sort-head table-fixed" id='taskTable'>
<?php $vars = "mode=$mode&type=$type&param=myQueryID&orderBy=%s&recTotal=$recTotal&recPerPage=$recPerPage&pageID=$pageID"; ?>
@@ -151,11 +158,18 @@
}
else
{
$attr = isset($kanbanList[$task->execution]) ? "disabled" : '';
$attr = isset($kanbanList[$task->execution]) ? "disabled" : '';
$canStart = ($task->status != 'pause' and common::hasPriv('task', 'start'));
$canRestart = ($task->status == 'pause' and common::hasPriv('task', 'restart'));
if($task->status != 'pause') common::printIcon('task', 'start', "taskID=$task->id", $task, 'list', '', '', 'iframe', true);
if($task->status == 'pause') common::printIcon('task', 'restart', "taskID=$task->id", $task, 'list', '', '', 'iframe', true);
common::printIcon('task', 'close', "taskID=$task->id", $task, 'list', '', '', 'iframe', true);
common::printIcon('task', 'finish', "taskID=$task->id", $task, 'list', '', '', 'iframe', true);
common::printIcon('task', 'close', "taskID=$task->id", $task, 'list', '', '', 'iframe', true);
if(($canStart or $canRestart or $canFinish or $canClose) and ($canRecordEstimate or $canEdit or $canBatchCreate))
{
echo "<div class='dividing-line'></div>";
}
common::printIcon('task', 'recordEstimate', "taskID=$task->id", $task, 'list', 'time', '', 'iframe', true);
common::printIcon('task', 'edit', "taskID=$task->id", $task, 'list', '', '', 'iframe', true, "data-width='95%'");
@@ -221,10 +235,17 @@
}
else
{
$canStart = ($child->status != 'pause' and common::hasPriv('task', 'start'));
$canRestart = ($child->status == 'pause' and common::hasPriv('task', 'restart'));
if($child->status != 'pause') common::printIcon('task', 'start', "taskID=$child->id", $child, 'list', '', '', 'iframe', true);
if($child->status == 'pause') common::printIcon('task', 'restart', "taskID=$child->id", $child, 'list', '', '', 'iframe', true);
common::printIcon('task', 'close', "taskID=$child->id", $child, 'list', '', '', 'iframe', true);
common::printIcon('task', 'finish', "taskID=$child->id", $child, 'list', '', '', 'iframe', true);
common::printIcon('task', 'close', "taskID=$child->id", $child, 'list', '', '', 'iframe', true);
if(($canStart or $canRestart or $canFinish or $canClose) and ($canRecordEstimate or $canEdit or $canBatchCreate))
{
echo "<div class='dividing-line'></div>";
}
common::printIcon('task', 'recordEstimate', "taskID=$child->id", $child, 'list', 'time', '', 'iframe', true);
common::printIcon('task', 'edit', "taskID=$child->id", $child, 'list', '', '', 'iframe', true, "data-width='95%'");
+1 -4
View File
@@ -147,10 +147,7 @@ class port extends control
{
$filter = '';
if($model == 'task') $filter = 'estimate';
if($model == 'story')
{
if($this->session->storyType) $this->loadModel('story')->replaceUserRequirementLang();
}
if($model == 'story' and $this->session->storyType) $this->loadModel('story')->replaceUserRequirementLang();
$this->loadModel($model);
$importFields = !empty($_SESSION[$model . 'TemplateFields']) ? $_SESSION[$model . 'TemplateFields'] : $this->config->$model->templateFields;
+7 -3
View File
@@ -259,6 +259,8 @@ class portModel extends model
foreach($fields as $key => $field)
{
$field = trim($field);
if($model == 'bug' and $this->session->currentProductType == 'normal' and $field == 'branch') continue;
$modelFieldList = isset($this->modelFieldList[$field]) ? $this->modelFieldList[$field] : array();
foreach($portFieldList as $portField => $value)
@@ -472,9 +474,7 @@ class portModel extends model
if(!$tmpFile)
{
$rows = $this->getRowsFromExcel();
$modelData = $this->processRows4Fields($rows, $fields);
$modelData = $this->getNatureDatas($model, $modelData, $filter, $fields);
$this->createTmpFile($modelData);
@@ -554,6 +554,10 @@ class portModel extends model
if(!empty($pairs[0])) $valuePairs[$value[$pairs[0]]] = $value[$pairs[1]];
}
$values = $valuePairs;
if(reset($values))
{
if(current($values) or (current($values) == 0)) $values[0] = '';
}
}
return $values;
@@ -624,7 +628,7 @@ class portModel extends model
}
/* if value = 0 or value = 0000:00:00 set value = ''*/
if(helper::isZeroDate($value))
if(helper::isZeroDate($rows[$id]->$field))
{
$rows[$id]->$field = '';
}
+1 -1
View File
@@ -24,7 +24,7 @@ thead > tr > th{width:150px;}
.c-id{width:50px}
.c-team {width:100px; padding:0px 0px 8px 0px !important;}
.c-estimate-1 {width:50px;padding:0px 0px 8px 8px !important;}
.load-indicator{width: 100px; height: 500px;}
#showData .load-indicator{width: 100px; height: 500px;}
</style>
<?php if(!empty($suhosinInfo)):?>
<div class='alert alert-info'><?php echo $suhosinInfo?></div>
+4
View File
@@ -1286,9 +1286,13 @@ class product extends control
$this->view->productStructure = $productStructure;
$this->view->productLines = $productLines;
$this->view->programLines = $programLines;
$this->view->users = $this->user->getPairs('noletter');
$this->view->userIdPairs = $this->user->getPairs('noletter|showid');
$this->view->usersAvatar = $this->user->getAvatarPairs('');
$this->view->orderBy = $orderBy;
$this->view->browseType = $browseType;
$this->view->pager = $pager;
$this->view->showBatchEdit = $this->cookie->showProductBatchEdit;
$this->display();
}
+6 -3
View File
@@ -38,15 +38,14 @@
#sidebar>.cell {width: 100%;}
th.c-name {width: 400px;}
th.c-requirement {width: 290px;}
th.c-PO {width: 100px;}
th.c-story {width: 290px;}
th.c-bug {width: 200px;}
th.c-bug {width: 150px;}
th.c-plan {width: 45px;}
th.c-release {width: 50px;}
th.c-actions {width: 50px;}
[lang='en'] .en-wrap-text {white-space: normal; height: 24px; line-height: 1; font-size: 12px;}
#productListForm thead>tr>th,
#productListForm tbody>tr>td {text-align: center; text-overflow: unset!important}
#productListForm thead>tr>th {padding: 0; line-height: 24px;}
@@ -86,7 +85,11 @@ th.c-actions {width: 50px;}
[lang^='zh-'] th.c-story {width: 220px;}
}
#productTableList .c-name > span.table-nest-icon {width: 0; visibility: hidden;}
#productTableList > tr.row-line.is-nest-child > td.text-left.table-nest-title > span.table-nest-icon.icon:before{content: '\e6f2'; background-color: white; display: inline;}
#productTableList > tr.row-line.no-nest > td.text-left.table-nest-title > span.table-nest-icon.icon:before{content: '\e6f2'; background-color: white; display: inline;}
.statistic {margin-left: 10px; color: #838a9d; float: left; position: relative; line-height: 28px;}
.table-footer.fixed-footer .statistic {color: #fff;}
#productTableList .c-manager {padding-left: 14px;}
#productTableList .c-manager a {top: 7px; left: 22px;}
.checkbox-primary {margin-right: 10px;}
+32 -4
View File
@@ -1,6 +1,13 @@
$("#" + browseType + "Tab").addClass('btn-active-text');
$(function()
{
$('input[name^="showEdit"]').click(function()
{
$.cookie('showProductBatchEdit', $(this).is(':checked') ? 1 : 0, {expires: config.cookieLife, path: config.webRoot});
setCheckbox();
});
setCheckbox();
/* Init table sort. */
$('#productTableList').addClass('sortable').sortable(
{
@@ -36,6 +43,23 @@ $(function()
}
});
/**
* Set batch edit checkbox.
*
* @access public
* @return void
*/
function setCheckbox()
{
$('#productListForm .c-checkbox, #productListForm .check-all').hide();
$('.c-name').css('border-left', 'none');
if($.cookie('showProductBatchEdit') == 1)
{
$('#productListForm .c-checkbox, #productListForm .check-all').show();
$('.c-name').css('border-left', '1px solid #ddd');
}
}
/* Update parent checkbox */
function updatePrarentCheckbox($parent)
{
@@ -69,17 +93,21 @@ $(function()
function addStatistic()
{
var checkedLength = $(":checkbox[name^='productIDList']:checked").length;
var summary = checkedProducts.replace('%s', checkedLength);
if(cilentLang == "en" && checkedLength < 2) summary = summary.replace('products', 'product');
var statistic = "<div id='productsSummary' class='statistic'>" + summary + "</div>";
if(checkedLength > 0)
{
var summary = checkedProducts.replace('%s', checkedLength);
if(cilentLang == "en" && checkedLength < 2) summary = summary.replace('products', 'product');
var statistic = "<div id='productsSummary' class='statistic'>" + summary + "</div>";
$('#productsCount').hide();
$('#productsSummary').remove();
$('#editBtn').after(statistic);
$('.table-actions').show();
}
else
{
$('.table-actions').hide();
$('#productsCount').show();
$('#productsSummary').addClass('hidden');
}
}
+3 -1
View File
@@ -37,6 +37,8 @@ $lang->product->addWhitelist = 'Add Whitelist';
$lang->product->unbindWhitelist = 'Remove Whitelist';
$lang->product->track = 'View Stories Matrix';
$lang->product->checkedProducts = '%s products selected';
$lang->product->pageSummary = 'Total products: %s.';
$lang->product->lineSummary = 'Total product lines: %s, Total products: %s.';
$lang->product->indexAction = "All {$lang->productCommon}";
$lang->product->closeAction = "Close {$lang->productCommon}";
@@ -186,7 +188,7 @@ $lang->product->statusList['closed'] = 'Geschlossen';
global $config;
if($config->systemMode == 'new')
{
$lang->product->aclList['private'] = "Private {$lang->productCommon} (Stakeholders and owner of the respective program, team members and stakeholders of the associated project can access)";
$lang->product->aclList['private'] = "Private {$lang->productCommon} (Manager and Stakeholders of the respective program, team members and stakeholders of the associated project can access)";
}
else
{
+3 -1
View File
@@ -37,6 +37,8 @@ $lang->product->addWhitelist = 'Add Whitelist';
$lang->product->unbindWhitelist = 'Unbind Whitelist';
$lang->product->track = 'View Stories Matrix';
$lang->product->checkedProducts = '%s products selected';
$lang->product->pageSummary = 'Total products: %s.';
$lang->product->lineSummary = 'Total product lines: %s, Total products: %s.';
$lang->product->indexAction = "All {$lang->productCommon}";
$lang->product->closeAction = "Close {$lang->productCommon}";
@@ -186,7 +188,7 @@ $lang->product->statusList['closed'] = 'Closed';
global $config;
if($config->systemMode == 'new')
{
$lang->product->aclList['private'] = "Private {$lang->productCommon} (Stakeholders and owner of the respective program, team members and stakeholders of the associated project can access)";
$lang->product->aclList['private'] = "Private {$lang->productCommon} (Manager and Stakeholders of the respective program, team members and stakeholders of the associated project can access)";
}
else
{
+3 -1
View File
@@ -37,6 +37,8 @@ $lang->product->addWhitelist = 'Add Whitelist';
$lang->product->unbindWhitelist = 'Remove Whitelist';
$lang->product->track = 'Consulter Stories Matrice';
$lang->product->checkedProducts = '%s produits s électionnés';
$lang->product->pageSummary = 'Total products: %s.';
$lang->product->lineSummary = 'Total product lines: %s, Total products: %s.';
$lang->product->indexAction = "All {$lang->productCommon}";
$lang->product->closeAction = "Fermer {$lang->productCommon}";
@@ -186,7 +188,7 @@ $lang->product->statusList['closed'] = 'Fermé';
global $config;
if($config->systemMode == 'new')
{
$lang->product->aclList['private'] = "Private {$lang->productCommon} (Stakeholders and owner of the respective program, team members and stakeholders of the associated project can access)";
$lang->product->aclList['private'] = "Private {$lang->productCommon} (Manager and Stakeholders of the respective program, team members and stakeholders of the associated project can access)";
}
else
{
+4 -2
View File
@@ -37,6 +37,8 @@ $lang->product->addWhitelist = '添加白名单';
$lang->product->unbindWhitelist = '移除白名单';
$lang->product->track = "查看需求矩阵";
$lang->product->checkedProducts = '已选择%s项产品';
$lang->product->pageSummary = '本页共%s个产品。';
$lang->product->lineSummary = '本页共%s个产品线,%s个产品。';
$lang->product->indexAction = "所有{$lang->productCommon}仪表盘";
$lang->product->closeAction = "关闭{$lang->productCommon}";
@@ -207,7 +209,7 @@ $lang->product->noModule = "<div>您现在还没有模块信息</div><div>
$lang->product->noProduct = "暂时没有{$lang->productCommon}。";
$lang->product->noMatched = '找不到包含"%s"的' . $lang->productCommon;
$lang->product->featureBar['browse']['allstory'] = $lang->product->allStory;
$lang->product->featureBar['browse']['allstory'] = '全部';
$lang->product->featureBar['browse']['unclosed'] = $lang->product->unclosed;
$lang->product->featureBar['browse']['assignedtome'] = $lang->product->assignedToMe;
$lang->product->featureBar['browse']['openedbyme'] = $lang->product->openedByMe;
@@ -216,7 +218,7 @@ $lang->product->featureBar['browse']['reviewbyme'] = $lang->product->reviewByM
$lang->product->featureBar['browse']['draftstory'] = $lang->product->draftStory;
$lang->product->featureBar['browse']['more'] = $lang->more;
$lang->product->featureBar['all']['all'] = '所有' . $lang->productCommon;
$lang->product->featureBar['all']['all'] = '全部' . $lang->productCommon;
$lang->product->featureBar['all']['noclosed'] = $lang->product->unclosed;
$lang->product->featureBar['all']['closed'] = $lang->product->statusList['closed'];
+8 -3
View File
@@ -1817,11 +1817,15 @@ class productModel extends model
{
$programKeys = array(0 => 0);
foreach($products as $product) $programKeys[] = $product->program;
$programs = $this->dao->select('id,name')->from(TABLE_PROGRAM)
$programs = $this->dao->select('id,name,PM')->from(TABLE_PROGRAM)
->where('id')->in(array_unique($programKeys))
->fetchPairs();
->fetchAll('id');
foreach($products as $product) $product->programName = isset($programs[$product->program]) ? $programs[$product->program] : '';
foreach($products as $product)
{
$product->programName = isset($programs[$product->program]) ? $programs[$product->program]->name : '';
$product->programPM = isset($programs[$product->program]) ? $programs[$product->program]->PM : '';
}
}
$stats = array();
@@ -2045,6 +2049,7 @@ class productModel extends model
/* Init vars. */
/* Program name. */
$productStructure[$product->program]['programName'] = $product->programName;
$productStructure[$product->program]['programPM'] = $product->programPM;
$productStructure[$product->program] = $this->statisticData('program', $productStructure, $product);
}
}
+41 -43
View File
@@ -11,13 +11,16 @@
?>
<?php include '../../common/view/header.html.php';?>
<?php include '../../common/view/sortable.html.php';?>
<?php js::set('productLines', $productLines); ?>
<?php $canBatchEdit = common::hasPriv('product', 'batchEdit'); ?>
<div id="mainMenu" class="clearfix">
<div class="btn-toolbar pull-left">
<div class="btn-toolBar pull-left">
<?php common::sortFeatureMenu();?>
<?php foreach($lang->product->featureBar['all'] as $key => $label):?>
<?php $recTotalLabel = $browseType == $key ? " <span class='label label-light label-badge'>{$recTotal}</span>" : '';?>
<?php echo html::a(inlink("all", "browseType=$key&orderBy=$orderBy"), "<span class='text'>{$label}</span>" . $recTotalLabel, '', "class='btn btn-link' id='{$key}Tab'");?>
<?php endforeach;?>
<?php if($canBatchEdit) echo html::checkbox('showEdit', array('1' => $lang->product->edit), $showBatchEdit);?>
<a class="btn btn-link querybox-toggle" id='bysearchTab'><i class="icon icon-search muted"></i> <?php echo $lang->product->searchStory;?></a>
</div>
<div class="btn-toolbar pull-right">
@@ -36,7 +39,6 @@
<div class="main-col">
<div class="cell<?php if($browseType == 'bySearch') echo ' show';?>" id="queryBox" data-module='product'></div>
<form class="main-table table-product" data-ride="table" data-nested='true' id="productListForm" method="post" action='<?php echo inLink('batchEdit', '');?>' data-preserve-nested='true' data-expand-nest-child='true'>
<?php $canBatchEdit = common::hasPriv('product', 'batchEdit'); ?>
<table id="productList" class="table has-sort-head table-nested table-fixed">
<?php $vars = "browseType=$browseType&orderBy=%s";?>
<thead>
@@ -50,11 +52,11 @@
<a class='table-nest-toggle table-nest-toggle-global' data-expand-text='<?php echo $lang->expand; ?>' data-collapse-text='<?php echo $lang->collapse; ?>'></a>
<?php common::printOrderLink('name', $orderBy, $vars, $lang->product->name);?>
</th>
<?php if($this->config->URAndSR):?>
<th class='c-requirement' colspan="5"><?php echo $lang->story->requirement;?></th>
<?php endif;?>
<th class='c-PO' rowspan="2">
<?php common::printOrderLink('PO', $orderBy, $vars, $lang->product->manager);?>
</th>
<th class="c-story" colspan="5"><?php echo $lang->story->story;?></th>
<th class="c-bug" colspan="3"><?php echo $lang->bug->common;?></th>
<th class="c-bug" colspan="2"><?php echo $lang->bug->common;?></th>
<th class="c-plan" rowspan="2"><?php echo $lang->product->plan;?></th>
<th class="c-release" rowspan="2"><?php echo $lang->product->release;?></th>
<?php
@@ -64,20 +66,12 @@
<th class='c-actions' rowspan="2"><?php echo $lang->actions;?></th>
</tr>
<tr class="text-center">
<?php if($this->config->URAndSR):?>
<th style="border-left: 1px solid #ddd;"><?php echo $lang->story->draft;?></th>
<th><?php echo $lang->story->activate;?></th>
<th><?php echo $lang->story->change;?></th>
<th><?php echo $lang->story->statusList['reviewing'];?></th>
<th><div class='en-wrap-text'><?php echo $lang->story->completeRate;?></div></th>
<?php endif;?>
<th style="border-left: 1px solid #ddd;"><?php echo $lang->story->draft;?></th>
<th><?php echo $lang->story->activate;?></th>
<th><?php echo $lang->story->change;?></th>
<th><?php echo $lang->story->statusList['reviewing'];?></th>
<th><div class='en-wrap-text'><?php echo $lang->story->completeRate;?></div></th>
<th style="border-left: 1px solid #ddd;"><?php echo $lang->bug->activate;?></th>
<th><?php echo $lang->close;?></th>
<th><?php echo $lang->bug->fixedRate;?></th>
</tr>
</thead>
@@ -112,20 +106,25 @@
<span class="table-nest-icon icon table-nest-toggle"></span>
<?php echo $program['programName']?>
</td>
<?php if($this->config->URAndSR):?>
<td><?php echo $program['draftRequirements'];?></td>
<td><?php echo $program['activeRequirements'];?></td>
<td><?php echo $program['changingRequirements'];?></td>
<td><?php echo $program['reviewingRequirements'];?></td>
<td><?php echo $program['totalRequirements'] == 0 ? 0 : round($program['closedRequirements'] / $program['totalRequirements'], 3) * 100;?>%</td>
<?php endif;?>
<td class='c-manager'>
<?php
if(!empty($program['programPM']))
{
$programPM = $program['programPM'];
$userName = zget($users, $programPM);
echo html::smallAvatar(array('avatar' => $usersAvatar[$programPM], 'account' => $programPM, 'name' => $userName), 'avatar-circle avatar-top avatar-' . zget($userIdPairs, $programPM));
$userID = isset($userIdPairs[$programPM]) ? $userIdPairs[$programPM] : '';
echo html::a($this->createLink('user', 'profile', "userID=$userID", '', true), $userName, '', "title='{$userName}' data-toggle='modal' data-type='iframe' data-width='600'");
}
?>
</td>
<td><?php echo $program['draftStories'];?></td>
<td><?php echo $program['activeStories'];?></td>
<td><?php echo $program['changingStories'];?></td>
<td><?php echo $program['reviewingStories'];?></td>
<td><?php echo $program['totalStories'] == 0 ? 0 : round($program['closedStories'] / $program['totalStories'], 3) * 100;?>%</td>
<td><?php echo $program['unResolvedBugs'];?></td>
<td><?php echo $program['closedBugs'];?></td>
<td><?php echo ($program['unResolvedBugs'] + $program['fixedBugs']) == 0 ? 0 : round($program['fixedBugs'] / ($program['unResolvedBugs'] + $program['fixedBugs']), 3) * 100;?>%</td>
<td><?php echo $program['plans'];?></td>
<td><?php echo $program['releases'];?></td>
@@ -159,20 +158,13 @@
<span class="table-nest-icon icon table-nest-toggle"></span>
<?php echo $line['lineName']?>
</td>
<?php if($this->config->URAndSR):?>
<td><?php echo isset($line['draftRequirements']) ? $line['draftRequirements'] : 0;?></td>
<td><?php echo isset($line['activeRequirements']) ? $line['activeRequirements'] : 0;?></td>
<td><?php echo isset($line['changingRequirements']) ? $line['changingRequirements'] : 0;?></td>
<td><?php echo isset($line['reviewingRequirements']) ? $line['reviewingRequirements'] : 0;?></td>
<td><?php echo (isset($line['totalRequirements']) and $line['totalRequirements'] != 0) ? round($line['closedRequirements'] / $line['totalRequirements'], 3) * 100 : 0;?>%</td>
<?php endif;?>
<td></td>
<td><?php echo isset($line['draftStories']) ? $line['draftStories'] : 0;?></td>
<td><?php echo isset($line['activeStories']) ? $line['activeStories'] : 0;?></td>
<td><?php echo isset($line['changingStories']) ? $line['changingStories'] : 0;?></td>
<td><?php echo isset($line['reviewingStories']) ? $line['reviewingStories'] : 0;?></td>
<td><?php echo (isset($line['totalStories']) and $line['totalStories'] != 0) ? round($line['closedStories'] / $line['totalStories'], 3) * 100 : 0;?>%</td>
<td><?php echo isset($line['unResolvedBugs']) ? $line['unResolvedBugs'] : 0;?></td>
<td><?php echo isset($line['closedBugs']) ? $line['closedBugs'] : 0;?></td>
<td><?php echo (isset($line['fixedBugs']) and ($line['unResolvedBugs'] + $line['fixedBugs'] != 0)) ? round($line['fixedBugs'] / ($line['unResolvedBugs'] + $line['fixedBugs']), 3) * 100 : 0;?>%</td>
<td><?php echo isset($line['plans']) ? $line['plans'] : 0;?></td>
<td><?php echo isset($line['releases']) ? $line['releases'] : 0;?></td>
@@ -185,8 +177,7 @@
<?php if(isset($line['products']) and is_array($line['products'])):?>
<?php foreach($line['products'] as $productID => $product):?>
<?php
$totalStories = $product->stories['active'] + $product->stories['closed'] + $product->stories['draft'] + $product->stories['changing'] + $product->stories['reviewing'];
$totalRequirements = $product->requirements['active'] + $product->requirements['closed'] + $product->requirements['draft'] + $product->requirements['changing'] + $product->requirements['reviewing'];
$totalStories = $product->stories['active'] + $product->stories['closed'] + $product->stories['draft'] + $product->stories['changing'] + $product->stories['reviewing'];
$trClass = '';
if($product->line)
@@ -216,24 +207,27 @@
<?php endif;?>
<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;
echo html::a($this->createLink('product', 'browse', 'productID=' . $product->id), $product->name);
?>
</td>
<td class='c-manager'>
<?php
if(!empty($product->PO))
{
$userName = zget($users, $product->PO);
echo html::smallAvatar(array('avatar' => $usersAvatar[$product->PO], 'account' => $product->PO, 'name' => $userName), 'avatar-circle avatar-' . zget($userIdPairs, $product->PO));
$userID = isset($userIdPairs[$product->PO]) ? $userIdPairs[$product->PO] : '';
echo html::a($this->createLink('user', 'profile', "userID=$userID", '', true), $userName, '', "title='{$userName}' data-toggle='modal' data-type='iframe' data-width='600'");
}
?>
</td>
<?php if($this->config->URAndSR):?>
<td><?php echo $product->requirements['draft'];?></td>
<td><?php echo $product->requirements['active'];?></td>
<td><?php echo $product->requirements['changing'];?></td>
<td><?php echo $product->requirements['reviewing'];?></td>
<td><?php echo $totalRequirements == 0 ? 0 : round($product->requirements['closed'] / $totalRequirements, 3) * 100;?>%</td>
<?php endif;?>
<td><?php echo $product->stories['draft'];?></td>
<td><?php echo $product->stories['active'];?></td>
<td><?php echo $product->stories['changing'];?></td>
<td><?php echo $product->stories['reviewing'];?></td>
<td><?php echo $totalStories == 0 ? 0 : round($product->stories['closed'] / $totalStories, 3) * 100;?>%</td>
<td><?php echo $product->unResolved;?></td>
<td><?php echo $product->closedBugs;?></td>
<td><?php echo ($product->unResolved + $product->fixedBugs) == 0 ? 0 : round($product->fixedBugs / ($product->unResolved + $product->fixedBugs), 3) * 100;?>%</td>
<td><?php echo $product->plans;?></td>
<td><?php echo $product->releases;?></td>
@@ -250,13 +244,17 @@
<?php echo $pager->show('left', 'pagerjs');?>
<?php if(!empty($product) and $canBatchEdit):?>
<div class="checkbox-primary check-all"><label><?php echo $lang->selectAll?></label></div>
<?php
$summary = empty($productLines) ? sprintf($lang->product->pageSummary, count($productStats)) : sprintf($lang->product->lineSummary, count($lineNames), count($productStats));
echo "<div id='productsCount' class='statistic'>$summary</div>";
?>
<div class="table-actions btn-toolbar">
<?php
$actionLink = $this->createLink('product', 'batchEdit');
echo html::commonButton($lang->edit, "id='editBtn' data-form-action='$actionLink'");
?>
<?php endif;?>
</div>
<?php endif;?>
</div>
</form>
</div>
+8 -5
View File
@@ -41,8 +41,9 @@ $projectIDParam = $isProjectStory ? "projectID=$projectID&" : '';
.btn-group a i.icon-plus, .btn-group a i.icon-link {font-size: 16px;}
.btn-group a.btn-secondary, .btn-group a.btn-primary {border-right: 1px solid rgba(255,255,255,0.2);}
.btn-group button.dropdown-toggle.btn-secondary, .btn-group button.dropdown-toggle.btn-primary {padding:6px;}
#productStoryForm table tbody tr td.c-actions {overflow: visible;}
#productStoryForm table tbody tr td.c-actions .dividing-line {width: 1px; height: 16px; display: inline-block; vertical-align: middle; background: #E4E4E4; margin: 0 4px 0 0;}
#productStoryForm table tbody tr td.c-actions .dividing-line {width: 1px; height: 16px; display: inline-block; vertical-align: middle; background: #F4F5F7; margin: 0 4px 0 0;}
</style>
<div id="mainMenu" class="clearfix">
<?php if(!$isProjectStory):?>
@@ -346,11 +347,11 @@ $projectIDParam = $isProjectStory ? "projectID=$projectID&" : '';
{
if($value->id == 'title' || $value->id == 'id' || $value->id == 'pri' || $value->id == 'status')
{
$this->story->printCell($value, $story, $users, $branchOption, $storyStages, $modulePairs, $storyTasks, $storyBugs, $storyCases, $useDatatable ? 'datatable' : 'table');
$this->story->printCell($value, $story, $users, $branchOption, $storyStages, $modulePairs, $storyTasks, $storyBugs, $storyCases, $useDatatable ? 'datatable' : 'table', $storyType);
}
}?>
<?php else:?>
<?php foreach($setting as $key => $value) $this->story->printCell($value, $story, $users, $branchOption, $storyStages, $modulePairs, $storyTasks, $storyBugs, $storyCases, $useDatatable ? 'datatable' : 'table');?>
<?php foreach($setting as $key => $value) $this->story->printCell($value, $story, $users, $branchOption, $storyStages, $modulePairs, $storyTasks, $storyBugs, $storyCases, $useDatatable ? 'datatable' : 'table', $storyType);?>
<?php endif;?>
</tr>
<?php if(!empty($story->children)):?>
@@ -387,8 +388,10 @@ $projectIDParam = $isProjectStory ? "projectID=$projectID&" : '';
<div class="table-actions btn-toolbar">
<div class='btn-group dropup'>
<?php
$disabled = $canBatchEdit ? '' : "disabled='disabled'";
$actionLink = $this->createLink('story', 'batchEdit', "productID=$productID&projectID=$projectID&branch=$branch&storyType=$storyType");
foreach($stories as $story) $storyProductIds[$story->product] = $story->product;
$storyProductID = count($storyProductIds) > 1 ? 0 : $productID;
$disabled = $canBatchEdit ? '' : "disabled='disabled'";
$actionLink = $this->createLink('story', 'batchEdit', "productID=$storyProductID&projectID=$projectID&branch=$branch&storyType=$storyType");
?>
<?php if($canBatchEdit or $canBatchClose or $canBatchUnlink or $canBatchReview or $canBatchChangeStage or $canBatchChangeBranch) echo html::commonButton($lang->edit, "data-form-action='$actionLink' $disabled");?>
<?php if($canBatchEdit or $canBatchClose or $canBatchUnlink or $canBatchReview or $canBatchChangeStage or $canBatchChangeBranch):?>
+12 -8
View File
@@ -49,11 +49,13 @@
<?php else:?>
<th><?php echo $lang->execution->name;?></th>
<?php endif;?>
<?php if(strpos('all,undone', $status) !== false):?>
<th class='c-status'><?php echo $lang->project->status;?></th>
<?php endif;?>
<th class='c-user text-left'><?php echo $lang->project->PM;?></th>
<th class="c-budget text-center"><?php echo $lang->project->budget;?></th>
<th class='c-date'><?php echo $lang->project->begin;?></th>
<th class='c-date'><?php echo $lang->project->end;?></th>
<th class='c-status'><?php echo $lang->project->status;?></th>
<th class="c-budget text-center"><?php echo $lang->project->budget;?></th>
<th class="c-number text-right"><?php echo $lang->project->estimate;?></th>
<th class="c-number text-right"><?php echo $lang->project->consume;?></th>
<th class="c-progress"><?php echo $lang->project->progress;?></th>
@@ -79,20 +81,22 @@
}
?>
</td>
<?php if(strpos('all,undone', $status) !== false):?>
<?php $statusTitle = $this->processStatus('project', $project);?>
<td class='c-status' title='<?php echo $statusTitle;?>'>
<span class="status-project status-<?php echo $project->status?>"><?php echo $statusTitle;?></span>
</td>
<?php endif;?>
<td class='padding-right'>
<?php $userID = isset($PMList[$project->PM]) ? $PMList[$project->PM]->id : ''?>
<?php if(!empty($project->PM)) echo html::a($this->createLink('user', 'profile', "userID=$userID", '', true), zget($users, $project->PM), '', "data-toggle='modal' data-type='iframe' data-width='800'");?>
</td>
<td class='padding-right text-left'><?php echo $project->begin;?></td>
<td class='padding-right text-left'><?php echo $project->end;?></td>
<?php $status = $this->processStatus('project', $project);?>
<td class='c-status' title='<?php echo $status;?>'>
<span class="status-project status-<?php echo $project->status?>"><?php echo $status;?></span>
</td>
<?php $projectBudget = in_array($this->app->getClientLang(), array('zh-cn','zh-tw')) ? round((float)$project->budget / 10000, 2) . $this->lang->project->tenThousand : round((float)$project->budget, 2);?>
<?php $budgetTitle = $project->budget != 0 ? zget($this->lang->project->currencySymbol, $project->budgetUnit) . ' ' . $projectBudget : $this->lang->project->future;?>
<?php $textStyle = $project->budget != 0 ? 'text-right' : 'text-center';?>
<td title='<?php echo $budgetTitle;?>' class="text-ellipsis <?php echo $textStyle;?>"><?php echo $budgetTitle;?></td>
<td class='padding-right text-left'><?php echo $project->begin;?></td>
<td class='padding-right text-left'><?php echo $project->end;?></td>
<td class="text-right" title="<?php echo $project->hours->totalEstimate . ' ' . $lang->execution->workHour;?>"><?php echo $project->hours->totalEstimate . $lang->execution->workHourUnit;?></td>
<td class="text-right" title="<?php echo $project->hours->totalConsumed . ' ' . $lang->execution->workHour;?>"><?php echo $project->hours->totalConsumed . $lang->execution->workHourUnit;?></td>
<td>
+4
View File
@@ -35,3 +35,7 @@ td.c-branch {overflow: hidden; text-align: left !important; text-overflow: ellip
.panel-actions {position: relative; padding: 0 0; padding-top: 1px;}
.icon-list {padding-left: 7px;}
.icon-kanban {padding-left: 7px; font-size: 16px;}
#productplanList .c-actions {width: 265px;}
#productplanList .c-actions .btn+.btn {margin-left: -1px;}
#productplanList .c-actions .btn {display: block; float: left;}
#productplanList td.c-actions .dividing-line {width: 1px; height: 16px; display: inline-block; vertical-align: middle; background: #F4F5F7; margin: 6px 4px 0 0; float: left;}
+1 -1
View File
@@ -135,7 +135,7 @@ $lang->productplan->endLetterChildTip = "父计划[%s]的完成日期:%s,
$lang->productplan->beginLetterParentTip = "子计划[%s]的开始日期:%s,不能小于父计划的开始日期: %s";
$lang->productplan->endGreaterParentTip = "子计划[%s]的完成日期:%s,不能大于父计划的完成日期: %s";
$lang->productplan->featureBar['browse']['all'] = '所有';
$lang->productplan->featureBar['browse']['all'] = '全部';
$lang->productplan->featureBar['browse']['undone'] = '未完成';
$lang->productplan->featureBar['browse']['wait'] = '未开始';
$lang->productplan->featureBar['browse']['doing'] = '进行中';
+20
View File
@@ -1130,6 +1130,16 @@ class productplanModel extends model
{
$params = "planID=$plan->id";
$canStart = common::hasPriv('productplan', 'start');
$canFinish = common::hasPriv('productplan', 'finish');
$canClose = common::hasPriv('productplan', 'close');
$canCreateExec = common::hasPriv('execution', 'create');
$canLinkStory = common::hasPriv('productplan', 'linkStory');
$canLinkBug = common::hasPriv('productplan', 'linkBug');
$canEdit = common::hasPriv('productplan', 'edit');
$canCreateChild = common::hasPriv('productplan', 'create');
$canDelete = common::hasPriv('productplan', 'delete');
$menu = '';
$menu .= $this->buildMenu('productplan', 'start', $params, $plan, $type, 'play', 'hiddenwin', '', false, '', $this->lang->productplan->startAB);
$menu .= $this->buildMenu('productplan', 'finish', $params, $plan, $type, 'checked', 'hiddenwin', '', false, '', $this->lang->productplan->finishAB);
@@ -1174,6 +1184,11 @@ class productplanModel extends model
$menu .= "<button type='button' class='btn disabled'><i class='icon-plus' title='{$this->lang->productplan->createExecution}'></i></button>";
}
if(($canStart or $canFinsh or $canClose or $canCreateExec) and ($canLinkStory or $canLinkBug or $canEdit or $canCreateChild or $canDelete))
{
$menu .= "<div class='dividing-line'></div>";
}
if(common::hasPriv('productplan', 'linkStory', $plan) and $plan->parent >= 0)
{
$menu .= $this->buildMenu('productplan', 'view', "{$params}&type=story&orderBy=id_desc&link=true", $plan, $type, 'link', '', '', '', '', $this->lang->productplan->linkStory);
@@ -1197,6 +1212,11 @@ class productplanModel extends model
$menu .= $this->buildMenu('productplan', 'create', "product={$plan->product}&branch={$plan->branch}&parent={$plan->id}", $plan, $type, 'split', '', '', '', '', $this->lang->productplan->children);
if(($canLinkStory or $canLinkBug or $canEdit or $canCreateChild) and $canDelete)
{
$menu .= "<div class='dividing-line'></div>";
}
if($type == 'browse') $menu .= $this->buildMenu('productplan', 'delete', "{$params}&confirm=no", $plan, $type, 'trash', 'hiddenwin', '', '', $this->lang->productplan->delete);
if($type == 'view')
@@ -52,7 +52,7 @@
<ul class='dropdown-menu' style='max-height:240px; max-width: 300px; overflow-y:auto'>
<?php foreach($lang->productplan->orderList as $order => $label):?>
<?php $active = $orderBy == $order ? 'active' : '';?>
<li class='<?php echo $active;?>'><?php echo html::a(inlink('browse', "productID=$productID&branch=$branchID&browseType=$browseType&orderBy=$order"), $label);?></li>
<li class='<?php echo $active;?>'><?php echo html::a(inlink('browse', "productID=$productID&branch=$branchID&browseType=$browseType&queryID=$queryID&orderBy=$order"), $label);?></li>
<?php endforeach;?>
</ul>
</div>

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