Merge branch 'master' into zenops_38

This commit is contained in:
caoyanyi
2022-07-14 08:37:24 +08:00
87 changed files with 5331 additions and 515 deletions
+1 -1
View File
@@ -1 +1 @@
17.2
17.3
+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.2'; // ZenTaoPHP的版本。 The version of ZenTaoPHP. Don't change it.
$config->version = '17.3'; // 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.
+1
View File
@@ -271,6 +271,7 @@ $filter->project->task->cookie['projectTaskOrder'] = 'reg::orderBy';
$filter->project->task->cookie['windowWidth'] = 'int';
$filter->project->export->cookie['checkedItem'] = 'reg::checked';
$filter->project->execution->cookie['pagerExecutionAll'] = 'int';
$filter->project->execution->cookie['showTask'] = 'code';
$filter->projectstory->story->cookie['storyModuleParam'] = 'int';
$filter->projectstory->story->cookie['pagerProductBrowse'] = 'int';
File diff suppressed because it is too large Load Diff
+2
View File
@@ -14,3 +14,5 @@ ALTER TABLE `zt_doc` CHANGE `assignedDate` `assignedDate` datetime NOT NULL AFTE
UPDATE `zt_approval` SET `createdDate` = '';
ALTER TABLE `zt_approval` CHANGE `createdDate` `createdDate` datetime NOT NULL AFTER `createdBy`;
ALTER TABLE `zt_reviewissue` ADD `approval` MEDIUMINT NOT NULL AFTER `review`;
+1
View File
@@ -9526,6 +9526,7 @@ CREATE TABLE IF NOT EXISTS `zt_reviewissue` (
`id` mediumint(8) NOT NULL AUTO_INCREMENT,
`project` mediumint(8) unsigned NOT NULL,
`review` mediumint(8) NOT NULL,
`approval` mediumint(8) NOT NULL,
`injection` mediumint(8) NOT NULL,
`identify` mediumint(8) NOT NULL,
`type` char(30) NOT NULL DEFAULT 'review',
+93
View File
@@ -1,3 +1,96 @@
2022-07-13 17.3
完成的需求
14130 点击按钮执行升级后禁用升级按钮
14578 总计消耗不为0时再次点击完成任务后消耗工时可以填写为0
15349 产品模块的维护增加历史记录
26444 重新激活父任务时需要同步更新子任务的历史记录
27723 年度总结按部门查看增加权限控制
30114 实现禅道中累积流图的帮助功能
30121 实现禅道执行视图下的需求累积流图
30128 实现禅道执行视图下的任务累积流图
30190 创建看板时增加复制看板功能
31342 批量创建任务表单的右侧增加添加和删除行的操作
31746 Scrum看板中任务看板按需求分组时需求以卡片方式展示
31848 删除测试测试单列表中操作按钮中间的小竖线
32329 跨应用跳转页面时直接展示跳转后的页面
32584 瀑布项目阶段列表中阶段名称前增加展开、收起按钮
32834 任务创建页面修改自定义表单后不影响已录入内容
32994 时间设置错误提示删除日历自动展开效果
33003 非所有标签的列表内容为空时,删除新建操作
33085 需求提交页面修改自定义表单后不影响已录入内容
33132 修改干系人新增页面中用户字段未定义提示
33168 复制执行页面增加项目的选择菜单
33170 BUG提交页面修改自定义表单后不影响已录入内容
33171 用例提交页面修改自定义表单后不影响已录入内容
33180 批量提需求表单的右侧增加添加和删除行的操作
33181 批量提Bug表单的右侧增加添加和删除行的操作
33182 批量建用例表单的右侧增加添加和删除行的操作
33307 加大bug提交页面中操作系统输入框的宽度
33308 加大bug提交页面中“关键词“字段标题框宽度
33415 用例库中的用例可以多次导入到同一个产品的不同模块
33418 瀑布项目阶段设置页面里程碑字段居中显示
33419 瀑布项目阶段设置页面中操作字段居中显示
33438 缩短组织下团队列表页面姓名跟用户名字段的间距
33445 bug提交页面中刷新按钮改为图标显示
33446 列表中日期没有定义时展示为空
33448 缩小bug编辑页面中标题输入框宽度
33516 后台全局设置中文档模板列表的的删除按钮改为垃圾桶样式
33519 后台自定义页面修改提示语样式
33540 优化搜索条件保存按钮样式
33542 用例列表页面的执行时间格式调整
33547 项目测试单列表的报告列表按钮修改
33607 项目集列表中对展开和收起的状态做记录
33617 瀑布项目阶段列表增加显示任务设置
33673 我参与标签中能显示我负责和我在团队中的空间和看板
33705 项目中测试的Bug列表增加产品模块功能
33706 执行中测试的Bug列表增加产品模块功能
33707 执行中测试的用例列表增加产品模块功能
33775 详情页面中附件增加预览和下载按钮
33777 研发需求变更页面增加附件编辑操作
33782 地盘仪表盘待处理区块对齐调整
33807 产品矩阵列表居左显示
33879 阶段列表中展示任务列表
33896 实现禅道执行视图下的Bug累积流图
33939 后台通知设置页面中“评论”字段修改为“备注”
33953 项目创建页面中,关联产品下拉框增加不可点击状态
33970 测试仪表盘测试统计区块中统计字体颜色调整
33972 增加国际版地盘任务列表页面截止日期字段的宽度
33973 计划详情列表中返回路径优化
33983 我的地盘日程中右侧任务和软需切换样式调整
33986 产品发布创建页面里程碑选中状态修改
33987 执行任务列表预计、消耗、剩余、进度字段居右显示
33988 执行任务列表"截止"字段居左显示
33999 统计产品页面删除“筛选条件"字段
34028 后台二次开发API列表页面表头字段加粗
34029 执行任务列表页面“完成者”字段内容过多时省略显示
34036 专业研发看板项目的执行模块添加累积流图入口
34038 累积流图中增加更新按钮
34048 累积流图页增加下拉框支持切换类型
34049 累积流图展示平均周期时间和吞吐率
34050 累积流图中增加悬浮样式
34138 scrum看板页面卡片局部刷新
34139 通用看板页面卡片局部刷新
34140 看板项目专业研发看板编辑区域后自动刷新
34142 专业研发看板页面卡片局部刷新
34266 修改产品计划详情页面提研发需求按钮的下拉菜单为右对齐
34349 国际版地盘仪表盘添加区块弹窗中待办和待处理的英文修改
34350 国际版中编辑和详情页面附件重命名的英文修改为Rename
34354 修改产品研发需求提交页面中附件操作按钮颜色
34367 累积流图增加隐藏周末按钮
34387 需求提交页面产品分支输入框显示完整
34497 邮箱修改密码优化格式校验提示语
34580 任务详情编辑页面中,团队设置弹窗增加关闭按钮
34609 修改产品分支合并的提示样式
34610 当所有标签的列表内容均为空时,增加新建按钮
34611 修改后台系统安全设置页面的提示语样式
修复的Bug
23123 项目/执行的Bug页左上角下拉组件未显示多分支产品的分支下拉
23827 批量编辑项目时,提示文案不清晰
24923 英文下项目集下新增干系人页面字段名称换行
24976 内禅3.3版本需求列表需求名称显示3个点
24981 隐藏来源没有同步隐藏其关联的文本框
25070 后台-自定义-必填项-任务-建任务页面设置最初预计为必填项,创建多人任务团队成员预计工时为空也可以保存
2022-06-29 17.2
完成的需求
12709 创建某一类型的待办时,若无指派给我的内容列表提示用户
+31 -2
View File
@@ -12,10 +12,11 @@ public function __construct($appName = '')
* @param int $browseType
* @param int $groupBy
* @param string $searchValue
* @param string $orderBy
* @access public
* @return array
*/
public function getKanban4Group($executionID, $browseType, $groupBy, $searchValue = '')
public function getKanban4Group($executionID, $browseType, $groupBy, $searchValue = '', $orderBy = 'pri_asc')
{
/* Get card data. */
$cardList = array();
@@ -23,7 +24,8 @@ public function getKanban4Group($executionID, $browseType, $groupBy, $searchValu
if($browseType == 'bug') $cardList = $this->loadModel('bug')->getExecutionBugs($executionID);
if($browseType == 'task') $cardList = $this->loadModel('execution')->getKanbanTasks($executionID, "id");
$lanes = $this->getLanes4Group($executionID, $browseType, $groupBy, $cardList);
if($groupBy == 'story' and $browseType == 'task' and !isset($this->lang->kanban->orderList[$orderBy])) $orderBy = 'pri_asc';
$lanes = $this->getLanes4Group($executionID, $browseType, $groupBy, $cardList, $orderBy);
if(empty($lanes)) return array();
$execution = $this->loadModel('execution')->getByID($executionID);
@@ -70,6 +72,33 @@ public function getKanban4Group($executionID, $browseType, $groupBy, $searchValu
$laneData['type'] = $browseType;
$laneData['defaultCardType'] = $browseType;
if($browseType == 'task' and $groupBy == 'story')
{
$columnData[0]['id'] = 0;
$columnData[0]['type'] = 'story';
$columnData[0]['name'] = zget($this->lang->kanban->orderList, $orderBy, '');
$columnData[0]['color'] = '#333';
$columnData[0]['limit'] = '-1';
$columnData[0]['laneType'] = $browseType;
$columnData[0]['asParent'] = false;
$columnData[0]['parentType'] = '';
$columnData[0]['actions'] = array();
if(empty($searchValue) or strpos($lane->name, $searchValue) !== false)
{
$cardData = array();
$cardData['id'] = $laneID;
$cardData['title'] = $lane->name;
$cardData['order'] = 1;
$cardData['pri'] = $lane->pri;
$cardData['estimate'] = '';
$cardData['assignedTo'] = $lane->assignedTo;
$cardData['deadline'] = '';
$cardData['severity'] = '';
$laneData['cards']['story'][] = $cardData;
}
}
/* Construct kanban column data. */
foreach($columns as $column)
{
@@ -21,6 +21,9 @@ class project extends control
if($this->execution->isClickable($kanban, 'delete')) $executionActions[$kanbanID][] = 'delete';
}
$allExecution = $this->execution->getList($projectID, 'all', 'all');
$this->view->allExecutionsNum = count($allExecution);
$this->view->title = $this->lang->project->kanban;
$this->view->kanbanList = array_values($kanbanList);
@@ -30,7 +30,7 @@
<div class="table-empty-tip">
<p>
<span class="text-muted"><?php echo $lang->execution->noExecution;?></span>
<?php if(common::hasPriv('execution', 'create') and $status == "all"):?>
<?php if(common::hasPriv('execution', 'create') and empty($allExecutionsNum)):?>
<?php echo html::a($this->createLink('execution', 'create', "projectID=$projectID"), "<i class='icon icon-plus'></i> " . $lang->project->createKanban, '', "class='btn btn-info' data-app='project'");?>
<?php endif;?>
</p>
+9 -2
View File
@@ -966,8 +966,9 @@ class baseJS
{
$cancleAction = "$cancleTarget.location = '$cancleURL';";
}
$js .= <<<EOT
if(strpos($_SERVER['HTTP_USER_AGENT'], 'xuanxuan') === false)
{
$js .= <<<EOT
if(confirm("$message"))
{
$confirmAction
@@ -977,6 +978,12 @@ else
$cancleAction
}
EOT;
}
else
{
$js .= $confirmAction;
}
$js .= self::end();
return $js;
}
+2 -1
View File
@@ -210,6 +210,7 @@ $lang->action->desc->importedbuild = '$date, imported to <strong>$extra</
$lang->action->desc->fromsonarqube = '$date, created by <strong>$actor</strong> from <strong>SonarQube Issue</strong>.' . "\n";
$lang->action->desc->tolib = '$date, imported by <strong>$actor</strong> .' . "\n";
$lang->action->desc->updatetolib = '$date, updated to ' . $lang->testcase->common . ' by <strong>$actor</strong>.' . "\n";
$lang->action->desc->adjusttasktowait = '$date, System Reminder: The task status will be set to Not Started as the consumed work hour is adjusted to 0. ' . "\n";
/* Used to describe the history of operations related to parent-child tasks. */
$lang->action->desc->createchildren = '$date, <strong>$actor</strong> created a child task <strong>$extra</strong>。' . "\n";
@@ -306,7 +307,7 @@ $lang->action->label->suspended = 'suspended ';
$lang->action->label->login = 'Login';
$lang->action->label->logout = "Logout";
$lang->action->label->notified = "Notified";
$lang->action->label->deleteestimate = "deleted ";
$lang->action->label->deleteestimate = "deleted hours";
$lang->action->label->linked2build = "linked ";
$lang->action->label->linked2bug = "linked ";
$lang->action->label->linked2testtask = "linked";
+2 -1
View File
@@ -210,6 +210,7 @@ $lang->action->desc->importedbuild = '$date, imported to <strong>$extra</
$lang->action->desc->fromsonarqube = '$date, created by <strong>$actor</strong> from <strong>SonarQube Issue</strong>.' . "\n";
$lang->action->desc->tolib = '$date, imported by <strong>$actor</strong> .' . "\n";
$lang->action->desc->updatetolib = '$date, updated to ' . $lang->testcase->common . ' by <strong>$actor</strong>.' . "\n";
$lang->action->desc->adjusttasktowait = '$date, System Reminder: The task status will be set to Not Started as the consumed work hour is adjusted to 0. ' . "\n";
/* Used to describe the history of operations related to parent-child tasks. */
$lang->action->desc->createchildren = '$date, <strong>$actor</strong> created a child task <strong>$extra</strong>。' . "\n";
@@ -306,7 +307,7 @@ $lang->action->label->suspended = 'suspended ';
$lang->action->label->login = 'login';
$lang->action->label->logout = "logout";
$lang->action->label->notified = "Notified";
$lang->action->label->deleteestimate = "deleted ";
$lang->action->label->deleteestimate = "deleted hours";
$lang->action->label->linked2build = "linked ";
$lang->action->label->linked2bug = "linked ";
$lang->action->label->linked2testtask = "linked";
+1
View File
@@ -210,6 +210,7 @@ $lang->action->desc->importedbuild = '$date, imported to <strong>$extra</
$lang->action->desc->fromsonarqube = '$date, created by <strong>$actor</strong> from <strong>SonarQube Issue</strong>.' . "\n";
$lang->action->desc->tolib = '$date, Importé par <strong>$actor</strong> .' . "\n";
$lang->action->desc->updatetolib = '$date, MàJ de ' . $lang->testcase->common . ' par <strong>$actor</strong>.' . "\n";
$lang->action->desc->adjusttasktowait = '$date, System Reminder: The task status will be set to Not Started as the consumed work hour is adjusted to 0. ' . "\n";
/* Used to describe the history of operations related to parent-child tasks. */
$lang->action->desc->createchildren = '$date, <strong>$actor</strong> a créé un sous-tâche <strong>$extra</strong>。' . "\n";
+1
View File
@@ -210,6 +210,7 @@ $lang->action->desc->importedbuild = '$date, 由 <strong>$actor</strong>
$lang->action->desc->fromsonarqube = '$date, 由 <strong>$actor</strong> 从<strong>SonarQube问题</strong>转化而来。' . "\n";
$lang->action->desc->tolib = '$date, 由 <strong>$actor</strong> 导入。' . "\n";
$lang->action->desc->updatetolib = '$date, 由 <strong>$actor</strong> 从' . $lang->testcase->common . '更新。' . "\n";
$lang->action->desc->adjusttasktowait = '$date, 系统判断由于消耗工时调整为0,将任务状态置为未开始。' . "\n";
/* 用来描述和父子任务相关的操作历史记录。*/
$lang->action->desc->createchildren = '$date, 由 <strong>$actor</strong> 创建子任务 <strong>$extra</strong>。' . "\n";
+1 -1
View File
@@ -73,7 +73,7 @@ class actionModel extends model
if($this->post->uid) $this->file->updateObjectID($this->post->uid, $objectID, $objectType);
/* Call the message notification function. */
$this->loadModel('message')->send(strtolower($objectType), $objectID, $actionType, $actionID, $actor);
$this->loadModel('message')->send(strtolower($objectType), $objectID, $actionType, $actionID, $actor, $extra);
/* Add index for global search. */
$this->saveIndex($objectType, $objectID, $actionType);
+1
View File
@@ -18,6 +18,7 @@
$i = 0;
foreach($actions as $action)
{
if($action->action == 'adjusttasktowait') continue;
$user = zget($users, $action->actor);
if($action->action == 'login' or $action->action == 'logout') $action->objectName = $action->objectLabel = '';
if($action->objectType == 'sonarqubeproject') $action->objectName = $action->extra;
+102 -87
View File
@@ -417,22 +417,23 @@ class bug extends control
$execution = $this->loadModel('execution')->getByID($executionID);
if($this->app->tab == 'execution')
{
$execLaneType = $this->session->execLaneType ? $this->session->execLaneType : 'all';
$execGroupBy = $this->session->execGroupBy ? $this->session->execGroupBy : 'default';
$rdSearchValue = $this->session->rdSearchValue ? $this->session->rdSearchValue : '';
$execLaneType = $this->session->execLaneType ? $this->session->execLaneType : 'all';
$execGroupBy = $this->session->execGroupBy ? $this->session->execGroupBy : 'default';
if($execution->type == 'kanban')
{
$kanbanData = $this->loadModel('kanban')->getRDKanban($executionID, $execLaneType, 'id_desc', 0, $execGroupBy, $rdSearchValue);
$kanbanData = json_encode($kanbanData);
$rdSearchValue = $this->session->rdSearchValue ? $this->session->rdSearchValue : '';
$kanbanData = $this->loadModel('kanban')->getRDKanban($executionID, $execLaneType, 'id_desc', 0, $execGroupBy, $rdSearchValue);
$kanbanData = json_encode($kanbanData);
return $this->send(array('result' => 'success', 'message' => $this->lang->saveSuccess, 'closeModal' => true, 'callback' => "parent.updateKanban($kanbanData, 0)"));
}
else
{
$kanbanData = $this->loadModel('kanban')->getExecutionKanban($executionID, $execLaneType, $execGroupBy, $rdSearchValue);
$kanbanType = $execLaneType == 'all' ? 'bug' : key($kanbanData);
$kanbanData = $kanbanData[$kanbanType];
$kanbanData = json_encode($kanbanData);
$taskSearchValue = $this->session->taskSearchValue ? $this->session->taskSearchValue : '';
$kanbanData = $this->loadModel('kanban')->getExecutionKanban($executionID, $execLaneType, $execGroupBy, $taskSearchValue);
$kanbanType = $execLaneType == 'all' ? 'bug' : key($kanbanData);
$kanbanData = $kanbanData[$kanbanType];
$kanbanData = json_encode($kanbanData);
return $this->send(array('result' => 'success', 'message' => $this->lang->saveSuccess, 'closeModal' => true, 'callback' => "parent.updateKanban(\"bug\", $kanbanData)"));
}
}
@@ -726,22 +727,23 @@ class bug extends control
$execution = $this->loadModel('execution')->getByID($executionID);
if($this->app->tab == 'execution')
{
$execLaneType = $this->session->execLaneType ? $this->session->execLaneType : 'all';
$execGroupBy = $this->session->execGroupBy ? $this->session->execGroupBy : 'default';
$rdSearchValue = $this->session->rdSearchValue ? $this->session->rdSearchValue : '';
$execLaneType = $this->session->execLaneType ? $this->session->execLaneType : 'all';
$execGroupBy = $this->session->execGroupBy ? $this->session->execGroupBy : 'default';
if($execution->type == 'kanban')
{
$kanbanData = $this->loadModel('kanban')->getRDKanban($executionID, $execLaneType, 'id_desc', 0, $execGroupBy, $rdSearchValue);
$kanbanData = json_encode($kanbanData);
$rdSearchValue = $this->session->rdSearchValue ? $this->session->rdSearchValue : '';
$kanbanData = $this->loadModel('kanban')->getRDKanban($executionID, $execLaneType, 'id_desc', 0, $execGroupBy, $rdSearchValue);
$kanbanData = json_encode($kanbanData);
return print(js::closeModal('parent.parent', '', "parent.parent.updateKanban($kanbanData)"));
}
else
{
$kanbanData = $this->loadModel('kanban')->getExecutionKanban($executionID, $execLaneType, $execGroupBy, $rdSearchValue);
$kanbanType = $execLaneType == 'all' ? 'bug' : key($kanbanData);
$kanbanData = $kanbanData[$kanbanType];
$kanbanData = json_encode($kanbanData);
$taskSearchValue = $this->session->taskSearchValue ? $this->session->taskSearchValue : '';
$kanbanData = $this->loadModel('kanban')->getExecutionKanban($executionID, $execLaneType, $execGroupBy, $taskSearchValue);
$kanbanType = $execLaneType == 'all' ? 'bug' : key($kanbanData);
$kanbanData = $kanbanData[$kanbanType];
$kanbanData = json_encode($kanbanData);
return print(js::closeModal('parent.parent', '', "parent.parent.updateKanban(\"bug\", $kanbanData)"));
}
}
@@ -999,22 +1001,23 @@ class bug extends control
$execution = $this->loadModel('execution')->getByID($bug->execution);
if($this->app->tab == 'execution')
{
$execLaneType = $this->session->execLaneType ? $this->session->execLaneType : 'all';
$execGroupBy = $this->session->execGroupBy ? $this->session->execGroupBy : 'default';
$rdSearchValue = $this->session->rdSearchValue ? $this->session->rdSearchValue : '';
$execLaneType = $this->session->execLaneType ? $this->session->execLaneType : 'all';
$execGroupBy = $this->session->execGroupBy ? $this->session->execGroupBy : 'default';
if(isset($execution->type) and $execution->type == 'kanban')
{
$rdSearchValue = $this->session->rdSearchValue ? $this->session->rdSearchValue : '';
$kanbanData = $this->loadModel('kanban')->getRDKanban($bug->execution, $execLaneType, 'id_desc', 0, $kanbanGroup, $rdSearchValue);
$kanbanData = json_encode($kanbanData);
return print(js::closeModal('parent.parent', '', "parent.parent.updateKanban($kanbanData)"));
}
else
{
$kanbanData = $this->loadModel('kanban')->getExecutionKanban($bug->execution, $execLaneType, $execGroupBy, $rdSearchValue);
$kanbanType = $execLaneType == 'all' ? 'bug' : key($kanbanData);
$kanbanData = $kanbanData[$kanbanType];
$kanbanData = json_encode($kanbanData);
$taskSearchValue = $this->session->taskSearchValue ? $this->session->taskSearchValue : '';
$kanbanData = $this->loadModel('kanban')->getExecutionKanban($bug->execution, $execLaneType, $execGroupBy, $taskSearchValue);
$kanbanType = $execLaneType == 'all' ? 'bug' : key($kanbanData);
$kanbanData = $kanbanData[$kanbanType];
$kanbanData = json_encode($kanbanData);
return print(js::closeModal('parent.parent', '', "parent.parent.updateKanban(\"bug\", $kanbanData)"));
}
}
@@ -1415,23 +1418,24 @@ class bug extends control
if(isonlybody())
{
$bug = $this->bug->getById($bugID);
$execution = $this->loadModel('execution')->getByID($bug->execution);
$execLaneType = $this->session->execLaneType ? $this->session->execLaneType : 'all';
$execGroupBy = $this->session->execGroupBy ? $this->session->execGroupBy : 'default';
$rdSearchValue = $this->session->rdSearchValue ? $this->session->rdSearchValue : '';
$bug = $this->bug->getById($bugID);
$execution = $this->loadModel('execution')->getByID($bug->execution);
$execLaneType = $this->session->execLaneType ? $this->session->execLaneType : 'all';
$execGroupBy = $this->session->execGroupBy ? $this->session->execGroupBy : 'default';
if($this->app->tab == 'execution' and isset($execution->type) and $execution->type == 'kanban')
{
$kanbanData = $this->loadModel('kanban')->getRDKanban($bug->execution, $execLaneType, 'id_desc', 0, $kanbanGroup, $rdSearchValue);
$kanbanData = json_encode($kanbanData);
$rdSearchValue = $this->session->rdSearchValue ? $this->session->rdSearchValue : '';
$kanbanData = $this->loadModel('kanban')->getRDKanban($bug->execution, $execLaneType, 'id_desc', 0, $kanbanGroup, $rdSearchValue);
$kanbanData = json_encode($kanbanData);
return print(js::closeModal('parent.parent', '', "parent.parent.updateKanban($kanbanData)"));
}
elseif($from == 'taskkanban')
{
$kanbanData = $this->loadModel('kanban')->getExecutionKanban($bug->execution, $execLaneType, $execGroupBy, $rdSearchValue);
$kanbanType = $execLaneType == 'all' ? 'bug' : key($kanbanData);
$kanbanData = $kanbanData[$kanbanType];
$kanbanData = json_encode($kanbanData);
$taskSearchValue = $this->session->taskSearchValue ? $this->session->taskSearchValue : '';
$kanbanData = $this->loadModel('kanban')->getExecutionKanban($bug->execution, $execLaneType, $execGroupBy, $taskSearchValue);
$kanbanType = $execLaneType == 'all' ? 'bug' : key($kanbanData);
$kanbanData = $kanbanData[$kanbanType];
$kanbanData = json_encode($kanbanData);
return print(js::closeModal('parent.parent', '', "parent.parent.updateKanban(\"bug\", $kanbanData)"));
}
else
@@ -1644,23 +1648,24 @@ class bug extends control
parse_str($extra, $output);
if(isonlybody())
{
$execution = $this->loadModel('execution')->getByID($bug->execution);
$execLaneType = $this->session->execLaneType ? $this->session->execLaneType : 'all';
$execGroupBy = $this->session->execGroupBy ? $this->session->execGroupBy : 'default';
$rdSearchValue = $this->session->rdSearchValue ? $this->session->rdSearchValue : '';
$execution = $this->loadModel('execution')->getByID($bug->execution);
$execLaneType = $this->session->execLaneType ? $this->session->execLaneType : 'all';
$execGroupBy = $this->session->execGroupBy ? $this->session->execGroupBy : 'default';
if($this->app->tab == 'execution' and isset($execution->type) and $execution->type == 'kanban')
{
$regionID = !empty($output['regionID']) ? $output['regionID'] : 0;
$kanbanData = $this->loadModel('kanban')->getRDKanban($bug->execution, $execLaneType, 'id_desc', $regionID, $execGroupBy, $rdSearchValue);
$kanbanData = json_encode($kanbanData);
$rdSearchValue = $this->session->rdSearchValue ? $this->session->rdSearchValue : '';
$regionID = !empty($output['regionID']) ? $output['regionID'] : 0;
$kanbanData = $this->loadModel('kanban')->getRDKanban($bug->execution, $execLaneType, 'id_desc', $regionID, $execGroupBy, $rdSearchValue);
$kanbanData = json_encode($kanbanData);
return print(js::closeModal('parent.parent', '', "parent.parent.updateKanban($kanbanData, $regionID)"));
}
elseif($from == 'taskkanban')
{
$kanbanData = $this->loadModel('kanban')->getExecutionKanban($bug->execution, $execLaneType, $execGroupBy, $rdSearchValue);
$kanbanType = $execLaneType == 'all' ? 'bug' : key($kanbanData);
$kanbanData = $kanbanData[$kanbanType];
$kanbanData = json_encode($kanbanData);
$taskSearchValue = $this->session->taskSearchValue ? $this->session->taskSearchValue : '';
$kanbanData = $this->loadModel('kanban')->getExecutionKanban($bug->execution, $execLaneType, $execGroupBy, $taskSearchValue);
$kanbanType = $execLaneType == 'all' ? 'bug' : key($kanbanData);
$kanbanData = $kanbanData[$kanbanType];
$kanbanData = json_encode($kanbanData);
return print(js::closeModal('parent.parent', '', "parent.parent.updateKanban(\"bug\", $kanbanData)"));
}
else
@@ -1748,22 +1753,23 @@ class bug extends control
parse_str($extra, $output);
if(isonlybody())
{
$execLaneType = $this->session->execLaneType ? $this->session->execLaneType : 'all';
$execGroupBy = $this->session->execGroupBy ? $this->session->execGroupBy : 'default';
$rdSearchValue = $this->session->rdSearchValue ? $this->session->rdSearchValue : '';
$execLaneType = $this->session->execLaneType ? $this->session->execLaneType : 'all';
$execGroupBy = $this->session->execGroupBy ? $this->session->execGroupBy : 'default';
if($this->app->tab == 'execution' and isset($execution->type) and $execution->type == 'kanban')
{
$regionID = !empty($output['regionID']) ? $output['regionID'] : 0;
$kanbanData = $this->loadModel('kanban')->getRDKanban($bug->execution, $execLaneType, 'id_desc', $regionID, $execGroupBy, $rdSearchValue);
$kanbanData = json_encode($kanbanData);
$rdSearchValue = $this->session->rdSearchValue ? $this->session->rdSearchValue : '';
$regionID = !empty($output['regionID']) ? $output['regionID'] : 0;
$kanbanData = $this->loadModel('kanban')->getRDKanban($bug->execution, $execLaneType, 'id_desc', $regionID, $execGroupBy, $rdSearchValue);
$kanbanData = json_encode($kanbanData);
return print(js::closeModal('parent.parent', '', "parent.parent.updateKanban($kanbanData, $regionID)"));
}
elseif($from == 'taskkanban')
{
$kanbanData = $this->loadModel('kanban')->getExecutionKanban($bug->execution, $execLaneType, $execGroupBy, $rdSearchValue);
$kanbanType = $execLaneType == 'all' ? 'bug' : key($kanbanData);
$kanbanData = $kanbanData[$kanbanType];
$kanbanData = json_encode($kanbanData);
$taskSearchValue = $this->session->taskSearchValue ? $this->session->taskSearchValue : '';
$kanbanData = $this->loadModel('kanban')->getExecutionKanban($bug->execution, $execLaneType, $execGroupBy, $taskSearchValue);
$kanbanType = $execLaneType == 'all' ? 'bug' : key($kanbanData);
$kanbanData = $kanbanData[$kanbanType];
$kanbanData = json_encode($kanbanData);
return print(js::closeModal('parent.parent', '', "parent.parent.updateKanban(\"bug\", $kanbanData)"));
}
else
@@ -1857,23 +1863,24 @@ class bug extends control
parse_str($extra, $output);
if(isonlybody())
{
$execution = $this->loadModel('execution')->getByID($bug->execution);
$execLaneType = $this->session->execLaneType ? $this->session->execLaneType : 'all';
$execGroupBy = $this->session->execGroupBy ? $this->session->execGroupBy : 'default';
$rdSearchValue = $this->session->rdSearchValue ? $this->session->rdSearchValue : '';
$execution = $this->loadModel('execution')->getByID($bug->execution);
$execLaneType = $this->session->execLaneType ? $this->session->execLaneType : 'all';
$execGroupBy = $this->session->execGroupBy ? $this->session->execGroupBy : 'default';
if($this->app->tab == 'execution' and isset($execution->type) and $execution->type == 'kanban')
{
$regionID = !empty($output['regionID']) ? $output['regionID'] : 0;
$kanbanData = $this->loadModel('kanban')->getRDKanban($bug->execution, $execLaneType, 'id_desc', $regionID, $execGroupBy, $rdSearchValue);
$kanbanData = json_encode($kanbanData);
$rdSearchValue = $this->session->rdSearchValue ? $this->session->rdSearchValue : '';
$regionID = !empty($output['regionID']) ? $output['regionID'] : 0;
$kanbanData = $this->loadModel('kanban')->getRDKanban($bug->execution, $execLaneType, 'id_desc', $regionID, $execGroupBy, $rdSearchValue);
$kanbanData = json_encode($kanbanData);
return print(js::closeModal('parent.parent', '', "parent.parent.updateKanban($kanbanData, $regionID)"));
}
elseif($from == 'taskkanban')
{
$kanbanData = $this->loadModel('kanban')->getExecutionKanban($bug->execution, $execLaneType, $execGroupBy, $rdSearchValue);
$kanbanType = $execLaneType == 'all' ? 'bug' : key($kanbanData);
$kanbanData = $kanbanData[$kanbanType];
$kanbanData = json_encode($kanbanData);
$taskSearchValue = $this->session->taskSearchValue ? $this->session->taskSearchValue : '';
$kanbanData = $this->loadModel('kanban')->getExecutionKanban($bug->execution, $execLaneType, $execGroupBy, $taskSearchValue);
$kanbanType = $execLaneType == 'all' ? 'bug' : key($kanbanData);
$kanbanData = $kanbanData[$kanbanType];
$kanbanData = json_encode($kanbanData);
return print(js::closeModal('parent.parent', '', "parent.parent.updateKanban(\"bug\", $kanbanData)"));
}
else
@@ -1926,23 +1933,24 @@ class bug extends control
parse_str($extra, $output);
if(isonlybody())
{
$execution = $this->loadModel('execution')->getByID($bug->execution);
$execLaneType = $this->session->execLaneType ? $this->session->execLaneType : 'all';
$execGroupBy = $this->session->execGroupBy ? $this->session->execGroupBy : 'default';
$rdSearchValue = $this->session->rdSearchValue ? $this->session->rdSearchValue : '';
$execution = $this->loadModel('execution')->getByID($bug->execution);
$execLaneType = $this->session->execLaneType ? $this->session->execLaneType : 'all';
$execGroupBy = $this->session->execGroupBy ? $this->session->execGroupBy : 'default';
if($this->app->tab == 'execution' and isset($execution->type) and $execution->type == 'kanban')
{
$regionID = !empty($output['regionID']) ? $output['regionID'] : 0;
$kanbanData = $this->loadModel('kanban')->getRDKanban($bug->execution, $execLaneType, 'id_desc', $regionID, $execGroupBy, $rdSearchValue);
$kanbanData = json_encode($kanbanData);
$rdSearchValue = $this->session->rdSearchValue ? $this->session->rdSearchValue : '';
$regionID = !empty($output['regionID']) ? $output['regionID'] : 0;
$kanbanData = $this->loadModel('kanban')->getRDKanban($bug->execution, $execLaneType, 'id_desc', $regionID, $execGroupBy, $rdSearchValue);
$kanbanData = json_encode($kanbanData);
return print(js::closeModal('parent.parent', '', "parent.parent.updateKanban($kanbanData, $regionID)"));
}
elseif($from == 'taskkanban')
{
$kanbanData = $this->loadModel('kanban')->getExecutionKanban($bug->execution, $execLaneType, $execGroupBy, $rdSearchValue);
$kanbanType = $execLaneType == 'all' ? 'bug' : key($kanbanData);
$kanbanData = $kanbanData[$kanbanType];
$kanbanData = json_encode($kanbanData);
$taskSearchValue = $this->session->taskSearchValue ? $this->session->taskSearchValue : '';
$kanbanData = $this->loadModel('kanban')->getExecutionKanban($bug->execution, $execLaneType, $execGroupBy, $taskSearchValue);
$kanbanType = $execLaneType == 'all' ? 'bug' : key($kanbanData);
$kanbanData = $kanbanData[$kanbanType];
$kanbanData = json_encode($kanbanData);
return print(js::closeModal('parent.parent', '', "parent.parent.updateKanban(\"bug\", $kanbanData)"));
}
else
@@ -2022,11 +2030,14 @@ class bug extends control
/**
* Batch close bugs.
*
* @param int $releaseID
* @param string $viewType
* @access public
* @return void
*/
public function batchClose()
public function batchClose($releaseID = '', $viewType = '')
{
if($releaseID) $this->post->bugIDList = $this->post->unlinkBugs;
if($this->post->bugIDList)
{
$bugIDList = $this->post->bugIDList;
@@ -2051,6 +2062,10 @@ class bug extends control
}
$this->loadModel('score')->create('ajax', 'batchOther');
if(isset($skipBugs)) echo js::alert(sprintf($this->lang->bug->skipClose, join(',', $skipBugs)));
if($viewType)
{
return print(js::locate($this->createLink($viewType, 'view', "releaseID=$releaseID&type=bug"), 'parent'));
}
}
return print(js::reload('parent'));
}
@@ -2144,13 +2159,13 @@ class bug extends control
if($from == 'taskkanban')
{
$execLaneType = $this->session->execLaneType ? $this->session->execLaneType : 'all';
$execGroupBy = $this->session->execGroupBy ? $this->session->execGroupBy : 'default';
$rdSearchValue = $this->session->rdSearchValue ? $this->session->rdSearchValue : '';
$kanbanData = $this->loadModel('kanban')->getExecutionKanban($bug->execution, $execLaneType, $execGroupBy, $rdSearchValue);
$kanbanType = $execLaneType == 'all' ? 'bug' : key($kanbanData);
$kanbanData = $kanbanData[$kanbanType];
$kanbanData = json_encode($kanbanData);
$execLaneType = $this->session->execLaneType ? $this->session->execLaneType : 'all';
$execGroupBy = $this->session->execGroupBy ? $this->session->execGroupBy : 'default';
$taskSearchValue = $this->session->taskSearchValue ? $this->session->taskSearchValue : '';
$kanbanData = $this->loadModel('kanban')->getExecutionKanban($bug->execution, $execLaneType, $execGroupBy, $taskSearchValue);
$kanbanType = $execLaneType == 'all' ? 'bug' : key($kanbanData);
$kanbanData = $kanbanData[$kanbanType];
$kanbanData = json_encode($kanbanData);
return print(js::closeModal('parent', '', "parent.updateKanban(\"bug\", $kanbanData)"));
}
+1 -1
View File
@@ -425,6 +425,7 @@ $lang->bug->placeholder->newBuildName = 'Nom Nouv Build';
$lang->bug->featureBar['browse']['all'] = $lang->bug->allBugs;
$lang->bug->featureBar['browse']['unclosed'] = $lang->bug->unclosed;
$lang->bug->featureBar['browse']['openedbyme'] = $lang->bug->openedByMe;
$lang->bug->featureBar['browse']['assigntome'] = $lang->bug->assignToMe;
$lang->bug->featureBar['browse']['resolvedbyme'] = $lang->bug->resolvedByMe;
@@ -432,7 +433,6 @@ $lang->bug->featureBar['browse']['unresolved'] = $lang->bug->unResolved;
$lang->bug->featureBar['browse']['more'] = $lang->more;
$lang->bug->moreSelects['assignedbyme'] = $lang->bug->assignedByMe;
$lang->bug->moreSelects['openedbyme'] = $lang->bug->openedByMe;
$lang->bug->moreSelects['unconfirmed'] = $lang->bug->unconfirmed;
$lang->bug->moreSelects['assigntonull'] = $lang->bug->assignToNull;
$lang->bug->moreSelects['longlifebugs'] = $lang->bug->longLifeBugs;
+2
View File
@@ -28,6 +28,8 @@ class caselibModel extends model
if(!empty($products) and $this->session->product) $this->loadModel('qa')->setMenu($products, $this->session->product);
if(empty($products)) $this->loadModel('qa')->setMenu(array(0 => ''), 0);
$this->lang->qa->menu->caselib['subModule'] .= ',testcase';
if($libraries)
{
$libName = '';
+1 -1
View File
@@ -245,7 +245,7 @@ $lang->scrum->menu->settings['subMenu']->group = array('link' => "{$lang->
/* Waterfall menu. */
$lang->waterfall->menu = new stdclass();
$lang->waterfall->menu->index = array('link' => "$lang->dashboard|project|index|project=%s");
$lang->waterfall->menu->execution = array('link' => "{$lang->stage->common}|project|execution|status=all&projectID=%s", 'subModule' => 'programplan');
$lang->waterfall->menu->execution = array('link' => "{$lang->stage->common}|project|execution|status=all&projectID=%s", 'subModule' => 'programplan,task');
$lang->waterfall->menu->story = array('link' => "$lang->SRCommon|projectstory|story|project=%s", 'subModule' => 'projectstory,tree', 'exclude' => 'projectstory-track');
$lang->waterfall->menu->design = array('link' => "{$lang->design->common}|design|browse|project=%s");
$lang->waterfall->menu->qa = array('link' => "{$lang->qa->common}|project|bug|projectID=%s", 'subModule' => 'testcase,testtask,bug,testreport', 'alias' => 'bug,testtask,testcase,testreport');
+1
View File
@@ -64,6 +64,7 @@
</div>
<ul class="timeline timeline-tag-left <?php if($browseType == 'all') echo 'margin-l-50px';?>">
<?php foreach($actions as $i => $action):?>
<?php if($action->action == 'adjusttasktowait') continue;?>
<?php if(empty($firstAction)) $firstAction = $action;?>
<li <?php if($action->major) echo "class='active'";?>>
<div>
@@ -44,9 +44,10 @@
<?php endif;?>
<td class='text-left SRBox'><?php echo $URSR['SRName'];?></td>
<td class='c-actions'>
<?php $disabled = $key == $config->custom->URSR ? "disabled=disabled" : '';?>
<?php $disabled = $key == $config->custom->URSR ? "disabled=disabled" : '';?>
<?php $deleteLink = empty($disabled) ? $this->createLink('custom', 'deleteStoryConcept', "id=$key") : '#';?>
<?php if(common::hasPriv('custom', 'editStoryConcept')) echo html::a($this->createLink('custom', 'editStoryConcept', "id=$key", '', true), "<i class='icon icon-edit'></i>", '', "class='btn iframe' data-width=" . ($this->config->URAndSR ? "480px" : "330px") . " title={$lang->edit}");?>
<?php if(common::hasPriv('custom', 'deleteStoryConcept')) echo html::a($this->createLink('custom', 'deleteStoryConcept', "id=$key"), "<i class='icon icon-trash'></i>", 'hiddenwin', "class='btn' $disabled title={$lang->delete} data-group='admin'");?>
<?php if(common::hasPriv('custom', 'deleteStoryConcept')) echo html::a($deleteLink, "<i class='icon icon-trash'></i>", 'hiddenwin', "class='btn' $disabled title={$lang->delete} data-group='admin'");?>
</td>
</tr>
<?php endforeach;?>
+14 -28
View File
@@ -3260,22 +3260,23 @@ class execution extends control
return $this->send($response);
}
$execution = $this->execution->getByID($executionID);
$execLaneType = $this->session->execLaneType ? $this->session->execLaneType : 'all';
$execGroupBy = $this->session->execGroupBy ? $this->session->execGroupBy : 'default';
$rdSearchValue = $this->session->rdSearchValue ? $this->session->rdSearchValue : '';
$execution = $this->execution->getByID($executionID);
$execLaneType = $this->session->execLaneType ? $this->session->execLaneType : 'all';
$execGroupBy = $this->session->execGroupBy ? $this->session->execGroupBy : 'default';
if($this->app->tab == 'execution' and $execution->type == 'kanban')
{
$kanbanData = $this->loadModel('kanban')->getRDKanban($executionID, $execLaneType, 'id_desc', 0, $execGroupBy, $rdSearchValue);
$kanbanData = json_encode($kanbanData);
$rdSearchValue = $this->session->rdSearchValue ? $this->session->rdSearchValue : '';
$kanbanData = $this->loadModel('kanban')->getRDKanban($executionID, $execLaneType, 'id_desc', 0, $execGroupBy, $rdSearchValue);
$kanbanData = json_encode($kanbanData);
return print(js::closeModal('parent', '', "parent.updateKanban($kanbanData)"));
}
elseif($from == 'taskkanban')
{
$kanbanData = $this->loadModel('kanban')->getExecutionKanban($executionID, $execLaneType, $execGroupBy);
$kanbanType = $execLaneType == 'all' ? 'story' : key($kanbanData);
$kanbanData = $kanbanData[$kanbanType];
$kanbanData = json_encode($kanbanData);
$taskSearchValue = $this->session->taskSearchValue ? $this->session->taskSearchValue : '';
$kanbanData = $this->loadModel('kanban')->getExecutionKanban($executionID, $execLaneType, $execGroupBy, $taskSearchValue);
$kanbanType = $execLaneType == 'all' ? 'story' : key($kanbanData);
$kanbanData = $kanbanData[$kanbanType];
$kanbanData = json_encode($kanbanData);
return print(js::closeModal('parent', '', "parent.updateKanban(\"story\", $kanbanData)"));
}
@@ -3668,18 +3669,6 @@ class execution extends control
$from = $this->app->tab;
if($from == 'execution') $this->session->set('executionList', $this->app->getURI(true), 'execution');
if($from == 'project')
{
$projects = $this->project->getPairsByProgram();
$projectID = $this->project->saveState($projectID, $projects);
$project = $this->loadModel('project')->getByID($projectID);
$this->view->project = $project;
$this->project->setMenu($projectID);
if(!$projectID) return print(js::locate($this->createLink('project', 'browse')));
if(!empty($project->model) and $project->model == 'kanban' and !(defined('RUN_MODE') and RUN_MODE == 'api')) return print(js::locate($this->createLink('project', 'index', "projectID=$projectID")));
}
if($this->app->viewType == 'mhtml')
{
if($this->app->rawModule == 'project' and $this->app->rawMethod == 'execution')
@@ -3713,11 +3702,8 @@ class execution extends control
$parents = array();
if($parentIdList) $parents = $this->execution->getByIdList($parentIdList);
$allExecutionsNum = $this->dao->select('COUNT(id) AS count')->from(TABLE_PROJECT)
->where('project')->eq($projectID)
->andWhere('deleted')->eq(0)
->fetch();
$this->view->allExecutionsNum = $allExecutionsNum;
$allExecutionsNum = $this->project->getStats($projectID, 'all');
$this->view->allExecutionsNum = count($allExecutionsNum);
$this->view->executionStats = $executionStats;
$this->view->productList = $this->loadModel('product')->getProductPairsByProject($projectID);
@@ -3978,8 +3964,8 @@ class execution extends control
$projectID = $this->dao->findByID($executionID)->from(TABLE_EXECUTION)->fetch('project');
$planStories = array_keys($planStory);
$this->execution->linkStory($executionID, $planStories, $planProducts, $extra);
if($this->config->systemMode == 'new' and $executionID != $projectID) $this->execution->linkStory($projectID, $planStories, $planProducts);
$this->execution->linkStory($executionID, $planStories, $planProducts, $extra);
}
$moduleName = 'execution';
-2
View File
@@ -811,8 +811,6 @@ function tips()
function renderHeaderCol($column, column, $header, kanbanData)
{
if(groupBy == 'story' && column.type == 'story') return;
console.log(groupBy);
console.log(column.type);
/* Render group header. */
var privs = kanbanData.actions;
var columnPrivs = kanbanData.columns[0].actions;
+1 -2
View File
@@ -434,8 +434,7 @@ $lang->execution->charts->cfd = new stdclass();
$lang->execution->charts->cfd->cfdTip = "<p>
1. The CFD(Cumulative Flow Diagram)reflects the trend of accumulated workload at each stage over time.<br>
2. The horizontal axis represents the date, and the vertical axis represents the number of work items.<br>
3. To learn about the team's delivery, you can calculate the WIP quantity, delivery rate and average lead time through the CFD.
<p>";
3. To learn about the team's delivery, you can calculate the WIP quantity, delivery rate and average lead time through the CFD. <p>";
$lang->execution->charts->cfd->cycleTime = 'Average cycle time';
$lang->execution->charts->cfd->cycleTimeTip = 'Average cycle time of each card from development start to completion';
$lang->execution->charts->cfd->throughput = 'Throughput Rate';
+1 -2
View File
@@ -434,8 +434,7 @@ $lang->execution->charts->cfd = new stdclass();
$lang->execution->charts->cfd->cfdTip = "<p>
1. The CFD(Cumulative Flow Diagram)reflects the trend of accumulated workload at each stage over time.<br>
2. The horizontal axis represents the date, and the vertical axis represents the number of work items.<br>
3. To learn about the team's delivery, you can calculate the WIP quantity, delivery rate and average lead time through the CFD.
<p>";
3. To learn about the team's delivery, you can calculate the WIP quantity, delivery rate and average lead time through the CFD. <p>";
$lang->execution->charts->cfd->cycleTime = 'Average cycle time';
$lang->execution->charts->cfd->cycleTimeTip = 'Average cycle time of each card from development start to completion';
$lang->execution->charts->cfd->throughput = 'Throughput Rate';
+3 -3
View File
@@ -300,10 +300,7 @@ $lang->execution->statusSelects[''] = 'Plus...';
$lang->execution->statusSelects['wait'] = 'En Attente';
$lang->execution->statusSelects['doing'] = 'En Cours';
$lang->execution->statusSelects['undone'] = 'Non terminées';
$lang->execution->statusSelects['myinvolved'] = $lang->execution->myInvolved;
$lang->execution->statusSelects['finishedbyme'] = 'Terminées par moi';
$lang->execution->statusSelects['assignedbyme'] = $lang->execution->assignedByMe;
$lang->execution->statusSelects['needconfirm'] = 'A confirmer';
$lang->execution->statusSelects['done'] = 'Faites';
$lang->execution->statusSelects['closed'] = 'Fermées';
$lang->execution->statusSelects['cancel'] = 'Annulées';
@@ -503,6 +500,9 @@ $lang->execution->typeList['kanban'] = 'Kanban';
$lang->execution->featureBar['task']['all'] = $lang->execution->allTasks;
$lang->execution->featureBar['task']['unclosed'] = $lang->execution->unclosed;
$lang->execution->featureBar['task']['assignedtome'] = $lang->execution->assignedToMe;
$lang->execution->featureBar['task']['myinvolved'] = $lang->execution->myInvolved;
$lang->execution->featureBar['task']['assignedbyme'] = $lang->execution->assignedByMe;
$lang->execution->featureBar['task']['needconfirm'] = 'Changed';
$lang->execution->featureBar['task']['status'] = $lang->execution->statusSelects[''];
$lang->execution->featureBar['all']['all'] = $lang->execution->all;
+97
View File
@@ -4305,6 +4305,103 @@ class executionModel extends model
return $html;
}
/**
* Print execution nested list.
*
* @param object $execution
* @param int $isChild
* @param array $users
* @access public
* @return void
*/
public function printNestedList($execution, $isChild = false, $users, $productID)
{
$this->loadModel('task');
$this->loadModel('execution');
$this->loadModel('programplan');
if(!$isChild)
{
$trClass = 'is-top-level table-nest-child-hide';
$trAttrs = "data-id='$execution->id' data-order='$execution->order' data-nested='true'";
}
else
{
$trClass = 'is-nest-child';
$trAttrs = "data-id={$execution->id} data-parent={$execution->parent}";
$trAttrs .= " data-nest-parent='$execution->parent' data-order='$execution->order' data-nest-path=',$execution->parent,$execution->id,'";
}
$burns = join(',', $execution->burns);
echo "<tr $trAttrs class=$trClass>";
echo "<td><span id=$execution->id class='table-nest-icon icon table-nest-toggle'></span>";
if($this->config->systemMode == 'new')
{
$spanClass = $execution->type == 'stage' ? 'label-warning' : 'label-info';
echo "<span class='project-type-label label label-outline $spanClass'>{$this->lang->execution->typeList[$execution->type]}</span> ";
}
echo html::a(helper::createLink('execution', 'view', "executionID=$execution->id"), $execution->name);
echo '<td>' . zget($users, $execution->PM) . '</td>';
echo "<td class='status-{$execution->status}'>" . zget($this->lang->project->statusList, $execution->status) . '</td>';
echo '<td>' . html::ring($execution->hours->progress) . '</td>';
echo '<td>' . $execution->begin . '</td>';
echo '<td>' . $execution->end . '</td>';
echo "<td class='hours' title='{$execution->hours->totalEstimate}{$this->lang->execution->workHour}'>" . $execution->hours->totalEstimate . $this->lang->execution->workHourUnit . '</td>';
echo "<td class='hours' title='{$execution->hours->totalConsumed}{$this->lang->execution->workHour}'>" . $execution->hours->totalConsumed . $this->lang->execution->workHourUnit . '</td>';
echo "<td class='hours' title='{$execution->hours->totalLeft}{$this->lang->execution->workHour}'>" . $execution->hours->totalLeft . $this->lang->execution->workHourUnit . '</td>';
echo "<td id='spark-{$execution->id}' class='sparkline text-left no-padding' values='$burns'></td>";
echo '<td class="c-actions">';
common::printIcon('execution', 'start', "executionID={$execution->id}", $execution, 'list', '', '', 'iframe', true);
$class = !empty($execution->children) ? 'disabled' : '';
common::printIcon('task', 'create', "executionID={$execution->id}", $execution, 'list', '', '', $class, false, "data-app='execution'");
if($execution->type == 'stage')
{
if($execution->grade == 1 && $this->loadModel('programplan')->isCreateTask($execution->id))
{
common::printIcon('programplan', 'create', "program={$execution->parent}&productID=$productID&planID=$execution->id", $execution, 'list', 'split', '', '', '', '', $this->lang->programplan->createSubPlan);
}
else
{
$disabled = ($execution->grade == 2) ? ' disabled' : '';
echo common::hasPriv('programplan', 'create') ? html::a('javascript:alert("' . $this->lang->programplan->error->createdTask . '");', '<i class="icon-programplan-create icon-split"></i>', '', 'class="btn ' . $disabled . '"') : '';
}
}
common::printIcon('programplan', 'edit', "stageID=$execution->id&projectID=$execution->project", $execution, 'list', '', '', 'iframe', true);
$disabled = !empty($execution->children) ? ' disabled' : '';
if($execution->status != 'closed' and common::hasPriv('execution', 'close', $execution))
{
common::printIcon('execution', 'close', "stageID=$execution->id", $execution, 'list', 'off', 'hiddenwin' , $disabled . ' iframe', true, '', $this->lang->execution->close);
}
elseif($execution->status == 'closed' and common::hasPriv('execution', 'activate', $execution))
{
common::printIcon('execution', 'activate', "stageID=$execution->id", $execution, 'list', 'magic', 'hiddenwin' , $disabled . ' iframe', true, '', $this->lang->execution->activate);
}
if(common::hasPriv('execution', 'delete', $execution))
{
common::printIcon('execution', 'delete', "stageID=$execution->id&confirm=no", $execution, 'list', 'trash', 'hiddenwin' , $disabled, '', '', $this->lang->delete);
}
echo '</td>';
echo '</tr>';
if(!empty($execution->children))
{
foreach($execution->children as $child) $this->printNestedList($child, true, $users, $productID);
}
if(!empty($execution->tasks))
{
foreach($execution->tasks as $task)
{
$showmore = (count($execution->tasks) == 50) && ($task == end($execution->tasks));
echo $this->task->buildNestedList($execution, $task, false, $showmore, $users);
}
}
}
/**
* Update user view of execution and it's product.
*
+1 -1
View File
@@ -73,7 +73,7 @@ js::set('isCNLang', !$this->loadModel('common')->checkNotCN())
<div class="table-empty-tip">
<p>
<span class="text-muted"><?php echo $from == 'execution' ? $lang->execution->noExecutions : $lang->execution->noExecution;?></span>
<?php if(empty($allExecutionsNum->count)):?>
<?php if(empty($allExecutionsNum)):?>
<?php if(common::hasPriv('programplan', 'create') and $isStage):?>
<?php echo html::a($this->createLink('programplan', 'create', "projectID=$projectID&productID=$productID"), "<i class='icon icon-plus'></i> " . $lang->programplan->create, '', "class='btn btn-info'");?>
<?php else: ?>
+1 -1
View File
@@ -148,7 +148,7 @@ js::set('priv',
<div class='btn-toolbar pull-right'>
<div class="input-group" id="rdKanbanSearch">
<div class="input-control search-box" id="rdSearchBox">
<input type="text" name="rdKanbanSearchInput" id="rdKanbanSearchInput" value="" class="form-control" oninput="searchCards(this.value)" placeholder="<?php echo $lang->execution->pleaseInput?>">
<input type="text" name="rdKanbanSearchInput" id="rdKanbanSearchInput" value="" class="form-control" oninput="searchCards(this.value)" placeholder="<?php echo $lang->execution->pleaseInput?>" autocomplete="off">
</div>
</div>
<?php
+1 -1
View File
@@ -40,7 +40,7 @@
<div class='btn-toolbar pull-right'>
<div class="input-group" id="taskKanbanSearch">
<div class="input-control search-box" id="searchBox">
<input type="text" name="taskKanbanSearchInput" id="taskKanbanSearchInput" value="" class="form-control" oninput="searchCards(this.value)" placeholder="<?php echo $lang->execution->pleaseInput;?>">
<input type="text" name="taskKanbanSearchInput" id="taskKanbanSearchInput" value="" class="form-control" oninput="searchCards(this.value)" placeholder="<?php echo $lang->execution->pleaseInput;?>" autocomplete="off">
</div>
</div>
<?php
+9 -1
View File
@@ -280,9 +280,14 @@ class file extends control
$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);
/* Fix Bug #1518. */
$fileRecord = $this->dao->select('id')->from(TABLE_FILE)->where('pathname')->eq($file->pathname)->fetch();
if(empty($fileRecord)) @unlink($file->realPath);
/* Update test case version for test case synchronization. */
if($file->objectType == 'testcase') $this->file->updateTestcaseVersion($file);
return print(js::reload('parent'));
}
}
@@ -331,9 +336,12 @@ class file extends control
$extension = "." . $file->extension;
$actionID = $this->loadModel('action')->create($file->objectType, $file->objectID, 'editfile', '', $fileName);
$changes[] = array('field' => 'fileName', 'old' => $file->title . $extension, 'new' => $fileName);
$changes[] = array('field' => 'fileName', 'old' => $file->title, 'new' => $fileName);
$this->action->logHistory($actionID, $changes);
/* Update test case version for test case synchronization. */
if($file->objectType == 'testcase' and $file->title != $fileName) $this->file->updateTestcaseVersion($file);
return print(js::reload('parent.parent'));
}
+19
View File
@@ -1046,4 +1046,23 @@ class fileModel extends model
->andWhere('deleted')->eq('0')
->fetchPairs();
}
/**
* Update test case version.
*
* @param object $file
* @access public
* @return void
*/
public function updateTestcaseVersion($file)
{
$oldCase = $this->loadModel('testcase')->getByID($file->objectID);
$isLibCase = ($oldCase->lib and empty($oldCase->product));
if($isLibCase)
{
$fromcaseVersion = $this->dao->select('fromCaseVersion')->from(TABLE_CASE)->where('fromCaseID')->eq($file->objectID)->fetch('fromCaseVersion');
$fromcaseVersion += 1;
$this->dao->update(TABLE_CASE)->set('`fromCaseVersion`')->eq($fromcaseVersion)->where('`fromCaseID`')->eq($file->objectID)->exec();
}
}
}
+1 -1
View File
@@ -1 +1 @@
.radio-inline {margin-left: 10px !important;}
#region_chosen.chosen-container .chosen-results {max-height: 115px;}
+1 -1
View File
@@ -24,7 +24,7 @@
</tr>
<tr>
<th><?php echo $lang->kanbanregion->style;?></th>
<td><?php echo html::radio('region', $regions, 'custom');?></td>
<td><?php echo html::select('region', $regions, 'custom', "class='form-control chosen' data-drop_direction='up'");?></td>
</tr>
<tr>
<td colspan='2' class='form-actions text-center'>
+3 -1
View File
@@ -59,10 +59,12 @@ class messageModel extends model
* @param int $objectID
* @param string $actionType
* @param int $actionID
* @param string $actor
* @param string $extra
* @access public
* @return void
*/
public function send($objectType, $objectID, $actionType, $actionID, $actor = '')
public function send($objectType, $objectID, $actionType, $actionID, $actor = '', $extra = '')
{
$objectType = strtolower($objectType);
$messageSetting = $this->config->message->setting;
+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.3'] = '2022-07-13';
$lang->misc->releaseDate['17.2'] = '2022-06-29';
$lang->misc->releaseDate['17.1'] = '2022-06-16';
$lang->misc->releaseDate['17.0'] = '2022-06-02';
@@ -184,6 +185,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.3'][] = array('title' => "UI optimization of the modules such as statistics and background, the use case library will synchronize the function optimization information. Fix bugs.", 'desc' => '');
$lang->misc->feature->all['17.2'][] = array('title' => "Adjust the display of agile project block; optimize the UI of programs, projects and tests; optimize the detailed experience. Fix bugs.", 'desc' => '');
$lang->misc->feature->all['17.1'][] = array('title' => "Modify the interaction problem of execution, project module. Complete customer's high priority requirements. The detail experience is optimized, fix bugs.", 'desc' => '');
$lang->misc->feature->all['17.0'][] = array('title' => 'The detail experience is optimized, fix bugs.', 'desc' => '');
+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.3'] = '2022-07-13';
$lang->misc->releaseDate['17.2'] = '2022-06-29';
$lang->misc->releaseDate['17.1'] = '2022-06-16';
$lang->misc->releaseDate['17.0'] = '2022-06-02';
@@ -184,6 +185,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.3'][] = array('title' => "UI optimization of the modules such as statistics and background, the use case library will synchronize the function optimization information. Fix bugs.", 'desc' => '');
$lang->misc->feature->all['17.2'][] = array('title' => "Adjust the display of agile project block; optimize the UI of programs, projects and tests; optimize the detailed experience. Fix bugs.", 'desc' => '');
$lang->misc->feature->all['17.1'][] = array('title' => "Modify the interaction problem of execution, project module. Complete customer's high priority requirements. The detail experience is optimized, fix bugs.", 'desc' => '');
$lang->misc->feature->all['17.0'][] = array('title' => 'The detail experience is optimized, fix bugs.', 'desc' => '');
+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.3'] = '2022-07-13';
$lang->misc->releaseDate['17.2'] = '2022-06-29';
$lang->misc->releaseDate['17.1'] = '2022-06-16';
$lang->misc->releaseDate['17.0'] = '2022-06-02';
@@ -184,6 +185,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.3'][] = array('title' => "UI optimization of the modules such as statistics and background, the use case library will synchronize the function optimization information. Fix bugs.", 'desc' => '');
$lang->misc->feature->all['17.2'][] = array('title' => "Adjust the display of agile project block; optimize the UI of programs, projects and tests; optimize the detailed experience. Fix bugs.", 'desc' => '');
$lang->misc->feature->all['17.1'][] = array('title' => "Modify the interaction problem of execution, project module. Complete customer's high priority requirements. The detail experience is optimized, fix bugs.", 'desc' => '');
$lang->misc->feature->all['17.0'][] = array('title' => 'The detail experience is optimized, fix bugs.', 'desc' => '');
+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.3'] = '2022-07-13';
$lang->misc->releaseDate['17.2'] = '2022-06-29';
$lang->misc->releaseDate['17.1'] = '2022-06-16';
$lang->misc->releaseDate['17.0'] = '2022-06-02';
@@ -184,6 +185,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.3'][] = array('title' => '统计、后台等模块的UI优化,用例库同步用例信息功能优化。修复Bug。', 'desc' => '');
$lang->misc->feature->all['17.2'][] = array('title' => '调整敏捷项目区块的展示,项目集、项目和测试相关UI优化,细节体验优化。修复Bug。', 'desc' => '');
$lang->misc->feature->all['17.1'][] = array('title' => '修改执行、项目模块的交互问题,完成客户巴高优先级需求,细节体验优化。修复Bug。', 'desc' => '');
$lang->misc->feature->all['17.0'][] = array('title' => '细节体验优化。修复Bug。', 'desc' => '');
+2 -2
View File
@@ -207,6 +207,8 @@ $lang->product->noMatched = '"%s" cannot be found.' . $lang->productCommon;
$lang->product->featureBar['browse']['allstory'] = $lang->product->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;
$lang->product->featureBar['browse']['reviewedbyme'] = $lang->product->reviewedByMe;
$lang->product->featureBar['browse']['reviewbyme'] = $lang->product->reviewByMe;
$lang->product->featureBar['browse']['draftstory'] = $lang->product->draftStory;
$lang->product->featureBar['browse']['more'] = $lang->more;
@@ -215,9 +217,7 @@ $lang->product->featureBar['all']['all'] = $lang->product->allProduct;
$lang->product->featureBar['all']['noclosed'] = $lang->product->unclosed;
$lang->product->featureBar['all']['closed'] = $lang->product->statusList['closed'];
$lang->product->moreSelects['openedbyme'] = $lang->product->openedByMe;
$lang->product->moreSelects['assignedbyme'] = $lang->product->assignedByMe;
$lang->product->moreSelects['reviewedbyme'] = $lang->product->reviewedByMe;
$lang->product->moreSelects['closedbyme'] = $lang->product->closedByMe;
$lang->product->moreSelects['activestory'] = $lang->product->activeStory;
$lang->product->moreSelects['changedstory'] = $lang->product->changedStory;
+1 -1
View File
@@ -72,7 +72,7 @@ class productplan extends control
if($this->viewType == 'json') return $this->send(array('result' => 'success', 'message' => $this->lang->saveSuccess, 'id' => $planID));
if(isonlybody()) return $this->send(array('result' => 'success', 'message' => $this->lang->saveSuccess, 'closeModal' => true, 'callback' => 'parent.refreshPlan()'));
return $this->send(array('result' => 'success', 'message' => $this->lang->saveSuccess, 'locate' => $this->createLink('productplan', 'browse', "productID=$productID&branch=$branchID&browseType=wait")));
return $this->send(array('result' => 'success', 'message' => $this->lang->saveSuccess, 'locate' => $this->createLink('productplan', 'browse', "productID=$productID&branch=$branchID&browseType=all")));
}
$this->commonAction($productID, $branchID);
+1
View File
@@ -15,3 +15,4 @@ tbody.sortable > tr > td.sort-handler {color: #3c4353 !important;}
.has-suffix > a {max-width: calc(100% - 100px); padding-right: 5px; color: #0c60e1; display: inline-block; max-width: calc(100% - 50px);}
div.checkbox-primary + span.table-nest-icon {margin-left:0px !important;}
#checkAll + label.hover:after {border-width: 0px;}
+12
View File
@@ -59,6 +59,7 @@ $(function()
$('#programSummary').addClass('hidden');
$('#projectsSummary').remove();
$('.editCheckbox').after(statistic);
$(this).next('label').addClass('hover');
}
else
{
@@ -66,8 +67,19 @@ $(function()
$('#programForm').removeClass('has-row-checked');
$('#programSummary').removeClass('hidden');
$('#projectsSummary').addClass('hidden');
$(this).next('label').removeClass('hover');
}
});
/* Solve the problem that clicking the browser back button causes the checkbox to be selected by default. */
setTimeout(function()
{
$(":checkbox[name^='projectIdList']").each(function()
{
$(this).prop('checked', false);
});
$('.table-footer #checkAll').prop('checked', false);
}, 10);
});
function showEditCheckbox(show)
+1
View File
@@ -23,6 +23,7 @@ $lang->programplan->createSubPlan = 'Create Sub Plan';
$lang->programplan->parent = 'Parent Stage';
$lang->programplan->emptyParent = 'N/A';
$lang->programplan->name = 'Stage Name';
$lang->programplan->status = 'Stage Progress';
$lang->programplan->PM = 'Stage Manager';
$lang->programplan->acl = 'Access Control';
$lang->programplan->subStageName = 'Sub Stage Name';
+1
View File
@@ -23,6 +23,7 @@ $lang->programplan->createSubPlan = 'Create Sub Stage';
$lang->programplan->parent = 'Parent Stage';
$lang->programplan->emptyParent = 'N/A';
$lang->programplan->name = 'Stage Name';
$lang->programplan->status = 'Stage Progress';
$lang->programplan->PM = 'Stage Manager';
$lang->programplan->acl = 'Access Control';
$lang->programplan->subStageName = 'Sub Stage Name';
+1
View File
@@ -23,6 +23,7 @@ $lang->programplan->createSubPlan = 'Create Sub Plan';
$lang->programplan->parent = 'Parent Stage';
$lang->programplan->emptyParent = 'N/A';
$lang->programplan->name = 'Stage Name';
$lang->programplan->status = 'Stage Progress';
$lang->programplan->PM = 'Stage Manager';
$lang->programplan->acl = 'Access Control';
$lang->programplan->subStageName = 'Sub Stage Name';
+1
View File
@@ -23,6 +23,7 @@ $lang->programplan->createSubPlan = '创建二级阶段';
$lang->programplan->parent = '父阶段';
$lang->programplan->emptyParent = '无';
$lang->programplan->name = '阶段名称';
$lang->programplan->status = '阶段进度';
$lang->programplan->PM = '阶段负责人';
$lang->programplan->acl = '访问控制';
$lang->programplan->subStageName = '子阶段名称';
+37 -4
View File
@@ -493,7 +493,10 @@ class project extends control
$products = $this->product->getProducts($copyProjectID);
foreach($products as $product)
{
$productPlans[$product->id] = $this->loadModel('productplan')->getPairs($product->id, '', 'noclosed');
foreach($product->branches as $branch)
{
$productPlans[$product->id][$branch] = $this->loadModel('productplan')->getPairs($product->id, $branch, 'noclosed', true);
}
}
}
@@ -962,10 +965,40 @@ class project extends control
*/
public function execution($status = 'all', $projectID = 0, $orderBy = 'order_asc', $productID = 0, $recTotal = 0, $recPerPage = 100, $pageID = 1)
{
$uri = $this->app->getURI(true);
$this->app->session->set('executionList', $uri, 'project');
$this->loadModel('execution');
$this->loadModel('task');
$this->loadModel('programplan');
echo $this->fetch('execution', 'all', "status=$status&projectID=$projectID&orderBy=$orderBy&productID=$productID&recTotal=$recTotal&recPerPage=$recPerPage&pageID=$pageID");
$projects = $this->project->getPairsByProgram();
$projectID = $this->project->saveState($projectID, $projects);
$project = $this->project->getByID($projectID);
$this->project->setMenu($projectID);
if(!$projectID) return print(js::locate($this->createLink('project', 'browse')));
if(!empty($project->model) and $project->model == 'kanban' and !(defined('RUN_MODE') and RUN_MODE == 'api')) return print(js::locate($this->createLink('project', 'index', "projectID=$projectID")));
/* Load pager and get tasks. */
$this->app->loadClass('pager', $static = true);
$pager = new pager($recTotal, $recPerPage, $pageID);
$allExecution = $this->project->getStats($projectID, 'all');
$this->view->allExecutionNum = count($allExecution);
$this->view->title = $this->lang->execution->allExecutions;
$this->view->position[] = $this->lang->execution->allExecutions;
$this->view->executionStats = $this->project->getStats($projectID, $status, $productID, 0, 30, $orderBy, $pager, $this->cookie->showTask);
$this->view->productList = $this->loadModel('product')->getProductPairsByProject($projectID);
$this->view->productID = $productID;
$this->view->projectID = $projectID;
$this->view->project = $project;
$this->view->pager = $pager;
$this->view->orderBy = $orderBy;
$this->view->users = $this->loadModel('user')->getPairs('noletter');
$this->view->status = $status;
$this->view->isStage = (isset($project->model) and $project->model == 'waterfall') ? true : false;
$this->display();
}
/**
+4
View File
@@ -0,0 +1,4 @@
#executionList > thead > tr > th .table-nest-toggle-global {top: 6px}
#executionList > thead > tr > th .table-nest-toggle-global:before {color: #a6aab8;}
#mainMenu .pull-left .checkbox-primary {margin-top: 5px;}
.main-table tbody>tr>td:first-child, .main-table thead>tr>th:first-child { padding-left: 8px; }
+11
View File
@@ -146,6 +146,17 @@ $(function()
});
$(document).on('change', "select[id^='branch']", disableSelectedBranch);
if(requiredFields.indexOf('budget') >= 0 && budget == 0)
{
$('#budget').removeAttr('disabled');
$('td .checkbox-primary').addClass('hidden');
}
if(requiredFields.indexOf('budget') >= 0 && budget != 0)
{
$('td .checkbox-primary').addClass('hidden');
}
});
/**
+82
View File
@@ -0,0 +1,82 @@
$(function()
{
$('input[name^="showTask"]').click(function()
{
var show = $(this).is(':checked') ? 1 : 0;
$.cookie('showTask', show, {expires:config.cookieLife, path:config.webRoot});
window.location.reload();
});
})
window.addEventListener('scroll', this.handleScroll)
function handleScroll(e)
{
var relative = 200; // 相对距离
$('tr.showmore').each(function()
{
var $showmore = $(this);
var offsetTop = $showmore[0].offsetTop;
if(offsetTop == 0) return true;
if(getScrollTop() + getWindowHeight() >= offsetTop - relative)
{
throttle(loadData($showmore), 150)
}
})
}
function loadData($showmore)
{
$showmore.removeClass('showmore');
var executionID = $showmore.attr('data-parent');
var maxTaskID = $showmore.attr('data-id');
var link = createLink('task', 'ajaxGetTasks', 'executionID=' + executionID + '&maxTaskID=' + maxTaskID);
$.get(link, function(data)
{
$showmore.after(data);
$(".iframe").modalTrigger({type:'iframe'});
$('#executionForm').table('initNestedList');
})
}
function throttle(fn, threshhold)
{
var last;
var timer;
threshhold || (threshhold = 250);
return function()
{
var context = this;
var args = arguments;
var now = +new Date()
if (last && now < last + threshhold)
{
clearTimeout(timer);
timer = setTimeout(function ()
{
last = now
fn.apply(context, args)
}, threshhold)
}
else
{
last = now
fn.apply(context, args)
}
}
}
function getScrollTop()
{
return scrollTop = document.body.scrollTop + document.documentElement.scrollTop
}
function getWindowHeight()
{
return document.compatMode == "CSS1Compat" ? windowHeight = document.documentElement.clientHeight : windowHeight = document.body.clientHeight
}
+43 -2
View File
@@ -1527,6 +1527,7 @@ class projectModel extends model
$projects[$projectID]->id = $projectID;
$projects[$projectID]->name = $projectName;
$projects[$projectID]->code = $projectCode;
$projects[$projectID]->model = $oldProjects[$projectID]->model;
$projects[$projectID]->PM = $data->PMs[$projectID];
$projects[$projectID]->begin = $data->begins[$projectID];
$projects[$projectID]->end = isset($data->ends[$projectID]) ? $data->ends[$projectID] : LONG_TIME;
@@ -1582,7 +1583,17 @@ class projectModel extends model
->where('id')->eq($projectID)
->exec();
if(dao::isError()) helper::end(js::error('project#' . $projectID . dao::getError(true)));
if(dao::isError())
{
$errors = dao::getError();
foreach($errors as $key => $error)
{
dao::$errors[$key][0] = 'project#' . $projectID . $error[0];
}
return false;
}
if(!dao::isError())
{
$linkedProducts = $this->dao->select('product')->from(TABLE_PROJECTPRODUCT)->where('project')->eq($projectID)->fetchPairs();
@@ -2306,7 +2317,7 @@ class projectModel extends model
* @access public
* @return array
*/
public function getStats($projectID = 0, $status = 'undone', $productID = 0, $branch = 0, $itemCounts = 30, $orderBy = 'id_asc', $pager = null)
public function getStats($projectID = 0, $status = 'undone', $productID = 0, $branch = 0, $itemCounts = 30, $orderBy = 'id_asc', $pager = null, $withTasks = false)
{
if(empty($productID))
{
@@ -2382,6 +2393,31 @@ class projectModel extends model
$burns[$executionID] = $executionBurns;
}
if($withTasks)
{
$executionTasks = $this->dao->select('*')->from(TABLE_TASK)
->where('deleted')->eq(0)
->andWhere('status')->notin('closed,cancel')
->andWhere('execution')->in(array_keys($executions))
->orderBy('id_asc')
->fetchGroup('execution', 'id');
foreach($executionTasks as $executionID => $tasks)
{
foreach($tasks as $task)
{
if($task->parent > 0)
{
if(isset($executionTasks[$executionID][$task->parent]))
{
$executionTasks[$executionID][$task->parent]->children[$task->id] = $task;
unset($executionTasks[$executionID][$task->id]);
}
}
}
}
}
/* Process executions. */
$parents = array();
$children = array();
@@ -2407,6 +2443,11 @@ class projectModel extends model
$execution->children = array();
$execution->grade == 1 ? $parents[$execution->id] = $execution : $children[$execution->parent][] = $execution;
if(isset($executionTasks) and isset($executionTasks[$execution->id]))
{
$tasks = array_chunk($executionTasks[$execution->id], 50, true);
$execution->tasks = $tasks[0];
}
}
/* In the case of the waterfall model, calculate the sub-stage. */
+11 -5
View File
@@ -27,6 +27,7 @@
<?php js::set('productName', $lang->product->name);?>
<?php js::set('manageProducts', $lang->project->manageProducts);?>
<?php $requiredFields = $config->project->create->requiredFields;?>
<?php js::set('requiredFields', $requiredFields);?>
<div id='mainContent' class='main-content'>
<div class='center-block'>
<div class='main-header'>
@@ -77,7 +78,7 @@
</div>
</td>
<td>
<div class='checkbox-primary c-future'>
<div class="checkbox-primary c-future <?php echo strpos($requiredFields, 'budget') !== false ? 'hidden' : '';?>">
<input type='checkbox' id='future' name='future' value='1' />
<label for='future'><?php echo $lang->project->future;?></label>
</div>
@@ -109,16 +110,18 @@
<div class='row'>
<?php $i = 0;?>
<?php foreach($products as $product):?>
<?php foreach($product->branches as $branch):?>
<div class="col-sm-4" style="margin-bottom: 10px; padding-right: 6px;">
<?php $hasBranch = $product->type != 'normal' and isset($branchGroups[$product->id]);?>
<div class="input-group<?php if($hasBranch) echo ' has-branch';?>">
<?php echo html::select("products[$i]", $allProducts, $product->id, "class='form-control chosen' onchange='loadBranches(this)' data-last='" . $product->id . "'");?>
<span class='input-group-addon fix-border'></span>
<?php if($hasBranch) echo html::select("branch[$i]", $branchGroups[$product->id], key($product->branches), "class='form-control chosen' onchange=\"loadPlans('#products{$i}', this.value)\"");?>
<?php if($hasBranch) echo html::select("branch[$i]", $branchGroups[$product->id], $branch, "class='form-control chosen' onchange=\"loadPlans('#products{$i}', this.value)\"");?>
</div>
</div>
<?php $i++;?>
<?php endforeach;?>
<?php endforeach;?>
<div class='col-sm-4 <?php if($programID) echo 'required';?>' style="padding-right: 6px;">
<div class='input-group'>
<?php echo html::select("products[$i]", $allProducts, '', "class='form-control chosen' onchange='loadBranches(this)'");?>
@@ -146,12 +149,15 @@
<?php if($copyProjectID):?>
<?php $i = 0;?>
<?php foreach($products as $product):?>
<?php $plans = zget($productPlans, $product->id, array(0 => ''));?>
<div class="col-sm-4" id="plan<?php echo $i;?>"><?php echo html::select("plans[" . $product->id . "]", $plans, '', "class='form-control chosen' multiple");?></div>
<?php $productPlan = zget($productPlans, $product->id, array(0 => ''));?>
<?php foreach($product->branches as $branch):?>
<?php $plans = zget($productPlan, $branch, array(0 => ''));?>
<div class="col-sm-4" id="plan<?php echo $i;?>"><?php echo html::select('plans[' . $product->id . '][' . $branch . '][]', $plans, '', "class='form-control chosen' multiple");?></div>
<?php $i++;?>
<?php endforeach;?>
<?php endforeach;?>
<?php else:?>
<div class="col-sm-4" id="plan0" style="padding-right: 6px;"><?php echo html::select("plans[][]", '', '', "class='form-control chosen' multiple");?></div>
<div class="col-sm-4" id="plan0" style="padding-right: 6px;"><?php echo html::select("plans[][][]", '', '', "class='form-control chosen' multiple");?></div>
<?php endif;?>
</div>
</td>
+2
View File
@@ -28,6 +28,8 @@
<?php js::set('multiBranchProducts', $multiBranchProducts);?>
<?php $aclList = $project->parent ? $lang->project->subAclList : $lang->project->aclList;?>
<?php $requiredFields = $config->project->edit->requiredFields;?>
<?php js::set('requiredFields', $requiredFields);?>
<?php js::set('budget', $project->budget);?>
<div id='mainContent' class='main-content'>
<div class='center-block'>
<div class='main-header'>
+93
View File
@@ -0,0 +1,93 @@
<?php include '../../common/view/header.html.php';?>
<?php js::set('projectID', $projectID);?>
<div id='mainMenu' class='clearfix'>
<div class='btn-toolbar pull-left'>
<div class='btn-group'>
<?php $viewName = $productID != 0 ? zget($productList,$productID) : $lang->product->allProduct;?>
<a href='javascript:;' class='btn btn-link btn-limit' data-toggle='dropdown'><span class='text' title='<?php echo $viewName;?>'><?php echo $viewName;?></span> <span class='caret'></span></a>
<ul class='dropdown-menu' style='max-height:240px; max-width: 300px; overflow-y:auto'>
<?php
$class = '';
if($productID == 0) $class = 'class="active"';
echo "<li $class>" . html::a($this->createLink('project', 'execution', "status=$status&projectID=$projectID&orderby=$orderBy"), $lang->product->allProduct) . "</li>";
foreach($productList as $key => $product)
{
$class = $productID == $key ? 'class="active"' : '';
echo "<li $class>" . html::a($this->createLink('project', 'execution', "status=$status&projectID=$projectID&orderby=$orderBy&productID=$key"), $product) . "</li>";
}
?>
</ul>
</div>
<?php foreach($lang->execution->featureBar['all'] as $key => $label):?>
<?php $label = "<span class='text'>$label</span>";?>
<?php if($status == $key) $label .= " <span class='label label-light label-badge'>{$pager->recTotal}</span>";?>
<?php echo html::a($this->createLink('project', 'execution', "status=$key&projectID=$projectID&orderBy=$orderBy&productID=$productID"), $label, '', "class='btn btn-link' id='{$key}Tab'");?>
<?php endforeach;?>
<?php echo html::checkbox('showTask', array('1' => $lang->programplan->stageCustom->task), '', $this->cookie->showTask ? 'checked=checked' : '');?>
</div>
<div class='btn-toolbar pull-right'>
<?php common::printLink('execution', 'export', "status=$status&productID=$productID&orderBy=$orderBy&from=project", "<i class='icon-export muted'> </i> " . $lang->export, '', "class='btn btn-link export'")?>
<?php if(common::hasPriv('programplan', 'create') and $isStage):?>
<?php echo html::a($this->createLink('programplan', 'create', "projectID=$projectID&productID=$productID"), "<i class='icon icon-plus'></i> " . $lang->programplan->create, '', "class='btn btn-primary'");?>
<?php else: ?>
<?php if(common::hasPriv('execution', 'create')) echo html::a($this->createLink('execution', 'create', "projectID=$projectID"), "<i class='icon icon-sm icon-plus'></i> " . $lang->execution->create, '', "class='btn btn-primary create-execution-btn' data-app='execution' onclick='$(this).removeAttr(\"data-toggle\")'");?>
<?php endif;?>
</div>
</div>
<div id='mainContent' class="main-row fade">
<?php if(empty($executionStats)):?>
<div class="table-empty-tip">
<p>
<span class="text-muted"><?php echo $lang->execution->noExecution;?></span>
<?php if(empty($allExecutionNum)):?>
<?php if(common::hasPriv('programplan', 'create') and $isStage):?>
<?php echo html::a($this->createLink('programplan', 'create', "projectID=$projectID&productID=$productID"), "<i class='icon icon-plus'></i> " . $lang->programplan->create, '', "class='btn btn-info'");?>
<?php else: ?>
<?php if(common::hasPriv('execution', 'create')):?>
<?php echo html::a($this->createLink('execution', 'create', "projectID=$projectID"), "<i class='icon icon-plus'></i> " . $lang->execution->create, '', "class='btn btn-info' data-app='execution'");?>
<?php endif;?>
<?php endif;?>
<?php endif;?>
</p>
</div>
<?php else:?>
<?php $canBatchEdit = common::hasPriv('execution', 'batchEdit'); ?>
<form class='main-table' id='executionForm' method='post' data-ride='table' data-nested='true' data-expand-nest-child='false' data-checkable='false' data-enable-empty-nested-row='true' data-replace-id='executionTableList' data-preserve-nested='true'>
<table class="table table-from table-fixed table-nested" id="executionList">
<?php $vars = "status=$status&orderBy=%s";?>
<thead>
<tr>
<th class='table-nest-title'>
<a class='table-nest-toggle icon table-nest-toggle-global' data-expand-text='<?php echo $lang->expand; ?>' data-collapse-text='<?php echo $lang->collapse;?>'></a>
<?php echo $lang->nameAB;?>
</th>
<th class='c-user'><?php echo $lang->execution->owner;?></th>
<th class='c-status'><?php echo $lang->project->status;?></th>
<th class='c-hours'><?php echo $lang->project->progress;?></th>
<th class='c-date'><?php echo $lang->programplan->begin;?></th>
<th class='c-date'><?php echo $lang->programplan->end;?></th>
<th class='c-hours'><?php echo $lang->task->estimateAB;?></th>
<th class='c-hours'><?php echo $lang->task->consumedAB;?></th>
<th class='c-hours'><?php echo $lang->task->leftAB;?> </th>
<th class='c-progress'><?php echo $lang->execution->burn;?> </th>
<th class='text-center c-actions-6'><?php echo $lang->actions;?></th>
</tr>
</thead>
<tbody id="executionTableList">
<?php foreach($executionStats as $execution):?>
<?php $this->execution->printNestedList($execution, false, $users, $productID);?>
<?php endforeach;?>
</tbody>
</table>
<div class='table-footer'>
<?php $pager->show('right', 'pagerjs');?>
</div>
</form>
<?php endif;?>
</div>
<?php js::set('status', $status)?>
<?php js::set('orderBy', $orderBy)?>
<script>
$("#<?php echo $status;?>Tab").addClass('btn-active-text');
</script>
<?php include '../../common/view/footer.html.php';?>
+16 -4
View File
@@ -150,9 +150,10 @@
<div class='actions'><?php echo html::a("javascript:showLink({$release->id}, \"bug\")", '<i class="icon-bug"></i> ' . $lang->release->linkBug, '', "class='btn btn-primary'");?></div>
<div class='linkBox cell hidden'></div>
<?php endif;?>
<form class='main-table table-bug' method='post' target='hiddenwin' action="<?php echo inLink('batchUnlinkBug', "releaseID=$release->id");?>" id='linkedBugsForm' data-ride="table">
<form class='main-table table-bug' method='post' target='hiddenwin' id='linkedBugsForm' data-ride="table">
<table class='table has-sort-head' id='bugList'>
<?php $canBatchUnlink = common::hasPriv('projectrelease', 'batchUnlinkBug');?>
<?php $canBatchClose = common::hasPriv('bug', 'batchClose');?>
<?php $vars = "releaseID={$release->id}&type=bug&link=$link&param=$param&orderBy=%s";?>
<thead>
<tr class='text-center'>
@@ -178,7 +179,7 @@
<?php $bugLink = $this->createLink('bug', 'view', "bugID=$bug->id", '', true);?>
<tr>
<td class='c-id text-left'>
<?php if($canBatchUnlink and $canBeChanged):?>
<?php if(($canBatchUnlink or $canBatchClose) and $canBeChanged):?>
<div class="checkbox-primary">
<input type='checkbox' name='unlinkBugs[]' value='<?php echo $bug->id;?>'/>
<label></label>
@@ -208,10 +209,21 @@
</tbody>
</table>
<div class='table-footer'>
<?php if($countBugs and $canBatchUnlink and $canBeChanged):?>
<?php if($countBugs and ($canBatchUnlink or $canBatchClose) and $canBeChanged):?>
<div class="checkbox-primary check-all"><label><?php echo $lang->selectAll?></label></div>
<div class="table-actions btn-toolbar">
<?php echo html::submitButton($lang->release->batchUnlink, '', 'btn');?>
<?php
if($canBatchUnlink and $canBeChanged)
{
$unlinkURL = $this->createLink('projectrelease', 'batchUnlinkBug', "releaseID=$release->id");
echo html::a("###", $lang->release->batchUnlink, '', "onclick='setFormAction(\"$unlinkURL\", \"hiddenwin\", this)' class='btn'");
}
if($canBatchClose and $canBeChanged)
{
$closeURL = $this->createLink('bug', 'batchClose', "releaseID=$release->id&viewType=projectrelease");
echo html::a("###", $lang->story->batchClose, '', "onclick='setFormAction(\"$closeURL\", \"hiddenwin\", this)' class='btn'");
}
?>
</div>
<div class='table-statistic'><?php echo sprintf($lang->release->resolvedBugs, $countBugs);?></div>
<?php endif;?>
+16 -4
View File
@@ -152,9 +152,10 @@
<div class='actions'><?php echo html::a("javascript:showLink({$release->id}, \"bug\")", '<i class="icon-bug"></i> ' . $lang->release->linkBug, '', "class='btn btn-primary'");?></div>
<div class='linkBox cell hidden'></div>
<?php endif;?>
<form class='main-table table-bug' method='post' target='hiddenwin' action="<?php echo inLink('batchUnlinkBug', "releaseID=$release->id");?>" id='linkedBugsForm' data-ride="table">
<form class='main-table table-bug' method='post' target='hiddenwin' id='linkedBugsForm' data-ride="table">
<table class='table has-sort-head' id='bugList'>
<?php $canBatchUnlink = common::hasPriv('release', 'batchUnlinkBug');?>
<?php $canBatchClose = common::hasPriv('bug', 'batchClose');?>
<?php $vars = "releaseID={$release->id}&type=bug&link=$link&param=$param&orderBy=%s";?>
<thead>
<tr class='text-center'>
@@ -180,7 +181,7 @@
<?php $bugLink = $this->createLink('bug', 'view', "bugID=$bug->id", '', true);?>
<tr>
<td class='c-id text-left'>
<?php if($canBatchUnlink and $canBeChanged):?>
<?php if($canBatchUnlink or $canBatchClose and $canBeChanged):?>
<div class="checkbox-primary">
<input type='checkbox' name='unlinkBugs[]' value='<?php echo $bug->id;?>'/>
<label></label>
@@ -210,10 +211,21 @@
</tbody>
</table>
<div class='table-footer'>
<?php if($countBugs and $canBatchUnlink and $canBeChanged):?>
<?php if($countBugs and ($canBatchUnlink or $canBatchClose) and $canBeChanged):?>
<div class="checkbox-primary check-all"><label><?php echo $lang->selectAll?></label></div>
<div class="table-actions btn-toolbar">
<?php echo html::submitButton($lang->release->batchUnlink, '', 'btn');?>
<?php
if($canBatchUnlink)
{
$unlinkURL = inlink('batchUnlinkBug', "release=$release->id");
echo html::a('###', $lang->release->batchUnlink, '', "onclick='setFormAction(\"$unlinkURL\", \"hiddenwin\", this)' class='btn'");
}
if($canBatchClose)
{
$closeURL = $this->createLink('bug', 'batchClose', "release=$release->id&viewType=release");
echo html::a("###", $lang->story->batchClose, '', "onclick='setFormAction(\"$closeURL\", \"hiddenwin\", this)' class='btn'");
}
?>
</div>
<div class='table-statistic'><?php echo sprintf($lang->release->resolvedBugs, $countBugs);?></div>
<?php endif;?>
+1 -1
View File
@@ -129,7 +129,7 @@ $config->story->datatable->fieldList['estimate']['required'] = 'no';
$config->story->datatable->fieldList['stage']['title'] = 'stageAB';
$config->story->datatable->fieldList['stage']['fixed'] = 'no';
$config->story->datatable->fieldList['stage']['width'] = '70';
$config->story->datatable->fieldList['stage']['width'] = '75';
$config->story->datatable->fieldList['stage']['required'] = 'no';
$config->story->datatable->fieldList['openedBy']['title'] = 'openedByAB';
+88 -79
View File
@@ -162,12 +162,14 @@ class story extends control
$object = $this->dao->findById((int)$objectID)->from(TABLE_PROJECT)->fetch();
if($object->type != 'project')
{
if($this->config->systemMode == 'new') $this->action->create('story', $storyID, 'linked2project', '', $object->project);
$actionType = $object->type == 'kanban' ? 'linked2kanban' : 'linked2execution';
$this->loadModel('action')->create('story', $storyID, $actionType, '', $objectID);
$this->action->create('story', $storyID, $actionType, '', $objectID);
}
else
{
$this->loadModel('action')->create('story', $storyID, 'linked2project', '', $objectID);
$this->action->create('story', $storyID, 'linked2project', '', $objectID);
}
}
@@ -195,23 +197,24 @@ class story extends control
$execution = $this->execution->getByID($this->session->execution);
if($this->app->tab == 'execution')
{
$execLaneType = $this->session->execLaneType ? $this->session->execLaneType : 'all';
$execGroupBy = $this->session->execGroupBy ? $this->session->execGroupBy : 'default';
$rdSearchValue = $this->session->rdSearchValue ? $this->session->rdSearchValue : '';
$execLaneType = $this->session->execLaneType ? $this->session->execLaneType : 'all';
$execGroupBy = $this->session->execGroupBy ? $this->session->execGroupBy : 'default';
if($execution->type == 'kanban')
{
$kanbanData = $this->loadModel('kanban')->getRDKanban($this->session->execution, $execLaneType, 'id_desc', 0, $execGroupBy, $rdSearchValue);
$kanbanData = json_encode($kanbanData);
$rdSearchValue = $this->session->rdSearchValue ? $this->session->rdSearchValue : '';
$kanbanData = $this->loadModel('kanban')->getRDKanban($this->session->execution, $execLaneType, 'id_desc', 0, $execGroupBy, $rdSearchValue);
$kanbanData = json_encode($kanbanData);
return $this->send(array('result' => 'success', 'message' => $this->lang->saveSuccess, 'closeModal' => true, 'callback' => "parent.updateKanban($kanbanData, 0)"));
}
else
{
$kanbanData = $this->loadModel('kanban')->getExecutionKanban($execution->id, $execLaneType, $execGroupBy, $rdSearchValue);
$kanbanType = $execLaneType == 'all' ? 'story' : key($kanbanData);
$kanbanData = $kanbanData[$kanbanType];
$kanbanData = json_encode($kanbanData);
$taskSearchValue = $this->session->taskSearchValue ? $this->session->taskSearchValue : '';
$kanbanData = $this->loadModel('kanban')->getExecutionKanban($execution->id, $execLaneType, $execGroupBy, $taskSearchValue);
$kanbanType = $execLaneType == 'all' ? 'story' : key($kanbanData);
$kanbanData = $kanbanData[$kanbanType];
$kanbanData = json_encode($kanbanData);
return $this->send(array('result' => 'success', 'message' => $this->lang->saveSuccess, 'closeModal' => true, 'callback' => "parent.updateKanban(\"story\", $kanbanData)"));
}
}
@@ -499,8 +502,8 @@ class story extends control
{
$products = array();
foreach($mails as $story) $products[$story->storyID] = $productID;
$this->execution->linkStory($executionID, $stories, $products, $extra, $lanes);
if($executionID != $this->session->project) $this->execution->linkStory($this->session->project, $stories, $products);
$this->execution->linkStory($executionID, $stories, $products, $extra, $lanes);
}
/* If storyID not equal zero, subdivide this story to child stories and close it. */
@@ -518,22 +521,23 @@ class story extends control
$execution = $this->execution->getByID($executionID);
if($this->app->tab == 'execution')
{
$execLaneType = $this->session->execLaneType ? $this->session->execLaneType : 'all';
$execGroupBy = $this->session->execGroupBy ? $this->session->execGroupBy : 'default';
$rdSearchValue = $this->session->rdSearchValue ? $this->session->rdSearchValue : '';
$execLaneType = $this->session->execLaneType ? $this->session->execLaneType : 'all';
$execGroupBy = $this->session->execGroupBy ? $this->session->execGroupBy : 'default';
if($execution->type == 'kanban')
{
$kanbanData = $this->loadModel('kanban')->getRDKanban($executionID, $execLaneType, 'id_desc', 0, $execGroupBy, $rdSearchValue);
$kanbanData = json_encode($kanbanData);
$rdSearchValue = $this->session->rdSearchValue ? $this->session->rdSearchValue : '';
$kanbanData = $this->loadModel('kanban')->getRDKanban($executionID, $execLaneType, 'id_desc', 0, $execGroupBy, $rdSearchValue);
$kanbanData = json_encode($kanbanData);
return print(js::closeModal('parent.parent', '', "parent.parent.updateKanban($kanbanData)"));
}
else
{
$kanbanData = $this->loadModel('kanban')->getExecutionKanban($execution->id, $execLaneType, $execGroupBy, $rdSearchValue);
$kanbanType = $execLaneType == 'all' ? 'story' : key($kanbanData);
$kanbanData = $kanbanData[$kanbanType];
$kanbanData = json_encode($kanbanData);
$taskSearchValue = $this->session->taskSearchValue ? $this->session->taskSearchValue : '';
$kanbanData = $this->loadModel('kanban')->getExecutionKanban($execution->id, $execLaneType, $execGroupBy, $taskSearchValue);
$kanbanType = $execLaneType == 'all' ? 'story' : key($kanbanData);
$kanbanData = $kanbanData[$kanbanType];
$kanbanData = json_encode($kanbanData);
return print(js::closeModal('parent.parent', '', "parent.parent.updateKanban(\"story\", $kanbanData)"));
}
}
@@ -749,22 +753,23 @@ class story extends control
$execution = $this->execution->getByID($this->session->execution);
if($this->app->tab == 'execution')
{
$execLaneType = $this->session->execLaneType ? $this->session->execLaneType : 'all';
$execGroupBy = $this->session->execGroupBy ? $this->session->execGroupBy : 'default';
$rdSearchValue = $this->session->rdSearchValue ? $this->session->rdSearchValue : '';
$execLaneType = $this->session->execLaneType ? $this->session->execLaneType : 'all';
$execGroupBy = $this->session->execGroupBy ? $this->session->execGroupBy : 'default';
if($execution->type == 'kanban')
{
$kanbanData = $this->loadModel('kanban')->getRDKanban($this->session->execution, $execLaneType, 'id_desc', 0, $kanbanGroup, $rdSearchValue);
$kanbanData = json_encode($kanbanData);
$rdSearchValue = $this->session->rdSearchValue ? $this->session->rdSearchValue : '';
$kanbanData = $this->loadModel('kanban')->getRDKanban($this->session->execution, $execLaneType, 'id_desc', 0, $kanbanGroup, $rdSearchValue);
$kanbanData = json_encode($kanbanData);
return print(js::closeModal('parent.parent', '', "parent.parent.updateKanban($kanbanData)"));
}
else
{
$kanbanData = $this->loadModel('kanban')->getExecutionKanban($execution->id, $execLaneType, $execGroupBy, $rdSearchValue);
$kanbanType = $execLaneType == 'all' ? 'story' : key($kanbanData);
$kanbanData = $kanbanData[$kanbanType];
$kanbanData = json_encode($kanbanData);
$taskSearchValue = $this->session->taskSearchValue ? $this->session->taskSearchValue : '';
$kanbanData = $this->loadModel('kanban')->getExecutionKanban($execution->id, $execLaneType, $execGroupBy, $taskSearchValue);
$kanbanType = $execLaneType == 'all' ? 'story' : key($kanbanData);
$kanbanData = $kanbanData[$kanbanType];
$kanbanData = json_encode($kanbanData);
return print(js::closeModal('parent.parent', '', "parent.parent.updateKanban(\"story\", $kanbanData)"));
}
}
@@ -1081,21 +1086,22 @@ class story extends control
$execution = $this->execution->getByID($this->session->execution);
if($this->app->tab == 'execution')
{
$execLaneType = $this->session->execLaneType ? $this->session->execLaneType : 'all';
$execGroupBy = $this->session->execGroupBy ? $this->session->execGroupBy : 'default';
$rdSearchValue = $this->session->rdSearchValue ? $this->session->rdSearchValue : '';
$execLaneType = $this->session->execLaneType ? $this->session->execLaneType : 'all';
$execGroupBy = $this->session->execGroupBy ? $this->session->execGroupBy : 'default';
if($execution->type == 'kanban')
{
$kanbanData = $this->loadModel('kanban')->getRDKanban($this->session->execution, $execLaneType, 'id_desc', 0, $execGroupBy, $rdSearchValue);
$kanbanData = json_encode($kanbanData);
$rdSearchValue = $this->session->rdSearchValue ? $this->session->rdSearchValue : '';
$kanbanData = $this->loadModel('kanban')->getRDKanban($this->session->execution, $execLaneType, 'id_desc', 0, $execGroupBy, $rdSearchValue);
$kanbanData = json_encode($kanbanData);
return print(js::closeModal('parent.parent', '', "parent.parent.updateKanban($kanbanData)"));
}
else
{
$kanbanData = $this->loadModel('kanban')->getExecutionKanban($execution->id, $execLaneType, $execGroupBy, $rdSearchValue);
$kanbanType = $execLaneType == 'all' ? 'story' : key($kanbanData);
$kanbanData = $kanbanData[$kanbanType];
$kanbanData = json_encode($kanbanData);
$taskSearchValue = $this->session->taskSearchValue ? $this->session->taskSearchValue : '';
$kanbanData = $this->loadModel('kanban')->getExecutionKanban($execution->id, $execLaneType, $execGroupBy, $taskSearchValue);
$kanbanType = $execLaneType == 'all' ? 'story' : key($kanbanData);
$kanbanData = $kanbanData[$kanbanType];
$kanbanData = json_encode($kanbanData);
return print(js::closeModal('parent.parent', '', "parent.parent.updateKanban(\"story\", $kanbanData)"));
}
}
@@ -1163,11 +1169,11 @@ class story extends control
$execution = $this->execution->getByID($this->session->execution);
if($this->app->tab == 'execution' and $execution->type == 'kanban')
{
$execLaneType = $this->session->execLaneType ? $this->session->execLaneType : 'all';
$execGroupBy = $this->session->execGroupBy ? $this->session->execGroupBy : 'default';
$rdSearchValue = $this->session->rdSearchValue ? $this->session->rdSearchValue : '';
$kanbanData = $this->loadModel('kanban')->getRDKanban($this->session->execution, $execLaneType, 'id_desc', 0, $execGroupBy, $rdSearchValue);
$kanbanData = json_encode($kanbanData);
$execLaneType = $this->session->execLaneType ? $this->session->execLaneType : 'all';
$execGroupBy = $this->session->execGroupBy ? $this->session->execGroupBy : 'default';
$taskSearchValue = $this->session->taskSearchValue ? $this->session->taskSearchValue : '';
$kanbanData = $this->loadModel('kanban')->getRDKanban($this->session->execution, $execLaneType, 'id_desc', 0, $execGroupBy, $taskSearchValue);
$kanbanData = json_encode($kanbanData);
return print(js::closeModal('parent.parent', '', "parent.parent.updateKanban($kanbanData)"));
}
@@ -1315,13 +1321,13 @@ class story extends control
if($this->app->tab == 'execution' and $from == 'taskkanban')
{
$execLaneType = $this->session->execLaneType ? $this->session->execLaneType : 'all';
$execGroupBy = $this->session->execGroupBy ? $this->session->execGroupBy : 'default';
$rdSearchValue = $this->session->rdSearchValue ? $this->session->rdSearchValue : '';
$kanbanData = $this->loadModel('kanban')->getExecutionKanban($this->session->execution, $execLaneType, $execGroupBy, $rdSearchValue);
$kanbanType = $execLaneType == 'all' ? 'story' : key($kanbanData);
$kanbanData = $kanbanData[$kanbanType];
$kanbanData = json_encode($kanbanData);
$execLaneType = $this->session->execLaneType ? $this->session->execLaneType : 'all';
$execGroupBy = $this->session->execGroupBy ? $this->session->execGroupBy : 'default';
$taskSearchValue = $this->session->taskSearchValue ? $this->session->taskSearchValue : '';
$kanbanData = $this->loadModel('kanban')->getExecutionKanban($this->session->execution, $execLaneType, $execGroupBy, $taskSearchValue);
$kanbanType = $execLaneType == 'all' ? 'story' : key($kanbanData);
$kanbanData = $kanbanData[$kanbanType];
$kanbanData = json_encode($kanbanData);
return print(js::closeModal('parent', '', "parent.updateKanban(\"story\", $kanbanData)"));
}
@@ -1363,21 +1369,22 @@ class story extends control
{
$this->loadModel('kanban')->updateLane($this->session->execution, 'story', $storyID);
$execLaneType = $this->session->execLaneType ? $this->session->execLaneType : 'all';
$execGroupBy = $this->session->execGroupBy ? $this->session->execGroupBy : 'default';
$rdSearchValue = $this->session->rdSearchValue ? $this->session->rdSearchValue : '';
$execLaneType = $this->session->execLaneType ? $this->session->execLaneType : 'all';
$execGroupBy = $this->session->execGroupBy ? $this->session->execGroupBy : 'default';
if($execution->type == 'kanban')
{
$kanbanData = $this->loadModel('kanban')->getRDKanban($this->session->execution, $execLaneType, 'id_desc', 0, $execGroupBy, $rdSearchValue);
$kanbanData = json_encode($kanbanData);
$rdSearchValue = $this->session->rdSearchValue ? $this->session->rdSearchValue : '';
$kanbanData = $this->loadModel('kanban')->getRDKanban($this->session->execution, $execLaneType, 'id_desc', 0, $execGroupBy, $rdSearchValue);
$kanbanData = json_encode($kanbanData);
return print(js::closeModal('parent.parent', '', "parent.parent.updateKanban($kanbanData)"));
}
else
{
$kanbanData = $this->loadModel('kanban')->getExecutionKanban($this->session->execution, $execLaneType, $execGroupBy, $rdSearchValue);
$kanbanType = $execLaneType == 'all' ? 'story' : key($kanbanData);
$kanbanData = $kanbanData[$kanbanType];
$kanbanData = json_encode($kanbanData);
$taskSearchValue = $this->session->taskSearchValue ? $this->session->taskSearchValue : '';
$kanbanData = $this->loadModel('kanban')->getExecutionKanban($this->session->execution, $execLaneType, $execGroupBy, $taskSearchValue);
$kanbanType = $execLaneType == 'all' ? 'story' : key($kanbanData);
$kanbanData = $kanbanData[$kanbanType];
$kanbanData = json_encode($kanbanData);
return print(js::closeModal('parent.parent', '', "parent.parent.updateKanban(\"story\", $kanbanData)"));
}
}
@@ -1506,12 +1513,12 @@ class story extends control
if(isonlybody())
{
$execution = $this->execution->getByID($this->session->execution);
$execLaneType = $this->session->execLaneType ? $this->session->execLaneType : 'all';
$execGroupBy = $this->session->execGroupBy ? $this->session->execGroupBy : 'default';
$rdSearchValue = $this->session->rdSearchValue ? $this->session->rdSearchValue : '';
$execution = $this->execution->getByID($this->session->execution);
$execLaneType = $this->session->execLaneType ? $this->session->execLaneType : 'all';
$execGroupBy = $this->session->execGroupBy ? $this->session->execGroupBy : 'default';
if($this->app->tab == 'execution' and $execution->type == 'kanban')
{
$rdSearchValue = $this->session->rdSearchValue ? $this->session->rdSearchValue : '';
$this->loadModel('kanban')->updateLane($this->session->execution, 'story', $storyID);
$kanbanData = $this->loadModel('kanban')->getRDKanban($this->session->execution, $execLaneType, 'id_desc', 0, $execGroupBy, $rdSearchValue);
@@ -1520,10 +1527,11 @@ class story extends control
}
elseif($from == 'taskkanban')
{
$kanbanData = $this->loadModel('kanban')->getExecutionKanban($this->session->execution, $execLaneType, $execGroupBy, $rdSearchValue);
$kanbanType = $execLaneType == 'all' ? 'story' : key($kanbanData);
$kanbanData = $kanbanData[$kanbanType];
$kanbanData = json_encode($kanbanData);
$taskSearchValue = $this->session->taskSearchValue ? $this->session->taskSearchValue : '';
$kanbanData = $this->loadModel('kanban')->getExecutionKanban($this->session->execution, $execLaneType, $execGroupBy, $taskSearchValue);
$kanbanType = $execLaneType == 'all' ? 'story' : key($kanbanData);
$kanbanData = $kanbanData[$kanbanType];
$kanbanData = json_encode($kanbanData);
return print(js::closeModal('parent.parent', '', "parent.parent.updateKanban(\"story\", $kanbanData)"));
}
else
@@ -1870,23 +1878,24 @@ class story extends control
if(isonlybody())
{
$execution = $this->execution->getByID($this->session->execution);
$execLaneType = $this->session->execLaneType ? $this->session->execLaneType : 'all';
$rdSearchValue = $this->session->rdSearchValue ? $this->session->rdSearchValue : '';
$execGroupBy = $this->session->execGroupBy ? $this->session->execGroupBy : 'default';
$execution = $this->execution->getByID($this->session->execution);
$execLaneType = $this->session->execLaneType ? $this->session->execLaneType : 'all';
$execGroupBy = $this->session->execGroupBy ? $this->session->execGroupBy : 'default';
if($this->app->tab == 'execution' and $execution->type == 'kanban')
{
$kanbanData = $this->loadModel('kanban')->getRDKanban($this->session->execution, $execLaneType, 'id_desc', 0, $kanbanGroup, $rdSearchValue);
$kanbanData = json_encode($kanbanData);
$rdSearchValue = $this->session->rdSearchValue ? $this->session->rdSearchValue : '';
$kanbanData = $this->loadModel('kanban')->getRDKanban($this->session->execution, $execLaneType, 'id_desc', 0, $kanbanGroup, $rdSearchValue);
$kanbanData = json_encode($kanbanData);
return print(js::closeModal('parent.parent', '', "parent.parent.updateKanban($kanbanData)"));
}
elseif($from == 'taskkanban')
{
$kanbanData = $this->loadModel('kanban')->getExecutionKanban($execution->id, $execLaneType, $execGroupBy, $rdSearchValue);
$kanbanType = $execLaneType == 'all' ? 'story' : key($kanbanData);
$kanbanData = $kanbanData[$kanbanType];
$kanbanData = json_encode($kanbanData);
return print(js::closeModal('parent.parent', '', "parent.parent.updateKanban(\"story\", $kanbanData)"));
$taskSearchValue = $this->session->taskSearchValue ? $this->session->taskSearchValue : '';
$kanbanData = $this->loadModel('kanban')->getExecutionKanban($execution->id, $execLaneType, $execGroupBy, $taskSearchValue);
$kanbanType = $execLaneType == 'all' ? 'story' : key($kanbanData);
$kanbanData = $kanbanData[$kanbanType];
$kanbanData = json_encode($kanbanData);
return print(js::closeModal('parent.parent', '', "parent.parent.updateKanban('$execLaneType', $kanbanData)"));
}
else
{
+1 -1
View File
@@ -3931,7 +3931,7 @@ class storyModel extends model
if($story->stage == 'projected') $title = $this->lang->story->subDivideTip['projected'];
}
}
$menu .= $this->buildMenu('story', 'batchCreate', "productID=$story->product&branch=$story->branch&module=$story->module&$params&executionID={$this->session->project}", $story, $type, 'split', '', 'showinonlybody', '', '', $title);
$menu .= $this->buildMenu('story', 'batchCreate', "productID=$story->product&branch=$story->branch&module=$story->module&$params", $story, $type, 'split', '', 'showinonlybody', '', '', $title);
}
if($this->app->rawModule == 'projectstory' and $this->config->vision != 'lite') $menu .= $this->buildMenu('projectstory', 'unlinkStory', "projectID={$this->session->project}&$params", $story, $type, 'unlink', 'hiddenwin', 'showinonlybody');
+219 -135
View File
@@ -49,6 +49,7 @@ class task extends control
$executionID = $this->execution->saveState($executionID, $executions);
$execution = $this->execution->getById($executionID);
$this->execution->setMenu($executionID);
if($this->app->tab == 'project') $this->loadModel('project')->setMenu($this->session->project);
$this->execution->getLimitedExecution();
$limitedExecutions = !empty($_SESSION['limitedExecutions']) ? $_SESSION['limitedExecutions'] : '';
@@ -185,22 +186,23 @@ class task extends control
{
if($this->app->tab == 'execution' or $this->config->vision == 'lite')
{
$execLaneType = $this->session->execLaneType ? $this->session->execLaneType : 'all';
$execGroupBy = $this->session->execGroupBy ? $this->session->execGroupBy : 'default';
$rdSearchValue = $this->session->rdSearchValue ? $this->session->rdSearchValue : '';
$execLaneType = $this->session->execLaneType ? $this->session->execLaneType : 'all';
$execGroupBy = $this->session->execGroupBy ? $this->session->execGroupBy : 'default';
if($execution->type == 'kanban')
{
$kanbanData = $this->loadModel('kanban')->getRDKanban($executionID, $execLaneType, 'id_desc', 0, $execGroupBy, $rdSearchValue);
$kanbanData = json_encode($kanbanData);
$rdSearchValue = $this->session->rdSearchValue ? $this->session->rdSearchValue : '';
$kanbanData = $this->loadModel('kanban')->getRDKanban($executionID, $execLaneType, 'id_desc', 0, $execGroupBy, $rdSearchValue);
$kanbanData = json_encode($kanbanData);
return $this->send(array('result' => 'success', 'message' => $this->lang->saveSuccess, 'closeModal' => true, 'callback' => "parent.updateKanban($kanbanData, 0)"));
}
else
{
$kanbanData = $this->kanban->getExecutionKanban($executionID, $execLaneType, $execGroupBy, $rdSearchValue);
$kanbanType = $execLaneType == 'all' ? 'task' : key($kanbanData);
$kanbanData = $kanbanData[$kanbanType];
$kanbanData = json_encode($kanbanData);
$taskSearchValue = $this->session->taskSearchValue ? $this->session->taskSearchValue : '';
$kanbanData = $this->kanban->getExecutionKanban($executionID, $execLaneType, $execGroupBy, $taskSearchValue);
$kanbanType = $execLaneType == 'all' ? 'task' : key($kanbanData);
$kanbanData = $kanbanData[$kanbanType];
$kanbanData = json_encode($kanbanData);
return $this->send(array('result' => 'success', 'message' => $this->lang->saveSuccess, 'closeModal' => true, 'callback' => "parent.updateKanban(\"task\", $kanbanData)"));
}
@@ -347,6 +349,7 @@ class task extends control
/* Set menu. */
$this->execution->setMenu($execution->id);
if($this->app->tab == 'project') $this->loadModel('project')->setMenu($this->session->project);
/* When common task are child tasks, query whether common task are consumed. */
$taskConsumed = 0;
@@ -372,22 +375,23 @@ class task extends control
{
if($this->app->tab == 'execution' or $this->config->vision == 'lite')
{
$execLaneType = $this->session->execLaneType ? $this->session->execLaneType : 'all';
$execGroupBy = $this->session->execGroupBy ? $this->session->execGroupBy : 'default';
$rdSearchValue = $this->session->rdSearchValue ? $this->session->rdSearchValue : '';
$execLaneType = $this->session->execLaneType ? $this->session->execLaneType : 'all';
$execGroupBy = $this->session->execGroupBy ? $this->session->execGroupBy : 'default';
if($execution->type == 'kanban')
{
$kanbanData = $this->loadModel('kanban')->getRDKanban($executionID, $execLaneType, 'id_desc', 0, $execGroupBy, $rdSearchValue);
$kanbanData = json_encode($kanbanData);
$rdSearchValue = $this->session->rdSearchValue ? $this->session->rdSearchValue : '';
$kanbanData = $this->loadModel('kanban')->getRDKanban($executionID, $execLaneType, 'id_desc', 0, $execGroupBy, $rdSearchValue);
$kanbanData = json_encode($kanbanData);
return print(js::closeModal('parent.parent', '', "parent.parent.updateKanban($kanbanData, 0)"));
}
else
{
$kanbanData = $this->loadModel('kanban')->getExecutionKanban($executionID, $execLaneType, $execGroupBy, $rdSearchValue);
$kanbanType = $execLaneType == 'all' ? 'task' : key($kanbanData);
$kanbanData = $kanbanData[$kanbanType];
$kanbanData = json_encode($kanbanData);
$taskSearchValue = $this->session->taskSearchValue ? $this->session->taskSearchValue : '';
$kanbanData = $this->loadModel('kanban')->getExecutionKanban($executionID, $execLaneType, $execGroupBy, $taskSearchValue);
$kanbanType = $execLaneType == 'all' ? 'task' : key($kanbanData);
$kanbanData = $kanbanData[$kanbanType];
$kanbanData = json_encode($kanbanData);
return print(js::closeModal('parent.parent', '', "parent.parent.updateKanban(\"task\", $kanbanData)"));
}
@@ -542,23 +546,24 @@ class task extends control
if(isonlybody())
{
$execution = $this->execution->getByID($task->execution);
$execLaneType = $this->session->execLaneType ? $this->session->execLaneType : 'all';
$execGroupBy = $this->session->execGroupBy ? $this->session->execGroupBy : 'default';
$rdSearchValue = $this->session->rdSearchValue ? $this->session->rdSearchValue : '';
$execution = $this->execution->getByID($task->execution);
$execLaneType = $this->session->execLaneType ? $this->session->execLaneType : 'all';
$execGroupBy = $this->session->execGroupBy ? $this->session->execGroupBy : 'default';
if($execution->type == 'kanban')
{
$kanbanData = $this->loadModel('kanban')->getRDKanban($task->execution, $execLaneType, 'id_desc', 0, $execGroupBy, $rdSearchValue);
$kanbanData = json_encode($kanbanData);
$rdSearchValue = $this->session->rdSearchValue ? $this->session->rdSearchValue : '';
$kanbanData = $this->loadModel('kanban')->getRDKanban($task->execution, $execLaneType, 'id_desc', 0, $execGroupBy, $rdSearchValue);
$kanbanData = json_encode($kanbanData);
return print(js::closeModal('parent.parent', '', "parent.parent.updateKanban($kanbanData)"));
}
else
{
$kanbanData = $this->loadModel('kanban')->getExecutionKanban($task->execution, $execLaneType, $execGroupBy, $rdSearchValue);
$kanbanType = $execLaneType == 'all' ? 'task' : key($kanbanData);
$kanbanData = $kanbanData[$kanbanType];
$kanbanData = json_encode($kanbanData);
$taskSearchValue = $this->session->taskSearchValue ? $this->session->taskSearchValue : '';
$kanbanData = $this->loadModel('kanban')->getExecutionKanban($task->execution, $execLaneType, $execGroupBy, $taskSearchValue);
$kanbanType = $execLaneType == 'all' ? 'task' : key($kanbanData);
$kanbanData = $kanbanData[$kanbanType];
$kanbanData = json_encode($kanbanData);
return print(js::closeModal('parent.parent', '', "parent.parent.updateKanban(\"task\", $kanbanData)"));
}
@@ -575,6 +580,8 @@ class task extends control
}
}
if($this->app->tab == 'project') $this->loadModel('project')->setMenu($this->session->project);
$tasks = $this->task->getParentTaskPairs($this->view->execution->id, $this->view->task->parent);
if(isset($tasks[$taskID])) unset($tasks[$taskID]);
@@ -777,24 +784,25 @@ class task extends control
if($this->viewType == 'json' or (defined('RUN_MODE') && RUN_MODE == 'api')) return $this->send(array('result' => 'success'));
if(isonlybody())
{
$task = $this->task->getById($taskID);
$execution = $this->execution->getByID($task->execution);
$execLaneType = $this->session->execLaneType ? $this->session->execLaneType : 'all';
$execGroupBy = $this->session->execGroupBy ? $this->session->execGroupBy : 'default';
$rdSearchValue = $this->session->rdSearchValue ? $this->session->rdSearchValue : '';
$task = $this->task->getById($taskID);
$execution = $this->execution->getByID($task->execution);
$execLaneType = $this->session->execLaneType ? $this->session->execLaneType : 'all';
$execGroupBy = $this->session->execGroupBy ? $this->session->execGroupBy : 'default';
if($execution->type == 'kanban')
{
$kanbanData = $this->loadModel('kanban')->getRDKanban($task->execution, $execLaneType, 'id_desc', 0, $execGroup, $rdSearchValue);
$kanbanData = json_encode($kanbanData);
$rdSearchValue = $this->session->rdSearchValue ? $this->session->rdSearchValue : '';
$kanbanData = $this->loadModel('kanban')->getRDKanban($task->execution, $execLaneType, 'id_desc', 0, $execGroup, $rdSearchValue);
$kanbanData = json_encode($kanbanData);
return print(js::closeModal('parent.parent', '', "parent.parent.updateKanban($kanbanData)"));
}
if($from == 'taskkanban')
{
$kanbanData = $this->loadModel('kanban')->getExecutionKanban($task->execution, $execLaneType, $execGroupBy, $rdSearchValue);
$kanbanType = $execLaneType == 'all' ? 'task' : key($kanbanData);
$kanbanData = $kanbanData[$kanbanType];
$kanbanData = json_encode($kanbanData);
$taskSearchValue = $this->session->taskSearchValue ? $this->session->taskSearchValue : '';
$kanbanData = $this->loadModel('kanban')->getExecutionKanban($task->execution, $execLaneType, $execGroupBy, $taskSearchValue);
$kanbanType = $execLaneType == 'all' ? 'task' : key($kanbanData);
$kanbanData = $kanbanData[$kanbanType];
$kanbanData = json_encode($kanbanData);
return print(js::closeModal('parent.parent', '', "parent.parent.updateKanban(\"task\", $kanbanData)"));
}
@@ -899,6 +907,7 @@ class task extends control
$this->session->set('executionList', $this->app->getURI(true), 'execution');
$this->commonAction($taskID);
if($this->app->tab == 'project') $this->loadModel('project')->setMenu($this->session->project);
$taskID = (int)$taskID;
$task = $this->task->getById($taskID, true);
@@ -1035,24 +1044,25 @@ class task extends control
if(isonlybody())
{
$execution = $this->execution->getByID($task->execution);
$execLaneType = $this->session->execLaneType ? $this->session->execLaneType : 'all';
$execGroupBy = $this->session->execGroupBy ? $this->session->execGroupBy : 'default';
$rdSearchValue = $this->session->rdSearchValue ? $this->session->rdSearchValue : '';
$execution = $this->execution->getByID($task->execution);
$execLaneType = $this->session->execLaneType ? $this->session->execLaneType : 'all';
$execGroupBy = $this->session->execGroupBy ? $this->session->execGroupBy : 'default';
if($execution->type == 'kanban')
{
$regionID = !empty($output['regionID']) ? $output['regionID'] : 0;
$kanbanData = $this->loadModel('kanban')->getRDKanban($task->execution, $execLaneType, 'id_desc', $regionID, $execGroupBy, $rdSearchValue);
$kanbanData = json_encode($kanbanData);
$rdSearchValue = $this->session->rdSearchValue ? $this->session->rdSearchValue : '';
$regionID = !empty($output['regionID']) ? $output['regionID'] : 0;
$kanbanData = $this->loadModel('kanban')->getRDKanban($task->execution, $execLaneType, 'id_desc', $regionID, $execGroupBy, $rdSearchValue);
$kanbanData = json_encode($kanbanData);
return print(js::closeModal('parent.parent', '', "parent.parent.updateKanban($kanbanData, $regionID)"));
}
if($output['from'] == 'taskkanban')
{
$kanbanData = $this->loadModel('kanban')->getExecutionKanban($task->execution, $execLaneType, $execGroupBy, $rdSearchValue);
$kanbanType = $execLaneType == 'all' ? 'task' : key($kanbanData);
$kanbanData = $kanbanData[$kanbanType];
$kanbanData = json_encode($kanbanData);
$taskSearchValue = $this->session->taskSearchValue ? $this->session->taskSearchValue : '';
$kanbanData = $this->loadModel('kanban')->getExecutionKanban($task->execution, $execLaneType, $execGroupBy, $taskSearchValue);
$kanbanType = $execLaneType == 'all' ? 'task' : key($kanbanData);
$kanbanData = $kanbanData[$kanbanType];
$kanbanData = json_encode($kanbanData);
return print(js::closeModal('parent.parent', '', "parent.parent.updateKanban(\"task\", $kanbanData)"));
}
@@ -1110,20 +1120,21 @@ class task extends control
$execution = $this->execution->getByID($task->execution);
$execLaneType = $this->session->execLaneType ? $this->session->execLaneType : 'all';
$execGroupBy = $this->session->execGroupBy ? $this->session->execGroupBy : 'default';
$rdSearchValue = $this->session->rdSearchValue ? $this->session->rdSearchValue : '';
if($execution->type == 'kanban')
{
$kanbanData = $this->loadModel('kanban')->getRDKanban($task->execution, $execLaneType, 'id_desc', 0, $execGroupBy, $rdSearchValue);
$kanbanData = json_encode($kanbanData);
$rdSearchValue = $this->session->rdSearchValue ? $this->session->rdSearchValue : '';
$kanbanData = $this->loadModel('kanban')->getRDKanban($task->execution, $execLaneType, 'id_desc', 0, $execGroupBy, $rdSearchValue);
$kanbanData = json_encode($kanbanData);
return print(js::closeModal('parent.parent', '', "parent.parent.updateKanban($kanbanData)"));
}
if($from == 'taskkanban')
{
$kanbanData = $this->loadModel('kanban')->getExecutionKanban($task->execution, $execLaneType, $execGroupBy, $rdSearchValue);
$kanbanType = $execLaneType == 'all' ? 'task' : key($kanbanData);
$kanbanData = $kanbanData[$kanbanType];
$kanbanData = json_encode($kanbanData);
$taskSearchValue = $this->session->taskSearchValue ? $this->session->taskSearchValue : '';
$kanbanData = $this->loadModel('kanban')->getExecutionKanban($task->execution, $execLaneType, $execGroupBy, $taskSearchValue);
$kanbanType = $execLaneType == 'all' ? 'task' : key($kanbanData);
$kanbanData = $kanbanData[$kanbanType];
$kanbanData = json_encode($kanbanData);
return print(js::closeModal('parent.parent', '', "parent.parent.updateKanban(\"task\", $kanbanData)"));
}
@@ -1182,19 +1193,36 @@ class task extends control
*/
public function deleteEstimate($estimateID, $confirm = 'no')
{
if($confirm == 'no')
$estimate = $this->task->getEstimateById($estimateID);
$task = $this->task->getById($estimate->task);
if($confirm == 'no' and $task->consumed - $estimate->consumed != 0)
{
return print(js::confirm($this->lang->task->confirmDeleteEstimate, $this->createLink('task', 'deleteEstimate', "estimateID=$estimateID&confirm=yes")));
}
elseif($confirm == 'no' and $task->consumed - $estimate->consumed == 0)
{
return print(js::confirm($this->lang->task->confirmDeleteLastEstimate, $this->createLink('task', 'deleteEstimate', "estimateID=$estimateID&confirm=yes")));
}
else
{
$estimate = $this->task->getEstimateById($estimateID);
$changes = $this->task->deleteEstimate($estimateID);
if(dao::isError()) return print(js::error(dao::getError()));
$actionID = $this->loadModel('action')->create('task', $estimate->task, 'DeleteEstimate');
$this->action->logHistory($actionID, $changes);
return print(js::reload('parent'));
if($task->consumed - $estimate->consumed == 0)
{
$actionID = $this->loadModel('action')->create('task', $estimate->task, 'Adjusttasktowait');
$this->action->logHistory($actionID, $changes);
}
if($task->consumed - $estimate->consumed == 0)
{
return print(js::reload('parent.parent'));
}
else
{
return print(js::reload('parent'));
}
}
}
@@ -1251,24 +1279,25 @@ class task extends control
if(isonlybody())
{
$execution = $this->execution->getByID($task->execution);
$execLaneType = $this->session->execLaneType ? $this->session->execLaneType : 'all';
$execGroupBy = $this->session->execGroupBy ? $this->session->execGroupBy : 'default';
$rdSearchValue = $this->session->rdSearchValue ? $this->session->rdSearchValue : '';
$execution = $this->execution->getByID($task->execution);
$execLaneType = $this->session->execLaneType ? $this->session->execLaneType : 'all';
$execGroupBy = $this->session->execGroupBy ? $this->session->execGroupBy : 'default';
if($execution->type == "kanban")
{
$regionID = !empty($output['regionID']) ? $output['regionID'] : 0;
$kanbanData = $this->loadModel('kanban')->getRDKanban($task->execution, $execLaneType, 'id_desc', $regionID, $execGroupBy, $rdSearchValue);
$kanbanData = json_encode($kanbanData);
$rdSearchValue = $this->session->rdSearchValue ? $this->session->rdSearchValue : '';
$regionID = !empty($output['regionID']) ? $output['regionID'] : 0;
$kanbanData = $this->loadModel('kanban')->getRDKanban($task->execution, $execLaneType, 'id_desc', $regionID, $execGroupBy, $rdSearchValue);
$kanbanData = json_encode($kanbanData);
return print(js::closeModal('parent.parent', '', "parent.parent.updateKanban($kanbanData, $regionID)"));
}
if($output['from'] == "taskkanban")
{
$kanbanData = $this->loadModel('kanban')->getExecutionKanban($task->execution, $execLaneType, $execGroupBy, $rdSearchValue);
$kanbanType = $execLaneType == 'all' ? 'task' : key($kanbanData);
$kanbanData = $kanbanData[$kanbanType];
$kanbanData = json_encode($kanbanData);
$taskSearchValue = $this->session->taskSearchValue ? $this->session->taskSearchValue : '';
$kanbanData = $this->loadModel('kanban')->getExecutionKanban($task->execution, $execLaneType, $execGroupBy, $taskSearchValue);
$kanbanType = $execLaneType == 'all' ? 'task' : key($kanbanData);
$kanbanData = $kanbanData[$kanbanType];
$kanbanData = json_encode($kanbanData);
return print(js::closeModal('parent.parent', '', "parent.parent.updateKanban(\"task\", $kanbanData)"));
}
@@ -1347,25 +1376,26 @@ class task extends control
if(isonlybody())
{
$task = $this->task->getById($taskID);
$execution = $this->execution->getByID($task->execution);
$execLaneType = $this->session->execLaneType ? $this->session->execLaneType : 'all';
$execGroupBy = $this->session->execGroupBy ? $this->session->execGroupBy : 'default';
$rdSearchValue = $this->session->rdSearchValue ? $this->session->rdSearchValue : '';
$task = $this->task->getById($taskID);
$execution = $this->execution->getByID($task->execution);
$execLaneType = $this->session->execLaneType ? $this->session->execLaneType : 'all';
$execGroupBy = $this->session->execGroupBy ? $this->session->execGroupBy : 'default';
if($execution->type == 'kanban')
{
$regionID = !empty($output['regionID']) ? $output['regionID'] : 0;
$kanbanData = $this->loadModel('kanban')->getRDKanban($task->execution, $execLaneType, 'id_desc', $regionID, $execGroupBy, $rdSearchValue);
$kanbanData = json_encode($kanbanData);
$rdSearchValue = $this->session->rdSearchValue ? $this->session->rdSearchValue : '';
$regionID = !empty($output['regionID']) ? $output['regionID'] : 0;
$kanbanData = $this->loadModel('kanban')->getRDKanban($task->execution, $execLaneType, 'id_desc', $regionID, $execGroupBy, $rdSearchValue);
$kanbanData = json_encode($kanbanData);
return print(js::closeModal('parent.parent', '', "parent.parent.updateKanban($kanbanData, $regionID)"));
}
if($output['from'] == 'taskkanban')
{
$kanbanData = $this->loadModel('kanban')->getExecutionKanban($task->execution, $execLaneType, $execGroupBy, $rdSearchValue);
$kanbanType = $execLaneType == 'all' ? 'task' : key($kanbanData);
$kanbanData = $kanbanData[$kanbanType];
$kanbanData = json_encode($kanbanData);
$taskSearchValue = $this->session->taskSearchValue ? $this->session->taskSearchValue : '';
$kanbanData = $this->loadModel('kanban')->getExecutionKanban($task->execution, $execLaneType, $execGroupBy, $taskSearchValue);
$kanbanType = $execLaneType == 'all' ? 'task' : key($kanbanData);
$kanbanData = $kanbanData[$kanbanType];
$kanbanData = json_encode($kanbanData);
return print(js::closeModal('parent.parent', '', "parent.parent.updateKanban(\"task\", $kanbanData)"));
}
@@ -1413,24 +1443,25 @@ class task extends control
if(isonlybody())
{
$task = $this->task->getById($taskID);
$execution = $this->execution->getByID($task->execution);
$execLaneType = $this->session->execLaneType ? $this->session->execLaneType : 'all';
$execGroupBy = $this->session->execGroupBy ? $this->session->execGroupBy : 'default';
$rdSearchValue = $this->session->rdSearchValue ? $this->session->rdSearchValue : '';
$task = $this->task->getById($taskID);
$execution = $this->execution->getByID($task->execution);
$execLaneType = $this->session->execLaneType ? $this->session->execLaneType : 'all';
$execGroupBy = $this->session->execGroupBy ? $this->session->execGroupBy : 'default';
if($execution->type == 'kanban')
{
$kanbanData = $this->loadModel('kanban')->getRDKanban($task->execution, $execLaneType, 'id_desc', 0, $execGroupBy, $rdSearchValue);
$kanbanData = json_encode($kanbanData);
$rdSearchValue = $this->session->rdSearchValue ? $this->session->rdSearchValue : '';
$kanbanData = $this->loadModel('kanban')->getRDKanban($task->execution, $execLaneType, 'id_desc', 0, $execGroupBy, $rdSearchValue);
$kanbanData = json_encode($kanbanData);
return print(js::closeModal('parent.parent', '', "parent.parent.updateKanban($kanbanData)"));
}
if($from == 'taskkanban')
{
$kanbanData = $this->loadModel('kanban')->getExecutionKanban($task->execution, $execLaneType, $execGroupBy, $rdSearchValue);
$kanbanType = $execLaneType == 'all' ? 'task' : key($kanbanData);
$kanbanData = $kanbanData[$kanbanType];
$kanbanData = json_encode($kanbanData);
$taskSearchValue = $this->session->taskSearchValue ? $this->session->taskSearchValue : '';
$kanbanData = $this->loadModel('kanban')->getExecutionKanban($task->execution, $execLaneType, $execGroupBy, $taskSearchValue);
$kanbanType = $execLaneType == 'all' ? 'task' : key($kanbanData);
$kanbanData = $kanbanData[$kanbanType];
$kanbanData = json_encode($kanbanData);
return print(js::closeModal('parent.parent', '', "parent.parent.updateKanban(\"task\", $kanbanData)"));
}
@@ -1495,23 +1526,24 @@ class task extends control
}
}
$execLaneType = $this->session->execLaneType ? $this->session->execLaneType : 'all';
$execGroupBy = $this->session->execGroupBy ? $this->session->execGroupBy : 'default';
$rdSearchValue = $this->session->rdSearchValue ? $this->session->rdSearchValue : '';
$execLaneType = $this->session->execLaneType ? $this->session->execLaneType : 'all';
$execGroupBy = $this->session->execGroupBy ? $this->session->execGroupBy : 'default';
if($execution->type == 'kanban')
{
$regionID = !empty($output['regionID']) ? $output['regionID'] : 0;
$kanbanData = $this->loadModel('kanban')->getRDKanban($task->execution, $execLaneType, 'id_desc', $regionID, $execGroupBy, $rdSearchValue);
$kanbanData = json_encode($kanbanData);
$rdSearchValue = $this->session->rdSearchValue ? $this->session->rdSearchValue : '';
$regionID = !empty($output['regionID']) ? $output['regionID'] : 0;
$kanbanData = $this->loadModel('kanban')->getRDKanban($task->execution, $execLaneType, 'id_desc', $regionID, $execGroupBy, $rdSearchValue);
$kanbanData = json_encode($kanbanData);
return print(js::closeModal('parent.parent', '', "parent.parent.updateKanban($kanbanData, $regionID)"));
}
if($output['from'] == 'taskkanban')
{
$kanbanData = $this->loadModel('kanban')->getExecutionKanban($task->execution, $execLaneType, $execGroupBy, $rdSearchValue);
$kanbanType = $execLaneType == 'all' ? 'task' : key($kanbanData);
$kanbanData = $kanbanData[$kanbanType];
$kanbanData = json_encode($kanbanData);
$taskSearchValue = $this->session->taskSearchValue ? $this->session->taskSearchValue : '';
$kanbanData = $this->loadModel('kanban')->getExecutionKanban($task->execution, $execLaneType, $execGroupBy, $taskSearchValue);
$kanbanType = $execLaneType == 'all' ? 'task' : key($kanbanData);
$kanbanData = $kanbanData[$kanbanType];
$kanbanData = json_encode($kanbanData);
return print(js::closeModal('parent.parent', '', "parent.parent.updateKanban(\"task\", $kanbanData)"));
}
@@ -1665,25 +1697,26 @@ class task extends control
if(isonlybody())
{
$task = $this->task->getById($taskID);
$execution = $this->execution->getByID($task->execution);
$execLaneType = $this->session->execLaneType ? $this->session->execLaneType : 'all';
$execGroupBy = $this->session->execGroupBy ? $this->session->execGroupBy : 'default';
$rdSearchValue = $this->session->rdSearchValue ? $this->session->rdSearchValue : '';
$task = $this->task->getById($taskID);
$execution = $this->execution->getByID($task->execution);
$execLaneType = $this->session->execLaneType ? $this->session->execLaneType : 'all';
$execGroupBy = $this->session->execGroupBy ? $this->session->execGroupBy : 'default';
if($execution->type == 'kanban')
{
$regionID = !empty($output['regionID']) ? $output['regionID'] : 0;
$kanbanData = $this->loadModel('kanban')->getRDKanban($task->execution, $execLaneType, 'id_desc', $regionID, $execGroupBy, $rdSearchValue);
$kanbanData = json_encode($kanbanData);
$rdSearchValue = $this->session->rdSearchValue ? $this->session->rdSearchValue : '';
$regionID = !empty($output['regionID']) ? $output['regionID'] : 0;
$kanbanData = $this->loadModel('kanban')->getRDKanban($task->execution, $execLaneType, 'id_desc', $regionID, $execGroupBy, $rdSearchValue);
$kanbanData = json_encode($kanbanData);
return print(js::closeModal('parent.parent', '', "parent.parent.updateKanban($kanbanData, $regionID)"));
}
if($output['from'] == 'taskkanban')
{
$kanbanData = $this->loadModel('kanban')->getExecutionKanban($task->execution, $execLaneType, $execGroupBy, $rdSearchValue);
$kanbanType = $execLaneType == 'all' ? 'task' : key($kanbanData);
$kanbanData = $kanbanData[$kanbanType];
$kanbanData = json_encode($kanbanData);
$taskSearchValue = $this->session->taskSearchValue ? $this->session->taskSearchValue : '';
$kanbanData = $this->loadModel('kanban')->getExecutionKanban($task->execution, $execLaneType, $execGroupBy, $taskSearchValue);
$kanbanType = $execLaneType == 'all' ? 'task' : key($kanbanData);
$kanbanData = $kanbanData[$kanbanType];
$kanbanData = json_encode($kanbanData);
return print(js::closeModal('parent.parent', '', "parent.parent.updateKanban(\"task\", $kanbanData)"));
}
@@ -1730,25 +1763,26 @@ class task extends control
if(isonlybody())
{
$task = $this->task->getById($taskID);
$execution = $this->execution->getByID($task->execution);
$execLaneType = $this->session->execLaneType ? $this->session->execLaneType : 'all';
$execGroupBy = $this->session->execGroupBy ? $this->session->execGroupBy : 'default';
$rdSearchValue = $this->session->rdSearchValue ? $this->session->rdSearchValue : '';
$task = $this->task->getById($taskID);
$execution = $this->execution->getByID($task->execution);
$execLaneType = $this->session->execLaneType ? $this->session->execLaneType : 'all';
$execGroupBy = $this->session->execGroupBy ? $this->session->execGroupBy : 'default';
if($execution->type == "kanban")
{
$regionID = !empty($output['regionID']) ? $output['regionID'] : 0;
$kanbanData = $this->loadModel('kanban')->getRDKanban($task->execution, $execLaneType, 'id_desc', $regionID, $execGroupBy, $rdSearchValue);
$kanbanData = json_encode($kanbanData);
$rdSearchValue = $this->session->rdSearchValue ? $this->session->rdSearchValue : '';
$regionID = !empty($output['regionID']) ? $output['regionID'] : 0;
$kanbanData = $this->loadModel('kanban')->getRDKanban($task->execution, $execLaneType, 'id_desc', $regionID, $execGroupBy, $rdSearchValue);
$kanbanData = json_encode($kanbanData);
return print(js::closeModal('parent.parent', '', "parent.parent.updateKanban($kanbanData, $regionID)"));
}
if($output['from'] == "taskkanban")
{
$kanbanData = $this->loadModel('kanban')->getExecutionKanban($task->execution, $execLaneType, $execGroupBy, $rdSearchValue);
$kanbanType = $execLaneType == 'all' ? 'task' : key($kanbanData);
$kanbanData = $kanbanData[$kanbanType];
$kanbanData = json_encode($kanbanData);
$taskSearchValue = $this->session->taskSearchValue ? $this->session->taskSearchValue : '';
$kanbanData = $this->loadModel('kanban')->getExecutionKanban($task->execution, $execLaneType, $execGroupBy, $taskSearchValue);
$kanbanType = $execLaneType == 'all' ? 'task' : key($kanbanData);
$kanbanData = $kanbanData[$kanbanType];
$kanbanData = json_encode($kanbanData);
return print(js::closeModal('parent.parent', '', "parent.parent.updateKanban(\"task\", $kanbanData)"));
}
@@ -1806,13 +1840,13 @@ class task extends control
if(isonlybody()) return print(js::reload('parent.parent'));
if($from == 'taskkanban')
{
$execLaneType = $this->session->execLaneType ? $this->session->execLaneType : 'all';
$execGroupBy = $this->session->execGroupBy ? $this->session->execGroupBy : 'default';
$rdSearchValue = $this->session->rdSearchValue ? $this->session->rdSearchValue : '';
$kanbanData = $this->loadModel('kanban')->getExecutionKanban($this->session->execution, $execLaneType, $execGroupBy, $rdSearchValue);
$kanbanType = $execLaneType == 'all' ? 'task' : key($kanbanData);
$kanbanData = $kanbanData[$kanbanType];
$kanbanData = json_encode($kanbanData);
$execLaneType = $this->session->execLaneType ? $this->session->execLaneType : 'all';
$execGroupBy = $this->session->execGroupBy ? $this->session->execGroupBy : 'default';
$taskSearchValue = $this->session->taskSearchValue ? $this->session->taskSearchValue : '';
$kanbanData = $this->loadModel('kanban')->getExecutionKanban($this->session->execution, $execLaneType, $execGroupBy, $taskSearchValue);
$kanbanType = $execLaneType == 'all' ? 'task' : key($kanbanData);
$kanbanData = $kanbanData[$kanbanType];
$kanbanData = json_encode($kanbanData);
return print(js::closeModal('parent', '', "parent.updateKanban(\"task\", $kanbanData)"));
}
@@ -1862,6 +1896,56 @@ class task extends control
echo html::select('task', empty($tasks) ? array('' => '') : $tasks, $taskID, "class='form-control'");
}
/**
* Ajax get tasks for execution list.
*
* @param int $executionID
* @param int $maxTaskID
* @access public
* @return void
*/
public function ajaxGetTasks($executionID, $maxTaskID = 0)
{
$this->loadModel('task');
$this->loadModel('execution');
$execution = $this->dao->findById($executionID)->from(TABLE_EXECUTION)->fetch();
$tasks = $this->dao->select('*')->from(TABLE_TASK)
->where('deleted')->eq(0)
->andWhere('status')->notin('closed,cancel')
->andWhere('execution')->eq($executionID)
->andWhere('id')->gt($maxTaskID)
->orderBy('id_asc')
->fetchAll('id');
$users = $this->loadModel('user')->getPairs('noletter|nodeleted');
foreach($tasks as $task)
{
if($task->parent > 0)
{
if(isset($tasks[$task->parent]))
{
$tasks[$task->parent]->children[$task->id] = $task;
unset($tasks[$task->id]);
}
}
}
if(empty($tasks)) die('');
$list = '';
$tasks = array_chunk($tasks, 50, true);
$tasks = $tasks[0];
$count = count($tasks);
foreach($tasks as $task)
{
$showmore = ($count == 50) && ($task == end($tasks));
$list .= $this->task->buildNestedList($execution, $task, false, $showmore, $users);
}
die($list);
}
/**
* AJAX: get the actions of a task. for web app.
*
+6 -4
View File
@@ -127,7 +127,8 @@ function loadExecutionStories(executionID)
*/
function loadModuleMenu(executionID)
{
var link = createLink('tree', 'ajaxGetOptionMenu', 'rootID=' + executionID + '&viewtype=task');
var extra = $('#showAllModule').prop('checked') ? 'allModule' : '';
var link = createLink('tree', 'ajaxGetOptionMenu', 'rootID=' + executionID + '&viewtype=task&branch=0&rootModuleID=0&returnType=html&fieldID=&needManage=0&extra=' + extra);
$('#moduleIdBox').load(link, function(){$('#module').chosen();});
}
@@ -501,11 +502,12 @@ $(document).ready(function()
$('#showAllModule').change(function()
{
var moduleID = $('#moduleIdBox #module').val();
var extra = $(this).prop('checked') ? 'allModule' : '';
var executionID = $('#execution').val();
var moduleID = $('#moduleIdBox #module').val();
var extra = $(this).prop('checked') ? 'allModule' : '';
$('#moduleIdBox').load(createLink('tree', 'ajaxGetOptionMenu', "rootID=" + executionID + '&viewType=task&branch=0&rootModuleID=0&returnType=html&fieldID=&needManage=0&extra=' + extra), function()
{
$('#moduleIdBox #module').val(moduleID).chosen();
$('#module').val(moduleID).chosen();
});
});
});
+21 -21
View File
@@ -214,27 +214,27 @@ $lang->task->legendDesc = 'Aufgabenbeschreibung';
$lang->task->legendDetail = 'Task Detail';
$lang->task->legendMisc = 'Misc.';
$lang->task->confirmDelete = "Möchten Sie diese Aufgabe löschen?";
$lang->task->confirmDeleteEstimate = "Möchten Sie das löschen?";
$lang->task->copyStoryTitle = "Story kopieren";
$lang->task->afterSubmit = "Nach der Erstellung,";
$lang->task->successSaved = "Erstellt!";
$lang->task->delayWarning = " <strong class='text-danger'> Verzögerung %s Tage </strong>";
$lang->task->remindBug = "Diese Aufgabe wurde aus einem Bus erzeugt. Möchten Sie den Bug aktualisieren:%s?";
$lang->task->remindIssue = "This task is converted from a issue. Do you want to update the Issue:%s?";
$lang->task->confirmChangeExecution = "Wenn Sie {$lang->executionCommon} ändern, das verwendete Modul, Story and Assignor will be changed. Do you want to do it?";
$lang->task->confirmFinish = '"Reststunden " sind 0. Möchten Sue den Status auf Erledigt setzen?';
$lang->task->confirmRecord = '"Reststunden " sind 0. Möchten Sie den Task auf Erledigt setzen?';
$lang->task->confirmTransfer = '"Reststunden " sind 0. Möchten Sie den Task transferieren?';
$lang->task->noticeTaskStart = '"Cost Hour" and "Left Hour" cannot be 0 at the same time.';
$lang->task->noticeLinkStory = "Es wurde keine Story verknüpft. Sie können %s für dieses Projekt, anschließend %s.";
$lang->task->noticeSaveRecord = 'Ihre Stunden wurden nicht gespeichrt. Bitte erst speichern.';
$lang->task->commentActions = '%s. %s, kommentiert von <strong>%s</strong>.';
$lang->task->deniedNotice = 'Nur %s kann die Aufgabe %s.';
$lang->task->noTask = 'Keine Aufagben. ';
$lang->task->createDenied = 'Aufgben erstellen it in diesem Projekt gesperrt';
$lang->task->cannotDeleteParent = 'Cannot delete parent task';
$lang->task->addChildTask = 'Because the task has already consumed consumption, to ensure data consistency, we will help you create a subtask with the same name to record the consumption.';
$lang->task->confirmDelete = "Möchten Sie diese Aufgabe löschen?";
$lang->task->confirmDeleteLastEstimate = "Do you want to delete the log? After deleting the last work log, the task status will be adjusted to Not Started.";
$lang->task->copyStoryTitle = "Story kopieren";
$lang->task->afterSubmit = "Nach der Erstellung,";
$lang->task->successSaved = "Erstellt!";
$lang->task->delayWarning = " <strong class='text-danger'> Verzögerung %s Tage </strong>";
$lang->task->remindBug = "Diese Aufgabe wurde aus einem Bus erzeugt. Möchten Sie den Bug aktualisieren:%s?";
$lang->task->remindIssue = "This task is converted from a issue. Do you want to update the Issue:%s?";
$lang->task->confirmChangeExecution = "Wenn Sie {$lang->executionCommon} ändern, das verwendete Modul, Story and Assignor will be changed. Do you want to do it?";
$lang->task->confirmFinish = '"Reststunden " sind 0. Möchten Sue den Status auf Erledigt setzen?';
$lang->task->confirmRecord = '"Reststunden " sind 0. Möchten Sie den Task auf Erledigt setzen?';
$lang->task->confirmTransfer = '"Reststunden " sind 0. Möchten Sie den Task transferieren?';
$lang->task->noticeTaskStart = '"Cost Hour" and "Left Hour" cannot be 0 at the same time.';
$lang->task->noticeLinkStory = "Es wurde keine Story verknüpft. Sie können %s für dieses Projekt, anschließend %s.";
$lang->task->noticeSaveRecord = 'Ihre Stunden wurden nicht gespeichrt. Bitte erst speichern.';
$lang->task->commentActions = '%s. %s, kommentiert von <strong>%s</strong>.';
$lang->task->deniedNotice = 'Nur %s kann die Aufgabe %s.';
$lang->task->noTask = 'Keine Aufagben. ';
$lang->task->createDenied = 'Aufgben erstellen it in diesem Projekt gesperrt';
$lang->task->cannotDeleteParent = 'Cannot delete parent task';
$lang->task->addChildTask = 'Because the task has already consumed consumption, to ensure data consistency, we will help you create a subtask with the same name to record the consumption.';
$lang->task->error = new stdclass();
$lang->task->error->totalNumber = '"Total Cost" must be numbers.';
+22 -21
View File
@@ -214,27 +214,28 @@ $lang->task->legendDesc = 'Task Description';
$lang->task->legendDetail = 'Task Detail';
$lang->task->legendMisc = 'Misc.';
$lang->task->confirmDelete = "Do you want to delete this task?";
$lang->task->confirmDeleteEstimate = "Do you want to delete it?";
$lang->task->copyStoryTitle = "Copy Story";
$lang->task->afterSubmit = "Next ";
$lang->task->successSaved = "Created!";
$lang->task->delayWarning = " <strong class='text-danger'> Delay %s days </strong>";
$lang->task->remindBug = "This task is converted from a bug. Do you want to update the Bug:%s?";
$lang->task->remindIssue = "This task is converted from a issue. Do you want to update the Issue:%s?";
$lang->task->confirmChangeExecution = "If you change {$lang->executionCommon}, Module, Story and AssignedTo will also be changed. Do you want to change it?";
$lang->task->confirmFinish = '"Left Hour" is 0. Do you want to change the status to "Finished"?';
$lang->task->confirmRecord = '"Left Hour" is 0. Do you want to set the task as "Finished"?';
$lang->task->confirmTransfer = '"Left Hour" is 0,Do you want to transfer task?';
$lang->task->noticeTaskStart = '"Cost Hour" and "Left Hour" cannot be 0 at the same time.';
$lang->task->noticeLinkStory = "No story has been linked. You can %s for this project, then %s.";
$lang->task->noticeSaveRecord = 'Your Hour is not saved. Please save it first.';
$lang->task->commentActions = '%s. %s, commented by <strong>%s</strong>.';
$lang->task->deniedNotice = 'Only the %s can %s the task.';
$lang->task->noTask = 'No tasks yet. ';
$lang->task->createDenied = 'Create Task is denied in this project';
$lang->task->cannotDeleteParent = 'Cannot delete parent task';
$lang->task->addChildTask = 'Because the task has cost hours, ZenTao will create a child task with the same name to record the cost housrs to ensure data consistency.';
$lang->task->confirmDelete = "Do you want to delete this task?";
$lang->task->confirmDeleteEstimate = "Do you want to delete it?";
$lang->task->confirmDeleteLastEstimate = "Do you want to delete the log? After deleting the last work log, the task status will be adjusted to Not Started.";
$lang->task->copyStoryTitle = "Copy Story";
$lang->task->afterSubmit = "Next ";
$lang->task->successSaved = "Created!";
$lang->task->delayWarning = " <strong class='text-danger'> Delay %s days </strong>";
$lang->task->remindBug = "This task is converted from a bug. Do you want to update the Bug:%s?";
$lang->task->remindIssue = "This task is converted from a issue. Do you want to update the Issue:%s?";
$lang->task->confirmChangeExecution = "If you change {$lang->executionCommon}, Module, Story and AssignedTo will also be changed. Do you want to change it?";
$lang->task->confirmFinish = '"Left Hour" is 0. Do you want to change the status to "Finished"?';
$lang->task->confirmRecord = '"Left Hour" is 0. Do you want to set the task as "Finished"?';
$lang->task->confirmTransfer = '"Left Hour" is 0,Do you want to transfer task?';
$lang->task->noticeTaskStart = '"Cost Hour" and "Left Hour" cannot be 0 at the same time.';
$lang->task->noticeLinkStory = "No story has been linked. You can %s for this project, then %s.";
$lang->task->noticeSaveRecord = 'Your Hour is not saved. Please save it first.';
$lang->task->commentActions = '%s. %s, commented by <strong>%s</strong>.';
$lang->task->deniedNotice = 'Only the %s can %s the task.';
$lang->task->noTask = 'No tasks yet. ';
$lang->task->createDenied = 'Create Task is denied in this project';
$lang->task->cannotDeleteParent = 'Cannot delete parent task';
$lang->task->addChildTask = 'Because the task has cost hours, ZenTao will create a child task with the same name to record the cost housrs to ensure data consistency.';
$lang->task->error = new stdclass();
$lang->task->error->totalNumber = '"Total Cost" must be numbers.';
+22 -21
View File
@@ -214,27 +214,28 @@ $lang->task->legendDesc = 'Description Tâche';
$lang->task->legendDetail = 'Task Detail';
$lang->task->legendMisc = 'Misc.';
$lang->task->confirmDelete = "Voulez-vous réellement supprimer cette tâche ?";
$lang->task->confirmDeleteEstimate = "Voulez-vous la supprimer ?";
$lang->task->copyStoryTitle = '<span style="color:blue;">StoryModel</span>';
$lang->task->afterSubmit = "Suiv. ";
$lang->task->successSaved = "Créée !";
$lang->task->delayWarning = " <strong class='text-danger'> Retard %s jours </strong>";
$lang->task->remindBug = "Cette tâche a été convertie depuis un bug. Voulez-vous mettre à jour le Bug : %s ?";
$lang->task->remindIssue = "This task is converted from a issue. Do you want to update the Issue:%s?";
$lang->task->confirmChangeExecution = "Si vous changez {$lang->executionCommon}, Module, Story et AssignedTo seront également changés. Voulez-vous le faire ?";
$lang->task->confirmFinish = '"Heures Restantes" à 0. Voulez-vous passer le statut à "Terminée" ?';
$lang->task->confirmRecord = '"Heures Restantes" à 0. Voulez-vous passer le statut de la tâche à "Finie" ?';
$lang->task->confirmTransfer = '"Heures Restantes" à 0. Voulez-vous transférer la tâche ?';
$lang->task->noticeTaskStart = '"Cost Hour" and "Left Hour" cannot be 0 at the same time.';
$lang->task->noticeLinkStory = "Aucune Story n'est associée. Vous pouvez %s pour ce projet, alors %s.";
$lang->task->noticeSaveRecord = "Votre temps n'a pas été sauvé. Enregistrez-le d'abord.";
$lang->task->commentActions = '%s. %s, commenté par <strong>%s</strong>.';
$lang->task->deniedNotice = 'Seulement le %s peut %s la tâche.';
$lang->task->noTask = "Pas de tâche pour l'instant. ";
$lang->task->createDenied = 'La création de tâches est interdite dans ce projet';
$lang->task->cannotDeleteParent = 'Impossible de supprimer la tâche parente';
$lang->task->addChildTask = 'Because the task has already consumed consumption, to ensure data consistency, we will help you create a subtask with the same name to record the consumption.';
$lang->task->confirmDelete = "Voulez-vous réellement supprimer cette tâche ?";
$lang->task->confirmDeleteEstimate = "Voulez-vous la supprimer ?";
$lang->task->confirmDeleteLastEstimate = "Do you want to delete the log? After deleting the last work log, the task status will be adjusted to Not Started.";
$lang->task->copyStoryTitle = '<span style="color:blue;">StoryModel</span>';
$lang->task->afterSubmit = "Suiv. ";
$lang->task->successSaved = "Créée !";
$lang->task->delayWarning = " <strong class='text-danger'> Retard %s jours </strong>";
$lang->task->remindBug = "Cette tâche a été convertie depuis un bug. Voulez-vous mettre à jour le Bug : %s ?";
$lang->task->remindIssue = "This task is converted from a issue. Do you want to update the Issue:%s?";
$lang->task->confirmChangeExecution = "Si vous changez {$lang->executionCommon}, Module, Story et AssignedTo seront également changés. Voulez-vous le faire ?";
$lang->task->confirmFinish = '"Heures Restantes" à 0. Voulez-vous passer le statut à "Terminée" ?';
$lang->task->confirmRecord = '"Heures Restantes" à 0. Voulez-vous passer le statut de la tâche à "Finie" ?';
$lang->task->confirmTransfer = '"Heures Restantes" à 0. Voulez-vous transférer la tâche ?';
$lang->task->noticeTaskStart = '"Cost Hour" and "Left Hour" cannot be 0 at the same time.';
$lang->task->noticeLinkStory = "Aucune Story n'est associée. Vous pouvez %s pour ce projet, alors %s.";
$lang->task->noticeSaveRecord = "Votre temps n'a pas été sauvé. Enregistrez-le d'abord.";
$lang->task->commentActions = '%s. %s, commenté par <strong>%s</strong>.';
$lang->task->deniedNotice = 'Seulement le %s peut %s la tâche.';
$lang->task->noTask = "Pas de tâche pour l'instant. ";
$lang->task->createDenied = 'La création de tâches est interdite dans ce projet';
$lang->task->cannotDeleteParent = 'Impossible de supprimer la tâche parente';
$lang->task->addChildTask = 'Because the task has already consumed consumption, to ensure data consistency, we will help you create a subtask with the same name to record the consumption.';
$lang->task->error = new stdclass();
$lang->task->error->totalNumber = '"Coût Total" doit être numérique.';
+22 -21
View File
@@ -214,27 +214,28 @@ $lang->task->legendDesc = '任务描述';
$lang->task->legendDetail = '任务详情';
$lang->task->legendMisc = '其他相关';
$lang->task->confirmDelete = "您确定要删除这个任务吗?";
$lang->task->confirmDeleteEstimate = "您确定要删除这个记录吗?";
$lang->task->copyStoryTitle = "同{$lang->SRCommon}";
$lang->task->afterSubmit = "添加之后";
$lang->task->successSaved = "成功添加,";
$lang->task->delayWarning = " <strong class='text-danger'> 延期%s天 </strong>";
$lang->task->remindBug = "该任务为Bug转化得到,是否更新Bug:%s ?";
$lang->task->remindIssue = "该任务为问题转化得到,是否更新问题:%s ?";
$lang->task->confirmChangeExecution = "修改{$lang->executionCommon}会导致相应的所属模块、相关{$lang->SRCommon}和指派人发生变化,确定吗?";
$lang->task->confirmFinish = '"预计剩余"为0,确认将任务状态改为"已完成"吗?';
$lang->task->confirmRecord = '"剩余"为0,任务将标记为"已完成",您确定吗?';
$lang->task->confirmTransfer = '"当前剩余"为0,任务将被转交,您确定吗?';
$lang->task->noticeTaskStart = '"总计消耗"和"预计剩余"不能同时为0';
$lang->task->noticeLinkStory = "没有可关联的相关{$lang->SRCommon},您可以为当前项目%s,然后%s";
$lang->task->noticeSaveRecord = '您有尚未保存的工时记录,请先将其保存。';
$lang->task->commentActions = '%s. %s, 由 <strong>%s</strong> 添加备注。';
$lang->task->deniedNotice = '当前任务只有%s才可以%s。';
$lang->task->noTask = '暂时没有任务。';
$lang->task->createDenied = '你不能在该项目添加任务';
$lang->task->cannotDeleteParent = '不能删除父任务。';
$lang->task->addChildTask = '因该任务已经产生消耗,为保证数据一致性,我们会帮您创建一条同名子任务记录该消耗。';
$lang->task->confirmDelete = "您确定要删除这个任务吗?";
$lang->task->confirmDeleteEstimate = "您确定要删除这个记录吗?";
$lang->task->confirmDeleteLastEstimate = "您确定要删除该条日志吗?删除最后一条工时日志后,该任务状态将调整为未开始。";
$lang->task->copyStoryTitle = "同{$lang->SRCommon}";
$lang->task->afterSubmit = "添加之后";
$lang->task->successSaved = "成功添加,";
$lang->task->delayWarning = " <strong class='text-danger'> 延期%s天 </strong>";
$lang->task->remindBug = "该任务为Bug转化得到,是否更新Bug:%s ?";
$lang->task->remindIssue = "该任务为问题转化得到,是否更新问题:%s ?";
$lang->task->confirmChangeExecution = "修改{$lang->executionCommon}会导致相应的所属模块、相关{$lang->SRCommon}和指派人发生变化,确定吗?";
$lang->task->confirmFinish = '"预计剩余"为0,确认将任务状态改为"已完成"吗?';
$lang->task->confirmRecord = '"剩余"为0,任务将标记为"已完成",您确定吗?';
$lang->task->confirmTransfer = '"当前剩余"为0,任务将被转交,您确定吗?';
$lang->task->noticeTaskStart = '"总计消耗"和"预计剩余"不能同时为0';
$lang->task->noticeLinkStory = "没有可关联的相关{$lang->SRCommon},您可以为当前项目%s,然后%s";
$lang->task->noticeSaveRecord = '您有尚未保存的工时记录,请先将其保存。';
$lang->task->commentActions = '%s. %s, 由 <strong>%s</strong> 添加备注。';
$lang->task->deniedNotice = '当前任务只有%s才可以%s。';
$lang->task->noTask = '暂时没有任务。';
$lang->task->createDenied = '你不能在该项目添加任务';
$lang->task->cannotDeleteParent = '不能删除父任务。';
$lang->task->addChildTask = '因该任务已经产生消耗,为保证数据一致性,我们会帮您创建一条同名子任务记录该消耗。';
$lang->task->error = new stdclass();
$lang->task->error->totalNumber = '"总计消耗"必须为数字';
+75 -4
View File
@@ -719,7 +719,6 @@ class taskModel extends model
$task->assignedTo = $childTask->assignedTo;
$task->assignedDate = $now;
}
$task->finishedBy = '';
$task->finishedDate = '';
$task->closedBy = '';
@@ -749,6 +748,7 @@ class taskModel extends model
if($status == 'doing' and $parentTask->status == 'wait') $action = 'Started';
if($status == 'doing' and $parentTask->status == 'pause') $action = 'Restarted';
if($status == 'doing' and $parentTask->status != 'wait' and $parentTask->status != 'pause') $action = 'Activated';
if($status == 'wait' and $parentTask->status != 'wait') $action = 'Adjusttasktowait';
if($action)
{
$actionID = $this->loadModel('action')->create('task', $parentID, $action, '', '', '', false);
@@ -833,7 +833,8 @@ class taskModel extends model
$currentTask->consumed += (float)$member->consumed;
$currentTask->left += (float)$member->left;
}
if(empty($oldTask->team) and isset($oldTask->consumed)) $currentTask->consumed += (float)$oldTask->consumed;
if($this->app->rawMethod == 'edit' and empty($oldTask->team) and isset($oldTask->consumed)) $currentTask->consumed += (float)$oldTask->consumed;
if(!empty($task))
{
@@ -1236,7 +1237,7 @@ class taskModel extends model
return false;
}
if(empty($task->closedReason))
if(empty($task->closedReason) and $task->status == 'closed')
{
if($oldTask->status == 'done') $task->closedReason = 'done';
if($oldTask->status == 'cancel') $task->closedReason = 'cancel';
@@ -2834,7 +2835,19 @@ class taskModel extends model
$data->consumed = $consumed;
$data->left = $left;
$data->status = ($left == 0 && $consumed != 0) ? 'done' : $task->status;
if($left == 0 and $consumed != 0)
{
$data->status = 'done';
}
elseif($consumed == 0)
{
$data->status = 'wait';
$data->left = $task->left + $estimate->consumed;
}
else
{
$data->status = $task->status;
}
if(!empty($task->team))
{
$oldConsumed = $task->team[$estimate->account]->consumed;
@@ -3734,6 +3747,64 @@ class taskModel extends model
->fetchPairs('actor');
}
/**
* Build nested list.
*
* @param objecct $execution
* @param object $task
* @param bool $isChild
* @param bool $showmore
* @access public
* @return string
*/
public function buildNestedList($execution, $task, $isChild = false, $showmore = false, $users)
{
$showmore = $showmore ? 'showmore' : '';
$trAttrs = "data-id=$task->id";
if(!$isChild)
{
$path = $execution->grade == 2 ? "$execution->parent,$execution->id,$task->id," : ",$execution->id,$task->id,";
$trAttrs .= " data-parent=$execution->id data-nest-parent=$execution->id data-nest-path=$path";
if(empty($task->children)) $trAttrs .= " data-nested='false'";
$trClass = empty($task->children) ? '' : " has-nest-child";
}
else
{
$path = $execution->grade == 2 ? "$execution->parent,$execution->id,$task->parent,$task->id," : ",$execution->id,$task->parent,$task->id,";
$trClass = 'is-nest-child no-nest';
$trAttrs .= " data-nested='false' data-parent=$task->parent data-nest-parent=$task->parent data-nest-path=$path";
}
$list = "<tr $trAttrs class='$trClass $showmore'>";
$list .= '<td>';
if($task->parent > 0) $list .= '<span class="label label-badge label-light" title="' . $this->lang->task->children . '">' . $this->lang->task->childrenAB . '</span> ';
$list .= html::a(helper::createLink('task', 'view', "id=$task->id"), $task->name, '', "data-app='project'");
$list .= '</td>';
$list .= '<td>' . zget($users, $task->assignedTo, '') . '</td>';
$list .= "<td class='status-{$task->status}'>" . $this->processStatus('task', $task) . '</td>';
$list .= '<td></td>';
$list .= '<td>' . $task->estStarted . '</td>';
$list .= '<td>' . $task->deadline . '</td>';
$list .= '<td>' . $task->estimate . $this->lang->execution->workHourUnit . '</td>';
$list .= '<td>' . $task->consumed . $this->lang->execution->workHourUnit . '</td>';
$list .= '<td>' . $task->left . $this->lang->execution->workHourUnit . '</td>';
$list .= '<td></td>';
$list .= '<td class="c-actions">';
$list .= $this->buildOperateMenu($task, 'browse');
$list .= '</td></tr>';
if(!empty($task->children))
{
foreach($task->children as $child)
{
$showmore = (count($task->children) == 50) && ($child == end($task->children));
$list .= $this->buildNestedList($execution, $child, true, $showmore, $users);
}
}
return $list;
}
/**
* Build task menu.
*
+24
View File
@@ -1403,10 +1403,33 @@ class testcase extends control
$case = $this->testcase->getById($caseID);
$libCase = $this->testcase->getById($libcaseID);
$version = $case->version + 1;
$this->dao->delete()->from(TABLE_FILE)->where('objectType')->eq('testcase')->andWhere('objectID')->eq($caseID)->exec();
foreach($libCase->files as $fileID => $file)
{
$fileName = pathinfo($file->pathname, PATHINFO_FILENAME);
$datePath = substr($file->pathname, 0, 6);
$realPath = $this->app->getAppRoot() . "www/data/upload/{$this->app->company->id}/" . "{$datePath}/" . $fileName;
$rand = rand();
$newFileName = $fileName . 'copy' . $rand;
$newFilePath = $this->app->getAppRoot() . "www/data/upload/{$this->app->company->id}/" . "{$datePath}/" . $newFileName;
copy($realPath, $newFilePath);
$newFileName = $file->pathname;
$newFileName = str_replace('.', "copy$rand.", $newFileName);
unset($file->id, $file->realPath, $file->webPath);
$file->objectID = $caseID;
$file->pathname = $newFileName;
$this->dao->insert(TABLE_FILE)->data($file)->exec();
}
$this->dao->update(TABLE_CASE)
->set('version')->eq($version)
->set('fromCaseVersion')->eq($version)
->set('precondition')->eq($libCase->precondition)
->set('title')->eq($libCase->title)
->where('id')->eq($caseID)
->exec();
@@ -1417,6 +1440,7 @@ class testcase extends control
$step->version = $version;
$this->dao->insert(TABLE_CASESTEP)->data($step)->exec();
}
echo js::locate($this->createLink('testcase', 'view', "caseID=$caseID&version=$version"), 'parent');
}
+11
View File
@@ -1,5 +1,16 @@
$(document).ready(function()
{
if(isLibCase)
{
$('#subNavbar [data-id=testcase]').removeClass('active');
$('#navbar [data-id=testcase]').removeClass('active');
}
else
{
$('#subNavbar [data-id=testcase]').addClass('active');
$('#navbar [data-id=testcase]').addClass('active');
}
if(config.onlybody != 'yes')$(".runCase").modalTrigger({width:'90%', type:'iframe', afterHide:function(){parent.location.href=parent.location.href;}});
if(config.onlybody != 'yes')$(".results").modalTrigger({width:'90%', type:'iframe'});
+22 -12
View File
@@ -285,7 +285,7 @@ class testcaseModel extends model
->leftJoin(TABLE_STORY)->alias('t4')->on('t3.story=t4.id')
->where('t1.project')->in($executions)
->beginIF(!empty($productID))->andWhere('t2.product')->eq((int)$productID)->fi()
->beginIF($branch !== 'all')->andWhere('t2.branch')->eq($branch)->fi()
->beginIF(!empty($productID) and $branch !== 'all')->andWhere('t2.branch')->eq($branch)->fi()
->beginIF($moduleIdList)->andWhere('t2.module')->in($moduleIdList)->fi()
->beginIF($browseType == 'wait')->andWhere('t2.status')->eq($browseType)->fi()
->beginIF($auto == 'unit')->andWhere('t2.auto')->eq('unit')->fi()
@@ -342,7 +342,7 @@ class testcaseModel extends model
->where('t1.project')->eq((int)$executionID)
->beginIF(!empty($productID))->andWhere('t1.product')->eq($productID)->fi()
->beginIF(!empty($moduleID))->andWhere('t4.path')->like("%,$moduleID,%")->fi()
->andWhere('t2.branch')->eq($branchID)
->beginIF(!empty($productID))->andWhere('t2.branch')->eq($branchID)->fi()
->andWhere('t2.deleted')->eq('0')
->andWhere('t3.version > t2.storyVersion')
->andWhere("t3.status")->eq('active')
@@ -358,7 +358,7 @@ class testcaseModel extends model
->beginIF($browseType != 'all' and $browseType != 'byModule')->andWhere('t2.status')->eq($browseType)->fi()
->beginIF(!empty($productID))->andWhere('t1.product')->eq($productID)->fi()
->beginIF(!empty($moduleID))->andWhere('t3.path')->like("%,$moduleID,%")->fi()
->andWhere('t2.branch')->eq($branchID)
->beginIF(!empty($productID))->andWhere('t2.branch')->eq($branchID)->fi()
->andWhere('t2.deleted')->eq('0')
->orderBy($orderBy)
->page($pager)
@@ -520,7 +520,7 @@ class testcaseModel extends model
->andWhere('t2.version > t1.storyVersion')
->beginIF(!empty($productID))->andWhere('t1.product')->eq($productID)->fi()
->beginIF($this->app->tab == 'project')->andWhere('t3.project')->eq($this->session->project)->fi()
->beginIF($branch !== 'all')->andWhere('t1.branch')->eq($branch)->fi()
->beginIF($branch !== 'all' and !empty($productID))->andWhere('t1.branch')->eq($branch)->fi()
->beginIF($modules)->andWhere('t1.module')->in($modules)->fi()
->beginIF($auto != 'unit')->andWhere('t1.auto')->ne('unit')->fi()
->beginIF($auto == 'unit')->andWhere('t1.auto')->eq('unit')->fi()
@@ -799,15 +799,12 @@ class testcaseModel extends model
$this->dao->update(TABLE_CASE)->data($case)->autoCheck()->batchCheck($requiredFields, 'notempty')->checkFlow()->where('id')->eq((int)$caseID)->exec();
if(!$this->dao->isError())
{
$isLibCase = ($oldCase->lib and empty($oldCase->product));
$titleChanged = ($case->title != $oldCase->title);
if($isLibCase and $titleChanged) $this->dao->update(TABLE_CASE)->set('`title`')->eq($case->title)->where('`fromCaseID`')->eq($caseID)->exec();
$this->updateCase2Project($oldCase, $case, $caseID);
if($stepChanged)
{
$parentStepID = 0;
$isLibCase = ($oldCase->lib and empty($oldCase->product));
if($isLibCase)
{
$fromcaseVersion = $this->dao->select('fromCaseVersion')->from(TABLE_CASE)->where('fromCaseID')->eq($caseID)->fetch('fromCaseVersion');
@@ -1103,6 +1100,11 @@ class testcaseModel extends model
foreach($cases as $caseID => $case)
{
$oldCase = $this->getByID($caseID);
$caseChanged = false;
if($oldCase->title != $case->title) $caseChanged = true;
if($oldCase->precondition != $case->precondition) $caseChanged = true;
$this->dao->update(TABLE_CASE)->data($case)
->autoCheck()
->batchCheck($this->config->testcase->edit->requiredFields, 'notempty')
@@ -1112,11 +1114,7 @@ class testcaseModel extends model
if(!dao::isError())
{
$isLibCase = ($oldCase->lib and empty($oldCase->product));
$titleChanged = ($case->title != $oldCase->title);
$case->product = $oldCase->product;
if($isLibCase and $titleChanged) $this->dao->update(TABLE_CASE)->set('`title`')->eq($case->title)->where('`fromCaseID`')->eq($caseID)->exec();
$this->updateCase2Project($oldCase, $case, $caseID);
$this->executeHooks($caseID);
@@ -1138,6 +1136,14 @@ class testcaseModel extends model
}
}
}
$isLibCase = ($oldCase->lib and empty($oldCase->product));
if($isLibCase and $caseChanged)
{
$fromcaseVersion = $this->dao->select('fromCaseVersion')->from(TABLE_CASE)->where('fromCaseID')->eq($caseID)->fetch('fromCaseVersion');
$fromcaseVersion += 1;
$this->dao->update(TABLE_CASE)->set('`fromCaseVersion`')->eq($fromcaseVersion)->where('`fromCaseID`')->eq($caseID)->exec();
}
}
else
{
@@ -2357,6 +2363,10 @@ class testcaseModel extends model
if(!$this->forceNotReview() and $stepChanged) $status = 'wait';
if(!empty($_POST['title']) and $case->title != $this->post->title) $stepChanged = true;
if(!empty($_POST['precondition']) and $case->precondition != $this->post->precondition) $stepChanged = true;
if(!empty($_POST['labels'][0])) $stepChanged = true;
return array($stepChanged, $status);
}
+1 -1
View File
@@ -261,7 +261,7 @@ js::set('suiteID', $suiteID);
<h4 class="modal-title"><?php echo $lang->testcase->importToLib;?></h4>
</div>
<div class="modal-body">
<form method='post' class='form-ajax' action='<?php echo $this->createLink('testcase', 'importToLib');?>'>
<form method='post' class='form-ajax not-watch' action='<?php echo $this->createLink('testcase', 'importToLib');?>'>
<table class='table table-form'>
<tr>
<td class='select-lib'><?php echo $lang->testcase->selectLibAB;?></td>
+1 -9
View File
@@ -366,14 +366,6 @@
<?php
js::set('fullscreen', $lang->fullscreen);
js::set('retrack', $lang->retrack);
js::set('isLibCase', $isLibCase);
?>
<?php if(!$isLibCase):?>
<script>
$(function()
{
$('#subNavbar [data-id=testcase]').addClass('active');
$('#navbar [data-id=testcase]').addClass('active');
})
</script>
<?php endif;?>
<?php include '../../common/view/footer.html.php';?>
+3 -1
View File
@@ -517,6 +517,7 @@ class tree extends control
{
$changeFunc = '';
if($viewType == 'bug' or $viewType == 'case') $changeFunc = "onchange='loadModuleRelated()'";
if($viewType == 'task') $changeFunc = "onchange='setStories(this.value, $rootID)'";
$field = $fieldID ? "modules[$fieldID]" : 'module';
$currentModule = $this->tree->getById($currentModuleID);
@@ -538,7 +539,8 @@ class tree extends control
if($returnType == 'mhtml')
{
$changeFunc = '';
if($viewType == 'task' or $viewType == 'bug' or $viewType == 'case') $changeFunc = "onchange='loadModuleRelated()'";
if($viewType == 'bug' or $viewType == 'case') $changeFunc = "onchange='loadModuleRelated()'";
if($viewType == 'task') $changeFunc = "onchange='setStories(this.value, $rootID)'";
$field = $fieldID ? "modules[$fieldID]" : 'module';
$output = html::select("$field", $optionMenu, '', "class='input' $changeFunc");
die($output);
+2
View File
@@ -20,6 +20,7 @@ $config->upgrade->maxVersion['max3_1_beta2'] = '17_0_beta2';
$config->upgrade->maxVersion['max3_1'] = '17_0';
$config->upgrade->maxVersion['max3_2'] = '17_1';
$config->upgrade->maxVersion['max3_3'] = '17_2';
$config->upgrade->maxVersion['max3_4'] = '17_3';
$config->upgrade->bizVersion = array();
$config->upgrade->bizVersion['biz1_0'] = '9_5_1';
@@ -78,6 +79,7 @@ $config->upgrade->bizVersion['biz7_0_beta2'] = '17_0_beta2';
$config->upgrade->bizVersion['biz7_0'] = '17_0';
$config->upgrade->bizVersion['biz7_1'] = '17_1';
$config->upgrade->bizVersion['biz7_2'] = '17_2';
$config->upgrade->bizVersion['biz7_3'] = '17_3';
$config->upgrade->proVersion = array();
$config->upgrade->proVersion['pro1_0'] = '3_1';
+3
View File
@@ -161,6 +161,7 @@ $lang->upgrade->fromVersions['17_0_beta2'] = '17.0.beta2';
$lang->upgrade->fromVersions['17_0'] = '17.0';
$lang->upgrade->fromVersions['17_1'] = '17.1';
$lang->upgrade->fromVersions['17_2'] = '17.2';
$lang->upgrade->fromVersions['17_3'] = '17.3';
global $config;
/* Lite. */
@@ -326,6 +327,7 @@ $lang->upgrade->fromVersions['biz7_0_beta2'] = 'Biz7.0.beta2';
$lang->upgrade->fromVersions['biz7_0'] = 'Biz7.0';
$lang->upgrade->fromVersions['biz7_1'] = 'Biz7.1';
$lang->upgrade->fromVersions['biz7_2'] = 'Biz7.2';
$lang->upgrade->fromVersions['biz7_3'] = 'Biz7.3';
/* Max. */
$lang->upgrade->fromVersions['max2_0_beta4'] = 'Max2.0.beta4';
@@ -347,3 +349,4 @@ $lang->upgrade->fromVersions['max3_1_beta1'] = 'Max3.1.beta1';
$lang->upgrade->fromVersions['max3_1_beta2'] = 'Max3.1.beta2';
$lang->upgrade->fromVersions['max3_1'] = 'Max3.1';
$lang->upgrade->fromVersions['max3_2'] = 'Max3.2';
$lang->upgrade->fromVersions['max3_3'] = 'Max3.3';
+45
View File
@@ -692,6 +692,9 @@ class upgradeModel extends model
case 'max3_0':
$this->moveResult2Node();
break;
case 'max3_3':
$this->addReviewIssusApprovalData();
break;
}
}
@@ -969,6 +972,8 @@ class upgradeModel extends model
$confirmContent .= file_get_contents($this->getUpgradeFile('17.1'));
$xuanxuanSql = $this->app->getAppRoot() . 'db' . DS . 'upgradexuanxuan5.6.sql';
$confirmContent .= file_get_contents($xuanxuanSql);
case '17_2':
$confirmContent .= file_get_contents($this->getUpgradeFile('17.2'));
}
return $confirmContent;
@@ -6509,6 +6514,46 @@ class upgradeModel extends model
return true;
}
/*
* Add review issue approval data.
*
* @access public
* @return bool
*/
public function addReviewIssusApprovalData()
{
$reviewIssues = $this->dao->select('id,review,type')->from(TABLE_REVIEWISSUE)
->where('type')->eq('review')
->andWhere('approval')->eq(0)
->andWhere('deleted')->eq('0')
->fetchAll('review');
if(empty($reviewIssues)) return false;
$reviewIds = array_unique(array_column($reviewIssues, 'review'));
$approvalsPairs = $this->dao->select('objectID, max(id) as approval')->from(TABLE_APPROVAL)
->where('objectID')->in($reviewIds)
->andWhere('objectType')->eq('review')
->andWhere('result')->eq('fail')
->andWhere('deleted')->eq(0)
->groupBy('objectID')
->fetchAll('objectID');
/* Add approval data. */
foreach($reviewIssues as $reviewIssue)
{
if(!isset($approvalsPairs[$reviewIssue->review]->approval)) continue;
$this->dao->update(TABLE_REVIEWISSUE)
->set('approval')->eq($approvalsPairs[$reviewIssue->review]->approval)
->where('review')->eq($reviewIssue->review)
->andWhere('type')->eq('review')
->andWhere('approval')->eq(0)
->andWhere('deleted')->eq('0')
->exec();
}
}
/**
* Xuan: Add `index` column to all message partition tables.
*
+2
View File
@@ -10,3 +10,5 @@ body {background: #1183fb linear-gradient(-90deg, #0a48d1 0%, #1183fb 100%); bac
#forgetForm .form-actions {padding-bottom: 20px;}
.required:after {top: 32px; right: -15px;}
.resetBox {float: right; font-size: 8px; margin-right: 2px;}
#forgetForm .form-actions > .btn-wide {min-width: 45%;}
#forgetForm .form-actions > a.btn-wide {margin-right: 0px;}
+2
View File
@@ -11,3 +11,5 @@ body {background: #1183fb linear-gradient(-90deg, #0a48d1 0%, #1183fb 100%); bac
.required:after {top: 32px; right: -15px;}
#resetPanel .form-group .input-group {width: 100%}
#resetPanel .form-group .input-group.required:after {top: 6px;}
#resetPanel .form-actions > .btn-wide {min-width: 45%;}
#resetPanel .form-actions > a.btn-wide {margin-right: 0px;}
@@ -207,14 +207,22 @@ class xuanxuanIm extends imModel
foreach($userMessages as $message)
{
/* Group by $message->content->content->objectType, ...->parentType, ...->action, ...->actor */
$contentData = json_decode($message->content);
$contentData = json_decode($contentData->content);
$contentDataOuter = json_decode($message->content);
$contentData = json_decode($contentDataOuter->content);
if(isset($contentData->contentType) && $contentData->contentType == 'text')
{
$messageGroups[$contentData->contentType][] = $message;
continue;
}
$messageGroups["$contentData->objectType-$contentData->parentType-$contentData->action-$contentData->actor"][] = $message;
if ($contentData->objectType == 'story' && $contentData->action == 'reviewed')
{
$extra = explode(',', $contentDataOuter->extra)[0];
$messageGroups["$contentData->objectType-$contentData->parentType-$contentData->action-$contentData->actor-$extra"][] = $message;
}
else
{
$messageGroups["$contentData->objectType-$contentData->parentType-$contentData->action-$contentData->actor"][] = $message;
}
}
foreach($messageGroups as $groupKey => $messages)
{
@@ -225,25 +233,24 @@ class xuanxuanIm extends imModel
$notificationContent = json_decode($notification->content);
$notificationInnerContent = json_decode($notificationContent->content);
/* Inner content: array($parentID => array($content1, $content2)) */
$objectGroups = array($notificationInnerContent->parent => array($notificationInnerContent));
/* Inner content: array($id => array($content1, $content2)) */
$objectGroups = array($notificationInnerContent->id => array($notificationInnerContent));
foreach($messages as $message)
{
$messageContent = json_decode($message->content);
$messageInnerContent = json_decode($messageContent->content);
$objectGroups[$messageInnerContent->parent][] = $messageInnerContent;
$objectGroups[$messageInnerContent->id][] = $messageInnerContent;
}
$objectTotal = 0;
foreach($objectGroups as $parent => $objectGroup)
foreach($objectGroups as $id => $objectGroup)
{
$object = current($objectGroup);
$object->count = count($objectGroup);
$object->url = $object->parentURL;
unset($object->title);
$objectGroups[$parent] = $object;
$objectTotal += $object->count;
$objectGroups[$id] = $object;
}
$objectTotal = count($objectGroups);
$notificationContent->content = json_encode(array_values($objectGroups));
/* Hack alert: title count replacement currently assumes that default count is 1. */
$notification->title = substr_replace($notification->title, "$objectTotal", strrpos($notification->title, '1'), 1);
@@ -3,7 +3,10 @@ $lang->message->typeList['xuanxuan'] = 'Chat';
$lang->message->sender = 'ZenTao';
$lang->message->notifyTitle = '%s %s%d %s';
$lang->message->notifyTitle = '%s %s%d %s';
$lang->message->notifyPassTitle = '%s passed %d stories';
$lang->message->notifyClarifyTitle = '%s clarify %d stories';
$lang->message->notifyRejectTitle = '%s reject %d stories';
$lang->message->mr = new stdClass();
$lang->message->mr->logTitle = 'Build log';
@@ -3,7 +3,10 @@ $lang->message->typeList['xuanxuan'] = 'Chat';
$lang->message->sender = 'ZenTao';
$lang->message->notifyTitle = '%s %s%d %s';
$lang->message->notifyTitle = '%s %s%d %s';
$lang->message->notifyPassTitle = '%s passed %d stories';
$lang->message->notifyClarifyTitle = '%s clarify %d stories';
$lang->message->notifyRejectTitle = '%s reject %d stories';
$lang->message->mr = new stdClass();
$lang->message->mr->logTitle = 'Build log';
@@ -3,7 +3,10 @@ $lang->message->typeList['xuanxuan'] = 'Chat';
$lang->message->sender = 'ZenTao';
$lang->message->notifyTitle = '%s %s%d %s';
$lang->message->notifyTitle = '%s %s%d %s';
$lang->message->notifyPassTitle = '%s passed %d stories';
$lang->message->notifyClarifyTitle = '%s clarify %d stories';
$lang->message->notifyRejectTitle = '%s reject %d stories';
$lang->message->mr = new stdClass();
$lang->message->mr->logTitle = 'Build log';
@@ -3,7 +3,10 @@ $lang->message->typeList['xuanxuan'] = '聊天';
$lang->message->sender = '禅道项目管理';
$lang->message->notifyTitle = '%s %s%d个%s';
$lang->message->notifyTitle = '%s %s%d个%s';
$lang->message->notifyPassTitle = '%s 通过了%d个研发需求';
$lang->message->notifyClarifyTitle = '%s 驳回了%d个研发需求';
$lang->message->notifyRejectTitle = '%s 拒绝了%d个研发需求';
$lang->message->mr = new stdClass();
$lang->message->mr->logTitle = '构建日志';
@@ -1,7 +1,7 @@
<?php
class xuanxuanMessage extends messageModel
{
public function send($objectType, $objectID, $actionType, $actionID, $actor = '')
public function send($objectType, $objectID, $actionType, $actionID, $actor = '', $extra = '')
{
$messageSetting = $this->config->message->setting;
if(is_string($messageSetting)) $messageSetting = json_decode($messageSetting, true);
@@ -44,6 +44,22 @@ class xuanxuanMessage extends messageModel
->fetch();
$field = $this->config->action->objectNameFields[$objectType];
$title = $objectType == 'mr' ? '' : sprintf($this->lang->message->notifyTitle, $this->app->user->realname, $this->lang->action->label->$actionType, 1, $this->lang->action->objectTypes[$objectType]);
if ($objectType == 'story' && $actionType == 'reviewed' && !empty($extra))
{
$notifyType = strtolower(explode(',', $extra)[0]);
if ($notifyType == 'pass')
{
$title = $objectType == 'mr' ? '' : sprintf($this->lang->message->notifyPassTitle, $this->app->user->realname, 1);
}
else if($notifyType == 'clarify')
{
$title = $objectType == 'mr' ? '' : sprintf($this->lang->message->notifyClarifyTitle, $this->app->user->realname, 1);
}
else if($notifyType == 'reject')
{
$title = $objectType == 'mr' ? '' : sprintf($this->lang->message->notifyRejectTitle, $this->app->user->realname, 1);
}
}
$server = $this->loadModel('im')->getServer('zentao');
$onlybody = isset($_GET['onlybody']) ? $_GET['onlybody'] : '';
@@ -52,7 +68,7 @@ class xuanxuanMessage extends messageModel
$url = $server . helper::createLink($objectType == 'kanbancard' ? 'kanban' : $objectType, 'view', "id=$dataID", 'html');
$target = '';
if(!empty($object->assignedTo)) $target .= $object->assignedTo;
if(!empty($object->assignedTo)) $target .= $object->assignedTo == 'closed' ? $object->openedBy : $object->assignedTo;
if(!empty($object->mailto)) $target .= ",{$object->mailto}";
if(($objectType == 'mr' or $objectType == 'kanbancard') and !empty($object->createdBy)) $target .= ",{$object->createdBy}";
$target = trim($target, ',');
@@ -130,6 +146,7 @@ class xuanxuanMessage extends messageModel
$contentData->actions = array();
$contentData->url = "xxc:openInApp/zentao-integrated/" . urlencode($url);
}
$contentData->extra = $extra;
$content = json_encode($contentData);
$avatarUrl = $server . $this->app->getWebRoot() . 'favicon.ico';
@@ -1,2 +1,2 @@
<?php
$this->loadExtension('xuanxuan')->send($objectType, $objectID, $actionType, $actionID, $actor);
$this->loadExtension('xuanxuan')->send($objectType, $objectID, $actionType, $actionID, $actor, $extra);