Merge branch 'master' of https://gitlab.zcorp.cc/easycorp/zentaopms into importExport
This commit is contained in:
@@ -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';
|
||||
|
||||
@@ -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`;
|
||||
|
||||
@@ -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',
|
||||
|
||||
@@ -209,6 +209,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";
|
||||
@@ -305,7 +306,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";
|
||||
|
||||
@@ -209,6 +209,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";
|
||||
@@ -305,7 +306,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";
|
||||
|
||||
@@ -209,6 +209,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";
|
||||
|
||||
@@ -209,6 +209,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";
|
||||
|
||||
@@ -38,7 +38,7 @@ $lang->block->lblBlock = 'Block';
|
||||
$lang->block->lblNum = 'Number';
|
||||
$lang->block->lblHtml = 'HTML';
|
||||
$lang->block->dynamic = 'Dynamics';
|
||||
$lang->block->assignToMe = 'Todo';
|
||||
$lang->block->assignToMe = 'Work';
|
||||
$lang->block->wait = 'Wait';
|
||||
$lang->block->doing = 'Doing';
|
||||
$lang->block->done = 'Done';
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -274,7 +274,7 @@ class branch extends control
|
||||
{
|
||||
$branchTagOption[$branchInfo->id] = $branchInfo->name . ($branchInfo->status == 'closed' ? ' (' . $this->lang->branch->statusList['closed'] . ')' : '');
|
||||
}
|
||||
if(!isset($branchTagOption[$oldBranch]))
|
||||
if(is_numeric($oldBranch) and !isset($branchTagOption[$oldBranch]))
|
||||
{
|
||||
$branch = $this->branch->getById($oldBranch, $productID, '');
|
||||
$branchTagOption[$oldBranch] = $oldBranch == BRANCH_MAIN ? $branch : ($branch->name . ($branch->status == 'closed' ? ' (' . $this->lang->branch->statusList['closed'] . ')' : ''));
|
||||
|
||||
+102
-110
@@ -1390,11 +1390,12 @@ class bug extends control
|
||||
* Update assign of bug.
|
||||
*
|
||||
* @param int $bugID
|
||||
* @parm string $kanbanGroup
|
||||
* @param string $kanbanGroup
|
||||
* @param string $from taskkanban
|
||||
* @access public
|
||||
* @return void
|
||||
*/
|
||||
public function assignTo($bugID, $kanbanGroup = 'default')
|
||||
public function assignTo($bugID, $kanbanGroup = 'default', $from = '')
|
||||
{
|
||||
$bug = $this->bug->getById($bugID);
|
||||
$this->bug->checkBugExecutionPriv($bug);
|
||||
@@ -1414,28 +1415,24 @@ class bug extends control
|
||||
|
||||
if(isonlybody())
|
||||
{
|
||||
$bug = $this->bug->getById($bugID);
|
||||
$execution = $this->loadModel('execution')->getByID($bug->execution);
|
||||
if($this->app->tab == 'execution')
|
||||
$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 : '';
|
||||
if($this->app->tab == 'execution' and isset($execution->type) 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 : '';
|
||||
|
||||
if(isset($execution->type) and $execution->type == 'kanban')
|
||||
{
|
||||
$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);
|
||||
return print(js::closeModal('parent.parent', '', "parent.parent.updateKanban(\"bug\", $kanbanData)"));
|
||||
}
|
||||
$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);
|
||||
return print(js::closeModal('parent.parent', '', "parent.parent.updateKanban(\"bug\", $kanbanData)"));
|
||||
}
|
||||
else
|
||||
{
|
||||
@@ -1627,10 +1624,11 @@ class bug extends control
|
||||
*
|
||||
* @param int $bugID
|
||||
* @param string $extra
|
||||
* @param string $from taskkanban
|
||||
* @access public
|
||||
* @return void
|
||||
*/
|
||||
public function confirmBug($bugID, $extra = '')
|
||||
public function confirmBug($bugID, $extra = '', $from = '')
|
||||
{
|
||||
$bug = $this->bug->getById($bugID);
|
||||
if(!empty($_POST))
|
||||
@@ -1646,28 +1644,24 @@ class bug extends control
|
||||
parse_str($extra, $output);
|
||||
if(isonlybody())
|
||||
{
|
||||
$execution = $this->loadModel('execution')->getByID($bug->execution);
|
||||
if($this->app->tab == 'execution')
|
||||
$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 : '';
|
||||
if($this->app->tab == 'execution' and isset($execution->type) 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 : '';
|
||||
|
||||
if(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);
|
||||
return print(js::closeModal('parent.parent', '', "parent.parent.updateKanban($kanbanData, $regionID)"));
|
||||
}
|
||||
else
|
||||
{
|
||||
$kanbanData = $this->loadModel('kanban')->getExecutionKanban($bug->execution, $execLaneType, $execGroupBy, $rdSearchValue);
|
||||
$kanbanType = $execLaneType == 'all' ? 'bug' : key($kanbanData);
|
||||
$kanbanData = $kanbanData[$kanbanType];
|
||||
$kanbanData = json_encode($kanbanData);
|
||||
return print(js::closeModal('parent.parent', '', "parent.parent.updateKanban(\"bug\", $kanbanData)"));
|
||||
}
|
||||
$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);
|
||||
return print(js::closeModal('parent.parent', '', "parent.parent.updateKanban(\"bug\", $kanbanData)"));
|
||||
}
|
||||
else
|
||||
{
|
||||
@@ -1714,10 +1708,11 @@ class bug extends control
|
||||
*
|
||||
* @param int $bugID
|
||||
* @param string $extra
|
||||
* @param string $from taskkanban
|
||||
* @access public
|
||||
* @return void
|
||||
*/
|
||||
public function resolve($bugID, $extra = '')
|
||||
public function resolve($bugID, $extra = '', $from = '')
|
||||
{
|
||||
$bug = $this->bug->getById($bugID);
|
||||
if($bug->execution) $execution = $this->loadModel('execution')->getByID($bug->execution);
|
||||
@@ -1753,27 +1748,23 @@ class bug extends control
|
||||
parse_str($extra, $output);
|
||||
if(isonlybody())
|
||||
{
|
||||
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 : '';
|
||||
if($this->app->tab == 'execution' and isset($execution->type) 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 : '';
|
||||
if(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);
|
||||
|
||||
return print(js::closeModal('parent.parent', '', "parent.parent.updateKanban($kanbanData, $regionID)"));
|
||||
}
|
||||
else
|
||||
{
|
||||
$kanbanData = $this->loadModel('kanban')->getExecutionKanban($bug->execution, $execLaneType, $execGroupBy, $rdSearchValue);
|
||||
$kanbanType = $execLaneType == 'all' ? 'bug' : key($kanbanData);
|
||||
$kanbanData = $kanbanData[$kanbanType];
|
||||
$kanbanData = json_encode($kanbanData);
|
||||
return print(js::closeModal('parent.parent', '', "parent.parent.updateKanban(\"bug\", $kanbanData)"));
|
||||
}
|
||||
$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);
|
||||
return print(js::closeModal('parent.parent', '', "parent.parent.updateKanban(\"bug\", $kanbanData)"));
|
||||
}
|
||||
else
|
||||
{
|
||||
@@ -1842,10 +1833,11 @@ class bug extends control
|
||||
*
|
||||
* @param int $bugID
|
||||
* @param string $extra
|
||||
* @param string $from taskkanban
|
||||
* @access public
|
||||
* @return void
|
||||
*/
|
||||
public function activate($bugID, $extra = '')
|
||||
public function activate($bugID, $extra = '', $from = '')
|
||||
{
|
||||
$bug = $this->bug->getById($bugID);
|
||||
if(!empty($_POST))
|
||||
@@ -1866,27 +1858,23 @@ class bug extends control
|
||||
if(isonlybody())
|
||||
{
|
||||
$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 : '';
|
||||
if($this->app->tab == 'execution' and isset($execution->type) 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 : '';
|
||||
|
||||
if(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);
|
||||
return print(js::closeModal('parent.parent', '', "parent.parent.updateKanban($kanbanData, $regionID)"));
|
||||
}
|
||||
else
|
||||
{
|
||||
$kanbanData = $this->loadModel('kanban')->getExecutionKanban($bug->execution, $execLaneType, $execGroupBy, $rdSearchValue);
|
||||
$kanbanType = $execLaneType == 'all' ? 'bug' : key($kanbanData);
|
||||
$kanbanData = $kanbanData[$kanbanType];
|
||||
$kanbanData = json_encode($kanbanData);
|
||||
return print(js::closeModal('parent.parent', '', "parent.parent.updateKanban(\"bug\", $kanbanData)"));
|
||||
}
|
||||
$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);
|
||||
return print(js::closeModal('parent.parent', '', "parent.parent.updateKanban(\"bug\", $kanbanData)"));
|
||||
}
|
||||
else
|
||||
{
|
||||
@@ -1917,10 +1905,11 @@ class bug extends control
|
||||
*
|
||||
* @param int $bugID
|
||||
* @param string $extra
|
||||
* @param string $from taskkanban
|
||||
* @access public
|
||||
* @return void
|
||||
*/
|
||||
public function close($bugID, $extra = '')
|
||||
public function close($bugID, $extra = '', $from = '')
|
||||
{
|
||||
$bug = $this->bug->getById($bugID);
|
||||
if(!empty($_POST))
|
||||
@@ -1937,28 +1926,24 @@ class bug extends control
|
||||
parse_str($extra, $output);
|
||||
if(isonlybody())
|
||||
{
|
||||
$execution = $this->loadModel('execution')->getByID($bug->execution);
|
||||
if($this->app->tab == 'execution')
|
||||
$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 : '';
|
||||
if($this->app->tab == 'execution' and isset($execution->type) 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 : '';
|
||||
if(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);
|
||||
|
||||
return print(js::closeModal('parent.parent', '', "parent.parent.updateKanban($kanbanData, $regionID)"));
|
||||
}
|
||||
else
|
||||
{
|
||||
$kanbanData = $this->loadModel('kanban')->getExecutionKanban($bug->execution, $execLaneType, $execGroupBy, $rdSearchValue);
|
||||
$kanbanType = $execLaneType == 'all' ? 'bug' : key($kanbanData);
|
||||
$kanbanData = $kanbanData[$kanbanType];
|
||||
$kanbanData = json_encode($kanbanData);
|
||||
return print(js::closeModal('parent.parent', '', "parent.parent.updateKanban(\"bug\", $kanbanData)"));
|
||||
}
|
||||
$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);
|
||||
return print(js::closeModal('parent.parent', '', "parent.parent.updateKanban(\"bug\", $kanbanData)"));
|
||||
}
|
||||
else
|
||||
{
|
||||
@@ -2037,11 +2022,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;
|
||||
@@ -2066,6 +2054,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'));
|
||||
}
|
||||
|
||||
@@ -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 = '';
|
||||
|
||||
@@ -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');
|
||||
|
||||
@@ -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>
|
||||
|
||||
@@ -0,0 +1,2 @@
|
||||
#readOnlyOfExecution {font-size: 13px; color: #5e626d;}
|
||||
#readOnlyOfExecution i {font-size: 14px; color: #0075ff; margin-right: 3px;}
|
||||
@@ -0,0 +1,2 @@
|
||||
#readOnlyOfKanban {font-size: 13px; color: #5e626d;}
|
||||
#readOnlyOfKanban i {font-size: 14px; color: #0075ff; margin-right: 3px;}
|
||||
@@ -0,0 +1,2 @@
|
||||
#readOnlyOfProduct {font-size: 13px; color: #5e626d;}
|
||||
#readOnlyOfProduct i {font-size: 14px; color: #0075ff; margin-right: 3px;}
|
||||
@@ -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;?>
|
||||
|
||||
@@ -21,7 +21,13 @@
|
||||
<label class="radio-inline"><input type="radio" name="execution" value="<?php echo $key?>"<?php echo $key == $checkedKey ? " checked='checked'" : ''?> id="execution<?php echo $key;?>"><?php echo $value;?></label>
|
||||
<?php endforeach;?>
|
||||
</td>
|
||||
<td><span class='alert alert-info no-margin'><?php echo $lang->custom->notice->readOnlyOfExecution;?></span></td>
|
||||
<td></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<th></th>
|
||||
<td colspan="2" id="readOnlyOfExecution">
|
||||
<i class="icon-exclamation-sign"></i> <?php echo $lang->custom->notice->readOnlyOfExecution;?>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<th></th>
|
||||
|
||||
@@ -21,7 +21,13 @@
|
||||
<label class="radio-inline"><input type="radio" name="kanban" value="<?php echo $key?>"<?php echo $key == $checkedKey ? " checked='checked'" : ''?> id="kanban<?php echo $key;?>"><?php echo $value;?></label>
|
||||
<?php endforeach;?>
|
||||
</td>
|
||||
<td><span class='alert alert-info no-margin'><?php echo $lang->custom->notice->readOnlyOfKanban;?></span></td>
|
||||
<td></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<th></th>
|
||||
<td colspan="2" id="readOnlyOfKanban">
|
||||
<i class="icon-exclamation-sign"></i> <?php echo $lang->custom->notice->readOnlyOfKanban;?>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<th></th>
|
||||
|
||||
@@ -21,7 +21,13 @@
|
||||
<label class="radio-inline"><input type="radio" name="product" value="<?php echo $key?>"<?php echo $key == $checkedKey ? " checked='checked'" : ''?> id="product<?php echo $key;?>"><?php echo $value;?></label>
|
||||
<?php endforeach;?>
|
||||
</td>
|
||||
<td><div class='alert alert-info no-margin'><?php echo $lang->custom->notice->readOnlyOfProduct;?></div></td>
|
||||
<td></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<th></th>
|
||||
<td colspan="2" id="readOnlyOfProduct">
|
||||
<i class="icon-exclamation-sign"></i> <?php echo $lang->custom->notice->readOnlyOfProduct;?>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<th></th>
|
||||
|
||||
@@ -54,9 +54,9 @@
|
||||
<?php echo $api['desc'];?>
|
||||
<table class='table table-bordered'>
|
||||
<tr>
|
||||
<td><?php echo $lang->dev->params?></td>
|
||||
<td><?php echo $lang->dev->type?></td>
|
||||
<td><?php echo $lang->dev->desc?></td>
|
||||
<th><?php echo $lang->dev->params?></th>
|
||||
<th><?php echo $lang->dev->type?></th>
|
||||
<th><?php echo $lang->dev->desc?></th>
|
||||
</tr>
|
||||
<?php if(isset($api['param'])):?>
|
||||
<?php foreach($api['param'] as $param):?>
|
||||
@@ -78,9 +78,9 @@
|
||||
<table class='table table-bordered'>
|
||||
<caption><?php echo $lang->dev->post;?></caption>
|
||||
<tr>
|
||||
<td><?php echo $lang->dev->params?></td>
|
||||
<td><?php echo $lang->dev->type?></td>
|
||||
<td><?php echo $lang->dev->desc?></td>
|
||||
<th><?php echo $lang->dev->params?></th>
|
||||
<th><?php echo $lang->dev->type?></th>
|
||||
<th><?php echo $lang->dev->desc?></th>
|
||||
</tr>
|
||||
<?php foreach($config->dev->postParams[$selectedModule][$methodName] as $paramName => $paramType):?>
|
||||
<tr>
|
||||
|
||||
@@ -107,7 +107,7 @@ class execution extends control
|
||||
* @access public
|
||||
* @return void
|
||||
*/
|
||||
public function task($executionID = 0, $status = 'unclosed', $param = 0, $orderBy = '', $recTotal = 0, $recPerPage = 100, $pageID = 1)
|
||||
public function task($executionID = 0, $status = 'all', $param = 0, $orderBy = '', $recTotal = 0, $recPerPage = 100, $pageID = 1)
|
||||
{
|
||||
$this->loadModel('tree');
|
||||
$this->loadModel('search');
|
||||
@@ -219,8 +219,14 @@ class execution extends control
|
||||
$showModule = !empty($this->config->datatable->executionTask->showModule) ? $this->config->datatable->executionTask->showModule : '';
|
||||
$this->view->modulePairs = $showModule ? $this->tree->getModulePairs($executionID, 'task', $showModule) : array();
|
||||
|
||||
$allTasksNum = $this->dao->select('COUNT(id) AS count')->from(TABLE_TASK)
|
||||
->where('execution')->eq($executionID)
|
||||
->andWhere('deleted')->eq(0)
|
||||
->fetch();
|
||||
|
||||
/* Assign. */
|
||||
$this->view->tasks = $tasks;
|
||||
$this->view->allTasksNum = $allTasksNum;
|
||||
$this->view->summary = $this->execution->summary($tasks);
|
||||
$this->view->tabID = 'task';
|
||||
$this->view->pager = $pager;
|
||||
@@ -1364,10 +1370,13 @@ class execution extends control
|
||||
*
|
||||
* @param int $executionID
|
||||
* @param string $type
|
||||
* @param string $withWeekend
|
||||
* @param string $begin
|
||||
* @param string $end
|
||||
* @access public
|
||||
* @return void
|
||||
*/
|
||||
public function cfd($executionID = 0, $type = 'story', $withWeekend = 'false')
|
||||
public function cfd($executionID = 0, $type = 'story', $withWeekend = 'false', $begin = '', $end = '')
|
||||
{
|
||||
$execution = $this->commonAction($executionID);
|
||||
$executionID = $execution->id;
|
||||
@@ -1375,7 +1384,30 @@ class execution extends control
|
||||
$this->loadModel('kanban');
|
||||
$this->app->loadClass('date');
|
||||
|
||||
list($begin, $end) = $this->execution->getBeginEnd4CFD($execution);
|
||||
if(!empty($_POST))
|
||||
{
|
||||
$begin = htmlspecialchars($this->post->begin, ENT_QUOTES);
|
||||
$end = htmlspecialchars($this->post->end, ENT_QUOTES);
|
||||
|
||||
if(empty($begin)) return $this->sendError(sprintf($this->lang->error->notempty, $this->lang->execution->charts->cfd->begin));
|
||||
if(empty($end)) return $this->sendError(sprintf($this->lang->error->notempty, $this->lang->execution->charts->cfd->end));
|
||||
if($begin >= $end) return $this->sendError($this->lang->execution->charts->cfd->errorBegin);
|
||||
if(date("Y-m-d", strtotime("-3 months", strtotime($end))) > $begin) return $this->sendError($this->lang->execution->charts->cfd->errorDateRange);
|
||||
|
||||
$this->execution->computeCFD($executionID);
|
||||
$this->execution->checkCFDData($executionID, $begin);
|
||||
return print(js::locate($this->createLink('execution', 'cfd', "executionID=$executionID&type=$type&withWeekend=$withWeekend&begin=" . helper::safe64Encode(urlencode($begin)) . "&end=" . helper::safe64Encode(urlencode($end))), 'parent'));
|
||||
}
|
||||
|
||||
if($begin and $end)
|
||||
{
|
||||
$begin = urldecode(helper::safe64Decode($begin));
|
||||
$end = urldecode(helper::safe64Decode($end));
|
||||
}
|
||||
else
|
||||
{
|
||||
list($begin, $end) = $this->execution->getBeginEnd4CFD($execution);
|
||||
}
|
||||
$dateList = date::getDateList($begin, $end, 'Y-m-d', $withWeekend == 'false'? 'noweekend' : '');
|
||||
|
||||
//list($cycleTimeAvg, $throughput) = $this->execution->getCFDStatistics($executionID, $dateList, $type);
|
||||
@@ -1390,6 +1422,8 @@ class execution extends control
|
||||
$this->view->executionName = $execution->name;
|
||||
$this->view->executionID = $executionID;
|
||||
$this->view->chartData = $chartData;
|
||||
$this->view->begin = $begin;
|
||||
$this->view->end = $end;
|
||||
$this->display();
|
||||
}
|
||||
|
||||
@@ -2442,11 +2476,12 @@ class execution extends control
|
||||
unset($this->lang->kanban->type['all']);
|
||||
}
|
||||
|
||||
$kanbanGroup = $this->kanban->getExecutionKanban($executionID, $browseType, $groupBy);
|
||||
if($groupBy == 'story' and $browseType == 'task' and !isset($this->lang->kanban->orderList[$orderBy])) $orderBy = 'pri_asc';
|
||||
$kanbanGroup = $this->kanban->getExecutionKanban($executionID, $browseType, $groupBy, '', $orderBy);
|
||||
if(empty($kanbanGroup))
|
||||
{
|
||||
$this->kanban->createExecutionLane($executionID, $browseType, $groupBy);
|
||||
$kanbanGroup = $this->kanban->getExecutionKanban($executionID, $browseType, $groupBy);
|
||||
$kanbanGroup = $this->kanban->getExecutionKanban($executionID, $browseType, $groupBy, '', $orderBy);
|
||||
}
|
||||
|
||||
/* Determines whether an object is editable. */
|
||||
@@ -3194,15 +3229,16 @@ class execution extends control
|
||||
* @param int $executionID
|
||||
* @param int $storyID
|
||||
* @param string $confirm yes|no
|
||||
* @param string $from taskkanban
|
||||
* @access public
|
||||
* @return void
|
||||
*/
|
||||
public function unlinkStory($executionID, $storyID, $confirm = 'no')
|
||||
public function unlinkStory($executionID, $storyID, $confirm = 'no', $from = '')
|
||||
{
|
||||
if($confirm == 'no')
|
||||
{
|
||||
$tip = $this->app->rawModule == 'projectstory' ? $this->lang->execution->confirmUnlinkExecutionStory : $this->lang->execution->confirmUnlinkStory;
|
||||
return print(js::confirm($tip, $this->createLink('execution', 'unlinkstory', "executionID=$executionID&storyID=$storyID&confirm=yes")));
|
||||
return print(js::confirm($tip, $this->createLink('execution', 'unlinkstory', "executionID=$executionID&storyID=$storyID&confirm=yes&from=$from")));
|
||||
}
|
||||
else
|
||||
{
|
||||
@@ -3224,26 +3260,23 @@ class execution extends control
|
||||
return $this->send($response);
|
||||
}
|
||||
|
||||
$execution = $this->execution->getByID($executionID);
|
||||
if($this->app->tab == 'execution')
|
||||
$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 : '';
|
||||
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 : '';
|
||||
if($execution->type == 'kanban')
|
||||
{
|
||||
$kanbanData = $this->loadModel('kanban')->getRDKanban($executionID, $execLaneType, 'id_desc', 0, $execGroupBy, $rdSearchValue);
|
||||
$kanbanData = json_encode($kanbanData);
|
||||
return print(js::closeModal('parent', '', "parent.updateKanban($kanbanData)"));
|
||||
}
|
||||
else
|
||||
{
|
||||
$kanbanData = $this->loadModel('kanban')->getExecutionKanban($executionID, $execLaneType, $execGroupBy);
|
||||
$kanbanType = $execLaneType == 'all' ? 'story' : key($kanbanData);
|
||||
$kanbanData = $kanbanData[$kanbanType];
|
||||
$kanbanData = json_encode($kanbanData);
|
||||
return print(js::closeModal('parent', '', "parent.updateKanban(\"story\", $kanbanData)"));
|
||||
}
|
||||
$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);
|
||||
return print(js::closeModal('parent', '', "parent.updateKanban(\"story\", $kanbanData)"));
|
||||
}
|
||||
|
||||
return print(js::reload('parent'));
|
||||
@@ -3635,18 +3668,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')
|
||||
@@ -3680,6 +3701,9 @@ class execution extends control
|
||||
$parents = array();
|
||||
if($parentIdList) $parents = $this->execution->getByIdList($parentIdList);
|
||||
|
||||
$allExecutionsNum = $this->project->getStats($projectID, 'all');
|
||||
$this->view->allExecutionsNum = count($allExecutionsNum);
|
||||
|
||||
$this->view->executionStats = $executionStats;
|
||||
$this->view->productList = $this->loadModel('product')->getProductPairsByProject($projectID);
|
||||
$this->view->productID = $productID;
|
||||
@@ -3939,8 +3963,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';
|
||||
@@ -4072,11 +4096,15 @@ class execution extends control
|
||||
* @param string $groupBy
|
||||
* @param string $from execution|RD
|
||||
* @param string $searchValue
|
||||
* @param string $orderBy
|
||||
* @access public
|
||||
* @return array
|
||||
*/
|
||||
public function ajaxUpdateKanban($executionID = 0, $enterTime = '', $browseType = '', $groupBy = '', $from = 'execution', $searchValue = '')
|
||||
public function ajaxUpdateKanban($executionID = 0, $enterTime = '', $browseType = '', $groupBy = '', $from = 'execution', $searchValue = '', $orderBy = 'id_asc')
|
||||
{
|
||||
$this->loadModel('kanban');
|
||||
if($groupBy == 'story' and $browseType == 'task' and !isset($this->lang->kanban->orderList[$orderBy])) $orderBy = 'pri_asc';
|
||||
|
||||
$enterTime = date('Y-m-d H:i:s', $enterTime);
|
||||
$lastEditedTime = $this->dao->select("max(lastEditedTime) as lastEditedTime")->from(TABLE_KANBANLANE)->where('execution')->eq($executionID)->fetch('lastEditedTime');
|
||||
|
||||
@@ -4084,7 +4112,7 @@ class execution extends control
|
||||
if($from == 'RD') $this->session->set('rdSearchValue', $searchValue);
|
||||
if(strtotime($lastEditedTime) < 0 or $lastEditedTime > $enterTime or $groupBy != 'default' or !empty($searchValue))
|
||||
{
|
||||
$kanbanGroup = $from == 'execution' ? $this->loadModel('kanban')->getExecutionKanban($executionID, $browseType, $groupBy, $searchValue) : $this->loadModel('kanban')->getRDKanban($executionID, $browseType, 'id_asc', 0, $groupBy, $searchValue);
|
||||
$kanbanGroup = $from == 'execution' ? $this->kanban->getExecutionKanban($executionID, $browseType, $groupBy, $searchValue, $orderBy) : $this->kanban->getRDKanban($executionID, $browseType, $orderBy, 0, $groupBy, $searchValue);
|
||||
return print(json_encode($kanbanGroup));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,4 +1,6 @@
|
||||
.main-content > h2 {font-size: 16px;}
|
||||
#mainContent h2 .icon-help {font-size: 16px; vertical-align: text-bottom;}
|
||||
.tooltip-inner {font-size: 13px; letter-spacing: 1px; line-height: 22px; max-width: 400px !important; text-align: left;}
|
||||
.container {max-width: 1700px !important}
|
||||
|
||||
.pull-left .input-control {margin-right: 10px;}
|
||||
@@ -29,3 +31,7 @@
|
||||
#burnStatistics .bg-primary {margin-right: 5px;}
|
||||
#burnStatistics .icon-help {color: black;}
|
||||
#burnStatistics h3 {margin-top: 10px; text-indent: 10px; margin-bottom: 30px;}
|
||||
|
||||
#cfdDateSelect {float: left;}
|
||||
#cfdDateSelect .input-group {width: 300px; float: left;}
|
||||
#datePreview {float: left; margin-left: 10px;}
|
||||
|
||||
@@ -36,6 +36,7 @@
|
||||
.region .kanban-header-col > .title {max-width: 80% !important;}
|
||||
.region .kanban-header-col > .title {margin: 0}
|
||||
.region .kanban-header-col > .title > span {display: inline-block; overflow: hidden; padding-right:2px; position: initial; max-width: 85px !important;}
|
||||
.region .kanban-header-col > .title > span.storyColumn {max-width: 100% !important;}
|
||||
.region .kanban-header-col > .title > .text-grey {opacity: .5; font-weight: bold; color: #8b91a2;}
|
||||
.region .kanban-header-col > .title > .count {opacity: .5; font-weight: bold; color: #8b91a2;}
|
||||
.region .kanban-header-col > .title > .error {color: #333333; padding-left: 2px; font-size: 10px; padding-top: 1px; padding-right: 2px;}
|
||||
|
||||
@@ -29,6 +29,7 @@
|
||||
.kanban-affixed .kanban-header-col > .title > .text,
|
||||
.kanban-affixed .kanban-header-col > .title > .count {color: #fff!important;}
|
||||
.kanban-header-col > .title > .text {max-width: 110px !important;}
|
||||
.kanban-header-col > .title > .storyColumn.text {max-width: 100% !important;}
|
||||
|
||||
#kanbanContainer {margin: 0;}
|
||||
#kanbanContainer > .panel-body {overflow: auto;}
|
||||
|
||||
@@ -132,6 +132,11 @@ $(function()
|
||||
{
|
||||
var type = $('#type').val();
|
||||
withWeekend = withWeekend == 'true' ? 'false' : 'true';
|
||||
location.href = createLink('execution', 'cfd', 'executionID=' + executionID + '&type=' + type + '&withWeekend=' + withWeekend);
|
||||
var begin = Base64.encode(encodeURIComponent($('#begin').val()));
|
||||
var end = Base64.encode(encodeURIComponent($('#end').val()));
|
||||
location.href = createLink('execution', 'cfd', 'executionID=' + executionID + '&type=' + type + '&withWeekend=' + withWeekend + '&begin=' + begin + '&end=' + end);
|
||||
});
|
||||
|
||||
$("#end, #begin").datetimepicker('setEndDate', today)
|
||||
$('.datetimepicker-days table tfoot').append('<tr><th colspan="7">' + dateRangeTip + '</th></tr>');
|
||||
});
|
||||
|
||||
@@ -322,7 +322,7 @@ function updateRegionName(regionID, name)
|
||||
*/
|
||||
function updateLaneName(laneID, name)
|
||||
{
|
||||
$('.kanban-lane[data-id="' + laneID + '"] > .kanban-lane-name > span').text(name);
|
||||
$('.kanban-lane[data-id="' + laneID + '"] > .kanban-lane-name > span').text(name).attr('title', name);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -349,7 +349,7 @@ function updateLaneColor(laneID, color)
|
||||
*/
|
||||
function updateColumnName(columnID, name, color)
|
||||
{
|
||||
$('.kanban-col[data-id="' + columnID + '"] > div.title > span:first').text(name).css('color', color);
|
||||
$('.kanban-col[data-id="' + columnID + '"] > div.title > span:first').text(name).attr('title', name).css('color', color);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -547,6 +547,15 @@ function renderEstStarted(estStarted, status)
|
||||
*/
|
||||
function renderStoryItem(item, $item, col)
|
||||
{
|
||||
if(groupBy == 'story' && item.id == '0')
|
||||
{
|
||||
$('.storyCell').css('width', '100%');
|
||||
$parentItem = $item[0] == undefined ? $('.storyCell') : $item.parent();
|
||||
$parentItem.addClass('text-center storyCell');
|
||||
$parentItem.css('line-height', ($parentItem.parent().height() - 20) + 'px');
|
||||
$item.replaceWith('<span class="text-muted">' + item.title + '</span>');
|
||||
return;
|
||||
}
|
||||
var scaleSize = window.kanbanScaleSize;
|
||||
if(+$item.attr('data-scale-size') !== scaleSize) $item.empty().attr('data-scale-size', scaleSize);
|
||||
|
||||
@@ -749,6 +758,14 @@ addColumnRenderer('task', renderTaskItem);
|
||||
*/
|
||||
function renderCount($count, count, column)
|
||||
{
|
||||
if(groupBy == 'story' && column.type == 'story')
|
||||
{
|
||||
$count.prev().addClass('storyColumn');
|
||||
$count.prev().parent().append('<span class="caret changeOrderBy"></span>');
|
||||
$count.remove();
|
||||
return;
|
||||
}
|
||||
|
||||
/* Render WIP. */
|
||||
var limit = !column.limit || column.limit == '-1' ? '<i class="icon icon-md icon-infinite"></i>' : column.limit;
|
||||
if($count.parent().find('.limit').length)
|
||||
@@ -793,6 +810,9 @@ 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;
|
||||
@@ -850,6 +870,11 @@ function renderHeaderCol($column, column, $header, kanbanData)
|
||||
*/
|
||||
function renderLaneName($lane, lane, $kanban, columns, kanban)
|
||||
{
|
||||
if(groupBy == 'story')
|
||||
{
|
||||
$lane.hide();
|
||||
return;
|
||||
}
|
||||
if(groupBy != 'default') return;
|
||||
var canEditLaneColor = lane.actions.includes('editLaneColor');
|
||||
var canEditLaneName = lane.actions.includes('editLaneName');
|
||||
@@ -1375,7 +1400,7 @@ function handleSortCards(event)
|
||||
}
|
||||
else
|
||||
{
|
||||
$.get(createLink('execution', 'ajaxUpdateKanban', "executionID=" + executionID + "&entertime=0&browseType=" + browseType + "&groupBy=" + groupBy + '&from=RD'), function(data)
|
||||
$.get(createLink('execution', 'ajaxUpdateKanban', "executionID=" + executionID + "&entertime=0&browseType=" + browseType + "&groupBy=" + groupBy + '&from=RD' + '&serachValue=' + rdSearchValue + '&orderBy=' + orderBy), function(data)
|
||||
{
|
||||
if(data && lastUpdateData !== data)
|
||||
{
|
||||
@@ -1567,6 +1592,12 @@ $(function()
|
||||
$('.color0 .cardcolor').css('border', '1px solid #fff');
|
||||
});
|
||||
|
||||
$(document).on('click', '#kanban span.caret.changeOrderBy', function(event)
|
||||
{
|
||||
orderBy = orderBy == 'pri_desc' ? 'pri_asc' : 'pri_desc';
|
||||
searchCards(rdSearchValue);
|
||||
})
|
||||
|
||||
/* Init sortable */
|
||||
var sortType = '';
|
||||
var $cards = null;
|
||||
@@ -1694,7 +1725,7 @@ $(function()
|
||||
{
|
||||
if(rdSearchValue == '')
|
||||
{
|
||||
$.get(createLink('execution', 'ajaxUpdateKanban', "executionID=" + executionID + "&entertime=" + entertime + "&browseType=" + browseType + "&groupBy=" + groupBy + '&from=RD&searchValue=' + rdSearchValue), function(data)
|
||||
$.get(createLink('execution', 'ajaxUpdateKanban', "executionID=" + executionID + "&entertime=" + entertime + "&browseType=" + browseType + "&groupBy=" + groupBy + '&from=RD&searchValue=' + rdSearchValue + '&orderBy=' + orderBy), function(data)
|
||||
{
|
||||
if(lastUpdateData == '') lastUpdateData = data;
|
||||
if(data && lastUpdateData !== data)
|
||||
@@ -1800,7 +1831,7 @@ function toggleRDSearchBox()
|
||||
function searchCards(value)
|
||||
{
|
||||
rdSearchValue = value;
|
||||
$.get(createLink('execution', 'ajaxUpdateKanban', "executionID=" + executionID + "&entertime=0&browseType=" + browseType + "&groupBy=" + groupBy + '&from=RD&searchValue=' + rdSearchValue), function(data)
|
||||
$.get(createLink('execution', 'ajaxUpdateKanban', "executionID=" + executionID + "&entertime=0&browseType=" + browseType + "&groupBy=" + groupBy + '&from=RD&searchValue=' + rdSearchValue + '&orderBy=' + orderBy), function(data)
|
||||
{
|
||||
lastUpdateData = data;
|
||||
kanbanData = $.parseJSON(data);
|
||||
|
||||
@@ -9,7 +9,7 @@
|
||||
*/
|
||||
function updateColumnName(columnID, name, color)
|
||||
{
|
||||
$('.kanban-col[data-id="' + columnID + '"] > div.title > span:first').text(name).css('color', color);
|
||||
$('.kanban-col[data-id="' + columnID + '"] > div.title > span:first').text(name).attr('title', name).css('color', color);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -43,17 +43,17 @@ function renderUserAvatar(user, objectType, objectID, size, objectStatus)
|
||||
if(objectType == 'task')
|
||||
{
|
||||
if(!priv.canAssignTask && !user) return $noPrivAndNoAssigned;
|
||||
var link = createLink('task', 'assignto', 'executionID=' + executionID + '&id=' + objectID, '', true);
|
||||
var link = createLink('task', 'assignto', 'executionID=' + executionID + '&id=' + objectID + '&kanbanGroup=default&from=taskkanban', '', true);
|
||||
}
|
||||
if(objectType == 'story')
|
||||
{
|
||||
if(!priv.canAssignStory && !user) return $noPrivAndNoAssigned;
|
||||
var link = createLink('story', 'assignto', 'id=' + objectID, '', true);
|
||||
var link = createLink('story', 'assignto', 'id=' + objectID + '&kanbanGroup=default&from=taskkanban', '', true);
|
||||
}
|
||||
if(objectType == 'bug')
|
||||
{
|
||||
if(!priv.canAssignBug && !user) return $noPrivAndNoAssigned;
|
||||
var link = createLink('bug', 'assignto', 'id=' + objectID, '', true);
|
||||
var link = createLink('bug', 'assignto', 'id=' + objectID + '&kanbanGroup=default&from=taskkanban', '', true);
|
||||
}
|
||||
|
||||
if(!user) return objectStatus == 'closed' ? '' : $('<a class="avatar has-text ' + avatarSizeClass + ' avatar-circle iframe" title="' + noAssigned + '" style="background: #ccc" href="' + link + '"><i class="icon icon-person"></i></a>');
|
||||
@@ -128,6 +128,15 @@ function renderEstStarted(estStarted, status)
|
||||
*/
|
||||
function renderStoryItem(item, $item, col)
|
||||
{
|
||||
if(groupBy == 'story' && item.id == '0')
|
||||
{
|
||||
$('.storyCell').css('width', '100%');
|
||||
$parentItem = $item[0] == undefined ? $('.storyCell') : $item.parent();
|
||||
$parentItem.addClass('text-center storyCell');
|
||||
$parentItem.css('line-height', ($parentItem.parent().height() - 20) + 'px');
|
||||
$item.replaceWith('<span class="text-muted">' + item.title + '</span>');
|
||||
return;
|
||||
}
|
||||
var scaleSize = window.kanbanScaleSize;
|
||||
if($item.attr('data-scale-size') !== scaleSize) $item.empty().attr('data-scale-size', scaleSize);
|
||||
|
||||
@@ -330,6 +339,14 @@ addColumnRenderer('task', renderTaskItem);
|
||||
*/
|
||||
function renderColumnCount($count, count, col)
|
||||
{
|
||||
if(groupBy == 'story' && col.type == 'story')
|
||||
{
|
||||
$count.prev().addClass('storyColumn');
|
||||
$count.prev().parent().append('<span class="caret changeOrderBy"></span>');
|
||||
$count.remove();
|
||||
return;
|
||||
}
|
||||
|
||||
var text = count + '/' + (col.limit < 0 ? '<i class="icon icon-infinite"></i>' : col.limit);
|
||||
$count.html(text + '<i class="icon icon-arrow-up"></i>');
|
||||
|
||||
@@ -370,7 +387,7 @@ function tips()
|
||||
function renderHeaderCol($col, col, $header, kanban)
|
||||
{
|
||||
if(col.asParent) $col = $col.children('.kanban-header-col');
|
||||
if($col.children('.actions').context != undefined) return;
|
||||
if($col.children('.actions').context != undefined || (groupBy == 'story' && col.type == 'story')) return;
|
||||
|
||||
var $actions = $('<div class="actions createButton" />');
|
||||
var printStoryButton = printTaskButton = printBugButton = false;
|
||||
@@ -410,6 +427,11 @@ function renderHeaderCol($col, col, $header, kanban)
|
||||
*/
|
||||
function renderLaneName($name, lane, $kanban, columns, kanban)
|
||||
{
|
||||
if(groupBy == 'story')
|
||||
{
|
||||
$name.hide();
|
||||
return;
|
||||
}
|
||||
if(lane.id != 'story' && lane.id != 'task' && lane.id != 'bug') return false;
|
||||
if(!$name.children('.actions').length && (priv.canSetLane || priv.canMoveLane))
|
||||
{
|
||||
@@ -650,7 +672,7 @@ function changeCardColType(cardID, fromColID, toColID, fromLaneID, toLaneID, car
|
||||
{
|
||||
if((fromColType == 'developing' || fromColType == 'wait') && priv.canFinishTask)
|
||||
{
|
||||
var link = createLink('task', 'finish', 'taskID=' + objectID, '', true);
|
||||
var link = createLink('task', 'finish', 'taskID=' + objectID + '&extra=from=' + 'taskkanban', '', true);
|
||||
showIframe = true;
|
||||
}
|
||||
}
|
||||
@@ -658,7 +680,7 @@ function changeCardColType(cardID, fromColID, toColID, fromLaneID, toLaneID, car
|
||||
{
|
||||
if(fromColType == 'developing' && priv.canPauseTask)
|
||||
{
|
||||
var link = createLink('task', 'pause', 'taskID=' + objectID, '', true);
|
||||
var link = createLink('task', 'pause', 'taskID=' + objectID + '&extra=from=' + 'taskkanban', '', true);
|
||||
showIframe = true;
|
||||
}
|
||||
}
|
||||
@@ -666,17 +688,17 @@ function changeCardColType(cardID, fromColID, toColID, fromLaneID, toLaneID, car
|
||||
{
|
||||
if((fromColType == 'canceled' || fromColType == 'closed' || fromColType == 'developed') && priv.canActivateTask)
|
||||
{
|
||||
var link = createLink('task', 'activate', 'taskID=' + objectID, '', true);
|
||||
var link = createLink('task', 'activate', 'taskID=' + objectID + '&extra=from=' + 'taskkanban', '', true);
|
||||
showIframe = true;
|
||||
}
|
||||
if(fromColType == 'pause' && priv.canActivateTask)
|
||||
{
|
||||
var link = createLink('task', 'restart', 'taskID=' + objectID, '', true);
|
||||
var link = createLink('task', 'restart', 'taskID=' + objectID + '&from=' + 'taskkanban', '', true);
|
||||
showIframe = true;
|
||||
}
|
||||
if(fromColType == 'wait' && priv.canStartTask)
|
||||
{
|
||||
var link = createLink('task', 'start', 'taskID=' + objectID, '', true);
|
||||
var link = createLink('task', 'start', 'taskID=' + objectID + '&extra=from=' + 'taskkanban', '', true);
|
||||
showIframe = true;
|
||||
}
|
||||
}
|
||||
@@ -684,7 +706,7 @@ function changeCardColType(cardID, fromColID, toColID, fromLaneID, toLaneID, car
|
||||
{
|
||||
if((fromColType == 'developing' || fromColType == 'wait' || fromColType == 'pause') && priv.canCancelTask)
|
||||
{
|
||||
var link = createLink('task', 'cancel', 'taskID=' + objectID, '', true);
|
||||
var link = createLink('task', 'cancel', 'taskID=' + objectID + '&extra=from=' + 'taskkanban', '', true);
|
||||
showIframe = true;
|
||||
}
|
||||
}
|
||||
@@ -692,7 +714,7 @@ function changeCardColType(cardID, fromColID, toColID, fromLaneID, toLaneID, car
|
||||
{
|
||||
if((fromColType == 'developed' || fromColType == 'canceled') && priv.canCloseTask)
|
||||
{
|
||||
var link = createLink('task', 'close', 'taskID=' + objectID, '', true);
|
||||
var link = createLink('task', 'close', 'taskID=' + objectID + '&extra=from=' + 'taskkanban', '', true);
|
||||
showIframe = true;
|
||||
}
|
||||
}
|
||||
@@ -705,7 +727,7 @@ function changeCardColType(cardID, fromColID, toColID, fromLaneID, toLaneID, car
|
||||
{
|
||||
if(fromColType == 'unconfirmed' && priv.canConfirmBug)
|
||||
{
|
||||
var link = createLink('bug', 'confirmBug', 'bugID=' + objectID, '', true);
|
||||
var link = createLink('bug', 'confirmBug', 'bugID=' + objectID + '&extra=&from=taskkanban', '', true);
|
||||
showIframe = true;
|
||||
}
|
||||
}
|
||||
@@ -714,7 +736,7 @@ function changeCardColType(cardID, fromColID, toColID, fromLaneID, toLaneID, car
|
||||
if(fromColType == 'confirmed' || fromColType == 'unconfirmed') moveCard = true;
|
||||
if((fromColType == 'closed' || fromColType == 'fixed' || fromColType == 'testing' || fromColType == 'tested') && priv.canActivateBug)
|
||||
{
|
||||
var link = createLink('bug', 'activate', 'bugID=' + objectID, '', true);
|
||||
var link = createLink('bug', 'activate', 'bugID=' + objectID + '&extra=&from=taskkanban', '', true);
|
||||
showIframe = true;
|
||||
}
|
||||
}
|
||||
@@ -722,7 +744,7 @@ function changeCardColType(cardID, fromColID, toColID, fromLaneID, toLaneID, car
|
||||
{
|
||||
if(fromColType == 'fixing' || fromColType == 'confirmed' || fromColType == 'unconfirmed')
|
||||
{
|
||||
var link = createLink('bug', 'resolve', 'bugID=' + objectID, '', true);
|
||||
var link = createLink('bug', 'resolve', 'bugID=' + objectID + '&extra=&from=taskkanban', '', true);
|
||||
showIframe = true;
|
||||
}
|
||||
}
|
||||
@@ -738,7 +760,7 @@ function changeCardColType(cardID, fromColID, toColID, fromLaneID, toLaneID, car
|
||||
{
|
||||
if(fromColType == 'testing' || fromColType == 'tested')
|
||||
{
|
||||
var link = createLink('bug', 'close', 'bugID=' + objectID, '', true);
|
||||
var link = createLink('bug', 'close', 'bugID=' + objectID + '&extra=&from=taskkanban', '', true);
|
||||
showIframe = true;
|
||||
}
|
||||
}
|
||||
@@ -769,7 +791,7 @@ function changeCardColType(cardID, fromColID, toColID, fromLaneID, toLaneID, car
|
||||
{
|
||||
if(toColType == 'closed' && priv.canCloseStory)
|
||||
{
|
||||
var link = createLink('story', 'close', 'storyID=' + objectID, '', true);
|
||||
var link = createLink('story', 'close', 'storyID=' + objectID + '&from=taskkanban', '', true);
|
||||
showIframe = true;
|
||||
}
|
||||
else
|
||||
@@ -930,7 +952,7 @@ function createColumnCreateMenu(options)
|
||||
|
||||
if(col.laneType == 'story')
|
||||
{
|
||||
if(priv.canCreateStory) items.push({label: storyLang.create, url: $.createLink('story', 'create', 'productID=' + productID, '', true), className: 'iframe'});
|
||||
if(priv.canCreateStory) items.push({label: storyLang.create, url: $.createLink('story', 'create', 'productID=' + productID + '&branch=0&moduleID=0&storyID=0&objectID=' + executionID, '', true), className: 'iframe'});
|
||||
if(priv.canBatchCreateStory) items.push({label: executionLang.batchCreateStory, url: $.createLink('story', 'batchcreate', 'productID=' + productID + '&branch=0&moduleID=0&storyID=0&executionID=' + executionID, '', true), className: 'iframe', attrs: {'data-width': '90%'}});
|
||||
if(priv.canLinkStory) items.push({label: executionLang.linkStory, url: $.createLink('execution', 'linkStory', 'executionID=' + executionID, '', true), className: 'iframe', attrs: {'data-width': '90%'}});
|
||||
if(priv.canLinkStoryByPlan) items.push({label: executionLang.linkStoryByPlan, url: '#linkStoryByPlan', 'attrs' : {'data-toggle': 'modal'}});
|
||||
@@ -1167,7 +1189,7 @@ function handleSortCards(event)
|
||||
}
|
||||
else
|
||||
{
|
||||
$.get(createLink('execution', 'ajaxUpdateKanban', "executionID=" + executionID + "&entertime=0&browseType=" + browseType + "&groupBy=" + groupBy + '&from=execution'), function(data)
|
||||
$.get(createLink('execution', 'ajaxUpdateKanban', "executionID=" + executionID + "&entertime=0&browseType=" + browseType + "&groupBy=" + groupBy + '&from=execution' + '&searchValue=' + searchValue + '&orderBy=' + orderBy), function(data)
|
||||
{
|
||||
if(data && lastUpdateData !== data)
|
||||
{
|
||||
@@ -1252,6 +1274,12 @@ $(function()
|
||||
event.preventDefault();
|
||||
});
|
||||
|
||||
$(document).on('click', '#kanbans span.caret.changeOrderBy', function(event)
|
||||
{
|
||||
orderBy = orderBy == 'pri_desc' ? 'pri_asc' : 'pri_desc';
|
||||
searchCards(searchValue);
|
||||
})
|
||||
|
||||
/* Init contextmenu */
|
||||
$('#kanbans').on('click', '[data-contextmenu]', function(event)
|
||||
{
|
||||
@@ -1311,7 +1339,7 @@ $(function()
|
||||
lastUpdateData = '';
|
||||
setInterval(function()
|
||||
{
|
||||
$.get(createLink('execution', 'ajaxUpdateKanban', "executionID=" + executionID + "&entertime=" + entertime + "&browseType=" + browseType + "&groupBy=" + groupBy + '&from=execution&searchValue=' + searchValue), function(data)
|
||||
$.get(createLink('execution', 'ajaxUpdateKanban', "executionID=" + executionID + "&entertime=" + entertime + "&browseType=" + browseType + "&groupBy=" + groupBy + '&from=execution&searchValue=' + searchValue + '&orderBy' + orderBy), function(data)
|
||||
{
|
||||
if(lastUpdateData == '') lastUpdateData = data;
|
||||
if(data && lastUpdateData !== data)
|
||||
@@ -1447,7 +1475,7 @@ function toggleSearchBox()
|
||||
function searchCards(value)
|
||||
{
|
||||
searchValue = value;
|
||||
$.get(createLink('execution', 'ajaxUpdateKanban', "executionID=" + executionID + "&entertime=0&browseType=" + browseType + "&groupBy=" + groupBy + '&from=execution&searchValue=' + value), function(data)
|
||||
$.get(createLink('execution', 'ajaxUpdateKanban', "executionID=" + executionID + "&entertime=0&browseType=" + browseType + "&groupBy=" + groupBy + '&from=execution&searchValue=' + value + '&orderBy=' + orderBy), function(data)
|
||||
{
|
||||
lastUpdateData = data;
|
||||
var kanbanData = $.parseJSON(data);
|
||||
|
||||
@@ -431,11 +431,22 @@ $lang->execution->charts->burn->graph->actuality = 'Aktualität';
|
||||
$lang->execution->charts->burn->graph->delay = 'Delay';
|
||||
|
||||
$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>";
|
||||
$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';
|
||||
$lang->execution->charts->cfd->throughputTip = 'Throughput Rate = WIP / Average cycle time';
|
||||
|
||||
$lang->execution->charts->cfd->begin = 'Begin';
|
||||
$lang->execution->charts->cfd->end = 'End';
|
||||
$lang->execution->charts->cfd->errorBegin = 'The start time cannot be greater than the end time.';
|
||||
$lang->execution->charts->cfd->errorDateRange = 'The Cumulative Flow Diagram(CFD) only provides data display within 3 months.';
|
||||
$lang->execution->charts->cfd->dateRangeTip = 'CFD only shows the data within 3 months';
|
||||
|
||||
$lang->execution->placeholder = new stdclass();
|
||||
$lang->execution->placeholder->code = 'Abkurzung des Projektnamens';
|
||||
$lang->execution->placeholder->totalLeft = 'Schätzungen zu Beginn des Projekts.';
|
||||
|
||||
@@ -431,11 +431,22 @@ $lang->execution->charts->burn->graph->actuality = 'Actual';
|
||||
$lang->execution->charts->burn->graph->delay = 'Delay';
|
||||
|
||||
$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>";
|
||||
$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';
|
||||
$lang->execution->charts->cfd->throughputTip = 'Throughput Rate = WIP / Average cycle time';
|
||||
|
||||
$lang->execution->charts->cfd->begin = 'Begin';
|
||||
$lang->execution->charts->cfd->end = 'End';
|
||||
$lang->execution->charts->cfd->errorBegin = 'The start time cannot be greater than the end time.';
|
||||
$lang->execution->charts->cfd->errorDateRange = 'The Cumulative Flow Diagram(CFD) only provides data display within 3 months.';
|
||||
$lang->execution->charts->cfd->dateRangeTip = 'CFD only shows the data within 3 months';
|
||||
|
||||
$lang->execution->placeholder = new stdclass();
|
||||
$lang->execution->placeholder->code = "Abbreviation of {$lang->executionCommon} name";
|
||||
$lang->execution->placeholder->totalLeft = "Hours estimated on the first day of the {$lang->executionCommon}.";
|
||||
|
||||
@@ -434,11 +434,21 @@ $lang->execution->charts->burn->graph->actuality = 'Actuel';
|
||||
$lang->execution->charts->burn->graph->delay = 'Delay';
|
||||
|
||||
$lang->execution->charts->cfd = new stdclass();
|
||||
$lang->execution->charts->cfd->cfdTip = "<p>
|
||||
1. Le CFD(Cumulative Flow Diagram)indique la tendance de la charge de travail cumulée de chaque étape au fil du temps.<br>
|
||||
2. L'axe horizontal représente la date et l'axe vertical représente le nombre de travaux.<br>
|
||||
3. Ce CFD vous permet de calculer les quantités de travail en cours (WIP), les taux de livraison et les délais moyens pour comprendre comment votre équipe travaille.<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';
|
||||
$lang->execution->charts->cfd->throughputTip = 'Throughput Rate = WIP / Average cycle time';
|
||||
|
||||
$lang->execution->charts->cfd->begin = 'Begin';
|
||||
$lang->execution->charts->cfd->end = 'End';
|
||||
$lang->execution->charts->cfd->errorBegin = 'The start time cannot be greater than the end time.';
|
||||
$lang->execution->charts->cfd->errorDateRange = 'The Cumulative Flow Diagram(CFD) only provides data display within 3 months.';
|
||||
$lang->execution->charts->cfd->dateRangeTip = 'CFD only shows the data within 3 months';
|
||||
|
||||
$lang->execution->placeholder = new stdclass();
|
||||
$lang->execution->placeholder->code = "Abréviation du nom du {$lang->executionCommon}";
|
||||
$lang->execution->placeholder->totalLeft = "Heures estimées le premier jour du {$lang->executionCommon}.";
|
||||
|
||||
@@ -431,11 +431,21 @@ $lang->execution->charts->burn->graph->actuality = '实际';
|
||||
$lang->execution->charts->burn->graph->delay = '延期';
|
||||
|
||||
$lang->execution->charts->cfd = new stdclass();
|
||||
$lang->execution->charts->cfd->cfdTip = "<p>
|
||||
1.累积流图反应各个阶段累积处理的工作项数量随时间的变化趋势。</br>
|
||||
2.横轴代表日期,纵轴代表工作项数量。</br>
|
||||
3.通过此图可计算出在制品数量,交付速率以及平均前置时间,从而了解团队的交付情况。</p>";
|
||||
$lang->execution->charts->cfd->cycleTime = '平均周期时间';
|
||||
$lang->execution->charts->cfd->cycleTimeTip = '平均每个卡片从开发启动到完成的周期时间';
|
||||
$lang->execution->charts->cfd->throughput = '吞吐率';
|
||||
$lang->execution->charts->cfd->throughputTip = '吞吐率 = 在制品 / 平均周期时间';
|
||||
|
||||
$lang->execution->charts->cfd->begin = '开始日期';
|
||||
$lang->execution->charts->cfd->end = '结束日期';
|
||||
$lang->execution->charts->cfd->errorBegin = '开始日期应小于结束日期';
|
||||
$lang->execution->charts->cfd->errorDateRange = '累积流图只提供3个月内的数据展示';
|
||||
$lang->execution->charts->cfd->dateRangeTip = '累积流图只展示3个月内的数据';
|
||||
|
||||
$lang->execution->placeholder = new stdclass();
|
||||
$lang->execution->placeholder->code = '团队内部的简称';
|
||||
$lang->execution->placeholder->totalLeft = "{$lang->executionCommon}开始时的总预计工时";
|
||||
|
||||
+134
-1
@@ -79,7 +79,7 @@ class executionModel extends model
|
||||
$executions = $this->getPairs(0, 'all', 'nocode');
|
||||
if(!$executionID and $this->session->execution) $executionID = $this->session->execution;
|
||||
if(!$executionID or !in_array($executionID, array_keys($executions))) $executionID = key($executions);
|
||||
$this->session->set('execution', $executionID);
|
||||
$this->session->set('execution', $executionID, $this->app->tab);
|
||||
|
||||
/* Unset story, bug, build and testtask if type is ops. */
|
||||
if($execution and $execution->type == 'stage' and $this->config->systemMode == 'new')
|
||||
@@ -3072,6 +3072,42 @@ class executionModel extends model
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Check whether there is data on the specified date of execution, and there is no data with the latest date added.
|
||||
*
|
||||
* @param int $executionID
|
||||
* @param string $date
|
||||
* @access public
|
||||
* @return void
|
||||
*/
|
||||
public function checkCFDData($executionID, $date)
|
||||
{
|
||||
$today = helper::today();
|
||||
if($date >= $today) return;
|
||||
|
||||
$checkData = $this->dao->select("date, `count` AS value, `name`")->from(TABLE_CFD)
|
||||
->where('execution')->eq((int)$executionID)
|
||||
->andWhere('date')->eq($date)
|
||||
->orderBy('date DESC, id asc')->fetchGroup('name', 'date');
|
||||
if(!$checkData)
|
||||
{
|
||||
$closetoDate = $this->dao->select("max(date) as date")->from(TABLE_CFD)->where('execution')->eq((int)$executionID)->andWhere('date')->lt($date)->fetch('date');
|
||||
if($closetoDate)
|
||||
{
|
||||
$copyData = $this->dao->select("*")->from(TABLE_CFD)
|
||||
->where('execution')->eq((int)$executionID)
|
||||
->andWhere('date')->eq($closetoDate)
|
||||
->fetchAll();
|
||||
foreach($copyData as $data)
|
||||
{
|
||||
unset($data->id);
|
||||
$data->date = $date;
|
||||
$this->dao->replace(TABLE_CFD)->data($data)->exec();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Fix burn for first day.
|
||||
*
|
||||
@@ -4269,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.
|
||||
*
|
||||
|
||||
@@ -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($status == "all"):?>
|
||||
<?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: ?>
|
||||
|
||||
@@ -13,11 +13,14 @@
|
||||
<?php include '../../common/view/header.html.php';?>
|
||||
<?php js::import($jsRoot . 'echarts/echarts.common.min.js'); ?>
|
||||
<?php js::import($jsRoot . 'html2canvas/min.js'); ?>
|
||||
<?php js::import($jsRoot . 'misc/base64.js');?>
|
||||
<?php js::set('executionID', $executionID); ?>
|
||||
<?php js::set('withWeekend', $withWeekend); ?>
|
||||
<?php js::set('chartData', $chartData); ?>
|
||||
<?php js::set('YUnit', $lang->execution->count); ?>
|
||||
<?php js::set('XUnit', $lang->execution->burnXUnit); ?>
|
||||
<?php js::set('dateRangeTip', $lang->execution->charts->cfd->dateRangeTip); ?>
|
||||
<?php js::set('today', date(DT_DATE1)); ?>
|
||||
<div id='mainMenu' class='clearfix'>
|
||||
<div class='btn-toolbar pull-left'>
|
||||
<?php
|
||||
@@ -32,10 +35,20 @@
|
||||
<div class='input-control w-100px'>
|
||||
<?php echo html::select('type', $lang->execution->cfdTypeList, $type, "class='form-control chosen'");?>
|
||||
</div>
|
||||
<div id="cfdDateSelect">
|
||||
<form method='post' target='hiddenwin' class='not-watch'>
|
||||
<div class='input-group'>
|
||||
<?php echo html::input('begin', $begin, "class='form-control form-date' onchange='$(\"#datePreview\").removeClass(\"hidden\")' placeholder='" . $lang->execution->charts->cfd->begin . "'");?>
|
||||
<span class='input-group-addon'><?php echo $lang->project->to;?></span>
|
||||
<?php echo html::input('end', $end, "class='form-control form-date' onchange='$(\"#datePreview\").removeClass(\"hidden\")' placeholder='" . $lang->execution->charts->cfd->end . "'");?>
|
||||
</div>
|
||||
<?php echo html::commonButton($lang->preview, "onclick='$(this).closest(\"form\").submit()' id='datePreview'", 'btn btn-primary hidden');?>
|
||||
</form>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div id='mainContent' class='main-content'>
|
||||
<h2 class='text-center'><?php echo $executionName . ' - ' . zget($lang->execution->cfdTypeList, $type) . $lang->execution->CFD;?></h2>
|
||||
<h2 class='text-center'><?php echo $executionName . ' - ' . zget($lang->execution->cfdTypeList, $type) . $lang->execution->CFD;?> <i class="icon icon-help" data-toggle="tooltip" data-tip-class="tooltip-help" data-html='true' data-placement="bottom" title="<?php echo $lang->execution->charts->cfd->cfdTip;?>"></i></h2>
|
||||
<?php if(isset($chartData['labels']) and count($chartData['labels']) != 1): ?>
|
||||
<div id="cfdWrapper">
|
||||
<div id="cfdChart" style="width: 1200px; height: 600px"></div>
|
||||
|
||||
@@ -118,6 +118,11 @@ js::set('priv',
|
||||
)
|
||||
);
|
||||
?>
|
||||
<?php if($groupBy == 'story' and $browseType == 'task'):?>
|
||||
<style>
|
||||
.kanban-cols {left: 0px !important;}
|
||||
</style>
|
||||
<?php endif;?>
|
||||
<div id='mainMenu' class='clearfix'>
|
||||
<div class='btn-toolbar pull-left'>
|
||||
<div class="input-control space c-type">
|
||||
@@ -143,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
|
||||
|
||||
@@ -198,7 +198,7 @@ body {margin-bottom: 25px;}
|
||||
<div class="table-empty-tip">
|
||||
<p>
|
||||
<span class="text-muted"><?php echo $lang->task->noTask;?></span>
|
||||
<?php if($canBeChanged and common::hasPriv('task', 'create') and $status == "all"):?>
|
||||
<?php if($canBeChanged and common::hasPriv('task', 'create') and empty($allTasksNum->count)):?>
|
||||
<?php echo html::a($taskCreateLink, "<i class='icon icon-plus'></i> " . $lang->task->create, '', "class='btn btn-info'");?>
|
||||
<?php endif;?>
|
||||
</p>
|
||||
|
||||
@@ -10,6 +10,11 @@
|
||||
?>
|
||||
<?php include '../../common/view/header.html.php';?>
|
||||
<?php include '../../common/view/kanban.html.php';?>
|
||||
<?php if($groupBy == 'story' and $browseType == 'task'):?>
|
||||
<style>
|
||||
.kanban-cols {left: 0px !important;}
|
||||
</style>
|
||||
<?php endif;?>
|
||||
<div id='mainMenu' class='clearfix'>
|
||||
<div class='btn-toolbar pull-left'>
|
||||
<div class="input-control space c-type">
|
||||
@@ -35,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
|
||||
@@ -220,4 +225,5 @@ js::set('priv',
|
||||
<?php js::set('displayCards', $execution->displayCards);?>
|
||||
<?php js::set('needLinkProducts', $lang->execution->needLinkProducts);?>
|
||||
<?php js::set('hourUnit', $config->hourUnit);?>
|
||||
<?php js::set('orderBy', $storyOrder);?>
|
||||
<?php include '../../common/view/footer.html.php';?>
|
||||
|
||||
@@ -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'));
|
||||
}
|
||||
|
||||
|
||||
@@ -18,7 +18,7 @@ $lang->file->deleted = 'Deleted';
|
||||
$lang->file->uploadImages = 'Batch Upload Images';
|
||||
$lang->file->download = 'Download Files';
|
||||
$lang->file->uploadDate = 'Uploaded';
|
||||
$lang->file->edit = 'Rename File';
|
||||
$lang->file->edit = 'Rename';
|
||||
$lang->file->inputFileName = 'Enter File Name';
|
||||
$lang->file->delete = 'Delete File';
|
||||
$lang->file->label = 'Label:';
|
||||
|
||||
@@ -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();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2,6 +2,7 @@
|
||||
<style>
|
||||
.file-input .file-editbox{max-width:40%;}
|
||||
.file-input-list .input-group-btn{float:left}
|
||||
.fileAction {color: #0c64eb !important;}
|
||||
</style>
|
||||
<?php js::set('dangerExtensions', ',' . $this->config->file->dangers . ',');?>
|
||||
<?php js::set('maxUploadSize', $maxUploadSize);?>
|
||||
@@ -25,8 +26,8 @@
|
||||
<small class="file-size muted"></small>
|
||||
</div>
|
||||
<div class="input-group-btn">
|
||||
<button type="button" class="btn btn-link file-input-rename"><?php echo $lang->file->edit;?></button>
|
||||
<button type="button" class="btn btn-link file-input-delete"><?php echo $lang->delete;?></button>
|
||||
<button type="button" class="fileAction btn btn-link file-input-rename"><?php echo $lang->file->edit;?></button>
|
||||
<button type="button" class="fileAction btn btn-link file-input-delete"><?php echo $lang->delete;?></button>
|
||||
</div>
|
||||
</div>
|
||||
<input type="file" name="<?php echo $filesName;?>[]" onchange="checkDangerExtension(this)" />
|
||||
|
||||
@@ -7,8 +7,7 @@
|
||||
<style>
|
||||
.files-list>li>a {display: inline; word-wrap: break-word;}
|
||||
.files-list>li>.right-icon {opacity: 1;}
|
||||
.files-list>li>.right-icon>a {padding-left: 7px;}
|
||||
html[lang|="zh"] .files-list>li>.right-icon>a {padding-left: 3px;}
|
||||
.fileAction {color: #0c64eb !important;}
|
||||
</style>
|
||||
<script>
|
||||
/* Delete a file. */
|
||||
@@ -93,8 +92,8 @@
|
||||
if(common::hasPriv($objectType, 'edit', $object))
|
||||
{
|
||||
echo "<span class='right-icon'> ";
|
||||
common::printLink('file', 'edit', "fileID=$file->id", $lang->file->edit, '', "data-width='400' class='edit iframe text-primary' title='{$lang->file->edit}'");
|
||||
if(common::hasPriv('file', 'delete')) echo html::a('###', $lang->delete, '', "class='text-primary' onclick='deleteFile($file->id)' title='$lang->delete'");
|
||||
common::printLink('file', 'edit', "fileID=$file->id", $lang->file->edit, '', "data-width='400' class='fileAction btn btn-link edit iframe text-primary' title='{$lang->file->edit}'");
|
||||
if(common::hasPriv('file', 'delete')) echo html::a('###', $lang->delete, '', "class='fileAction btn btn-link text-primary' onclick='deleteFile($file->id)' title='$lang->delete'");
|
||||
echo '</span>';
|
||||
}
|
||||
echo '</li>';
|
||||
|
||||
@@ -8,8 +8,7 @@
|
||||
<style>
|
||||
.files-list>li>a {display: inline; word-wrap: break-word;}
|
||||
.files-list>li>.right-icon {opacity: 1;}
|
||||
.files-list>li>.right-icon>a {padding-left: 7px;}
|
||||
html[lang|="zh"] .files-list>li>.right-icon>a {padding-left: 3px;}
|
||||
.fileAction {color: #0c64eb !important;}
|
||||
</style>
|
||||
<script>
|
||||
/* Delete a file. */
|
||||
@@ -107,7 +106,7 @@
|
||||
/* For the open source version of the file judgment. */
|
||||
if(stripos('txt|jpg|jpeg|gif|png|bmp', $file->extension) !== false)
|
||||
{
|
||||
echo html::a($downloadLink, $lang->file->preview, '_blank', "class='text-primary' onclick=\"return downloadFile($file->id, '$file->extension', $imageWidth, '$file->title')\"");
|
||||
echo html::a($downloadLink, $lang->file->preview, '_blank', "class='fileAction btn btn-link text-primary' onclick=\"return downloadFile($file->id, '$file->extension', $imageWidth, '$file->title')\"");
|
||||
}
|
||||
|
||||
/* For the max version of the file judgment. */
|
||||
@@ -116,13 +115,13 @@
|
||||
$officeTypes = 'doc|docx|xls|xlsx|ppt|pptx|pdf';
|
||||
if(stripos($officeTypes, $file->extension) !== false)
|
||||
{
|
||||
echo html::a($downloadLink, $lang->file->preview, '_blank', "class='text-primary' onclick=\"return downloadFile($file->id, '$file->extension', $imageWidth, '$file->title')\"");
|
||||
echo html::a($downloadLink, $lang->file->preview, '_blank', "class='fileAction btn btn-link text-primary' onclick=\"return downloadFile($file->id, '$file->extension', $imageWidth, '$file->title')\"");
|
||||
}
|
||||
}
|
||||
|
||||
common::printLink('file', 'download', "fileID=$file->id", $lang->file->downloadFile, '_blank', "class='text-primary' title='{$lang->file->downloadFile}'");
|
||||
common::printLink('file', 'edit', "fileID=$file->id", $lang->file->edit, '', "data-width='400' class='edit iframe text-primary' title='{$lang->file->edit}'");
|
||||
if(common::hasPriv('file', 'delete')) echo html::a('###', $lang->delete, '', "class='text-primary' onclick='deleteFile($file->id)' title='$lang->delete'");
|
||||
common::printLink('file', 'download', "fileID=$file->id", $lang->file->downloadFile, '_blank', "class='fileAction btn btn-link text-primary' title='{$lang->file->downloadFile}'");
|
||||
common::printLink('file', 'edit', "fileID=$file->id", $lang->file->edit, '', "data-width='400' class='fileAction btn btn-link edit iframe text-primary' title='{$lang->file->edit}'");
|
||||
if(common::hasPriv('file', 'delete')) echo html::a('###', $lang->delete, '', "class='fileAction btn btn-link text-primary' onclick='deleteFile($file->id)' title='$lang->delete'");
|
||||
echo '</span>';
|
||||
}
|
||||
echo '</li>';
|
||||
|
||||
+58
-11
@@ -14,7 +14,7 @@ class kanban extends control
|
||||
/**
|
||||
* Kanban space.
|
||||
*
|
||||
* @param string $browseType all|my|other|closed
|
||||
* @param string $browseType involved|cooperation|public|private
|
||||
* @param int $recTotal
|
||||
* @param int $recPerPage
|
||||
* @param int $pageID
|
||||
@@ -201,11 +201,16 @@ class kanban extends control
|
||||
*
|
||||
* @param int $spaceID
|
||||
* @param string $type
|
||||
* @param int $copyKanbanID
|
||||
* @param string $extra
|
||||
* @access public
|
||||
* @return void
|
||||
*/
|
||||
public function create($spaceID = 0, $type = 'private')
|
||||
public function create($spaceID = 0, $type = 'private', $copyKanbanID = 0, $extra = '')
|
||||
{
|
||||
$extra = str_replace(array(',', ' '), array('&', ''), $extra);
|
||||
parse_str($extra, $output);
|
||||
|
||||
if(!empty($_POST))
|
||||
{
|
||||
$kanbanID = $this->kanban->create();
|
||||
@@ -216,6 +221,15 @@ class kanban extends control
|
||||
return $this->send(array('result' => 'success', 'message' => $this->lang->saveSuccess, 'locate' => 'parent'));
|
||||
}
|
||||
|
||||
$enableImport = 'off';
|
||||
$importObjects = array();
|
||||
if($copyKanbanID)
|
||||
{
|
||||
$copyKanban = $this->kanban->getByID($copyKanbanID);
|
||||
$enableImport = empty($copyKanban->object) ? 'off' : 'on';
|
||||
$importObjects = empty($copyKanban->object) ? array() : explode(',', $copyKanban->object);
|
||||
}
|
||||
|
||||
unset($this->lang->kanbanspace->featureBar['involved']);
|
||||
|
||||
$space = $this->kanban->getSpaceById($spaceID);
|
||||
@@ -223,12 +237,18 @@ class kanban extends control
|
||||
$users = $this->loadModel('user')->getPairs('noclosed|nodeleted', '', 0, $spaceUsers);
|
||||
$whitelist = (isset($space->whitelist) and !empty($space->whitelist)) ? $space->whitelist : ',';
|
||||
|
||||
$this->view->users = $users;
|
||||
$this->view->whitelist = $this->user->getPairs('noclosed|nodeleted', '', 0, $whitelist);
|
||||
$this->view->spaceID = $spaceID;
|
||||
$this->view->spacePairs = array(0 => '') + $this->kanban->getSpacePairs($type);
|
||||
$this->view->type = $type;
|
||||
$this->view->typeList = $this->lang->kanbanspace->featureBar;
|
||||
$this->view->users = $users;
|
||||
$this->view->whitelist = $this->user->getPairs('noclosed|nodeleted', '', 0, $whitelist);
|
||||
$this->view->spaceID = $spaceID;
|
||||
$this->view->spacePairs = array(0 => '') + $this->kanban->getSpacePairs($type);
|
||||
$this->view->type = $type;
|
||||
$this->view->typeList = $this->lang->kanbanspace->featureBar;
|
||||
$this->view->kanbans = array('' => '') + $this->kanban->getPairs();
|
||||
$this->view->copyKanbanID = $copyKanbanID;
|
||||
$this->view->copyKanban = $copyKanbanID ? $copyKanban : '';
|
||||
$this->view->enableImport = $enableImport;
|
||||
$this->view->importObjects = $importObjects;
|
||||
$this->view->copyRegion = isset($output['copyRegion']) ? true : false;
|
||||
|
||||
$this->display();
|
||||
}
|
||||
@@ -386,19 +406,20 @@ class kanban extends control
|
||||
*
|
||||
* @param int $kanbanID
|
||||
* @param string $confirm
|
||||
* @param string $browseType involved|cooperation|public|private
|
||||
* @access public
|
||||
* @return void
|
||||
*/
|
||||
public function delete($kanbanID, $confirm = 'no')
|
||||
public function delete($kanbanID, $confirm = 'no', $browseType = 'involved')
|
||||
{
|
||||
if($confirm == 'no')
|
||||
{
|
||||
return print(js::confirm($this->lang->kanban->confirmDeleteKanban, $this->createLink('kanban', 'delete', "kanbanID=$kanbanID&confirm=yes")));
|
||||
return print(js::confirm($this->lang->kanban->confirmDeleteKanban, $this->createLink('kanban', 'delete', "kanbanID=$kanbanID&confirm=yes&browseType=$browseType")));
|
||||
}
|
||||
else
|
||||
{
|
||||
$this->kanban->delete(TABLE_KANBAN, $kanbanID);
|
||||
return print(js::locate($this->createLink('kanban', 'space'), 'parent'));
|
||||
return print(js::locate($this->createLink('kanban', 'space', "browseType=$browseType"), 'parent'));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1883,4 +1904,30 @@ class kanban extends control
|
||||
|
||||
return print(html::select($field, $lanes, '', "class='form-control'"));
|
||||
}
|
||||
|
||||
/**
|
||||
* Ajax load space users.
|
||||
*
|
||||
* @param int $spaceID
|
||||
* @param string $field team|whitelist|owner
|
||||
* @param string $selectedUser
|
||||
* @access public
|
||||
* @return string
|
||||
*/
|
||||
public function ajaxLoadSpaceUsers($spaceID, $field = '', $selectedUser = '')
|
||||
{
|
||||
$space = $this->kanban->getSpaceById($spaceID);
|
||||
$accounts = '';
|
||||
if(!empty($space))
|
||||
{
|
||||
if($space->type == 'private' and !empty($space->whitelist)) $accounts = $space->whitelist;
|
||||
if($space->type != 'private') $accounts = trim($space->owner) . ',' . trim($space->team);
|
||||
}
|
||||
|
||||
$users = $this->loadModel('user')->getPairs('noclosed|nodeleted', '', 0, $accounts);
|
||||
$multiple = in_array($field, array('team', 'whitelist')) ? 'multiple' : '';
|
||||
$fieldName = $multiple ? $field . '[]' : $field;
|
||||
|
||||
return print(html::select($fieldName, $users, $selectedUser, "class='form-control' $multiple"));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -9,3 +9,17 @@
|
||||
#mainContent .objectBox .checkbox-primary>label:after {width: 14px; height: 14px;}
|
||||
[lang^='en'] .columnWidth {width: 120px;}
|
||||
[lang^='zh-cn'] .columnWidth {width: 80px;}
|
||||
|
||||
#copyKanbanModal {padding: 0;}
|
||||
#copyKanbanModal {padding: 0 2px;}
|
||||
#copyKanbanModal > div {position: relative;}
|
||||
#copyKanbanModal a {display: block; min-height: 30px; line-height: 30px; padding: 5px 15px; border: 1px solid #e5e5e5; color: #333; margin: 5px 0; border-radius: 3px;}
|
||||
#copyKanbanModal a > i {display: inline-block; margin-right: 5px;}
|
||||
#copyKanbanModal a:hover {border: 1px solid #00a9fc; background-color: #E9F2FB; text-decoration: none;}
|
||||
#copyKanbanModal a.active {border-color: #00da88; color: #00da88; background-color: #E5FFE6;}
|
||||
#copyKanbanModal a.active:after {position: absolute; content: '\e92f'; font-family: ZentaoIcon; font-size: 20px; right: 25px;}
|
||||
#copyKanbanModal a.cancel {color: #ff5d5d;}
|
||||
#copyKanbanModal .copyContentBox {display: inline-block;}
|
||||
#copyKanbanModal .copyContentBox > .checkbox-primary {display: inline-block; margin-left: 10px; margin-top: -1px;}
|
||||
#copyKanbanModal .copyContentBox > .checkbox-primary:first-child {margin-left: 20px;}
|
||||
#copyContentbasicInfo {cursor: not-allowed;}
|
||||
|
||||
@@ -1,6 +1,14 @@
|
||||
$(function()
|
||||
{
|
||||
if(enableImport == 'off') $("input[name^='importObjectList']").attr('disabled', 'disabled');
|
||||
$("input[id='copyContentbasicInfo']").click(function(){return false;})
|
||||
|
||||
copyRegion = $("input[id='copyContentregion']").prop('checked');
|
||||
$("input[id='copyContentregion']").click(function()
|
||||
{
|
||||
copyRegion = $(this).prop('checked');
|
||||
$('#copyRegion').val(copyRegion);
|
||||
});
|
||||
|
||||
$("input[name='import']").change(function()
|
||||
{
|
||||
@@ -30,10 +38,28 @@ $(function()
|
||||
return false;
|
||||
}
|
||||
})
|
||||
|
||||
$(document).on('click', '#copyKanbans a', function()
|
||||
{
|
||||
setCopyKanban($(this).data('id')); $('#copyKanbanModal').modal('hide');
|
||||
});
|
||||
})
|
||||
|
||||
/**
|
||||
* When space type or space value change.
|
||||
* Set copy kanban.
|
||||
*
|
||||
* @param int $kanbanID
|
||||
* @access public
|
||||
* @return void
|
||||
*/
|
||||
function setCopyKanban(kanbanID)
|
||||
{
|
||||
var extra = copyRegion ? '&extra=copyRegion=' + copyRegion : '';
|
||||
location.href = createLink('kanban', 'create', 'spaceID=' + spaceID + '&type=' + spaceType + '©KanbanID=' + kanbanID + extra);
|
||||
}
|
||||
|
||||
/**
|
||||
* When space type change.
|
||||
*
|
||||
* @oaram int spaceID
|
||||
* @param string type
|
||||
@@ -45,3 +71,44 @@ function changeValue(spaceID, type)
|
||||
if(typeof type === 'undefined') type = spaceType;
|
||||
location.href = createLink('kanban', 'create', 'spaceID=' + spaceID + '&type=' + type);
|
||||
}
|
||||
|
||||
/**
|
||||
* The team or whitelist member that loads kanban.
|
||||
*
|
||||
* @oaram int spaceID
|
||||
* @access public
|
||||
* @return void
|
||||
*/
|
||||
function loadUsers(spaceID)
|
||||
{
|
||||
var field = spaceType == 'private' ? 'whitelist' : 'team';
|
||||
var link = createLink('kanban', 'ajaxLoadSpaceUsers', 'spaceID='+ spaceID + '&field=' + field + '&selectedUser=' + $('#' + field).val());
|
||||
$.get(link, function(data)
|
||||
{
|
||||
$('#' + field).replaceWith(data);
|
||||
$('#' + field).next('.picker').remove();
|
||||
$('#' + field).picker();
|
||||
});
|
||||
|
||||
if(spaceType != 'private') loadOwners(spaceID);
|
||||
}
|
||||
|
||||
/**
|
||||
* The owners that loads kanban.
|
||||
*
|
||||
* @oaram int spaceID
|
||||
* @access public
|
||||
* @return void
|
||||
*/
|
||||
function loadOwners(spaceID)
|
||||
{
|
||||
var link = createLink('kanban', 'ajaxLoadSpaceUsers', 'spaceID='+ spaceID + '&field=owner&selectedUser=' + $('#owner').val());
|
||||
|
||||
$.get(link, function(data)
|
||||
{
|
||||
$('#owner').replaceWith(data);
|
||||
$('#owner' + "_chosen").remove();
|
||||
$('#owner').next('.picker').remove();
|
||||
$('#owner').chosen();
|
||||
});
|
||||
}
|
||||
|
||||
@@ -922,7 +922,7 @@ function updateRegionName(regionID, name)
|
||||
*/
|
||||
function updateLaneName(laneID, name)
|
||||
{
|
||||
$('.kanban-lane[data-id="' + laneID + '"] > .kanban-lane-name > span').text(name);
|
||||
$('.kanban-lane[data-id="' + laneID + '"] > .kanban-lane-name > span').text(name).attr('title', name);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -949,7 +949,7 @@ function updateLaneColor(laneID, color)
|
||||
*/
|
||||
function updateColumnName(columnID, name, color)
|
||||
{
|
||||
$('.kanban-col[data-id="' + columnID + '"] > div.title > span:first').text(name).css('color', color);
|
||||
$('.kanban-col[data-id="' + columnID + '"] > div.title > span:first').text(name).attr('title', name).css('color', color);
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -203,6 +203,10 @@ $lang->kanban->setting = 'Setting';
|
||||
$lang->kanban->my = 'My';
|
||||
$lang->kanban->other = 'Other';
|
||||
$lang->kanban->showWIP = 'Show WIP';
|
||||
$lang->kanban->copyTitle = 'Please select a Kanban to copy';
|
||||
$lang->kanban->copyNoKanban = 'No Kanban available to copy';
|
||||
$lang->kanban->cancelCopy = 'Cancel Copying';
|
||||
$lang->kanban->copyContent = 'Copy Content';
|
||||
|
||||
$lang->kanban->error = new stdclass();
|
||||
$lang->kanban->error->mustBeInt = 'The WIPs must be positive integer.';
|
||||
@@ -211,6 +215,9 @@ $lang->kanban->error->childLimitNote = 'The sum of products in the child colu
|
||||
$lang->kanban->error->importObjNotEmpty = 'Please select at least one import object.';
|
||||
$lang->kanban->error->childLimitEmpty = 'Please set the WIP quantity of the sub column before operation.';
|
||||
|
||||
$lang->kanban->orderList['pri_asc'] = 'Story Priority Ascending';
|
||||
$lang->kanban->orderList['pri_desc'] = 'Story Priority Descending';
|
||||
|
||||
$lang->kanban->importList = array();
|
||||
$lang->kanban->importList['off'] = 'Import is not enabled';
|
||||
$lang->kanban->importList['on'] = 'Enable the import function, you can only import content that you have permission to view.';
|
||||
@@ -269,6 +276,10 @@ $lang->kanban->taskColumn['pause'] = 'Pause';
|
||||
$lang->kanban->taskColumn['canceled'] = 'Canceled';
|
||||
$lang->kanban->taskColumn['closed'] = 'Closed';
|
||||
|
||||
$lang->kanban->copyContentList = array();
|
||||
$lang->kanban->copyContentList['basicInfo'] = 'Basic Information';
|
||||
$lang->kanban->copyContentList['region'] = 'Columns and swimlanes';
|
||||
|
||||
$lang->kanbanspace = new stdclass();
|
||||
$lang->kanbanspace->common = 'Kanban Space';
|
||||
$lang->kanbanspace->name = 'Name';
|
||||
|
||||
@@ -203,6 +203,10 @@ $lang->kanban->setting = 'Setting';
|
||||
$lang->kanban->my = 'My';
|
||||
$lang->kanban->other = 'Other';
|
||||
$lang->kanban->showWIP = 'Show WIP';
|
||||
$lang->kanban->copyTitle = 'Please select a Kanban to copy';
|
||||
$lang->kanban->copyNoKanban = 'No Kanban available to copy';
|
||||
$lang->kanban->cancelCopy = 'Cancel Copying';
|
||||
$lang->kanban->copyContent = 'Copy Content';
|
||||
|
||||
$lang->kanban->error = new stdclass();
|
||||
$lang->kanban->error->mustBeInt = 'The WIPs must be positive integer.';
|
||||
@@ -211,6 +215,9 @@ $lang->kanban->error->childLimitNote = 'The sum of products in the child colu
|
||||
$lang->kanban->error->importObjNotEmpty = 'Please select at least one import object.';
|
||||
$lang->kanban->error->childLimitEmpty = 'Please set the WIP quantity of the sub column before operation.';
|
||||
|
||||
$lang->kanban->orderList['pri_asc'] = 'Story Priority Ascending';
|
||||
$lang->kanban->orderList['pri_desc'] = 'Story Priority Descending';
|
||||
|
||||
$lang->kanban->importList = array();
|
||||
$lang->kanban->importList['off'] = 'Import is not enabled';
|
||||
$lang->kanban->importList['on'] = 'Enable import function (You can import content that you have permission to view as cards.)';
|
||||
@@ -269,6 +276,10 @@ $lang->kanban->taskColumn['pause'] = 'Pause';
|
||||
$lang->kanban->taskColumn['canceled'] = 'Canceled';
|
||||
$lang->kanban->taskColumn['closed'] = 'Closed';
|
||||
|
||||
$lang->kanban->copyContentList = array();
|
||||
$lang->kanban->copyContentList['basicInfo'] = 'Basic Information';
|
||||
$lang->kanban->copyContentList['region'] = 'Columns and swimlanes';
|
||||
|
||||
$lang->kanbanspace = new stdclass();
|
||||
$lang->kanbanspace->common = 'Kanban Space';
|
||||
$lang->kanbanspace->name = 'Name';
|
||||
|
||||
@@ -203,6 +203,10 @@ $lang->kanban->setting = 'Setting';
|
||||
$lang->kanban->my = 'My';
|
||||
$lang->kanban->other = 'Other';
|
||||
$lang->kanban->showWIP = 'Show WIP';
|
||||
$lang->kanban->copyTitle = 'Veuillez sélectionner un Kanban àcopier';
|
||||
$lang->kanban->copyNoKanban = 'Aucun Kanban disponible àcopier';
|
||||
$lang->kanban->cancelCopy = 'Annuler Copie';
|
||||
$lang->kanban->copyContent = 'Copier Contenu';
|
||||
|
||||
$lang->kanban->error = new stdclass();
|
||||
$lang->kanban->error->mustBeInt = 'The WIPs must be positive integer.';
|
||||
@@ -211,6 +215,9 @@ $lang->kanban->error->childLimitNote = 'The sum of products in the child colu
|
||||
$lang->kanban->error->importObjNotEmpty = 'Please select at least one import object.';
|
||||
$lang->kanban->error->childLimitEmpty = 'Please set the WIP quantity of the sub column before operation.';
|
||||
|
||||
$lang->kanban->orderList['pri_asc'] = 'Story Priorité Ascendante';
|
||||
$lang->kanban->orderList['pri_desc'] = 'Story Priorité Descendante';
|
||||
|
||||
$lang->kanban->importList = array();
|
||||
$lang->kanban->importList['off'] = 'Import is not enabled';
|
||||
$lang->kanban->importList['on'] = 'Enable the import function, you can only import content that you have permission to view.';
|
||||
@@ -269,6 +276,10 @@ $lang->kanban->taskColumn['pause'] = 'Pause';
|
||||
$lang->kanban->taskColumn['canceled'] = 'Canceled';
|
||||
$lang->kanban->taskColumn['closed'] = 'Closed';
|
||||
|
||||
$lang->kanban->copyContentList = array();
|
||||
$lang->kanban->copyContentList['basicInfo'] = 'Informations de base';
|
||||
$lang->kanban->copyContentList['region'] = 'Colonnes et swimlanes';
|
||||
|
||||
$lang->kanbanspace = new stdclass();
|
||||
$lang->kanbanspace->common = 'Kanban Space';
|
||||
$lang->kanbanspace->name = 'Name';
|
||||
|
||||
@@ -203,6 +203,10 @@ $lang->kanban->setting = '设置';
|
||||
$lang->kanban->my = '我的看板';
|
||||
$lang->kanban->other = '其他';
|
||||
$lang->kanban->showWIP = '显示在制品限制';
|
||||
$lang->kanban->copyTitle = '请选择一个看板来复制';
|
||||
$lang->kanban->copyNoKanban = '没有可用的看板来复制';
|
||||
$lang->kanban->cancelCopy = '取消复制';
|
||||
$lang->kanban->copyContent = '复制内容';
|
||||
|
||||
$lang->kanban->error = new stdclass();
|
||||
$lang->kanban->error->mustBeInt = '在制品数量必须是正整数。';
|
||||
@@ -211,6 +215,9 @@ $lang->kanban->error->childLimitNote = '子列在制品数量之和不能大
|
||||
$lang->kanban->error->importObjNotEmpty = '请至少选择一个导入对象';
|
||||
$lang->kanban->error->childLimitEmpty = '请先设置子列的在制品数量后再操作';
|
||||
|
||||
$lang->kanban->orderList['pri_asc'] = '需求优先级正序排序';
|
||||
$lang->kanban->orderList['pri_desc'] = '需求优先级倒序排序';
|
||||
|
||||
$lang->kanban->importList = array();
|
||||
$lang->kanban->importList['off'] = '不启用导入功能';
|
||||
$lang->kanban->importList['on'] = '启用导入功能(可以导入自己有权查看的内容作为卡片)';
|
||||
@@ -269,6 +276,10 @@ $lang->kanban->taskColumn['pause'] = '已暂停';
|
||||
$lang->kanban->taskColumn['canceled'] = '已取消';
|
||||
$lang->kanban->taskColumn['closed'] = '已关闭';
|
||||
|
||||
$lang->kanban->copyContentList = array();
|
||||
$lang->kanban->copyContentList['basicInfo'] = '基本信息';
|
||||
$lang->kanban->copyContentList['region'] = '列和泳道';
|
||||
|
||||
$lang->kanbanspace = new stdclass();
|
||||
$lang->kanbanspace->common = '看板空间';
|
||||
$lang->kanbanspace->name = '空间名称';
|
||||
|
||||
+132
-37
@@ -50,15 +50,44 @@ class kanbanModel extends model
|
||||
public function createDefaultRegion($kanban)
|
||||
{
|
||||
$region = new stdclass();
|
||||
$region->name = $this->lang->kanbanregion->default;
|
||||
$region->kanban = $kanban->id;
|
||||
$region->space = $kanban->space;
|
||||
$region->createdBy = $this->app->user->account;
|
||||
$region->createdDate = helper::today();
|
||||
$region->name = $this->lang->kanbanregion->default;
|
||||
$region->kanban = $kanban->id;
|
||||
$region->space = $kanban->space;
|
||||
$region->createdBy = $this->app->user->account;
|
||||
$region->createdDate = helper::now();
|
||||
|
||||
return $this->createRegion($kanban, $region);
|
||||
}
|
||||
|
||||
/**
|
||||
* Copy kanban regions.
|
||||
*
|
||||
* @param object $kanban
|
||||
* @param int $copyKanbanID
|
||||
* @access public
|
||||
* @return void
|
||||
*/
|
||||
public function copyRegions($kanban, $copyKanbanID)
|
||||
{
|
||||
if(empty($kanban) or empty($copyKanbanID)) return;
|
||||
|
||||
$regions = $this->getRegionPairs($copyKanbanID);
|
||||
$order = 1;
|
||||
foreach($regions as $copyID => $copyName)
|
||||
{
|
||||
$region = new stdclass();
|
||||
$region->name = $copyName;
|
||||
$region->kanban = $kanban->id;
|
||||
$region->space = $kanban->space;
|
||||
$region->createdBy = $this->app->user->account;
|
||||
$region->createdDate = helper::now();
|
||||
$region->order = $order;
|
||||
|
||||
$this->createRegion($kanban, $region, $copyID, 'kanban', 'withArchived');
|
||||
$order ++;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a new region.
|
||||
*
|
||||
@@ -66,10 +95,11 @@ class kanbanModel extends model
|
||||
* @param object $region
|
||||
* @param int $copyRegionID
|
||||
* @param string $from kanban|execution
|
||||
* @param string $param
|
||||
* @access public
|
||||
* @return int
|
||||
*/
|
||||
public function createRegion($kanban, $region = null, $copyRegionID = 0, $from = 'kanban')
|
||||
public function createRegion($kanban, $region = null, $copyRegionID = 0, $from = 'kanban', $param = '')
|
||||
{
|
||||
$account = $this->app->user->account;
|
||||
$order = 1;
|
||||
@@ -90,7 +120,7 @@ class kanbanModel extends model
|
||||
$region->space = $from == 'kanban' ? $kanban->space : 0;
|
||||
}
|
||||
|
||||
$region->order = $order;
|
||||
$region->order = isset($region->order) ? $region->order : $order;
|
||||
$this->dao->insert(TABLE_KANBANREGION)->data($region)
|
||||
->batchCheck($this->config->kanban->require->createregion, 'notempty')
|
||||
->check('name', 'unique', "kanban = {$kanban->id} AND deleted = '0' AND space='$region->space'")
|
||||
@@ -107,7 +137,7 @@ class kanbanModel extends model
|
||||
/* Gets the groups, lanes and columns of the replication region. */
|
||||
$copyGroups = $this->getGroupGroupByRegions($copyRegionID);
|
||||
$copyLaneGroup = $this->getLaneGroupByRegions($copyRegionID);
|
||||
$copyColumnGroup = $this->getColumnGroupByRegions($copyRegionID, 'id_asc');
|
||||
$copyColumnGroup = $this->getColumnGroupByRegions($copyRegionID, 'id_asc', $param);
|
||||
|
||||
/* Create groups, lanes, and columns. */
|
||||
if(empty($copyGroups)) return $regionID;
|
||||
@@ -651,6 +681,21 @@ class kanbanModel extends model
|
||||
return $kanban;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get kanban pairs.
|
||||
*
|
||||
* @access public
|
||||
* @return array
|
||||
*/
|
||||
public function getPairs()
|
||||
{
|
||||
$idList = $this->getCanViewObjects();
|
||||
return $this->dao->select('id,name')->from(TABLE_KANBAN)
|
||||
->where('id')->in($idList)
|
||||
->andWhere('deleted')->eq('0')
|
||||
->fetchPairs();
|
||||
}
|
||||
|
||||
/**
|
||||
* Get kanban data.
|
||||
*
|
||||
@@ -827,7 +872,7 @@ class kanbanModel extends model
|
||||
*/
|
||||
public function getRDKanban($executionID, $browseType = 'all', $orderBy = 'id_desc', $regionID = 0, $groupBy = 'default', $searchValue = '')
|
||||
{
|
||||
if($groupBy != 'default' and $groupBy != '') return $this->getKanban4Group($executionID, $browseType, $groupBy, $searchValue);
|
||||
if($groupBy != 'default' and $groupBy != '') return $this->getKanban4Group($executionID, $browseType, $groupBy, $searchValue, $orderBy);
|
||||
|
||||
$kanbanData = array();
|
||||
$actions = array('sortGroup');
|
||||
@@ -996,15 +1041,16 @@ class kanbanModel extends model
|
||||
*
|
||||
* @param array $regions
|
||||
* @param string $order order|id_asc
|
||||
* @param string $param
|
||||
* @access public
|
||||
* @return array
|
||||
*/
|
||||
public function getColumnGroupByRegions($regions, $order = 'order')
|
||||
public function getColumnGroupByRegions($regions, $order = 'order', $param = '')
|
||||
{
|
||||
$columnGroup = $this->dao->select("*")->from(TABLE_KANBANCOLUMN)
|
||||
->where('deleted')->eq('0')
|
||||
->andWhere('archived')->eq('0')
|
||||
->andWhere('region')->in($regions)
|
||||
->beginIF(strpos(",$param,", ',withArchived,') === false)->andWhere('archived')->eq('0')->fi()
|
||||
->orderBy($order)
|
||||
->fetchGroup('group');
|
||||
|
||||
@@ -1347,9 +1393,9 @@ class kanbanModel extends model
|
||||
* @access public
|
||||
* @return array
|
||||
*/
|
||||
public function getExecutionKanban($executionID, $browseType = 'all', $groupBy = 'default', $searchValue = '')
|
||||
public function getExecutionKanban($executionID, $browseType = 'all', $groupBy = 'default', $searchValue = '', $orderBy = 'pri_asc')
|
||||
{
|
||||
if($groupBy != 'default') return $this->getKanban4Group($executionID, $browseType, $groupBy, $searchValue);
|
||||
if($groupBy != 'default') return $this->getKanban4Group($executionID, $browseType, $groupBy, $searchValue, $orderBy);
|
||||
|
||||
$lanes = $this->dao->select('*')->from(TABLE_KANBANLANE)
|
||||
->where('execution')->eq($executionID)
|
||||
@@ -1470,11 +1516,12 @@ class kanbanModel extends model
|
||||
* @param string $browseType
|
||||
* @param string $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();
|
||||
@@ -1500,7 +1547,8 @@ class kanbanModel extends model
|
||||
if($browseType == 'bug') $bugCardMenu = $this->getKanbanCardMenu($executionID, $cardList, 'bug');
|
||||
if($browseType == 'task') $taskCardMenu = $this->getKanbanCardMenu($executionID, $cardList, 'task');
|
||||
|
||||
$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);
|
||||
@@ -1547,6 +1595,33 @@ class kanbanModel extends model
|
||||
$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)
|
||||
{
|
||||
@@ -1638,9 +1713,11 @@ class kanbanModel extends model
|
||||
* @param string $browseType
|
||||
* @param string $groupBy
|
||||
* @param array $cardList
|
||||
* @param string $orderBy
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public function getLanes4Group($executionID, $browseType, $groupBy, $cardList)
|
||||
public function getLanes4Group($executionID, $browseType, $groupBy, $cardList, $orderBy = 'pri_asc')
|
||||
{
|
||||
$lanes = array();
|
||||
$groupByList = array();
|
||||
@@ -1673,7 +1750,14 @@ class kanbanModel extends model
|
||||
$objectPairs += $this->dao->select('id,title')->from(TABLE_STORY)
|
||||
->where('deleted')->eq(0)
|
||||
->andWhere('id')->in($groupByList)
|
||||
->orderBy($orderBy)
|
||||
->fetchPairs();
|
||||
|
||||
$objects = $this->dao->select('*')->from(TABLE_STORY)
|
||||
->where('deleted')->eq(0)
|
||||
->andWhere('id')->in($groupByList)
|
||||
->orderBy($orderBy)
|
||||
->fetchAll('id');
|
||||
}
|
||||
else
|
||||
{
|
||||
@@ -1701,12 +1785,14 @@ class kanbanModel extends model
|
||||
if(!isset($groupByList[$objectType]) and $objectType and !in_array($objectType, array('feature', 'design'))) continue;
|
||||
|
||||
$lane = new stdclass();
|
||||
$lane->id = $groupBy . $objectType;
|
||||
$lane->type = $browseType;
|
||||
$lane->execution = $executionID;
|
||||
$lane->name = $objectName;
|
||||
$lane->order = $order;
|
||||
$lane->color = $this->config->kanban->laneColorList[$laneColor];
|
||||
$lane->id = $groupBy . $objectType;
|
||||
$lane->type = $browseType;
|
||||
$lane->execution = $executionID;
|
||||
$lane->name = $objectName;
|
||||
$lane->order = $order;
|
||||
$lane->color = $this->config->kanban->laneColorList[$laneColor];
|
||||
$lane->pri = (isset($objects) and isset($objects[$objectType]->pri)) ? $objects[$objectType]->pri : '';
|
||||
$lane->assignedTo = (isset($objects) and isset($objects[$objectType]->assignedTo)) ? $objects[$objectType]->assignedTo : '';
|
||||
|
||||
$order += 1;
|
||||
$laneColor += 1;
|
||||
@@ -1791,11 +1877,11 @@ class kanbanModel extends model
|
||||
* Get can view objects.
|
||||
*
|
||||
* @param string $objectType kanbanspace|kanban
|
||||
* @param string $param noclosed|private|cooperation|public|involved
|
||||
* @param string $param all|noclosed|private|cooperation|public|involved
|
||||
* @access public
|
||||
* @return array
|
||||
*/
|
||||
public function getCanViewObjects($objectType = 'kanban', $param = '')
|
||||
public function getCanViewObjects($objectType = 'kanban', $param = 'all')
|
||||
{
|
||||
$table = $this->config->objectTables[$objectType];
|
||||
$objects = $this->dao->select('*')->from($table)
|
||||
@@ -2104,7 +2190,7 @@ class kanbanModel extends model
|
||||
->join('whitelist', ',')
|
||||
->join('team', ',')
|
||||
->trim('name')
|
||||
->remove('uid,contactListMenu,type,import,importObjectList')
|
||||
->remove('contactListMenu,type,import,importObjectList,copyKanbanID,copyRegion')
|
||||
->get();
|
||||
|
||||
if($this->post->import == 'on') $kanban->object = implode(',', $this->post->importObjectList);
|
||||
@@ -2134,7 +2220,15 @@ class kanbanModel extends model
|
||||
$kanbanID = $this->dao->lastInsertID();
|
||||
$kanban = $this->getByID($kanbanID);
|
||||
|
||||
$this->createDefaultRegion($kanban);
|
||||
if($this->post->copyRegion)
|
||||
{
|
||||
$this->copyRegions($kanban, $this->post->copyKanbanID);
|
||||
}
|
||||
else
|
||||
{
|
||||
$this->createDefaultRegion($kanban);
|
||||
}
|
||||
|
||||
$this->loadModel('file')->saveUpload('kanban', $kanbanID);
|
||||
$this->file->updateObjectID($this->post->uid, $kanbanID, 'kanban');
|
||||
|
||||
@@ -3660,6 +3754,7 @@ class kanbanModel extends model
|
||||
public function getKanbanCardMenu($executionID, $objects, $objecType)
|
||||
{
|
||||
$this->app->loadLang('execution');
|
||||
$methodName = $this->app->rawMethod;
|
||||
|
||||
$menus = array();
|
||||
switch ($objecType)
|
||||
@@ -3679,7 +3774,7 @@ class kanbanModel extends model
|
||||
if(common::hasPriv('task', 'create') and $toTaskPriv) $menu[] = array('label' => $this->lang->execution->wbs, 'icon' => 'plus', 'url' => helper::createLink('task', 'create', "executionID=$executionID&storyID=$story->id&moduleID=$story->module", '', true), 'size' => '95%');
|
||||
if(common::hasPriv('task', 'batchCreate') and $toTaskPriv) $menu[] = array('label' => $this->lang->execution->batchWBS, 'icon' => 'pluses', 'url' => helper::createLink('task', 'batchCreate', "executionID=$executionID&storyID=$story->id&moduleID=0&taskID=0&iframe=true", '', true), 'size' => '95%');
|
||||
if(common::hasPriv('story', 'activate') and $this->story->isClickable($story, 'activate')) $menu[] = array('label' => $this->lang->story->activate, 'icon' => 'magic', 'url' => helper::createLink('story', 'activate', "storyID=$story->id", '', true));
|
||||
if(common::hasPriv('execution', 'unlinkStory')) $menu[] = array('label' => $this->lang->execution->unlinkStory, 'icon' => 'unlink', 'url' => helper::createLink('execution', 'unlinkStory', "executionID=$executionID&storyID=$story->story&confirm=no", '', true));
|
||||
if(common::hasPriv('execution', 'unlinkStory')) $menu[] = array('label' => $this->lang->execution->unlinkStory, 'icon' => 'unlink', 'url' => helper::createLink('execution', 'unlinkStory', "executionID=$executionID&storyID=$story->story&confirm=no&from=taskkanban", '', true));
|
||||
if(common::hasPriv('story', 'delete')) $menu[] = array('label' => $this->lang->story->delete, 'icon' => 'trash', 'url' => helper::createLink('story', 'delete', "storyID=$story->id&confirm=no&from=taskkanban"));
|
||||
|
||||
$menus[$story->id] = $menu;
|
||||
@@ -3693,11 +3788,11 @@ class kanbanModel extends model
|
||||
$menu = array();
|
||||
|
||||
if(common::hasPriv('bug', 'edit') and $this->bug->isClickable($bug, 'edit')) $menu[] = array('label' => $this->lang->bug->edit, 'icon' => 'edit', 'url' => helper::createLink('bug', 'edit', "bugID=$bug->id", '', true), 'size' => '95%');
|
||||
if(common::hasPriv('bug', 'confirmBug') and $this->bug->isClickable($bug, 'confirmBug')) $menu[] = array('label' => $this->lang->bug->confirmBug, 'icon' => 'ok', 'url' => helper::createLink('bug', 'confirmBug', "bugID=$bug->id", '', true));
|
||||
if(common::hasPriv('bug', 'resolve') and $this->bug->isClickable($bug, 'resolve')) $menu[] = array('label' => $this->lang->bug->resolve, 'icon' => 'checked', 'url' => helper::createLink('bug', 'resolve', "bugID=$bug->id", '', true));
|
||||
if(common::hasPriv('bug', 'close') and $this->bug->isClickable($bug, 'close')) $menu[] = array('label' => $this->lang->bug->close, 'icon' => 'off', 'url' => helper::createLink('bug', 'close', "bugID=$bug->id", '', true));
|
||||
if(common::hasPriv('bug', 'confirmBug') and $this->bug->isClickable($bug, 'confirmBug')) $menu[] = array('label' => $this->lang->bug->confirmBug, 'icon' => 'ok', 'url' => helper::createLink('bug', 'confirmBug', "bugID=$bug->id&extra=&from=taskkanban", '', true));
|
||||
if(common::hasPriv('bug', 'resolve') and $this->bug->isClickable($bug, 'resolve')) $menu[] = array('label' => $this->lang->bug->resolve, 'icon' => 'checked', 'url' => helper::createLink('bug', 'resolve', "bugID=$bug->id&extra=&from=taskkanban", '', true));
|
||||
if(common::hasPriv('bug', 'close') and $this->bug->isClickable($bug, 'close')) $menu[] = array('label' => $this->lang->bug->close, 'icon' => 'off', 'url' => helper::createLink('bug', 'close', "bugID=$bug->id&extra=&from=taskkanban", '', true));
|
||||
if(common::hasPriv('bug', 'create') and $this->bug->isClickable($bug, 'create')) $menu[] = array('label' => $this->lang->bug->copy, 'icon' => 'copy', 'url' => helper::createLink('bug', 'create', "productID=$bug->product&branch=$bug->branch&extras=bugID=$bug->id", '', true), 'size' => '95%');
|
||||
if(common::hasPriv('bug', 'activate') and $this->bug->isClickable($bug, 'activate')) $menu[] = array('label' => $this->lang->bug->activate, 'icon' => 'magic', 'url' => helper::createLink('bug', 'activate', "bugID=$bug->id", '', true));
|
||||
if(common::hasPriv('bug', 'activate') and $this->bug->isClickable($bug, 'activate')) $menu[] = array('label' => $this->lang->bug->activate, 'icon' => 'magic', 'url' => helper::createLink('bug', 'activate', "bugID=$bug->id&extra=&from=taskkanban", '', true));
|
||||
if(common::hasPriv('story', 'create') and $bug->status != 'closed') $menu[] = array('label' => $this->lang->bug->toStory, 'icon' => 'lightbulb', 'url' => helper::createLink('story', 'create', "product=$bug->product&branch=$bug->branch&module=0&story=0&execution=0&bugID=$bug->id", '', true), 'size' => '95%');
|
||||
if(common::hasPriv('bug', 'delete')) $menu[] = array('label' => $this->lang->bug->delete, 'icon' => 'trash', 'url' => helper::createLink('bug', 'delete', "bugID=$bug->id&confirm=no&from=taskkanban"));
|
||||
|
||||
@@ -3712,14 +3807,14 @@ class kanbanModel extends model
|
||||
$menu = array();
|
||||
|
||||
if(common::hasPriv('task', 'edit') and $this->task->isClickable($task, 'edit')) $menu[] = array('label' => $this->lang->task->edit, 'icon' => 'edit', 'url' => helper::createLink('task', 'edit', "taskID=$task->id", '', true), 'size' => '95%');
|
||||
if(common::hasPriv('task', 'pause') and $this->task->isClickable($task, 'pause')) $menu[] = array('label' => $this->lang->task->pause, 'icon' => 'pause', 'url' => helper::createLink('task', 'pause', "taskID=$task->id", '', true));
|
||||
if(common::hasPriv('task', 'restart') and $this->task->isClickable($task, 'restart')) $menu[] = array('label' => $this->lang->task->restart, 'icon' => 'play', 'url' => helper::createLink('task', 'restart', "taskID=$task->id", '', true));
|
||||
if(common::hasPriv('task', 'recordEstimate') and $this->task->isClickable($task, 'recordEstimate')) $menu[] = array('label' => $this->lang->task->recordEstimate, 'icon' => 'time', 'url' => helper::createLink('task', 'recordEstimate', "taskID=$task->id", '', true));
|
||||
if(common::hasPriv('task', 'activate') and $this->task->isClickable($task, 'activate')) $menu[] = array('label' => $this->lang->task->activate, 'icon' => 'magic', 'url' => helper::createLink('task', 'activate', "taskID=$task->id", '', true));
|
||||
if(common::hasPriv('task', 'pause') and $this->task->isClickable($task, 'pause')) $menu[] = array('label' => $this->lang->task->pause, 'icon' => 'pause', 'url' => helper::createLink('task', 'pause', "taskID=$task->id&extra=from=taskkanban", '', true));
|
||||
if(common::hasPriv('task', 'restart') and $this->task->isClickable($task, 'restart')) $menu[] = array('label' => $this->lang->task->restart, 'icon' => 'play', 'url' => helper::createLink('task', 'restart', "taskID=$task->id&from=taskkanban", '', true));
|
||||
if(common::hasPriv('task', 'recordEstimate') and $this->task->isClickable($task, 'recordEstimate')) $menu[] = array('label' => $this->lang->task->recordEstimate, 'icon' => 'time', 'url' => helper::createLink('task', 'recordEstimate', "taskID=$task->id&from=taskkanban", '', true));
|
||||
if(common::hasPriv('task', 'activate') and $this->task->isClickable($task, 'activate')) $menu[] = array('label' => $this->lang->task->activate, 'icon' => 'magic', 'url' => helper::createLink('task', 'activate', "taskID=$task->id&extra=from=taskkanban", '', true));
|
||||
if(common::hasPriv('task', 'batchCreate') and $this->task->isClickable($task, 'batchCreate')) $menu[] = array('label' => $this->lang->task->children, 'icon' => 'split', 'url' => helper::createLink('task', 'batchCreate', "execution=$task->execution&storyID=$task->story&moduleID=$task->module&taskID=$task->id", '', true), 'size' => '95%');
|
||||
if(common::hasPriv('task', 'create') and $this->task->isClickable($task, 'create')) $menu[] = array('label' => $this->lang->task->copy, 'icon' => 'copy', 'url' => helper::createLink('task', 'create', "projctID=$task->execution&storyID=$task->story&moduleID=$task->module&taskID=$task->id", '', true), 'size' => '95%');
|
||||
if(common::hasPriv('task', 'cancel') and $this->task->isClickable($task, 'cancel')) $menu[] = array('label' => $this->lang->task->cancel, 'icon' => 'ban-circle', 'url' => helper::createLink('task', 'cancel', "taskID=$task->id", '', true));
|
||||
if(common::hasPriv('task', 'delete')) $menu[] = array('label' => $this->lang->task->delete, 'icon' => 'trash', 'url' => helper::createLink('task', 'delete', "executionID=$task->execution&taskID=$task->id&confirm=no&from=taskkanban"));
|
||||
if(common::hasPriv('task', 'cancel') and $this->task->isClickable($task, 'cancel')) $menu[] = array('label' => $this->lang->task->cancel, 'icon' => 'ban-circle', 'url' => helper::createLink('task', 'cancel', "taskID=$task->id&extra=from=taskkanban", '', true));
|
||||
if(common::hasPriv('task', 'delete')) $menu[] = array('label' => $this->lang->task->delete, 'icon' => 'trash', 'url' => helper::createLink('task', 'delete', "executionID=$task->execution&taskID=$task->id&confirm=no&from=taskkanban"));
|
||||
|
||||
$menus[$task->id] = $menu;
|
||||
}
|
||||
|
||||
@@ -12,12 +12,16 @@
|
||||
?>
|
||||
<?php include '../../common/view/header.html.php';?>
|
||||
<?php include '../../common/view/kindeditor.html.php';?>
|
||||
<?php js::set('spaceID', $spaceID);?>
|
||||
<?php js::set('spaceType', $type);?>
|
||||
<?php js::set('enableImport', 'off');?>
|
||||
<?php js::set('enableImport', $enableImport);?>
|
||||
<?php js::set('vision', $this->config->vision);?>
|
||||
<div id='mainContent' class='main-content'>
|
||||
<div class='main-header'>
|
||||
<h2><?php echo $lang->kanban->create;?></h2>
|
||||
<div class="pull-right btn-toolbar">
|
||||
<button type='button' class='btn btn-link' data-toggle='modal' data-target='#copyKanbanModal'><?php echo html::icon($lang->icons['copy'], 'muted') . ' ' . $lang->kanban->copy . $lang->kanban->common;?></button>
|
||||
</div>
|
||||
</div>
|
||||
<form class='form-indicator main-form form-ajax' method='post' enctype='multipart/form-data' id='dataform'>
|
||||
<table class='table table-form'>
|
||||
@@ -28,78 +32,107 @@
|
||||
</tr>
|
||||
<tr>
|
||||
<th><?php echo $lang->kanban->WIPCount;?></th>
|
||||
<td><?php echo html::radio('showWIP', $lang->kanban->showWIPList, 1);?></td>
|
||||
<td><?php echo html::radio('showWIP', $lang->kanban->showWIPList, isset($copyKanban->showWIP) ? $copyKanban->showWIP : 1);?></td>
|
||||
<td></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<th><?php echo $lang->kanban->space;?></th>
|
||||
<td><?php echo html::select('space', $spacePairs, $spaceID, "onchange='changeValue(this.value)' class='form-control chosen'");?></td>
|
||||
<td><?php echo html::select('space', $spacePairs, isset($copyKanban->space) ? $copyKanban->space : $spaceID, "onchange='loadUsers(this.value)' class='form-control chosen'");?></td>
|
||||
<td></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<th><?php echo $lang->kanban->name;?></th>
|
||||
<td><?php echo html::input('name', '', "class='form-control'");?></td>
|
||||
<td><?php echo html::input('name', isset($copyKanban->name) ? $copyKanban->name : '', "class='form-control'");?></td>
|
||||
</tr>
|
||||
<?php if($type != 'private'):?>
|
||||
<tr>
|
||||
<th><?php echo $lang->kanban->owner;?></th>
|
||||
<td><?php echo html::select('owner', $users, '', "class='form-control chosen' data-drop_direction='down'");?></td>
|
||||
<td><?php echo html::select('owner', $users, isset($copyKanban->owner) ? $copyKanban->owner : '', "class='form-control chosen' data-drop_direction='down'");?></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<th><?php echo $lang->kanban->team;?></th>
|
||||
<td colspan='2'>
|
||||
<div class="input-group">
|
||||
<?php echo html::select('team[]', $users, '', "class='form-control picker-select' multiple data-dropDirection='bottom'");?>
|
||||
<?php echo html::select('team[]', $users, isset($copyKanban->team) ? $copyKanban->team : '', "class='form-control picker-select' multiple data-dropDirection='bottom'");?>
|
||||
</div>
|
||||
</td>
|
||||
</tr>
|
||||
<?php endif;?>
|
||||
<tr>
|
||||
<th class='columnWidth'><?php echo $lang->kanban->columnWidth;?></th>
|
||||
<td><?php echo nl2br(html::radio('fluidBoard', $lang->kanbancolumn->fluidBoardList, 0));?></td>
|
||||
</tr>
|
||||
<tr class="hidden" id='cardBox'>
|
||||
<th class='c-count'><?php echo $lang->kanban->cardCount;?></th>
|
||||
<td><?php echo html::input('displayCards', '', "class='form-control' required placeholder='{$lang->kanban->cardCountTip}' autocomplete='off'");?></td>
|
||||
<td><?php echo nl2br(html::radio('fluidBoard', $lang->kanbancolumn->fluidBoardList, isset($copyKanban->fluidBoard) ? $copyKanban->fluidBoard : 0));?></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<th rowspan='2'><?php echo $lang->kanban->import?></th>
|
||||
<td colspan='2' class='importBox'><?php echo nl2br(html::radio('import', $lang->kanban->importList, 'off'));?></td>
|
||||
<td colspan='2' class='importBox'><?php echo nl2br(html::radio('import', $lang->kanban->importList, $enableImport));?></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td colspan='2' class='objectBox'><?php echo html::checkbox('importObjectList', $lang->kanban->importObjectList, array());?></td>
|
||||
<td colspan='2' class='objectBox'><?php echo html::checkbox('importObjectList', $lang->kanban->importObjectList, $importObjects);?></td>
|
||||
</tr>
|
||||
<tr id='emptyTip' class='hidden'><th></th><td colspan='2' style='color: red;'><?php echo $lang->kanban->error->importObjNotEmpty;?></td></tr>
|
||||
<tr>
|
||||
<th class='w-90px'><?php echo $lang->kanban->archive;?></th>
|
||||
<td><?php echo nl2br(html::radio('archived', $lang->kanban->archiveList, '0'));?></td>
|
||||
<td><?php echo nl2br(html::radio('archived', $lang->kanban->archiveList, isset($copyKanban->archived) ? $copyKanban->archived : '0'));?></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<th id='c-title'><?php echo $lang->kanban->manageProgress;?></th>
|
||||
<td><?php echo nl2br(html::radio('performable', $lang->kanban->enableList, '0'));?></td>
|
||||
<td><?php echo nl2br(html::radio('performable', $lang->kanban->enableList, isset($copyKanban->performable) ? $copyKanban->performable : '0'));?></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<th id='c-title'><?php echo $lang->kanban->alignment;?></th>
|
||||
<td><?php echo nl2br(html::radio('alignment', $lang->kanban->alignmentList, 'center'));?></td>
|
||||
<td><?php echo nl2br(html::radio('alignment', $lang->kanban->alignmentList, isset($copyKanban->alignment) ? $copyKanban->alignment : 'center'));?></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<th><?php echo $lang->kanban->desc;?></th>
|
||||
<td colspan='2'>
|
||||
<?php echo html::textarea('desc', '', "rows='10' class='form-control'");?>
|
||||
<?php echo html::textarea('desc', isset($copyKanban->desc) ? $copyKanban->desc : '', "rows='10' class='form-control'");?>
|
||||
</td>
|
||||
</tr>
|
||||
<?php if($type == 'private'):?>
|
||||
<tr id="whitelistBox">
|
||||
<th><?php echo $lang->whitelist;?></th>
|
||||
<td><?php echo html::select('whitelist[]', $whitelist, '', 'class="form-control picker-select" multiple');?></td>
|
||||
<td><?php echo html::select('whitelist[]', $whitelist, isset($copyKanban->whitelist) ? $copyKanban->whitelist : '', 'class="form-control picker-select" multiple');?></td>
|
||||
</tr>
|
||||
<?php endif;?>
|
||||
<tr>
|
||||
<td colspan='3' class='text-center form-actions'>
|
||||
<?php echo html::hidden('copyKanbanID', $copyKanbanID)?>
|
||||
<?php echo html::hidden('copyRegion', $copyRegion)?>
|
||||
<?php echo html::submitButton();?>
|
||||
</td>
|
||||
</tr>
|
||||
</table>
|
||||
</form>
|
||||
</div>
|
||||
<div class='modal fade modal-scroll-inside' id='copyKanbanModal'>
|
||||
<div class='modal-dialog mw-900px'>
|
||||
<div class='modal-header'>
|
||||
<button type='button' class='close' data-dismiss='modal'><i class="icon icon-close"></i></button>
|
||||
<div class='titleBox'><h4 class='modal-title' id='myModalLabel'><?php echo $lang->kanban->copyTitle;?></h4></div>
|
||||
</div>
|
||||
<div class='modal-body'>
|
||||
<?php if(count($kanbans) == 1):?>
|
||||
<div class='alert with-icon'>
|
||||
<i class='icon-exclamation-sign'></i>
|
||||
<div class='content'><?php echo $lang->kanban->copyNoKanban;?></div>
|
||||
</div>
|
||||
<?php else:?>
|
||||
<?php $copyContent = array('basicInfo');?>
|
||||
<?php if($copyRegion) $copyContent[] = 'region';?>
|
||||
<div class='copyContentBox'><?php echo $lang->kanban->copyContent . html::checkbox('copyContent', $lang->kanban->copyContentList, $copyContent);?></div>
|
||||
<div id='copyKanbans' class='row'>
|
||||
<?php foreach ($kanbans as $id => $name):?>
|
||||
<?php if(empty($id)):?>
|
||||
<?php if($copyKanbanID != 0):?>
|
||||
<div class='col-md-4 col-sm-4'><a href='javascript:;' data-id='' class='cancel'><?php echo html::icon($lang->icons['cancel']) . ' ' . $lang->kanban->cancelCopy;?></a></div>
|
||||
<?php endif;?>
|
||||
<?php else: ?>
|
||||
<div class='col-md-4 col-sm-4'><a href='javascript:;' data-id='<?php echo $id;?>' class='nobr <?php echo ($copyKanbanID == $id) ? ' active' : '';?>'><?php echo html::icon($lang->icons['kanban'], 'text-muted') . ' ' . $name;?></a></div>
|
||||
<?php endif; ?>
|
||||
<?php endforeach;?>
|
||||
</div>
|
||||
<?php endif;?>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<?php include '../../common/view/footer.html.php';?>
|
||||
|
||||
@@ -115,7 +115,7 @@
|
||||
if($canDelete)
|
||||
{
|
||||
echo '<li>';
|
||||
common::printLink('kanban', 'delete', "kanbanID={$kanban->id}", '<i class="icon icon-trash"></i> ' . $lang->kanban->delete, 'hiddenwin');
|
||||
common::printLink('kanban', 'delete', "kanbanID={$kanban->id}&confirm=no&browseType=$browseType", '<i class="icon icon-trash"></i> ' . $lang->kanban->delete, 'hiddenwin');
|
||||
echo '</li>';
|
||||
}
|
||||
?>
|
||||
|
||||
@@ -27,7 +27,7 @@ $lang->message->label->assigned = '指派';
|
||||
$lang->message->label->closed = '关闭';
|
||||
$lang->message->label->deleted = '删除';
|
||||
$lang->message->label->undeleted = '还原';
|
||||
$lang->message->label->commented = '评论';
|
||||
$lang->message->label->commented = '备注';
|
||||
$lang->message->label->activated = '激活';
|
||||
$lang->message->label->resolved = '解决';
|
||||
$lang->message->label->reviewed = '评审';
|
||||
|
||||
@@ -27,7 +27,7 @@ $lang->message->label->assigned = '指派';
|
||||
$lang->message->label->closed = '關閉';
|
||||
$lang->message->label->deleted = '刪除';
|
||||
$lang->message->label->undeleted = '還原';
|
||||
$lang->message->label->commented = '評論';
|
||||
$lang->message->label->commented = '備註';
|
||||
$lang->message->label->activated = '激活';
|
||||
$lang->message->label->resolved = '解決';
|
||||
$lang->message->label->reviewed = '評審';
|
||||
|
||||
@@ -1,2 +1,5 @@
|
||||
.c-gender {width: 80px;}
|
||||
.c-phone, .c-skype, .c-visits {width: 100px;}
|
||||
.c-skype, .c-visits {width: 100px;}
|
||||
.c-phone {width: 128px;}
|
||||
.c-email {width: 128px;}
|
||||
.c-role {width: 96px;}
|
||||
|
||||
@@ -292,7 +292,7 @@ class productplan extends control
|
||||
* @access public
|
||||
* @return void
|
||||
*/
|
||||
public function browse($productID = 0, $branch = '', $browseType = 'undone', $queryID = 0, $orderBy = 'begin_desc', $recTotal = 0, $recPerPage = 20, $pageID = 1 )
|
||||
public function browse($productID = 0, $branch = '', $browseType = 'all', $queryID = 0, $orderBy = 'begin_desc', $recTotal = 0, $recPerPage = 20, $pageID = 1 )
|
||||
{
|
||||
$branchID = $branch === '' ? 'all' : $branch;
|
||||
if(!$branch) $branch = 0;
|
||||
@@ -351,6 +351,12 @@ class productplan extends control
|
||||
$this->view->kanbanData = $this->loadModel('kanban')->getPlanKanban($product, $branchID, $planGroup);
|
||||
}
|
||||
|
||||
$productPlansNum = $this->dao->select('COUNT(id) AS count')->from(TABLE_PRODUCTPLAN)
|
||||
->where('product')->eq($productID)
|
||||
->andWhere('deleted')->eq(0)
|
||||
->fetch();
|
||||
$this->view->productPlansNum = $productPlansNum;
|
||||
|
||||
$this->view->title = $productName . $this->lang->colon . $this->lang->productplan->browse;
|
||||
$this->view->position[] = $this->lang->productplan->browse;
|
||||
$this->view->productID = $productID;
|
||||
|
||||
@@ -41,7 +41,7 @@
|
||||
<div class="table-empty-tip">
|
||||
<p>
|
||||
<span class="text-muted"><?php echo $lang->productplan->noPlan;?></span>
|
||||
<?php if(common::canModify('product', $product) and common::hasPriv('productplan', 'create') and $browseType == "all"):?>
|
||||
<?php if(common::canModify('product', $product) and common::hasPriv('productplan', 'create') and empty($productPlansNum->count)):?>
|
||||
<?php echo html::a($this->createLink('productplan', 'create', "productID=$product->id&branch=$branch"), "<i class='icon icon-plus'></i> " . $lang->productplan->create, '', "class='btn btn-info'");?>
|
||||
<?php endif;?>
|
||||
</p>
|
||||
|
||||
@@ -88,7 +88,7 @@
|
||||
$createMisc = common::hasPriv('story', 'create') ? 'btn btn-secondary' : " btn btn-secondary disabled";
|
||||
echo html::a($createLink, "<i class='icon icon-plus'></i><span class='text'>" . $lang->story->create . "</span><span class='caret'>", '', "class='$createMisc'");
|
||||
?>
|
||||
<ul class='dropdown-menu'>
|
||||
<ul class='dropdown-menu pull-right'>
|
||||
<?php $disabled = common::hasPriv('story', 'batchCreate') ? '' : "class='disabled'";?>
|
||||
<li <?php echo $disabled?>>
|
||||
<?php
|
||||
|
||||
@@ -450,7 +450,7 @@ class program extends control
|
||||
* @access public
|
||||
* @return void
|
||||
*/
|
||||
public function project($programID = 0, $browseType = 'doing', $orderBy = 'order_desc', $recTotal = 0, $recPerPage = 15, $pageID = 1)
|
||||
public function project($programID = 0, $browseType = 'all', $orderBy = 'order_desc', $recTotal = 0, $recPerPage = 15, $pageID = 1)
|
||||
{
|
||||
$programID = $this->program->saveState($programID, $this->program->getPairs());
|
||||
setCookie("lastProgram", $programID, $this->config->cookieLife, $this->config->webRoot, '', false, true);
|
||||
@@ -473,6 +473,13 @@ class program extends control
|
||||
$sortField = zget($this->config->program->sortFields, $order[0], 'id') . '_' . $order[1];
|
||||
$projectStats = $this->program->getProjectStats($programID, $browseType, 0, $sortField, $pager, $programTitle);
|
||||
|
||||
$allProjectsNum = $this->dao->select('COUNT(id) AS count')->from(TABLE_PROJECT)
|
||||
->where('parent')->eq($programID)
|
||||
->andWhere('type')->eq('project')
|
||||
->andWhere('deleted')->eq(0)
|
||||
->fetch();
|
||||
$this->view->allProjectsNum = $allProjectsNum;
|
||||
|
||||
$this->view->title = $this->lang->program->project;
|
||||
$this->view->position[] = $this->lang->program->project;
|
||||
|
||||
|
||||
@@ -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;}
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -35,7 +35,7 @@ js::set('browseType', $browseType);
|
||||
<div class="table-empty-tip">
|
||||
<p>
|
||||
<span class="text-muted"><?php echo $lang->project->empty;?></span>
|
||||
<?php if($browseType == 'all') common::printLink('project', 'createGuide', "programID=$programID", '<i class="icon icon-plus"></i> ' . $lang->project->create, '', 'class="btn btn-info btn-wide " data-toggle="modal"');?>
|
||||
<?php if(empty($allProjectsNum->count)) common::printLink('project', 'createGuide', "programID=$programID", '<i class="icon icon-plus"></i> ' . $lang->project->create, '', 'class="btn btn-info btn-wide " data-toggle="modal"');?>
|
||||
</p>
|
||||
</div>
|
||||
<?php else:?>
|
||||
|
||||
@@ -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 = '子阶段名称';
|
||||
|
||||
@@ -309,6 +309,12 @@ class project extends control
|
||||
$programTitle = $this->loadModel('setting')->getItem('owner=' . $this->app->user->account . '&module=project&key=programTitle');
|
||||
$projectStats = $this->loadModel('program')->getProjectStats($programID, $browseType, $queryID, $orderBy, $pager, $programTitle);
|
||||
|
||||
$allProjectsNum = $this->dao->select('COUNT(id) AS count')->from(TABLE_PROJECT)
|
||||
->where('type')->eq('project')
|
||||
->andWhere('deleted')->eq(0)
|
||||
->fetch();
|
||||
$this->view->allProjectsNum = $allProjectsNum;
|
||||
|
||||
$this->view->title = $this->lang->project->browse;
|
||||
$this->view->position[] = $this->lang->project->browse;
|
||||
|
||||
@@ -487,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);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -956,10 +965,37 @@ 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);
|
||||
|
||||
$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();
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -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; }
|
||||
@@ -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.before(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
|
||||
}
|
||||
@@ -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;
|
||||
@@ -1544,15 +1545,13 @@ class projectModel extends model
|
||||
/* Child project begin cannot less than parent. */
|
||||
if(!empty($projects[$projectID]->name) and $projects[$projectID]->begin < $parentProject->begin)
|
||||
{
|
||||
dao::$errors['begin'] = sprintf($this->lang->project->beginGreateChild, $parentProject->begin);
|
||||
return false;
|
||||
dao::$errors[] = "ID {$projects[$projectID]->id}" . sprintf($this->lang->project->beginGreateChild, $parentProject->begin) . "\n";
|
||||
}
|
||||
|
||||
/* When parent set end then child project end cannot greater than parent. */
|
||||
if(!empty($projects[$projectID]->name) and $parentProject->end != '0000-00-00' and $projects[$projectID]->end > $parentProject->end)
|
||||
{
|
||||
dao::$errors['end'] = sprintf($this->lang->project->endLetterChild, $parentProject->end);
|
||||
return false;
|
||||
dao::$errors[] = "ID {$projects[$projectID]->id}" . sprintf($this->lang->project->endLetterChild, $parentProject->end) . "\n";
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1584,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();
|
||||
@@ -2308,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))
|
||||
{
|
||||
@@ -2384,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();
|
||||
@@ -2409,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. */
|
||||
|
||||
@@ -73,7 +73,7 @@
|
||||
<div class="table-empty-tip">
|
||||
<p>
|
||||
<span class="text-muted"><?php echo $lang->project->empty;?></span>
|
||||
<?php if($browseType == "all"):?>
|
||||
<?php if(empty($allProjectsNum->count)):?>
|
||||
<?php if(!defined('TUTORIAL')):?>
|
||||
<?php if(common::hasPriv('project', 'create') and $browseType != 'bysearch') common::printLink('project', 'createGuide', "programID=$programID", '<i class="icon icon-plus"></i> ' . $lang->project->create, '', 'class="btn btn-info" data-toggle="modal"');?>
|
||||
<?php else:?>
|
||||
|
||||
@@ -109,16 +109,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 +148,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>
|
||||
|
||||
@@ -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($status == "all"):?>
|
||||
<?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';?>
|
||||
@@ -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¶m=$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;?>
|
||||
|
||||
@@ -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¶m=$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,3 +1,5 @@
|
||||
td.child {padding-left: 15px;}
|
||||
.c-name {width: 200px;}
|
||||
.c-count {width: 70px;}
|
||||
#conditions {display: flex;}
|
||||
#conditions .condition-options {margin-left: 16px;}
|
||||
|
||||
@@ -22,10 +22,9 @@
|
||||
<div class='panel'>
|
||||
<div class="panel-heading">
|
||||
<div class="panel-title">
|
||||
<div class="table-row" id='conditions'>
|
||||
<div class="col-xs"><?php echo $title;?></div>
|
||||
<div class="col-xs text-right text-gray text-middle"><?php echo $lang->report->conditions?></div>
|
||||
<div class='col'>
|
||||
<div id='conditions'>
|
||||
<div><?php echo $title;?></div>
|
||||
<div class='condition-options'>
|
||||
<div class="checkbox-primary inline-block">
|
||||
<input type="checkbox" name="closedProduct" value="closedProduct" id="closedProduct" <?php if(strpos($conditions, 'closedProduct') !== false) echo "checked='checked'"?> />
|
||||
<label for="closedProduct"><?php echo $lang->report->closedProduct?></label>
|
||||
|
||||
@@ -248,7 +248,7 @@ foreach($fieldParams as $fieldName => $param)
|
||||
echo html::submitButton($lang->search->common, '', 'btn btn-primary') . " ";
|
||||
if($style != 'simple') echo html::commonButton($lang->search->reset, '', 'btn-reset-form btn');
|
||||
echo html::commonButton('<i class="icon icon-chevron-double-down"></i>', '', 'btn-expand-form btn btn-info pull-right');
|
||||
if($style != 'simple' and common::hasPriv('search', 'saveQuery')) echo html::a($this->createLink('search', 'saveQuery', "module=$module&onMenuBar=$onMenuBar"), '<span class="text"><i class="icon-bug-confirmBug icon-ok"></i> ' . $lang->search->saveCondition . '</span>', '', "class='btn-save-form btn btn-link btn-active-text text iframe' id='save-query'");
|
||||
if($style != 'simple' and common::hasPriv('search', 'saveQuery')) echo html::a($this->createLink('search', 'saveQuery', "module=$module&onMenuBar=$onMenuBar"), '<span class="text"><i class="icon-bug-confirmBug icon-save"></i> ' . $lang->search->saveCondition . '</span>', '', "class='btn-save-form btn btn-link btn-active-text text iframe' id='save-query'");
|
||||
echo html::hidden('formType', zget($formSession, 'formType', 'lite'));
|
||||
?>
|
||||
</td>
|
||||
|
||||
+42
-45
@@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -499,8 +501,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. */
|
||||
@@ -1200,8 +1202,7 @@ class story extends control
|
||||
public function view($storyID, $version = 0, $param = 0)
|
||||
{
|
||||
$uri = $this->app->getURI(true);
|
||||
$this->session->set('productList', $uri . "#app={$this->app->tab}", 'product');
|
||||
$this->session->set('productPlanList', $uri, 'product');
|
||||
$this->session->set('productList', $uri . "#app={$this->app->tab}", 'product');
|
||||
|
||||
$storyID = (int)$storyID;
|
||||
$story = $this->story->getById($storyID, $version, true);
|
||||
@@ -1485,10 +1486,11 @@ class story extends control
|
||||
* Close a story.
|
||||
*
|
||||
* @param int $storyID
|
||||
* @param string $from taskkanban
|
||||
* @access public
|
||||
* @return void
|
||||
*/
|
||||
public function close($storyID)
|
||||
public function close($storyID, $from = '')
|
||||
{
|
||||
if(!empty($_POST))
|
||||
{
|
||||
@@ -1506,28 +1508,25 @@ class story extends control
|
||||
|
||||
if(isonlybody())
|
||||
{
|
||||
$execution = $this->execution->getByID($this->session->execution);
|
||||
if($this->app->tab == 'execution')
|
||||
$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 : '';
|
||||
if($this->app->tab == 'execution' and $execution->type == 'kanban')
|
||||
{
|
||||
$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 : '';
|
||||
if($execution->type == 'kanban')
|
||||
{
|
||||
$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);
|
||||
return print(js::closeModal('parent.parent', '', "parent.parent.updateKanban(\"story\", $kanbanData)"));
|
||||
}
|
||||
$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)"));
|
||||
}
|
||||
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);
|
||||
return print(js::closeModal('parent.parent', '', "parent.parent.updateKanban(\"story\", $kanbanData)"));
|
||||
}
|
||||
else
|
||||
{
|
||||
@@ -1853,10 +1852,11 @@ class story extends control
|
||||
*
|
||||
* @param int $storyID
|
||||
* @param string $kanbanGroup
|
||||
* @param string $from taskkanban
|
||||
* @access public
|
||||
* @return void
|
||||
*/
|
||||
public function assignTo($storyID, $kanbanGroup = 'default')
|
||||
public function assignTo($storyID, $kanbanGroup = 'default', $from = '')
|
||||
{
|
||||
if(!empty($_POST))
|
||||
{
|
||||
@@ -1872,26 +1872,23 @@ class story extends control
|
||||
|
||||
if(isonlybody())
|
||||
{
|
||||
$execution = $this->execution->getByID($this->session->execution);
|
||||
if($this->app->tab == 'execution')
|
||||
$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';
|
||||
if($this->app->tab == 'execution' and $execution->type == 'kanban')
|
||||
{
|
||||
$execLaneType = $this->session->execLaneType ? $this->session->execLaneType : 'all';
|
||||
$rdSearchValue = $this->session->rdSearchValue ? $this->session->rdSearchValue : '';
|
||||
$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);
|
||||
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);
|
||||
return print(js::closeModal('parent.parent', '', "parent.parent.updateKanban(\"story\", $kanbanData)"));
|
||||
}
|
||||
$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('$execLaneType', $kanbanData)"));
|
||||
}
|
||||
else
|
||||
{
|
||||
|
||||
@@ -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');
|
||||
|
||||
|
||||
+248
-235
@@ -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'] : '';
|
||||
@@ -347,6 +348,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;
|
||||
@@ -542,33 +544,27 @@ class task extends control
|
||||
|
||||
if(isonlybody())
|
||||
{
|
||||
if($this->app->tab == 'execution' or $this->config->vision == 'lite')
|
||||
$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')
|
||||
{
|
||||
$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);
|
||||
$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);
|
||||
|
||||
return print(js::closeModal('parent.parent', '', "parent.parent.updateKanban(\"task\", $kanbanData)"));
|
||||
}
|
||||
return print(js::closeModal('parent.parent', '', "parent.parent.updateKanban($kanbanData)"));
|
||||
}
|
||||
else
|
||||
{
|
||||
return print(js::reload('parent.parent'));
|
||||
$kanbanData = $this->loadModel('kanban')->getExecutionKanban($task->execution, $execLaneType, $execGroupBy, $rdSearchValue);
|
||||
$kanbanType = $execLaneType == 'all' ? 'task' : key($kanbanData);
|
||||
$kanbanData = $kanbanData[$kanbanType];
|
||||
$kanbanData = json_encode($kanbanData);
|
||||
|
||||
return print(js::closeModal('parent.parent', '', "parent.parent.updateKanban(\"task\", $kanbanData)"));
|
||||
}
|
||||
return print(js::reload('parent.parent'));
|
||||
}
|
||||
|
||||
if(defined('RUN_MODE') && RUN_MODE == 'api')
|
||||
@@ -581,6 +577,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]);
|
||||
|
||||
@@ -750,10 +748,11 @@ class task extends control
|
||||
* @param int $requestID
|
||||
* @param int $taskID
|
||||
* @param string $kanbanGroup
|
||||
* @param string $from
|
||||
* @access public
|
||||
* @return void
|
||||
*/
|
||||
public function assignTo($executionID, $taskID, $kanbanGroup = 'default')
|
||||
public function assignTo($executionID, $taskID, $kanbanGroup = 'default', $from = '')
|
||||
{
|
||||
$this->commonAction($taskID);
|
||||
$task = $this->task->getByID($taskID);
|
||||
@@ -782,34 +781,28 @@ class task extends control
|
||||
if($this->viewType == 'json' or (defined('RUN_MODE') && RUN_MODE == 'api')) return $this->send(array('result' => 'success'));
|
||||
if(isonlybody())
|
||||
{
|
||||
if($this->app->tab == 'execution' or $this->config->vision == 'lite')
|
||||
$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 : '';
|
||||
if($execution->type == 'kanban')
|
||||
{
|
||||
$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 : '';
|
||||
if($execution->type == 'kanban')
|
||||
{
|
||||
$kanbanData = $this->loadModel('kanban')->getRDKanban($task->execution, $execLaneType, 'id_desc', 0, $execGroup, $rdSearchValue);
|
||||
$kanbanData = json_encode($kanbanData);
|
||||
$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)"));
|
||||
}
|
||||
else
|
||||
{
|
||||
$kanbanData = $this->loadModel('kanban')->getExecutionKanban($task->execution, $execLaneType, $execGroupBy, $rdSearchValue);
|
||||
$kanbanType = $execLaneType == 'all' ? 'task' : key($kanbanData);
|
||||
$kanbanData = $kanbanData[$kanbanType];
|
||||
$kanbanData = json_encode($kanbanData);
|
||||
|
||||
return print(js::closeModal('parent.parent', '', "parent.parent.updateKanban(\"task\", $kanbanData)"));
|
||||
}
|
||||
return print(js::closeModal('parent.parent', '', "parent.parent.updateKanban($kanbanData)"));
|
||||
}
|
||||
else
|
||||
if($from == 'taskkanban')
|
||||
{
|
||||
return print(js::closeModal('parent.parent', 'this'));
|
||||
$kanbanData = $this->loadModel('kanban')->getExecutionKanban($task->execution, $execLaneType, $execGroupBy, $rdSearchValue);
|
||||
$kanbanType = $execLaneType == 'all' ? 'task' : key($kanbanData);
|
||||
$kanbanData = $kanbanData[$kanbanType];
|
||||
$kanbanData = json_encode($kanbanData);
|
||||
|
||||
return print(js::closeModal('parent.parent', '', "parent.parent.updateKanban(\"task\", $kanbanData)"));
|
||||
}
|
||||
return print(js::closeModal('parent.parent', 'this'));
|
||||
}
|
||||
return print(js::locate($this->createLink('task', 'view', "taskID=$taskID"), 'parent'));
|
||||
}
|
||||
@@ -910,6 +903,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);
|
||||
@@ -1046,34 +1040,28 @@ class task extends control
|
||||
|
||||
if(isonlybody())
|
||||
{
|
||||
if($this->app->tab == 'execution' or $this->config->vision == 'lite')
|
||||
$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')
|
||||
{
|
||||
$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')
|
||||
{
|
||||
$regionID = !empty($output['regionID']) ? $output['regionID'] : 0;
|
||||
$kanbanData = $this->loadModel('kanban')->getRDKanban($task->execution, $execLaneType, 'id_desc', $regionID, $execGroupBy, $rdSearchValue);
|
||||
$kanbanData = json_encode($kanbanData);
|
||||
$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)"));
|
||||
}
|
||||
else
|
||||
{
|
||||
$kanbanData = $this->loadModel('kanban')->getExecutionKanban($task->execution, $execLaneType, $execGroupBy, $rdSearchValue);
|
||||
$kanbanType = $execLaneType == 'all' ? 'task' : key($kanbanData);
|
||||
$kanbanData = $kanbanData[$kanbanType];
|
||||
$kanbanData = json_encode($kanbanData);
|
||||
|
||||
return print(js::closeModal('parent.parent', '', "parent.parent.updateKanban(\"task\", $kanbanData)"));
|
||||
}
|
||||
return print(js::closeModal('parent.parent', '', "parent.parent.updateKanban($kanbanData, $regionID)"));
|
||||
}
|
||||
else
|
||||
if($output['from'] == 'taskkanban')
|
||||
{
|
||||
return print(js::closeModal('parent.parent', 'this', "function(){parent.parent.location.reload();}"));
|
||||
$kanbanData = $this->loadModel('kanban')->getExecutionKanban($task->execution, $execLaneType, $execGroupBy, $rdSearchValue);
|
||||
$kanbanType = $execLaneType == 'all' ? 'task' : key($kanbanData);
|
||||
$kanbanData = $kanbanData[$kanbanType];
|
||||
$kanbanData = json_encode($kanbanData);
|
||||
|
||||
return print(js::closeModal('parent.parent', '', "parent.parent.updateKanban(\"task\", $kanbanData)"));
|
||||
}
|
||||
return print(js::closeModal('parent.parent', 'this', "function(){parent.parent.location.reload();}"));
|
||||
}
|
||||
return print(js::locate($this->createLink('task', 'view', "taskID=$taskID"), 'parent'));
|
||||
}
|
||||
@@ -1091,10 +1079,11 @@ class task extends control
|
||||
* Record consumed and estimate.
|
||||
*
|
||||
* @param int $taskID
|
||||
* @param string $from
|
||||
* @access public
|
||||
* @return void
|
||||
*/
|
||||
public function recordEstimate($taskID)
|
||||
public function recordEstimate($taskID, $from = '')
|
||||
{
|
||||
$this->commonAction($taskID);
|
||||
|
||||
@@ -1123,33 +1112,27 @@ class task extends control
|
||||
|
||||
if(isonlybody())
|
||||
{
|
||||
if($this->app->tab == 'execution' or $this->config->vision == 'lite')
|
||||
$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')
|
||||
{
|
||||
$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);
|
||||
$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);
|
||||
|
||||
return print(js::closeModal('parent.parent', '', "parent.parent.updateKanban(\"task\", $kanbanData)"));
|
||||
}
|
||||
return print(js::closeModal('parent.parent', '', "parent.parent.updateKanban($kanbanData)"));
|
||||
}
|
||||
else
|
||||
if($from == 'taskkanban')
|
||||
{
|
||||
return print(js::closeModal('parent.parent', 'this'));
|
||||
$kanbanData = $this->loadModel('kanban')->getExecutionKanban($task->execution, $execLaneType, $execGroupBy, $rdSearchValue);
|
||||
$kanbanType = $execLaneType == 'all' ? 'task' : key($kanbanData);
|
||||
$kanbanData = $kanbanData[$kanbanType];
|
||||
$kanbanData = json_encode($kanbanData);
|
||||
|
||||
return print(js::closeModal('parent.parent', '', "parent.parent.updateKanban(\"task\", $kanbanData)"));
|
||||
}
|
||||
return print(js::closeModal('parent.parent', 'this'));
|
||||
}
|
||||
return print(js::locate($this->createLink('task', 'view', "taskID=$taskID"), 'parent'));
|
||||
}
|
||||
@@ -1204,19 +1187,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'));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1273,34 +1273,28 @@ class task extends control
|
||||
|
||||
if(isonlybody())
|
||||
{
|
||||
if($this->app->tab == 'execution' or $this->config->vision == 'lite')
|
||||
$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")
|
||||
{
|
||||
$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')
|
||||
{
|
||||
$regionID = !empty($output['regionID']) ? $output['regionID'] : 0;
|
||||
$kanbanData = $this->loadModel('kanban')->getRDKanban($task->execution, $execLaneType, 'id_desc', $regionID, $execGroupBy, $rdSearchValue);
|
||||
$kanbanData = json_encode($kanbanData);
|
||||
$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)"));
|
||||
}
|
||||
else
|
||||
{
|
||||
$kanbanData = $this->loadModel('kanban')->getExecutionKanban($task->execution, $execLaneType, $execGroupBy, $rdSearchValue);
|
||||
$kanbanType = $execLaneType == 'all' ? 'task' : key($kanbanData);
|
||||
$kanbanData = $kanbanData[$kanbanType];
|
||||
$kanbanData = json_encode($kanbanData);
|
||||
|
||||
return print(js::closeModal('parent.parent', '', "parent.parent.updateKanban(\"task\", $kanbanData)"));
|
||||
}
|
||||
return print(js::closeModal('parent.parent', '', "parent.parent.updateKanban($kanbanData, $regionID)"));
|
||||
}
|
||||
else
|
||||
if($output['from'] == "taskkanban")
|
||||
{
|
||||
return print(js::closeModal('parent.parent', 'this', "function(){parent.parent.location.reload();}"));
|
||||
$kanbanData = $this->loadModel('kanban')->getExecutionKanban($task->execution, $execLaneType, $execGroupBy, $rdSearchValue);
|
||||
$kanbanType = $execLaneType == 'all' ? 'task' : key($kanbanData);
|
||||
$kanbanData = $kanbanData[$kanbanType];
|
||||
$kanbanData = json_encode($kanbanData);
|
||||
|
||||
return print(js::closeModal('parent.parent', '', "parent.parent.updateKanban(\"task\", $kanbanData)"));
|
||||
}
|
||||
return print(js::closeModal('parent.parent', 'this', "function(){parent.parent.location.reload();}"));
|
||||
}
|
||||
|
||||
if(defined('RUN_MODE') && RUN_MODE == 'api')
|
||||
@@ -1375,35 +1369,29 @@ class task extends control
|
||||
|
||||
if(isonlybody())
|
||||
{
|
||||
if($this->app->tab == 'execution' or $this->config->vision == 'lite')
|
||||
$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 : '';
|
||||
if($execution->type == 'kanban')
|
||||
{
|
||||
$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 : '';
|
||||
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);
|
||||
$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)"));
|
||||
}
|
||||
else
|
||||
{
|
||||
$kanbanData = $this->loadModel('kanban')->getExecutionKanban($task->execution, $execLaneType, $execGroupBy, $rdSearchValue);
|
||||
$kanbanType = $execLaneType == 'all' ? 'task' : key($kanbanData);
|
||||
$kanbanData = $kanbanData[$kanbanType];
|
||||
$kanbanData = json_encode($kanbanData);
|
||||
|
||||
return print(js::closeModal('parent.parent', '', "parent.parent.updateKanban(\"task\", $kanbanData)"));
|
||||
}
|
||||
return print(js::closeModal('parent.parent', '', "parent.parent.updateKanban($kanbanData, $regionID)"));
|
||||
}
|
||||
else
|
||||
if($output['from'] == 'taskkanban')
|
||||
{
|
||||
return print(js::closeModal('parent.parent', 'this'));
|
||||
$kanbanData = $this->loadModel('kanban')->getExecutionKanban($task->execution, $execLaneType, $execGroupBy, $rdSearchValue);
|
||||
$kanbanType = $execLaneType == 'all' ? 'task' : key($kanbanData);
|
||||
$kanbanData = $kanbanData[$kanbanType];
|
||||
$kanbanData = json_encode($kanbanData);
|
||||
|
||||
return print(js::closeModal('parent.parent', '', "parent.parent.updateKanban(\"task\", $kanbanData)"));
|
||||
}
|
||||
return print(js::closeModal('parent.parent', 'this'));
|
||||
}
|
||||
|
||||
return print(js::locate($this->createLink('task', 'view', "taskID=$taskID"), 'parent'));
|
||||
@@ -1420,10 +1408,11 @@ class task extends control
|
||||
* Restart task
|
||||
*
|
||||
* @param int $taskID
|
||||
* @param string $from
|
||||
* @access public
|
||||
* @return void
|
||||
*/
|
||||
public function restart($taskID)
|
||||
public function restart($taskID, $from = '')
|
||||
{
|
||||
$this->commonAction($taskID);
|
||||
|
||||
@@ -1446,34 +1435,28 @@ class task extends control
|
||||
|
||||
if(isonlybody())
|
||||
{
|
||||
if($this->app->tab == 'execution' or $this->config->vision == 'lite')
|
||||
$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 : '';
|
||||
if($execution->type == 'kanban')
|
||||
{
|
||||
$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 : '';
|
||||
if($execution->type == 'kanban')
|
||||
{
|
||||
$kanbanData = $this->loadModel('kanban')->getRDKanban($task->execution, $execLaneType, 'id_desc', 0, $execGroupBy, $rdSearchValue);
|
||||
$kanbanData = json_encode($kanbanData);
|
||||
$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);
|
||||
|
||||
return print(js::closeModal('parent.parent', '', "parent.parent.updateKanban(\"task\", $kanbanData)"));
|
||||
}
|
||||
return print(js::closeModal('parent.parent', '', "parent.parent.updateKanban($kanbanData)"));
|
||||
}
|
||||
else
|
||||
if($from == 'taskkanban')
|
||||
{
|
||||
return print(js::closeModal('parent.parent', 'this'));
|
||||
$kanbanData = $this->loadModel('kanban')->getExecutionKanban($task->execution, $execLaneType, $execGroupBy, $rdSearchValue);
|
||||
$kanbanType = $execLaneType == 'all' ? 'task' : key($kanbanData);
|
||||
$kanbanData = $kanbanData[$kanbanType];
|
||||
$kanbanData = json_encode($kanbanData);
|
||||
|
||||
return print(js::closeModal('parent.parent', '', "parent.parent.updateKanban(\"task\", $kanbanData)"));
|
||||
}
|
||||
return print(js::closeModal('parent.parent', 'this'));
|
||||
}
|
||||
return print(js::locate($this->createLink('task', 'view', "taskID=$taskID"), 'parent'));
|
||||
}
|
||||
@@ -1534,33 +1517,27 @@ 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 : '';
|
||||
if($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 : '';
|
||||
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);
|
||||
$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)"));
|
||||
}
|
||||
else
|
||||
{
|
||||
$kanbanData = $this->loadModel('kanban')->getExecutionKanban($task->execution, $execLaneType, $execGroupBy, $rdSearchValue);
|
||||
$kanbanType = $execLaneType == 'all' ? 'task' : key($kanbanData);
|
||||
$kanbanData = $kanbanData[$kanbanType];
|
||||
$kanbanData = json_encode($kanbanData);
|
||||
|
||||
return print(js::closeModal('parent.parent', '', "parent.parent.updateKanban(\"task\", $kanbanData)"));
|
||||
}
|
||||
return print(js::closeModal('parent.parent', '', "parent.parent.updateKanban($kanbanData, $regionID)"));
|
||||
}
|
||||
else
|
||||
if($output['from'] == 'taskkanban')
|
||||
{
|
||||
return print(js::closeModal('parent.parent', 'this', "function(){parent.parent.location.reload();}"));
|
||||
$kanbanData = $this->loadModel('kanban')->getExecutionKanban($task->execution, $execLaneType, $execGroupBy, $rdSearchValue);
|
||||
$kanbanType = $execLaneType == 'all' ? 'task' : key($kanbanData);
|
||||
$kanbanData = $kanbanData[$kanbanType];
|
||||
$kanbanData = json_encode($kanbanData);
|
||||
|
||||
return print(js::closeModal('parent.parent', '', "parent.parent.updateKanban(\"task\", $kanbanData)"));
|
||||
}
|
||||
return print(js::closeModal('parent.parent', 'this', "function(){parent.parent.location.reload();}"));
|
||||
}
|
||||
|
||||
if(defined('RUN_MODE') && RUN_MODE == 'api')
|
||||
@@ -1710,35 +1687,29 @@ class task extends control
|
||||
|
||||
if(isonlybody())
|
||||
{
|
||||
if($this->app->tab == 'execution' or $this->config->vision == 'lite')
|
||||
$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 : '';
|
||||
if($execution->type == 'kanban')
|
||||
{
|
||||
$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 : '';
|
||||
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);
|
||||
$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)"));
|
||||
}
|
||||
else
|
||||
{
|
||||
$kanbanData = $this->loadModel('kanban')->getExecutionKanban($task->execution, $execLaneType, $execGroupBy, $rdSearchValue);
|
||||
$kanbanType = $execLaneType == 'all' ? 'task' : key($kanbanData);
|
||||
$kanbanData = $kanbanData[$kanbanType];
|
||||
$kanbanData = json_encode($kanbanData);
|
||||
|
||||
return print(js::closeModal('parent.parent', '', "parent.parent.updateKanban(\"task\", $kanbanData)"));
|
||||
}
|
||||
return print(js::closeModal('parent.parent', '', "parent.parent.updateKanban($kanbanData, $regionID)"));
|
||||
}
|
||||
else
|
||||
if($output['from'] == 'taskkanban')
|
||||
{
|
||||
return print(js::closeModal('parent.parent', 'this'));
|
||||
$kanbanData = $this->loadModel('kanban')->getExecutionKanban($task->execution, $execLaneType, $execGroupBy, $rdSearchValue);
|
||||
$kanbanType = $execLaneType == 'all' ? 'task' : key($kanbanData);
|
||||
$kanbanData = $kanbanData[$kanbanType];
|
||||
$kanbanData = json_encode($kanbanData);
|
||||
|
||||
return print(js::closeModal('parent.parent', '', "parent.parent.updateKanban(\"task\", $kanbanData)"));
|
||||
}
|
||||
return print(js::closeModal('parent.parent', 'this'));
|
||||
}
|
||||
return print(js::locate($this->createLink('task', 'view', "taskID=$taskID"), 'parent'));
|
||||
}
|
||||
@@ -1781,35 +1752,29 @@ class task extends control
|
||||
|
||||
if(isonlybody())
|
||||
{
|
||||
if($this->app->tab == 'execution' or $this->config->vision == 'lite')
|
||||
$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 : '';
|
||||
if($execution->type == "kanban")
|
||||
{
|
||||
$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 : '';
|
||||
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);
|
||||
$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)"));
|
||||
}
|
||||
else
|
||||
{
|
||||
$kanbanData = $this->loadModel('kanban')->getExecutionKanban($task->execution, $execLaneType, $execGroupBy, $rdSearchValue);
|
||||
$kanbanType = $execLaneType == 'all' ? 'task' : key($kanbanData);
|
||||
$kanbanData = $kanbanData[$kanbanType];
|
||||
$kanbanData = json_encode($kanbanData);
|
||||
|
||||
return print(js::closeModal('parent.parent', '', "parent.parent.updateKanban(\"task\", $kanbanData)"));
|
||||
}
|
||||
return print(js::closeModal('parent.parent', '', "parent.parent.updateKanban($kanbanData, $regionID)"));
|
||||
}
|
||||
else
|
||||
if($output['from'] == "taskkanban")
|
||||
{
|
||||
return print(js::closeModal('parent.parent', 'this'));
|
||||
$kanbanData = $this->loadModel('kanban')->getExecutionKanban($task->execution, $execLaneType, $execGroupBy, $rdSearchValue);
|
||||
$kanbanType = $execLaneType == 'all' ? 'task' : key($kanbanData);
|
||||
$kanbanData = $kanbanData[$kanbanType];
|
||||
$kanbanData = json_encode($kanbanData);
|
||||
|
||||
return print(js::closeModal('parent.parent', '', "parent.parent.updateKanban(\"task\", $kanbanData)"));
|
||||
}
|
||||
return print(js::closeModal('parent.parent', 'this'));
|
||||
}
|
||||
return print(js::locate($this->createLink('task', 'view', "taskID=$taskID"), 'parent'));
|
||||
}
|
||||
@@ -1919,6 +1884,54 @@ 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]);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
$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.
|
||||
*
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
.pl-10px {padding-left: 10px;}
|
||||
#showAllModuleBox{width:60px;}
|
||||
#showAllModuleBox .no-margin {padding-left:22px;}
|
||||
#taskTeamEditor .sortable .input-group .input-group-addon.required:after {top: 10px; right: 2px; z-index: 3;}
|
||||
|
||||
@@ -274,7 +274,7 @@ function setLane(regionID)
|
||||
}
|
||||
|
||||
/* Get select of stories.*/
|
||||
function setStories(moduleID, executionID)
|
||||
function setStories(moduleID)
|
||||
{
|
||||
link = createLink('story', 'ajaxGetExecutionStories', 'executionID=' + executionID + '&productID=0&branch=all&moduleID=' + moduleID + '&storyID=0&number=&type=full&status=unclosed');
|
||||
$.get(link, function(stories)
|
||||
@@ -530,8 +530,9 @@ $(document).on('click', '#testStory_chosen', function()
|
||||
|
||||
$('#modalTeam .btn').click(function()
|
||||
{
|
||||
var team = '';
|
||||
var time = 0;
|
||||
var team = '';
|
||||
var time = 0;
|
||||
var error = false;
|
||||
|
||||
/* Unique team. */
|
||||
$('select[name^=team]').each(function(i)
|
||||
@@ -548,9 +549,10 @@ $('#modalTeam .btn').click(function()
|
||||
|
||||
$('select[name^=team]').each(function()
|
||||
{
|
||||
if($(this).find('option:selected').text() != '')
|
||||
var account = $(this).find('option:selected').text();
|
||||
if(account != '')
|
||||
{
|
||||
team += ' ' + $(this).find('option:selected').text();
|
||||
team += ' ' + account;
|
||||
}
|
||||
|
||||
estimate = parseFloat($(this).parents('td').next('td').find('[name^=teamEstimate]').val());
|
||||
@@ -559,9 +561,16 @@ $('#modalTeam .btn').click(function()
|
||||
time += estimate;
|
||||
}
|
||||
|
||||
$('#teamMember').val(team);
|
||||
$('#estimate').val(time);
|
||||
})
|
||||
var requiredFieldList = ',' + requiredFields + ',';
|
||||
if(account && requiredFieldList.indexOf(',estimate,') >= 0 && (estimate == 0 || isNaN(estimate)))
|
||||
{
|
||||
alert(estimateNotEmpty);
|
||||
error = true;
|
||||
return false;
|
||||
}
|
||||
});
|
||||
|
||||
if(error) return false;
|
||||
var teamList = team.split(" ");
|
||||
if(teamList.length <= 2)
|
||||
{
|
||||
@@ -570,6 +579,9 @@ $('#modalTeam .btn').click(function()
|
||||
}
|
||||
else
|
||||
{
|
||||
$('#teamMember').val(team);
|
||||
$('#estimate').val(time);
|
||||
|
||||
if(config.onlybody == 'yes' && vision == 'lite')
|
||||
{
|
||||
$('.close').parent().click();
|
||||
|
||||
+19
-4
@@ -176,6 +176,7 @@ $('#confirmButton').click(function()
|
||||
var totalEstimate = 0;
|
||||
var totalConsumed = oldConsumed;
|
||||
var totalLeft = 0;
|
||||
var error = false;
|
||||
$('select[name^=team]').each(function()
|
||||
{
|
||||
if($(this).find('option:selected').text() == '') return;
|
||||
@@ -190,22 +191,36 @@ $('#confirmButton').click(function()
|
||||
|
||||
left = parseFloat($(this).parents('td').next('td').find('[name^=teamLeft]').val());
|
||||
if(!isNaN(left)) totalLeft += left;
|
||||
|
||||
var requiredFieldList = ',' + requiredFields + ',';
|
||||
if(requiredFieldList.indexOf(',estimate,') >= 0 && (estimate == 0 || isNaN(estimate)))
|
||||
{
|
||||
$(this).val('').trigger("chosen:updated");
|
||||
alert(estimateNotEmpty);
|
||||
error = true;
|
||||
return false;
|
||||
}
|
||||
})
|
||||
$('#estimate').val(totalEstimate);
|
||||
$('#consumedSpan').html(totalConsumed);
|
||||
$('#left').val(totalLeft);
|
||||
updateAssignedTo();
|
||||
|
||||
if(error) return false;
|
||||
|
||||
if(memberCount < 2)
|
||||
{
|
||||
alert(teamMemberError);
|
||||
return false;
|
||||
}
|
||||
|
||||
if(totalLeft == 0 && (taskStatus == 'doing' || taskStatus == 'pause'))
|
||||
{
|
||||
alert(totalLeftError);
|
||||
return false;
|
||||
}
|
||||
|
||||
$('#estimate').val(totalEstimate);
|
||||
$('#consumedSpan').html(totalConsumed);
|
||||
$('#left').val(totalLeft);
|
||||
updateAssignedTo();
|
||||
|
||||
$('.close').click();
|
||||
});
|
||||
|
||||
|
||||
+21
-21
@@ -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
@@ -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
@@ -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
@@ -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 = '"总计消耗"必须为数字';
|
||||
|
||||
+74
-3
@@ -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))
|
||||
{
|
||||
@@ -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.
|
||||
*
|
||||
|
||||
@@ -118,7 +118,7 @@ $colspan = count($visibleFields) + 3;
|
||||
<tr>
|
||||
<td class='text-left c-id'><?php echo $i;?></td>
|
||||
<td class="<?php echo zget($visibleFields, 'module', 'hidden')?> moduleBox" style='overflow:visible'>
|
||||
<?php echo html::select("module[$i]", $modules, $moduleID, "class='form-control chosen'")?>
|
||||
<?php echo html::select("module[$i]", $modules, $moduleID, "class='form-control chosen' onchange='setStories(this.value, $execution->id)'")?>
|
||||
<?php echo html::hidden("parent[$i]", $parent);?>
|
||||
</td>
|
||||
<?php if($execution->type != 'ops'):?>
|
||||
|
||||
@@ -13,17 +13,21 @@
|
||||
<?php include '../../common/view/header.html.php';?>
|
||||
<?php include '../../common/view/kindeditor.html.php';?>
|
||||
<?php include '../../common/view/sortable.html.php';?>
|
||||
<?php js::set('executionID', $execution->id);?>
|
||||
<?php js::set('toTaskList', !empty($task->id));?>
|
||||
<?php js::set('blockID', $blockID);?>
|
||||
<?php js::set('teamMemberError', $lang->task->error->teamMember);?>
|
||||
<?php js::set('vision', $config->vision);?>
|
||||
<?php js::set('requiredFields', $config->task->create->requiredFields);?>
|
||||
<?php js::set('estimateNotEmpty', sprintf($lang->error->notempty, $lang->task->estimate))?>
|
||||
<?php if(!empty($storyID)):?>
|
||||
<style> .title-group.required > .required:after {right: 110px;}</style>
|
||||
<?php endif;?>
|
||||
<?php
|
||||
$requiredFields = array();
|
||||
foreach(explode(',', $config->task->create->requiredFields) as $field)
|
||||
{
|
||||
if($field) $requiredFields[$field] = '';
|
||||
if($field and strpos($showFields, $field) === false) $showFields .= ',' . $field;
|
||||
}
|
||||
?>
|
||||
@@ -56,7 +60,7 @@ foreach(explode(',', $config->task->create->requiredFields) as $field)
|
||||
</tr>
|
||||
<tr>
|
||||
<th><?php echo $lang->task->module;?></th>
|
||||
<td id='moduleIdBox'><?php echo html::select('module', $moduleOptionMenu, $task->module, "class='form-control chosen'");?></td>
|
||||
<td id='moduleIdBox'><?php echo html::select('module', $moduleOptionMenu, $task->module, "class='form-control chosen' onchange='setStories(this.value)'");?></td>
|
||||
<td>
|
||||
<div class="checkbox-primary c-modulel">
|
||||
<input type="checkbox" id="showAllModule" <?php if($showAllModule) echo 'checked';?>><label for="showAllModule" class="no-margin"><?php echo $lang->task->allModule;?></label>
|
||||
@@ -283,7 +287,7 @@ foreach(explode(',', $config->task->create->requiredFields) as $field)
|
||||
<tbody class='sortable'>
|
||||
<tr class='template'>
|
||||
<td><?php echo html::select("team[]", $members, '', "class='form-control chosen'");?></td>
|
||||
<td>
|
||||
<td class="<?php echo zget($requiredFields, 'estimate', '', ' required')?>">
|
||||
<div class='input-group'>
|
||||
<?php echo html::input("teamEstimate[]", '', "class='form-control text-center' placeholder='{$lang->task->estimateAB}'") ?>
|
||||
<span class='input-group-addon'><?php echo $lang->task->hour;?></span>
|
||||
|
||||
@@ -27,6 +27,15 @@
|
||||
<?php js::set('newRowCount', count($task->team) < 6 ? 6 - count($task->team) : 1);?>
|
||||
<?php js::set('teamMemberError', $lang->task->error->teamMember);?>
|
||||
<?php js::set('totalLeftError', sprintf($this->lang->task->error->leftEmptyAB, $this->lang->task->statusList[$task->status]));?>
|
||||
<?php js::set('estimateNotEmpty', sprintf($lang->error->notempty, $lang->task->estimate))?>
|
||||
<?php js::set('requiredFields', $config->task->edit->requiredFields);?>
|
||||
<?php
|
||||
$requiredFields = array();
|
||||
foreach(explode(',', $config->task->edit->requiredFields) as $field)
|
||||
{
|
||||
if($field) $requiredFields[$field] = '';
|
||||
}
|
||||
?>
|
||||
<div class='main-content' id='mainContent'>
|
||||
<form method='post' enctype='multipart/form-data' target='hiddenwin' id='dataform'>
|
||||
<div class='main-header'>
|
||||
@@ -275,7 +284,7 @@
|
||||
<td class='w-250px'><?php echo html::select("team[]", $members, $member->account, "class='form-control chosen'")?></td>
|
||||
<td>
|
||||
<div class='input-group'>
|
||||
<span class='input-group-addon'><?php echo $lang->task->estimate?></span>
|
||||
<span class="input-group-addon <?php echo zget($requiredFields, 'estimate', '', ' required');?>"><?php echo $lang->task->estimate?></span>
|
||||
<?php echo html::input("teamEstimate[]", (float)$member->estimate, "class='form-control text-center' placeholder='{$lang->task->hour}'")?>
|
||||
<span class='input-group-addon fix-border'><?php echo $lang->task->consumed?></span>
|
||||
<?php echo html::input("teamConsumed[]", (float)$member->consumed, "class='form-control text-center' readonly placeholder='{$lang->task->hour}'")?>
|
||||
@@ -294,7 +303,7 @@
|
||||
<td class='w-250px'><?php echo html::select("team[]", $members, '', "class='form-control chosen'")?></td>
|
||||
<td>
|
||||
<div class='input-group'>
|
||||
<span class='input-group-addon'><?php echo $lang->task->estimate?></span>
|
||||
<span class="input-group-addon <?php echo zget($requiredFields, 'estimate', '', ' required');?>"><?php echo $lang->task->estimate?></span>
|
||||
<?php echo html::input("teamEstimate[]", '', "class='form-control text-center' placeholder='{$lang->task->hour}'")?>
|
||||
<span class='input-group-addon fix-border'><?php echo $lang->task->consumed?></span>
|
||||
<?php echo html::input("teamConsumed[]", '', "class='form-control text-center' placeholder='{$lang->task->hour}'")?>
|
||||
|
||||
@@ -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');
|
||||
}
|
||||
|
||||
|
||||
@@ -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
@@ -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);
|
||||
}
|
||||
|
||||
|
||||
@@ -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';?>
|
||||
|
||||
@@ -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)'";
|
||||
$field = $fieldID ? "modules[$fieldID]" : 'module';
|
||||
|
||||
$currentModule = $this->tree->getById($currentModuleID);
|
||||
|
||||
@@ -528,6 +528,10 @@ class upgradeModel extends model
|
||||
$this->moveProjectAdmins();
|
||||
$this->addStoryViewPriv();
|
||||
break;
|
||||
case '17_2':
|
||||
$this->addReviewIssusApprovalData();
|
||||
break;
|
||||
|
||||
}
|
||||
|
||||
$this->deletePatch();
|
||||
@@ -6509,6 +6513,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.
|
||||
*
|
||||
|
||||
@@ -9,3 +9,5 @@ body {background: #1183fb linear-gradient(-90deg, #0a48d1 0%, #1183fb 100%); bac
|
||||
#resetForm .form-control:focus {border-color: #2272eb; background: #fff;}
|
||||
#resetForm .form-actions {padding-bottom: 20px;}
|
||||
.required:after {top: 32px; right: -15px;}
|
||||
#resetPanel .form-group .input-group {width: 100%}
|
||||
#resetPanel .form-group .input-group.required:after {top: 6px;}
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user