Merge branch 'master' of https://gitlab.zcorp.cc/easycorp/zentaopms into zentaopms_289
This commit is contained in:
@@ -80,7 +80,7 @@ class executionsEntry extends entry
|
||||
*/
|
||||
public function post($projectID = 0)
|
||||
{
|
||||
$fields = 'project,code,name,begin,end,lifetime,desc,days';
|
||||
$fields = 'project,code,name,begin,end,lifetime,desc,days,percent,parent';
|
||||
$this->batchSetPost($fields);
|
||||
|
||||
$projectID = $this->param('project', $projectID);
|
||||
|
||||
@@ -1 +1,10 @@
|
||||
DELETE FROM `zt_config` WHERE module = 'datatable' AND section = 'executionAll';
|
||||
|
||||
update `zt_task` set `assignedTo` = '' where `mode` = 'multi' and `status` != 'done' and `status` != 'closed';
|
||||
|
||||
REPLACE INTO `zt_lang` (`lang`, `module`, `section`, `key`, `value`, `system`, `vision`) SELECT `lang`, `module`, 'scrumClassify', `key`, `value`, `system`, `vision` FROM `zt_lang` WHERE `module` = 'process' and `section` = 'classify' ORDER BY id ASC;
|
||||
REPLACE INTO `zt_lang` (`lang`, `module`, `section`, `key`, `value`, `system`, `vision`) SELECT `lang`, `module`, 'agileplusClassify', `key`, `value`, `system`, `vision` FROM `zt_lang` WHERE `module` = 'process' and `section` = 'classify' ORDER BY id ASC;
|
||||
|
||||
UPDATE `zt_project` AS parent INNER JOIN (select `id`,`parent`,`attribute` from `zt_project` where `parent` != 0 and `type` = 'stage') AS child ON parent.`id` = child.`parent` SET parent.`attribute`='mix' where parent.`grade`=1 and parent.`type`='stage' and parent.`attribute` != child.`attribute`;
|
||||
|
||||
REPLACE INTO `zt_grouppriv` (SELECT `group`,`module`,'batchChangeStatus' FROM `zt_grouppriv` WHERE `module` = 'execution' AND `method` = 'batchEdit');
|
||||
|
||||
@@ -1,8 +0,0 @@
|
||||
update `zt_task` set `assignedTo` = '' where `mode` = 'multi' and `status` != 'done' and `status` != 'closed';
|
||||
|
||||
REPLACE INTO `zt_lang` (`lang`, `module`, `section`, `key`, `value`, `system`, `vision`) SELECT `lang`, `module`, 'scrumClassify', `key`, `value`, `system`, `vision` FROM `zt_lang` WHERE `module` = 'process' and `section` = 'classify' ORDER BY id ASC;
|
||||
REPLACE INTO `zt_lang` (`lang`, `module`, `section`, `key`, `value`, `system`, `vision`) SELECT `lang`, `module`, 'agileplusClassify', `key`, `value`, `system`, `vision` FROM `zt_lang` WHERE `module` = 'process' and `section` = 'classify' ORDER BY id ASC;
|
||||
|
||||
UPDATE `zt_project` AS parent INNER JOIN (select `id`,`parent`,`attribute` from `zt_project` where `parent` != 0 and `type` = 'stage') AS child ON parent.`id` = child.`parent` SET parent.`attribute`='mix' where parent.`grade`=1 and parent.`type`='stage' and parent.`attribute` != child.`attribute`;
|
||||
|
||||
REPLACE INTO `zt_grouppriv` (SELECT `group`,`module`,'batchChangeStatus' FROM `zt_grouppriv` WHERE `module` = 'execution' AND `method` = 'batchEdit');
|
||||
@@ -376,7 +376,7 @@ class action extends control
|
||||
|
||||
/* Check type of siblings. */
|
||||
$siblings = $this->dao->select('DISTINCT type')->from(TABLE_EXECUTION)->where('deleted')->eq(0)->andWhere('parent')->eq($execution->parent)->fetchPairs('type');
|
||||
if($execution->type == 'stage' and (isset($bsiblings['sprint']) or isset($siblings['kanban']))) die(js::alert($this->lang->action->hasOtherType[$execution->type]));
|
||||
if($execution->type == 'stage' and (isset($siblings['sprint']) or isset($siblings['kanban']))) die(js::alert($this->lang->action->hasOtherType[$execution->type]));
|
||||
if(($execution->type == 'sprint' or $execution->type == 'kanban') and isset($siblings['stage'])) die(js::alert($this->lang->action->hasOtherType[$execution->type]));
|
||||
|
||||
/* If parent stage is not exists, you should recover its parent stages, refresh status. */
|
||||
|
||||
@@ -489,7 +489,7 @@ class actionModel extends model
|
||||
elseif($actionName == 'importedcard')
|
||||
{
|
||||
$title = $this->dao->select('name')->from(TABLE_KANBAN)->where('id')->eq($action->extra)->fetch('name');
|
||||
if($title) $action->extra = common::hasPriv('kanban', 'view') ? html::a(helper::createLink('kanban', 'view', "kanbanID=$action->extra"), "#$action->extra " . $title) : "#$action->extra " . $title;
|
||||
if($title) $action->extra = (common::hasPriv('kanban', 'view') and !isonlybody()) ? html::a(helper::createLink('kanban', 'view', "kanbanID=$action->extra"), "#$action->extra " . $title) : "#$action->extra " . $title;
|
||||
}
|
||||
elseif($actionName == 'createchildren')
|
||||
{
|
||||
|
||||
+11
-11
@@ -269,13 +269,13 @@ class adminModel extends model
|
||||
$this->setSwitcher($menuKey);
|
||||
if(isset($this->lang->admin->menuList->$menuKey))
|
||||
{
|
||||
if(isset($this->lang->admin->menuList->$menuKey['subMenu']))
|
||||
if(isset($this->lang->admin->menuList->{$menuKey}['subMenu']))
|
||||
{
|
||||
$moduleName = $this->app->rawModule;
|
||||
$methodName = $this->app->rawMethod;
|
||||
$firstParam = $this->app->rawParams ? reset($this->app->rawParams) : '';
|
||||
|
||||
foreach($this->lang->admin->menuList->$menuKey['subMenu'] as $subMenuKey => $subMenu)
|
||||
foreach($this->lang->admin->menuList->{$menuKey}['subMenu'] as $subMenuKey => $subMenu)
|
||||
{
|
||||
$subModule = '';
|
||||
if($moduleName == 'custom' and strpos(',required,set,', $methodName) !== false)
|
||||
@@ -285,25 +285,25 @@ class adminModel extends model
|
||||
}
|
||||
|
||||
if(!empty($subModule)) $subMenu['subModule'] = $subModule;
|
||||
if(isset($this->lang->admin->menuList->$menuKey['tabMenu'][$subMenuKey]))
|
||||
if(isset($this->lang->admin->menuList->{$menuKey}['tabMenu'][$subMenuKey]))
|
||||
{
|
||||
if(!empty($subModule))
|
||||
{
|
||||
$this->lang->admin->menuList->$menuKey['tabMenu'][$subMenuKey][$firstParam]['subModule'] = $subModule;
|
||||
unset($this->lang->admin->menuList->$menuKey['tabMenu'][$subMenuKey][$firstParam]['exclude']);
|
||||
$this->lang->admin->menuList->{$menuKey}['tabMenu'][$subMenuKey][$firstParam]['subModule'] = $subModule;
|
||||
unset($this->lang->admin->menuList->{$menuKey}['tabMenu'][$subMenuKey][$firstParam]['exclude']);
|
||||
}
|
||||
$subMenu['subMenu'] = $this->lang->admin->menuList->$menuKey['tabMenu'][$subMenuKey];
|
||||
$subMenu['subMenu'] = $this->lang->admin->menuList->{$menuKey}['tabMenu'][$subMenuKey];
|
||||
}
|
||||
if(isset($this->lang->admin->menuList->$menuKey['tabMenu']['menuOrder'][$subMenuKey])) $subMenu['menuOrder'] = $this->lang->admin->menuList->$menuKey['tabMenu']['menuOrder'][$subMenuKey];
|
||||
if(isset($this->lang->admin->menuList->$menuKey['tabMenu']['dividerMenu'][$subMenuKey])) $subMenu['dividerMenu'] = $this->lang->admin->menuList->$menuKey['tabMenu']['dividerMenu'][$subMenuKey];
|
||||
if(isset($this->lang->admin->menuList->{$menuKey}['tabMenu']['menuOrder'][$subMenuKey])) $subMenu['menuOrder'] = $this->lang->admin->menuList->{$menuKey}['tabMenu']['menuOrder'][$subMenuKey];
|
||||
if(isset($this->lang->admin->menuList->{$menuKey}['tabMenu']['dividerMenu'][$subMenuKey])) $subMenu['dividerMenu'] = $this->lang->admin->menuList->{$menuKey}['tabMenu']['dividerMenu'][$subMenuKey];
|
||||
|
||||
$this->lang->admin->menu->$subMenuKey = $subMenu;
|
||||
}
|
||||
}
|
||||
|
||||
if(isset($this->lang->admin->menuList->$menuKey['menuOrder'])) $this->lang->admin->menuOrder = $this->lang->admin->menuList->$menuKey['menuOrder'];
|
||||
if(isset($this->lang->admin->menuList->$menuKey['dividerMenu'])) $this->lang->admin->dividerMenu = $this->lang->admin->menuList->$menuKey['dividerMenu'];
|
||||
if(isset($this->lang->admin->menuList->$menuKey['tabMenu'])) $this->lang->admin->tabMenu = $this->lang->admin->menuList->$menuKey['tabMenu'];
|
||||
if(isset($this->lang->admin->menuList->{$menuKey}['menuOrder'])) $this->lang->admin->menuOrder = $this->lang->admin->menuList->{$menuKey}['menuOrder'];
|
||||
if(isset($this->lang->admin->menuList->{$menuKey}['dividerMenu'])) $this->lang->admin->dividerMenu = $this->lang->admin->menuList->{$menuKey}['dividerMenu'];
|
||||
if(isset($this->lang->admin->menuList->{$menuKey}['tabMenu'])) $this->lang->admin->tabMenu = $this->lang->admin->menuList->{$menuKey}['tabMenu'];
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -72,7 +72,7 @@ class build extends control
|
||||
if($this->app->tab == 'project')
|
||||
{
|
||||
$this->project->setMenu($projectID);
|
||||
$executions = $this->execution->getPairs($projectID, 'all', 'stagefilter|leaf');
|
||||
$executions = $this->execution->getPairs($projectID, 'all', 'stagefilter|leaf|order_asc');
|
||||
$executionID = empty($executionID) ? key($executions) : $executionID;
|
||||
$productGroups = $executionID ? $this->product->getProducts($executionID) : array();
|
||||
$branchGroups = $executionID ? $this->project->getBranchesByProject($executionID) : array();
|
||||
@@ -81,7 +81,7 @@ class build extends control
|
||||
elseif($this->app->tab == 'execution')
|
||||
{
|
||||
$execution = $this->execution->getByID($executionID);
|
||||
$executions = $this->execution->getPairs($execution->project, 'all', 'stagefilter|leaf');
|
||||
$executions = $this->execution->getPairs($execution->project, 'all', 'stagefilter|leaf|order_asc');
|
||||
$projectID = $execution->project;
|
||||
$productGroups = $this->product->getProducts($executionID);
|
||||
$branchGroups = $this->project->getBranchesByProject($executionID);
|
||||
|
||||
@@ -1792,7 +1792,8 @@ EOD;
|
||||
$executionPairs = array();
|
||||
$userCondition = !$app->user->admin ? " AND `id` " . helper::dbIN($app->user->view->sprints) : '';
|
||||
$orderBy = $object->type == 'stage' ? 'ORDER BY `id` ASC' : 'ORDER BY `id` DESC';
|
||||
$executionList = $app->dbh->query("SELECT id,name,parent FROM " . TABLE_EXECUTION . " WHERE `project` = '{$object->project}' AND `deleted` = '0' $userCondition $orderBy")->fetchAll();
|
||||
$executionList = $app->dbh->query("SELECT id,name,parent,project FROM " . TABLE_EXECUTION . " WHERE `project` = '{$object->project}' AND `deleted` = '0' $userCondition $orderBy")->fetchAll();
|
||||
$executionList = $app->control->loadModel('execution')->resetExecutionSorts($executionList);
|
||||
foreach($executionList as $execution)
|
||||
{
|
||||
if(isset($executionPairs[$execution->parent])) unset($executionPairs[$execution->parent]);
|
||||
|
||||
@@ -1727,15 +1727,8 @@ class execution extends control
|
||||
}
|
||||
|
||||
$importPlanStoryTips = $multiBranchProduct ? $this->lang->execution->importBranchPlanStory : $this->lang->execution->importPlanStory;
|
||||
if(!$execution->hasProduct)
|
||||
{
|
||||
return print(js::locate(inlink('create', "projectID=$projectID&executionID=$executionID")));
|
||||
}
|
||||
else
|
||||
{
|
||||
return print(js::confirm($importPlanStoryTips, inlink('create', "projectID=$projectID&executionID=$executionID©ExecutionID=&planID=$planID&confirm=yes"), inlink('create', "projectID=$projectID&executionID=$executionID")));
|
||||
|
||||
}
|
||||
return print(js::confirm($importPlanStoryTips, inlink('create', "projectID=$projectID&executionID=$executionID©ExecutionID=&planID=$planID&confirm=yes"), inlink('create', "projectID=$projectID&executionID=$executionID")));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1801,16 +1794,11 @@ class execution extends control
|
||||
{
|
||||
if(isset($_POST['attribute']) and in_array($_POST['attribute'], array('request', 'design', 'review'))) unset($_POST['plans']);
|
||||
|
||||
/* No product execution link plans. */
|
||||
if(isset($project->hasProduct) and empty($project->hasProduct) and !empty($_POST['plans']))
|
||||
/* Filter empty plans. */
|
||||
if(!empty($_POST['plans']))
|
||||
{
|
||||
$plansItem = array();
|
||||
foreach($_POST['plans'] as $planItem)
|
||||
{
|
||||
if(empty($planItem[0][0])) continue;
|
||||
$plansItem[] = $planItem[0][0];
|
||||
}
|
||||
$_POST['plans'] = array($_POST['products'][0] => array(0 => $plansItem));
|
||||
foreach($_POST['plans'] as $key => $planItem) $_POST['plans'][$key] = array_filter($_POST['plans'][$key]);
|
||||
$_POST['plans'] = array_filter($_POST['plans']);
|
||||
}
|
||||
|
||||
$executionID = $this->execution->create($copyExecutionID);
|
||||
@@ -1912,7 +1900,7 @@ class execution extends control
|
||||
$this->view->users = $this->loadModel('user')->getPairs('nodeleted|noclosed');
|
||||
$this->view->copyExecution = isset($copyExecution) ? $copyExecution : '';
|
||||
$this->view->from = $this->app->tab;
|
||||
$this->view->isStage = (isset($project->model) and $project->model == 'waterfall') ? true : false;
|
||||
$this->view->isStage = (isset($project->model) and ($project->model == 'waterfall' or $project->model == 'waterfallplus')) ? true : false;
|
||||
$this->view->project = $project;
|
||||
$this->view->division = !empty($project) ? $project->division : 1;
|
||||
$this->view->type = $type;
|
||||
@@ -2006,15 +1994,11 @@ class execution extends control
|
||||
$newPlans = array();
|
||||
if(isset($_POST['plans']))
|
||||
{
|
||||
|
||||
foreach($_POST['plans'] as $plans)
|
||||
{
|
||||
foreach($plans as $planList)
|
||||
foreach($plans as $planID)
|
||||
{
|
||||
foreach($planList as $planID)
|
||||
{
|
||||
if(array_search($planID, $oldPlans) === false) $newPlans[$planID] = $planID;
|
||||
}
|
||||
if(array_search($planID, $oldPlans) === false) $newPlans[$planID] = $planID;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -2238,8 +2222,6 @@ class execution extends control
|
||||
{
|
||||
$executionIdList = $this->post->executionIDList;
|
||||
if(is_string($executionIdList)) $executionIdList = explode(',', $executionIdList);
|
||||
/* Sub-phases are changed first and then parented. */
|
||||
rsort($executionIdList);
|
||||
|
||||
$pointOutStages = $this->execution->batchChangeStatus($executionIdList, $status);
|
||||
$project = $this->loadModel('project')->getById($projectID);
|
||||
@@ -2632,6 +2614,12 @@ class execution extends control
|
||||
$execution = $this->commonAction($executionID);
|
||||
if($execution->type != 'kanban') return print(js::locate(inlink('view', "executionID=$executionID")));
|
||||
|
||||
if($execution->lifetime == 'ops' or in_array($execution->attribute, array('request', 'review')))
|
||||
{
|
||||
$browseType = 'task';
|
||||
unset($this->lang->kanban->group->task['story']);
|
||||
}
|
||||
|
||||
$kanbanData = $this->loadModel('kanban')->getRDKanban($executionID, $browseType, $orderBy, 0, $groupBy);
|
||||
$executionActions = array();
|
||||
foreach($this->config->execution->statusActions as $action)
|
||||
@@ -2639,12 +2627,6 @@ class execution extends control
|
||||
if($this->execution->isClickable($execution, $action)) $executionActions[] = $action;
|
||||
}
|
||||
|
||||
if($execution->lifetime == 'ops' or in_array($execution->attribute, array('request', 'review')))
|
||||
{
|
||||
$browseType = 'task';
|
||||
unset($this->lang->kanban->group->task['story']);
|
||||
}
|
||||
|
||||
$userList = array();
|
||||
$users = $this->loadModel('user')->getPairs('noletter|nodeleted');
|
||||
$avatarPairs = $this->user->getAvatarPairs('all');
|
||||
@@ -3808,7 +3790,7 @@ class execution extends control
|
||||
->andWhere('type')->in('sprint,stage,kanban')
|
||||
->beginIF(!$this->app->user->admin)->andWhere('id')->in($this->app->user->view->sprints)->fi()
|
||||
->andWhere('project')->in(array_keys($projects))
|
||||
->orderBy('id_desc')
|
||||
->orderBy('order_asc')
|
||||
->fetchGroup('project', 'id');
|
||||
|
||||
$teams = $this->dao->select('root,account')->from(TABLE_TEAM)
|
||||
@@ -3822,9 +3804,15 @@ class execution extends control
|
||||
$executions = zget($executionGroups, $project->id, array());
|
||||
if(isset($project->model) and $project->model == 'waterfall') ksort($executions);
|
||||
|
||||
$parents = array();
|
||||
foreach($executions as $execution) $parents[$execution->parent] = $execution->parent;
|
||||
$parents = array();
|
||||
$firstGradeExecs = array();
|
||||
foreach($executions as $execution)
|
||||
{
|
||||
$parents[$execution->parent] = $execution->parent;
|
||||
if($execution->grade == 1) $firstGradeExecs[$execution->id] = $execution->id;
|
||||
}
|
||||
|
||||
$executions = $this->execution->resetExecutionSorts($executions, $firstGradeExecs);
|
||||
foreach($executions as $execution)
|
||||
{
|
||||
/* Only show leaf executions. */
|
||||
@@ -4108,22 +4096,7 @@ class execution extends control
|
||||
unset($fields[$key]);
|
||||
}
|
||||
|
||||
$executionStats = $this->execution->getStatData($projectID, $status == 'byproduct' ? 'all' : $status, $productID, 0, false, '', 'id_asc');
|
||||
if(isset($project->model) and $project->model == 'waterfall')
|
||||
{
|
||||
$stageList = array();
|
||||
foreach($executionStats as $stage)
|
||||
{
|
||||
$stageList[] = $stage;
|
||||
foreach($stage->children as $child)
|
||||
{
|
||||
$child->name = $stage->name . '/' . $child->name;
|
||||
$stageList[] = $child;
|
||||
}
|
||||
}
|
||||
|
||||
$executionStats = $stageList;
|
||||
}
|
||||
$executionStats = $this->execution->getStatData($projectID, $status == 'byproduct' ? 'all' : $status, $productID, 0, false, 'hasParentName', 'order_asc');
|
||||
|
||||
$users = $this->loadModel('user')->getPairs('noletter');
|
||||
foreach($executionStats as $i => $execution)
|
||||
@@ -4134,6 +4107,7 @@ class execution extends control
|
||||
$execution->totalConsumed = $execution->hours->totalConsumed;
|
||||
$execution->totalLeft = $execution->hours->totalLeft;
|
||||
$execution->progress = $execution->hours->progress . '%';
|
||||
$execution->name = isset($execution->title) ? $execution->title : $execution->name;
|
||||
if($this->app->tab == 'project' and ($project->model == 'agileplus' or $project->model == 'waterfallplus')) $execution->method = zget($executionLang->typeList, $execution->type);
|
||||
|
||||
if($this->post->exportType == 'selected')
|
||||
|
||||
@@ -1,9 +1,17 @@
|
||||
body {margin-bottom: 25px;}
|
||||
|
||||
#main {padding-bottom: 0;}
|
||||
#myTable .dtable-header, #executionsForm .dtable-rows {z-index: 4;}
|
||||
.table-header.fixed-right > .btn-toolbar {right: 0}
|
||||
.table-header.fixed-right > .btn-toolbar {right: 0; background-color: #f1f5f9;}
|
||||
|
||||
#myTable input[type=checkbox] {margin: 0px}
|
||||
|
||||
.table-footer {border-top: 1px solid #fff4ea}
|
||||
.table-footer .pager{z-index: 10}
|
||||
#myTable .scrollbar {z-index: 11}
|
||||
|
||||
.dtable {--dtable-checked-bg: #fff4ea; --dtable-border-color: #f4f5f7}
|
||||
.dtable-row {border-bottom-style: solid;}
|
||||
.dtable-cell-html a{color: #2463c7}
|
||||
.dtable-cell[data-sort='up'] .dtable-sort:before {color: #000; opacity: 1}
|
||||
.dtable-cell[data-sort='down'] .dtable-sort:after {color: #000; opacity: 1}
|
||||
.dtable .toggle-icon {border-radius: 50%; border-style: solid;}
|
||||
.dtable-nested-toggle.is-no-child {display: block; opacity: 0; pointer-events: none;}
|
||||
|
||||
@@ -180,7 +180,7 @@ function loadBranches(product)
|
||||
var branch = $('#branch' + index);
|
||||
loadPlans(product, branch);
|
||||
|
||||
if(typeof isWaterfall != 'undefined' && isWaterfall == true)
|
||||
if(typeof isStage != 'undefined' && isStage == true)
|
||||
{
|
||||
$tableRow.find("select[name^='branch'] option").attr('selected', 'selected');
|
||||
$tableRow.find("select[name^='branch']").trigger('chosen:updated');
|
||||
|
||||
+81
-31
@@ -387,6 +387,7 @@ class executionModel extends model
|
||||
->setDefault('lastEditedDate', helper::now())
|
||||
->setDefault('team', $this->post->name)
|
||||
->setDefault('parent', $this->post->project)
|
||||
->setIF($this->post->parent, 'parent', $this->post->parent)
|
||||
->setIF($this->post->heightType == 'auto', 'displayCards', 0)
|
||||
->setIF(!isset($_POST['whitelist']), 'whitelist', '')
|
||||
->setIF($this->post->acl == 'open', 'whitelist', '')
|
||||
@@ -396,7 +397,7 @@ class executionModel extends model
|
||||
->remove('products, workDays, delta, branch, uid, plans, teams, teamMembers, contactListMenu, heightType')
|
||||
->get();
|
||||
|
||||
if(!empty($sprint->parent))
|
||||
if(!empty($sprint->parent) and ($sprint->project == $sprint->parent))
|
||||
{
|
||||
$project = $this->loadModel('project')->getByID($sprint->parent);
|
||||
$sprint->hasProduct = $project->hasProduct;
|
||||
@@ -459,6 +460,15 @@ class executionModel extends model
|
||||
|
||||
if((isset($project) and $project->model != 'kanban') or empty($project)) $this->loadModel('kanban')->createExecutionLane($executionID);
|
||||
|
||||
/* Api create infinitus stages. */
|
||||
if(isset($sprint->parent) and ($sprint->parent != $sprint->project) and $sprint->type == 'stage')
|
||||
{
|
||||
$parent = $this->getByID($sprint->parent);
|
||||
$grade = $parent->grade + 1;
|
||||
$path = rtrim($parent->path, ',') . ",{$executionID}";
|
||||
$this->dao->update(TABLE_EXECUTION)->set('path')->eq($path)->set('grade')->eq($grade)->where('id')->eq($executionID)->exec();
|
||||
}
|
||||
|
||||
/* Save order. */
|
||||
$this->dao->update(TABLE_EXECUTION)->set('`order`')->eq($executionID * 5)->where('id')->eq($executionID)->exec();
|
||||
$this->file->updateObjectID($this->post->uid, $executionID, 'execution');
|
||||
@@ -985,6 +995,9 @@ class executionModel extends model
|
||||
$this->loadModel('programplan');
|
||||
$this->loadModel('action');
|
||||
|
||||
/* Sort the IDs, the child stage comes first, and the parent stage follows. */
|
||||
$executionIdList = $this->dao->select('id')->from(TABLE_EXECUTION)->where('id')->in($executionIdList)->orderBy('grade_desc')->fetchPairs();
|
||||
|
||||
$pointOutStages = '';
|
||||
foreach($executionIdList as $executionID)
|
||||
{
|
||||
@@ -1603,7 +1616,7 @@ class executionModel extends model
|
||||
*
|
||||
* @param int $projectID
|
||||
* @param string $type all|sprint|stage|kanban
|
||||
* @param string $mode all|noclosed|stagefilter|withdelete|multiple|leaf or empty
|
||||
* @param string $mode all|noclosed|stagefilter|withdelete|multiple|leaf|order_asc or empty
|
||||
* @access public
|
||||
* @return array
|
||||
*/
|
||||
@@ -1638,20 +1651,19 @@ class executionModel extends model
|
||||
->beginIF(strpos($mode, 'withdelete') === false)->andWhere('deleted')->eq(0)->fi()
|
||||
->beginIF(!$this->app->user->admin and strpos($mode, 'all') === false)->andWhere('id')->in($this->app->user->view->sprints)->fi()
|
||||
->orderBy($orderBy)
|
||||
->fetchAll();
|
||||
->fetchAll('id');
|
||||
|
||||
/* If mode == leaf, only show leaf executions. */
|
||||
$allExecutions = $this->dao->select('id,name,parent')->from(TABLE_EXECUTION)
|
||||
$allExecutions = $this->dao->select('id,name,parent,grade')->from(TABLE_EXECUTION)
|
||||
->where('type')->notin(array('program', 'project'))
|
||||
->andWhere('deleted')->eq('0')
|
||||
->beginIf($projectID)->andWhere('project')->eq($projectID)->fi()
|
||||
->fetchAll('id');
|
||||
|
||||
$parents = array();
|
||||
foreach($allExecutions as $exec)
|
||||
{
|
||||
$parents[$exec->parent] = true;
|
||||
}
|
||||
foreach($allExecutions as $exec) $parents[$exec->parent] = true;
|
||||
|
||||
if(strpos($mode, 'order_asc') !== false) $executions = $this->resetExecutionSorts($executions);
|
||||
|
||||
$pairs = array();
|
||||
$noMultiples = array();
|
||||
@@ -2017,9 +2029,7 @@ class executionModel extends model
|
||||
{
|
||||
if(defined('TUTORIAL')) return $this->loadModel('tutorial')->getExecutionPairs();
|
||||
|
||||
$project = $this->loadModel('project')->getByID($projectID);
|
||||
$orderBy = (isset($project->model) and $project->model == 'waterfall') ? 'begin_asc,id_asc' : 'begin_desc,id_desc';
|
||||
|
||||
$project = $this->loadModel('project')->getByID($projectID);
|
||||
$executions = $this->dao->select('*')->from(TABLE_EXECUTION)
|
||||
->where('type')->in('stage,sprint,kanban')
|
||||
->andWhere('deleted')->eq('0')
|
||||
@@ -2031,12 +2041,12 @@ class executionModel extends model
|
||||
->beginIF($status == 'noclosed')->andWhere('status')->ne('closed')->fi()
|
||||
->beginIF($devel === true)->andWhere('attribute')->in('dev,qa,release')->fi()
|
||||
->beginIF($appendedID)->orWhere('id')->eq($appendedID)->fi()
|
||||
->orderBy($orderBy)
|
||||
->orderBy('order_asc')
|
||||
->beginIF($limit)->limit($limit)->fi()
|
||||
->fetchAll('id');
|
||||
|
||||
/* Add product name and parent stage name to stage name. */
|
||||
if(isset($project->model) and $project->model == 'waterfall')
|
||||
if(isset($project->model) and in_array($project->model, array('waterfall', 'waterfallplus')))
|
||||
{
|
||||
$executionProducts = array();
|
||||
if($project->hasProduct and $project->division)
|
||||
@@ -2049,8 +2059,8 @@ class executionModel extends model
|
||||
->fetchPairs();
|
||||
}
|
||||
|
||||
$allExecutions = $this->dao->select('id,name,parent')->from(TABLE_EXECUTION)
|
||||
->where('type')->eq('stage')
|
||||
$allExecutions = $this->dao->select('id,name,parent,grade')->from(TABLE_EXECUTION)
|
||||
->where('type')->in('stage,sprint,kanban')
|
||||
->andWhere('deleted')->eq('0')
|
||||
->beginIf($projectID)->andWhere('project')->eq($projectID)->fi()
|
||||
->fetchAll('id');
|
||||
@@ -2058,6 +2068,7 @@ class executionModel extends model
|
||||
$parents = array();
|
||||
foreach($allExecutions as $id => $execution) $parents[$execution->parent] = $execution->parent;
|
||||
|
||||
$executions = $this->resetExecutionSorts($executions);
|
||||
foreach($executions as $id => $execution)
|
||||
{
|
||||
if(isset($parents[$execution->id]))
|
||||
@@ -2073,7 +2084,6 @@ class executionModel extends model
|
||||
if($executionName) $execution->name = ltrim($executionName, '/');
|
||||
if(isset($executionProducts[$id])) $execution->name = $executionProducts[$id] . '/' . $execution->name;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
$projects = array();
|
||||
@@ -5303,18 +5313,6 @@ class executionModel extends model
|
||||
return $productpairs;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get lifetime by id list.
|
||||
*
|
||||
* @param string $idList
|
||||
* @access public
|
||||
* @return array
|
||||
*/
|
||||
public function getLifetimeByIdList($idList = '')
|
||||
{
|
||||
return $this->dao->select('id,lifetime')->from(TABLE_EXECUTION)->where('id')->in($idList)->fetchPairs();
|
||||
}
|
||||
|
||||
/**
|
||||
* Set stage tree path.
|
||||
*
|
||||
@@ -5552,15 +5550,15 @@ class executionModel extends model
|
||||
/**
|
||||
* Generate col for dtable.
|
||||
*
|
||||
* @param string $orderBy
|
||||
* @access public
|
||||
* @return void
|
||||
*/
|
||||
public function generateCol()
|
||||
public function generateCol($orderBy = '')
|
||||
{
|
||||
$this->loadModel('datatable');
|
||||
|
||||
$setting = $this->datatable->getSetting('execution');
|
||||
|
||||
$setting = $this->datatable->getSetting('execution');
|
||||
$fieldList = $this->config->execution->datatable->fieldList;
|
||||
|
||||
foreach($fieldList as $field => $items)
|
||||
@@ -5582,6 +5580,13 @@ class executionModel extends model
|
||||
$set->name = $value;
|
||||
$set->title = $fieldList[$id]['title'];
|
||||
|
||||
$sortType = '';
|
||||
if(strpos($orderBy, $id) !== false)
|
||||
{
|
||||
$sort = str_replace("{$id}_", '', $orderBy);
|
||||
$sortType = $sort == 'asc' ? 'up' : 'down';
|
||||
}
|
||||
|
||||
if(isset($fieldList[$id]['checkbox'])) $set->checkbox = $fieldList[$id]['checkbox'];
|
||||
if(isset($fieldList[$id]['nestedToggle'])) $set->nestedToggle = $fieldList[$id]['nestedToggle'];
|
||||
if(isset($fieldList[$id]['fixed'])) $set->fixed = $fieldList[$id]['fixed'];
|
||||
@@ -5593,6 +5598,8 @@ class executionModel extends model
|
||||
if(isset($fieldList[$id]['maxWidth'])) $set->maxWidth = $fieldList[$id]['maxWidth'];
|
||||
if(isset($fieldList[$id]['pri'])) $set->pri = $fieldList[$id]['pri'];
|
||||
|
||||
if($sortType) $set->sortType = $sortType;
|
||||
|
||||
$setting[$key] = $set;
|
||||
}
|
||||
}
|
||||
@@ -5606,6 +5613,13 @@ class executionModel extends model
|
||||
continue;
|
||||
}
|
||||
|
||||
$sortType = '';
|
||||
if(strpos($orderBy, $set->id) !== false)
|
||||
{
|
||||
$sort = str_replace("{$set->id}_", '', $orderBy);
|
||||
$sortType = $sort == 'asc' ? 'up' : 'down';
|
||||
}
|
||||
|
||||
$set->name = $set->id;
|
||||
$set->title = $fieldList[$set->id]['title'];
|
||||
|
||||
@@ -5619,6 +5633,8 @@ class executionModel extends model
|
||||
if(isset($fieldList[$set->id]['maxWidth'])) $set->maxWidth = $fieldList[$set->id]['maxWidth'];
|
||||
if(isset($fieldList[$set->id]['pri'])) $set->pri = $fieldList[$set->id]['pri'];
|
||||
|
||||
if($sortType) $set->sortType = $sortType;
|
||||
|
||||
$set->width = str_replace('px', '', $set->width);
|
||||
|
||||
unset($set->id);
|
||||
@@ -5902,4 +5918,38 @@ class executionModel extends model
|
||||
|
||||
return $execution;
|
||||
}
|
||||
|
||||
/**
|
||||
* Reset execution orders.
|
||||
*
|
||||
* @param array $executions
|
||||
* @param array $parentExecutions
|
||||
* @access public
|
||||
* @return array
|
||||
*/
|
||||
public function resetExecutionSorts($executions, $parentExecutions = array())
|
||||
{
|
||||
if(empty($executions)) return array();
|
||||
if(empty($parentExecutions))
|
||||
{
|
||||
$execution = current($executions);
|
||||
$parentExecutions = $this->dao->select('*')->from(TABLE_EXECUTION)
|
||||
->where('deleted')->eq(0)
|
||||
->andWhere('type')->in('kanban,sprint,stage')
|
||||
->andWhere('grade')->eq(1)
|
||||
->andWhere('project')->eq($execution->project)
|
||||
->orderBy('order_asc')
|
||||
->fetchAll('id');
|
||||
}
|
||||
|
||||
$sortedExecutions = array();
|
||||
foreach($parentExecutions as $executionID => $execution)
|
||||
{
|
||||
if(!isset($sortedExecutions[$executionID]) and isset($executions[$executionID])) $sortedExecutions[$executionID] = $executions[$executionID];
|
||||
|
||||
$children = $this->getChildExecutions($executionID, 'order_asc');
|
||||
if(!empty($children)) $sortedExecutions += $this->resetExecutionSorts($executions, $children);
|
||||
}
|
||||
return $sortedExecutions;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -15,7 +15,7 @@
|
||||
js::import($jsRoot . 'dtable/min.js');
|
||||
css::import($jsRoot . 'dtable/min.css');
|
||||
|
||||
$cols = $this->execution->generateCol();
|
||||
$cols = $this->execution->generateCol($orderBy);
|
||||
$executions = $this->execution->generateRow($executionStats, $users, $productID);
|
||||
|
||||
$sortLink = $this->createLink('execution', 'all', "status=$status&orderBy={orderBy}&productID=$productID¶m=$param&recTotal=$pager->recTotal&recPerPage=$pager->recPerPage&pageID=$pager->pageID");
|
||||
@@ -93,7 +93,7 @@ js::set('isCNLang', !$this->loadModel('common')->checkNotCN());
|
||||
{
|
||||
$actionLink = $this->createLink('project', 'batchEdit');
|
||||
$misc = "id='batchEditBtn'";
|
||||
echo html::commonButton($lang->edit, $misc);
|
||||
echo html::commonButton($lang->edit, $misc);
|
||||
}
|
||||
if($canBatchChangeStatus)
|
||||
{
|
||||
@@ -117,17 +117,43 @@ js::set('isCNLang', !$this->loadModel('common')->checkNotCN());
|
||||
<script>
|
||||
cols = JSON.parse(cols);
|
||||
data = JSON.parse(data);
|
||||
const options = {
|
||||
height: 'auto',
|
||||
const options =
|
||||
{
|
||||
striped: true,
|
||||
plugins: ['nested', 'checkable'],
|
||||
checkOnClickRow: true,
|
||||
sortLink: createSortLink,
|
||||
cols: cols,
|
||||
data: data,
|
||||
footer: false,
|
||||
responsive: true,
|
||||
onCheckChange: toggleActions,
|
||||
height: function(height)
|
||||
{
|
||||
return Math.min($(window).height() - $('#header').outerHeight() - $('#mainMenu').outerHeight() - $('.table-footer').outerHeight() - 30, height);
|
||||
},
|
||||
onRenderCell: function(result, info)
|
||||
{
|
||||
if(info.col.name === 'burn' && Array.isArray(info.row.data.burns) && info.row.data.burns.length)
|
||||
{
|
||||
tryRenderSparkline();
|
||||
return [{html: '<span class="sparkline pending text-left no-padding" values="' + info.row.data.burns.join(',') + '"></span>'}];
|
||||
}
|
||||
return result;
|
||||
}
|
||||
};
|
||||
|
||||
function renderSparkline()
|
||||
{
|
||||
$('#myTable .dtable-rows .sparkline.pending').removeClass('pending').sparkline();
|
||||
}
|
||||
|
||||
function tryRenderSparkline()
|
||||
{
|
||||
if(window.renderingSparkline) clearTimeout(window.renderingSparkline);
|
||||
window.renderingSparkline = setTimeout(renderSparkline, 200);
|
||||
}
|
||||
|
||||
function createSortLink(col)
|
||||
{
|
||||
var sort = col.name + '_asc';
|
||||
|
||||
@@ -31,7 +31,6 @@
|
||||
|
||||
<?php include '../../common/view/header.html.php';?>
|
||||
<?php include '../../common/view/kindeditor.html.php';?>
|
||||
<?php $isWaterfall = (!empty($project->model) and ($project->model == 'waterfall' or $project->model == 'waterfallplus')) ? true : false;?>
|
||||
<?php js::import($jsRoot . 'misc/date.js');?>
|
||||
<?php js::set('weekend', $config->execution->weekend);?>
|
||||
<?php js::set('holders', $lang->execution->placeholder);?>
|
||||
@@ -47,7 +46,6 @@
|
||||
<?php js::set('cancelCopy', $lang->execution->cancelCopy);?>
|
||||
<?php js::set('copyNoExecution', $lang->execution->copyNoExecution);?>
|
||||
<?php js::set('model', isset($project->model) ? $project->model : '');?>
|
||||
<?php js::set('isWaterfall', $isWaterfall);?>
|
||||
<div id='mainContent' class='main-content'>
|
||||
<div class='center-block'>
|
||||
<div class='main-header'>
|
||||
@@ -140,7 +138,7 @@
|
||||
<?php $this->printExtendFields('', 'table', 'columns=3');?>
|
||||
<?php $hidden = 'hide'?>
|
||||
<?php if(!empty($project->hasProduct)) $hidden = ''?>
|
||||
<?php if($products):?>
|
||||
<?php if(isset($project->hasProduct) and !empty($project->hasProduct) and $products):?>
|
||||
<?php $i = 0;?>
|
||||
<?php foreach($products as $product):?>
|
||||
<tr class="<?php echo $hidden;?>">
|
||||
@@ -153,9 +151,9 @@
|
||||
<?php $hasBranch = $product->type != 'normal' and isset($branchGroups[$product->id]);?>
|
||||
<div class='input-group <?php if($hasBranch) echo ' has-branch';?>'>
|
||||
<span class='input-group-addon'><?php echo $lang->product->common;?></span>
|
||||
<?php $disabled = ($isWaterfall and !$project->division) ? "disabled='disabled'" : '';?>
|
||||
<?php $disabled = ($isStage and !$project->division) ? "disabled='disabled'" : '';?>
|
||||
<?php echo html::select("products[$i]", $allProducts, $product->id, "class='form-control chosen' $disabled onchange='loadBranches(this)' data-last='" . $product->id . "' data-type='" . $product->type . "'");?>
|
||||
<?php if($isWaterfall and !$project->division) echo html::hidden("products[$i]", $product->id);?>
|
||||
<?php if($isStage and !$project->division) echo html::hidden("products[$i]", $product->id);?>
|
||||
</div>
|
||||
</div>
|
||||
<div class='table-col <?php if(!$hasBranch) echo 'hidden'; if($disabled) echo ' disabledBranch'?>'>
|
||||
@@ -171,7 +169,7 @@
|
||||
<div class='input-group' <?php echo "id='plan$i'";?>>
|
||||
<span class='input-group-addon'><?php echo $lang->product->plan;?></span>
|
||||
<?php echo html::select("plans[$product->id][]", isset($productPlans[$product->id]) ? $productPlans[$product->id] : array(), isset($product->plans) ? $product->plans : '', "class='form-control chosen' multiple");?>
|
||||
<?php if(!($isWaterfall and !$project->division)):?>
|
||||
<?php if(!($isStage and !$project->division)):?>
|
||||
<div class='input-group-btn'>
|
||||
<a href='javascript:;' onclick='addNewLine(this)' class='btn btn-link addLine'><i class='icon-plus'></i></a>
|
||||
<a href='javascript:;' onclick='removeLine(this)' class='btn btn-link removeLine' <?php if($i == 0) echo "style='visibility: hidden'";?>><i class='icon-close'></i></a>
|
||||
@@ -184,6 +182,16 @@
|
||||
</tr>
|
||||
<?php $i ++;?>
|
||||
<?php endforeach;?>
|
||||
<?php elseif(!empty($project) and empty($project->hasProduct)):?>
|
||||
<tr>
|
||||
<th><?php echo $lang->execution->linkPlan;?></th>
|
||||
<td id="plansBox">
|
||||
<?php $planProductID = current(array_keys($allProducts));?>
|
||||
<?php echo html::select("plans[$planProductID][]", isset($productPlan) ? $productPlan : array(), '', "class='form-control chosen' multiple");?>
|
||||
<?php echo html::hidden("products[]", $planProductID);?>
|
||||
<?php echo html::hidden("branch[0][0]", '0');?>
|
||||
</td>
|
||||
</tr>
|
||||
<?php else:?>
|
||||
<tr class='<?php echo $hidden;?>'>
|
||||
<th id='productTitle'><?php echo $lang->project->manageProductPlan;?></th>
|
||||
@@ -209,7 +217,7 @@
|
||||
<div class='input-group' id='plan0'>
|
||||
<span class='input-group-addon'><?php echo $lang->product->plan;?></span>
|
||||
<?php echo html::select("plans[][]", $productPlan, '', "class='form-control chosen' multiple");?>
|
||||
<?php if(!($isWaterfall and $project->division)):?>
|
||||
<?php if(!($isStage and $project->division)):?>
|
||||
<div class='input-group-btn'>
|
||||
<a href='javascript:;' onclick='addNewLine(this)' class='btn btn-link addLine'><i class='icon-plus'></i></a>
|
||||
<a href='javascript:;' onclick='removeLine(this)' class='btn btn-link removeLine' style='visibility: hidden'><i class='icon-close'></i></a>
|
||||
|
||||
@@ -151,7 +151,7 @@
|
||||
<?php if($project->model != 'waterfall' and $project->model != 'waterfallplus'): ?>
|
||||
<?php $hidden = 'hide'?>
|
||||
<?php if(!empty($project->hasProduct)) $hidden = ''?>
|
||||
<?php if($linkedProducts):?>
|
||||
<?php if(!empty($project) and !empty($project->hasProduct) and $linkedProducts):?>
|
||||
<?php $i = 0;?>
|
||||
<?php foreach($linkedProducts as $product):?>
|
||||
<tr class="<?php echo $hidden;?>">
|
||||
@@ -195,6 +195,16 @@
|
||||
</tr>
|
||||
<?php $i ++;?>
|
||||
<?php endforeach;?>
|
||||
<?php elseif(!empty($project) and empty($project->hasProduct)):?>
|
||||
<tr>
|
||||
<th><?php echo $lang->execution->linkPlan;?></th>
|
||||
<td id="plansBox">
|
||||
<?php $planProductID = current(array_keys($linkedProducts));?>
|
||||
<?php echo html::select("plans[$planProductID][]", isset($productPlans[$planProductID]) ? $productPlans[$planProductID] : array(), isset($linkedProducts[$planProductID]) ? $linkedProducts[$planProductID]->plans : '', "class='form-control chosen' multiple");?>
|
||||
<?php echo html::hidden("products[]", $planProductID);?>
|
||||
<?php echo html::hidden("branch[0][0]", '0');?>
|
||||
</td>
|
||||
</tr>
|
||||
<?php else:?>
|
||||
<tr class='<?php echo $hidden;?>'>
|
||||
<th id='productTitle'><?php echo $lang->project->manageProductPlan;?></th>
|
||||
|
||||
@@ -411,7 +411,8 @@
|
||||
<div class="modal-body">
|
||||
<div class='input-group'>
|
||||
<?php echo html::select('plan', $allPlans, '', "class='form-control chosen' id='plan'");?>
|
||||
<?php $disabled = empty(array_filter($allPlans)) ? 'disabled' : ''?>
|
||||
<?php $allPlans = array_filter($allPlans);?>
|
||||
<?php $disabled = empty($allPlans) ? 'disabled' : ''?>
|
||||
<span class='input-group-btn'><?php echo html::commonButton($lang->execution->linkStory, "id='toTaskButton'", 'btn btn-primary ' . $disabled);?></span>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@@ -1464,10 +1464,9 @@ class productModel extends model
|
||||
/* Only show leaf executions. */
|
||||
$allExecutions = $this->dao->select('id,name,attribute,parent')->from(TABLE_EXECUTION)->where('type')->notin(array('program', 'project'))->fetchAll('id');
|
||||
$parents = array();
|
||||
foreach($allExecutions as $exec)
|
||||
{
|
||||
$parents[$exec->parent] = true;
|
||||
}
|
||||
foreach($allExecutions as $exec) $parents[$exec->parent] = true;
|
||||
|
||||
if($projectID) $executions = $this->loadModel('execution')->resetExecutionSorts($executions);
|
||||
|
||||
$executionPairs = array('0' => '');
|
||||
foreach($executions as $execID=> $execution)
|
||||
@@ -1535,6 +1534,7 @@ class productModel extends model
|
||||
}
|
||||
}
|
||||
|
||||
if($projectID) $executions = $this->loadModel('execution')->resetExecutionSorts($executions);
|
||||
foreach($executions as $execution)
|
||||
{
|
||||
if(isset($execution->children))
|
||||
|
||||
@@ -1109,7 +1109,7 @@ class productplanModel extends model
|
||||
foreach($planStory as $id => $story)
|
||||
{
|
||||
$projectBranches = zget($projectProducts, $story->product, array());
|
||||
if($story->status == 'active' or (!empty($story->branch) and !empty($projectBranches) and !isset($projectBranches[$story->branch])))
|
||||
if($story->status != 'active' or (!empty($story->branch) and !empty($projectBranches) and !isset($projectBranches[$story->branch])))
|
||||
{
|
||||
unset($planStory[$id]);
|
||||
continue;
|
||||
|
||||
@@ -82,7 +82,7 @@ $lang->programplan->delayList[0] = 'No';
|
||||
|
||||
$lang->programplan->typeList = array();
|
||||
$lang->programplan->typeList['stage'] = 'Stage';
|
||||
$lang->programplan->typeList['agileplus'] = 'Sprint/Kanban';
|
||||
$lang->programplan->typeList['agileplus'] = $lang->executionCommon . '/Kanban';
|
||||
|
||||
$lang->programplan->noData = 'No Data';
|
||||
$lang->programplan->children = 'Sub Plan';
|
||||
@@ -118,7 +118,7 @@ $lang->programplan->error->sameName = 'Stage name cannot be the same!';
|
||||
$lang->programplan->error->sameCode = 'Stage code cannot be the same!';
|
||||
$lang->programplan->error->taskDrag = 'The %s task cannot be dragged';
|
||||
$lang->programplan->error->planDrag = 'The %s stage cannot be dragged';
|
||||
$lang->programplan->error->notStage = 'Sprint/Kanban cannot create a sub stage.';
|
||||
$lang->programplan->error->notStage = $lang->executionCommon . '/Kanban cannot create a sub stage.';
|
||||
|
||||
$lang->programplan->ganttBrowseType['gantt'] = 'Group by Stage';
|
||||
$lang->programplan->ganttBrowseType['assignedTo'] = 'Group by AssignedTo';
|
||||
|
||||
@@ -82,7 +82,7 @@ $lang->programplan->delayList[0] = 'No';
|
||||
|
||||
$lang->programplan->typeList = array();
|
||||
$lang->programplan->typeList['stage'] = 'Stage';
|
||||
$lang->programplan->typeList['agileplus'] = 'Sprint/Kanban';
|
||||
$lang->programplan->typeList['agileplus'] = $lang->executionCommon . '/Kanban';
|
||||
|
||||
$lang->programplan->noData = 'No Data';
|
||||
$lang->programplan->children = 'Sub Plan';
|
||||
@@ -118,7 +118,7 @@ $lang->programplan->error->sameName = 'Stage name cannot be the same!';
|
||||
$lang->programplan->error->sameCode = 'Stage code cannot be the same!';
|
||||
$lang->programplan->error->taskDrag = 'The %s task cannot be dragged';
|
||||
$lang->programplan->error->planDrag = 'The %s stage cannot be dragged';
|
||||
$lang->programplan->error->notStage = 'Sprint/Kanban cannot create a sub stage.';
|
||||
$lang->programplan->error->notStage = $lang->executionCommon . '/Kanban cannot create a sub stage.';
|
||||
|
||||
$lang->programplan->ganttBrowseType['gantt'] = 'Group by Stage';
|
||||
$lang->programplan->ganttBrowseType['assignedTo'] = 'Group by AssignedTo';
|
||||
|
||||
@@ -82,7 +82,7 @@ $lang->programplan->delayList[0] = 'No';
|
||||
|
||||
$lang->programplan->typeList = array();
|
||||
$lang->programplan->typeList['stage'] = 'Stage';
|
||||
$lang->programplan->typeList['agileplus'] = 'Sprint/Kanban';
|
||||
$lang->programplan->typeList['agileplus'] = $lang->executionCommon . '/Kanban';
|
||||
|
||||
$lang->programplan->noData = 'No Data';
|
||||
$lang->programplan->children = 'Sub Plan';
|
||||
@@ -118,7 +118,7 @@ $lang->programplan->error->sameName = 'Stage name cannot be the same!';
|
||||
$lang->programplan->error->sameCode = 'Stage code cannot be the same!';
|
||||
$lang->programplan->error->taskDrag = 'The %s task cannot be dragged';
|
||||
$lang->programplan->error->planDrag = 'The %s stage cannot be dragged';
|
||||
$lang->programplan->error->notStage = 'Sprint/Kanban cannot create a sub stage.';
|
||||
$lang->programplan->error->notStage = $lang->executionCommon . '/Kanban cannot create a sub stage.';
|
||||
|
||||
$lang->programplan->ganttBrowseType['gantt'] = 'Group by Stage';
|
||||
$lang->programplan->ganttBrowseType['assignedTo'] = 'Group by AssignedTo';
|
||||
|
||||
@@ -82,7 +82,7 @@ $lang->programplan->delayList[0] = '否';
|
||||
|
||||
$lang->programplan->typeList = array();
|
||||
$lang->programplan->typeList['stage'] = '阶段';
|
||||
$lang->programplan->typeList['agileplus'] = '迭代/看板';
|
||||
$lang->programplan->typeList['agileplus'] = $lang->executionCommon . '/看板';
|
||||
|
||||
$lang->programplan->noData = '暂无数据。';
|
||||
$lang->programplan->children = '二级计划';
|
||||
@@ -118,7 +118,7 @@ $lang->programplan->error->sameName = '阶段名称不能相同!';
|
||||
$lang->programplan->error->sameCode = '阶段代号不能相同!';
|
||||
$lang->programplan->error->taskDrag = '%s的任务不可以拖动';
|
||||
$lang->programplan->error->planDrag = '%s的阶段不可以拖动';
|
||||
$lang->programplan->error->notStage = '迭代/看板不支持创建子阶段';
|
||||
$lang->programplan->error->notStage = $lang->executionCommon . '/看板不支持创建子阶段';
|
||||
|
||||
$lang->programplan->ganttBrowseType['gantt'] = '按阶段分组';
|
||||
$lang->programplan->ganttBrowseType['assignedTo'] = '按指派给分组';
|
||||
|
||||
@@ -53,10 +53,12 @@ class programplanModel extends model
|
||||
public function getStage($executionID = 0, $productID = 0, $browseType = 'all', $orderBy = 'id_asc')
|
||||
{
|
||||
if(empty($executionID)) return array();
|
||||
$projectModel = $this->dao->select('model')->from(TABLE_PROJECT)->where('id')->eq($executionID)->fetch('model');
|
||||
|
||||
$plans = $this->dao->select('t1.*')->from(TABLE_EXECUTION)->alias('t1')
|
||||
->leftJoin(TABLE_PROJECTPRODUCT)->alias('t2')->on('t1.id = t2.project')
|
||||
->where('t1.type')->eq('stage')
|
||||
->where('1 = 1')
|
||||
->beginIF($projectModel != 'waterfallplus')->andWhere('t1.type')->eq('stage')->fi()
|
||||
->beginIF($productID)->andWhere('t2.product')->eq($productID)->fi()
|
||||
->beginIF($browseType == 'all')->andWhere('t1.project')->eq($executionID)->fi()
|
||||
->beginIF($browseType == 'parent')->andWhere('t1.parent')->eq($executionID)->fi()
|
||||
@@ -749,7 +751,7 @@ class programplanModel extends model
|
||||
foreach($datas as $index => $plan)
|
||||
{
|
||||
if(!empty($sameNames) and in_array($plan->name, $sameNames)) dao::$errors[$index]['name'] = empty($type) ? $this->lang->programplan->error->sameName : str_replace($this->lang->execution->stage, '', $this->lang->programplan->error->sameName);
|
||||
if($setCode and $sameCodes !== true and !empty($sameCodes) and in_array($plan->code, $sameCodes)) dao::$errors[$index]['code'] = sprintf($this->lang->error->repeat, $this->lang->execution->code, $plan->code);
|
||||
if($setCode and $sameCodes !== true and !empty($sameCodes) and in_array($plan->code, $sameCodes)) dao::$errors[$index]['code'] = sprintf($this->lang->error->repeat, $plan->type == 'stage' ? $this->lang->execution->code : $this->lang->code, $plan->code);
|
||||
|
||||
if($plan->percent and !preg_match("/^[0-9]+(.[0-9]{1,3})?$/", $plan->percent))
|
||||
{
|
||||
@@ -778,7 +780,7 @@ class programplanModel extends model
|
||||
if(isset($parentStage) and ($plan->end > $parentStage->end || $plan->begin < $parentStage->begin))
|
||||
{
|
||||
if($plan->begin < $parentStage->begin and empty(dao::$errors[$index]['begin'])) dao::$errors[$index]['begin'] = $this->lang->programplan->error->parentDuration;
|
||||
if($plan->end < $parentStage->end and empty(dao::$errors[$index]['end'])) dao::$errors[$index]['end'] = $this->lang->programplan->error->parentDuration;
|
||||
if($plan->end > $parentStage->end and empty(dao::$errors[$index]['end'])) dao::$errors[$index]['end'] = $this->lang->programplan->error->parentDuration;
|
||||
}
|
||||
if($plan->begin < $project->begin and empty(dao::$errors[$index]['begin']))
|
||||
{
|
||||
@@ -793,7 +795,7 @@ class programplanModel extends model
|
||||
if(helper::isZeroDate($plan->end)) $plan->end = '';
|
||||
if($setCode and empty($plan->code))
|
||||
{
|
||||
dao::$errors[$index]['code'] = sprintf($this->lang->error->notempty, $this->lang->execution->code);
|
||||
dao::$errors[$index]['code'] = sprintf($this->lang->error->notempty, $plan->type == 'stage' ? $this->lang->execution->code : $this->lang->code);
|
||||
}
|
||||
foreach(explode(',', $this->config->programplan->create->requiredFields) as $field)
|
||||
{
|
||||
@@ -833,6 +835,22 @@ class programplanModel extends model
|
||||
}
|
||||
}
|
||||
|
||||
$linkProducts = array();
|
||||
$linkBranches = array();
|
||||
$productList = $this->loadModel('product')->getProducts($projectID);
|
||||
if($project->division)
|
||||
{
|
||||
$linkProducts = array(0 => $productID);
|
||||
$linkBranches = array(0 => $productList[$productID]->branches);
|
||||
}
|
||||
else
|
||||
{
|
||||
$linkProducts = array_keys($productList);
|
||||
foreach($linkProducts as $index => $productID) $linkBranches[$index] = $productList[$productID]->branches;
|
||||
}
|
||||
$this->post->set('products', $linkProducts);
|
||||
$this->post->set('branch', $linkBranches);
|
||||
|
||||
foreach($datas as $data)
|
||||
{
|
||||
/* Set planDuration and realDuration. */
|
||||
@@ -846,6 +864,7 @@ class programplanModel extends model
|
||||
$data->days = helper::diffDate($data->end, $data->begin) + 1;
|
||||
$data->order = current($orders);
|
||||
|
||||
|
||||
if($data->id)
|
||||
{
|
||||
$stageID = $data->id;
|
||||
@@ -985,22 +1004,6 @@ class programplanModel extends model
|
||||
$this->computeProgress($stageID, 'create');
|
||||
}
|
||||
}
|
||||
|
||||
$linkProducts = array();
|
||||
$linkBranches = array();
|
||||
$productList = $this->loadModel('product')->getProducts($projectID);
|
||||
if($project->division)
|
||||
{
|
||||
$linkProducts = array(0 => $productID);
|
||||
$linkBranches = array(0 => $productList[$productID]->branches);
|
||||
}
|
||||
else
|
||||
{
|
||||
$linkProducts = array_keys($productList);
|
||||
foreach($linkProducts as $index => $productID) $linkBranches[$index] = $productList[$productID]->branches;
|
||||
}
|
||||
$this->post->set('products', $linkProducts);
|
||||
$this->post->set('branch', $linkBranches);
|
||||
$this->execution->updateProducts($stageID);
|
||||
|
||||
/* If child plans has milestone, update parent plan set milestone eq 0 . */
|
||||
@@ -1346,15 +1349,15 @@ class programplanModel extends model
|
||||
public function checkCodeUnique($codes, $planIDList)
|
||||
{
|
||||
$codes = array_filter($codes);
|
||||
if(count(array_unique($codes)) != count($codes)) return false;
|
||||
|
||||
$code = $this->dao->select('code')->from(TABLE_EXECUTION)
|
||||
$sameCodes = $this->dao->select('code')->from(TABLE_EXECUTION)
|
||||
->where('type')->in('sprint,stage,kanban')
|
||||
->andWhere('deleted')->eq('0')
|
||||
->andWhere('code')->in($codes)
|
||||
->beginIF($planIDList)->andWhere('id')->notin($planIDList)->fi()
|
||||
->fetchPairs('code');
|
||||
return $code ? $code : true;
|
||||
if(count(array_unique($codes)) != count($codes)) $sameCodes += array_diff_assoc($codes, array_unique($codes));
|
||||
return $sameCodes ? $sameCodes : true;
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -140,7 +140,7 @@
|
||||
<?php $disabled = isset($plan->setMilestone) ? '' : "disabled='disabled'"?>
|
||||
<?php echo html::hidden("planIDList[$i]", $plan->id);?>
|
||||
<tr>
|
||||
<td class='<?php echo $typeClass;?>'><?php echo html::select("type[$i]", $lang->execution->typeList, $plan->type, "class='form-control chosen'");?></td>
|
||||
<td class='<?php echo $typeClass . ' text-center ' .zget($lang->execution->typeList, $plan->type);?>'><?php echo zget($lang->execution->typeList, $plan->type);?></td>
|
||||
<td><input type='text' name="names[<?php echo $i;?>]" id='names<?php echo $i;?>' value='<?php echo $plan->name;?>' class='form-control' /></td>
|
||||
<?php if(!isset($config->setCode) or $config->setCode == 1):?>
|
||||
<td><?php echo html::input("codes[$i]", $plan->code, "class='form-control'");?></td>
|
||||
|
||||
@@ -578,7 +578,6 @@ class project extends control
|
||||
$multiple = $copyProject->multiple;
|
||||
$hasProduct = $copyProject->hasProduct;
|
||||
$programID = $copyProject->parent;
|
||||
$model = $copyProject->model;
|
||||
$products = $this->product->getProducts($copyProjectID);
|
||||
|
||||
if(!$copyProject->hasProduct) $shadow = 1;
|
||||
@@ -1106,9 +1105,9 @@ class project extends control
|
||||
$changeStatusHtml = "<div class='btn-group dropup'>";
|
||||
$changeStatusHtml .= "<button data-toggle='dropdown' type='button' class='btn'>{$this->lang->statusAB} <span class='caret'></span></button>";
|
||||
$changeStatusHtml .= "<div class='dropdown-menu search-list'><div class='list-group'>";
|
||||
foreach($this->lang->execution->statusList as $status => $statusText)
|
||||
foreach($this->lang->execution->statusList as $statusAB => $statusText)
|
||||
{
|
||||
$actionLink = $this->createLink('execution', 'batchChangeStatus', "status=$status&projectID=$projectID");
|
||||
$actionLink = $this->createLink('execution', 'batchChangeStatus', "status=$statusAB&projectID=$projectID");
|
||||
$changeStatusHtml .= html::a('#', $statusText, '', "onclick=\"setFormAction('$actionLink', 'hiddenwin', '#executionForm')\" onmouseover=\"setBadgeStyle(this, true);\" onmouseout=\"setBadgeStyle(this, false)\"");
|
||||
}
|
||||
$changeStatusHtml .= "</div></div></div>";
|
||||
@@ -1313,6 +1312,7 @@ class project extends control
|
||||
* @param string|int $branch
|
||||
* @param string $browseType
|
||||
* @param int $param
|
||||
* @param string $caseType
|
||||
* @param string $orderBy
|
||||
* @param int $recTotal
|
||||
* @param int $recPerPage
|
||||
@@ -1320,7 +1320,7 @@ class project extends control
|
||||
* @access public
|
||||
* @return void
|
||||
*/
|
||||
public function testcase($projectID = 0, $productID = 0, $branch = 'all', $browseType = 'all', $param = 0, $orderBy = 'id_desc', $recTotal = 0, $recPerPage = 20, $pageID = 1)
|
||||
public function testcase($projectID = 0, $productID = 0, $branch = 'all', $browseType = 'all', $param = 0, $caseType = '', $orderBy = 'id_desc', $recTotal = 0, $recPerPage = 20, $pageID = 1)
|
||||
{
|
||||
$this->loadModel('product');
|
||||
$this->session->set('bugList', $this->app->getURI(true), 'project');
|
||||
@@ -1333,7 +1333,7 @@ class project extends control
|
||||
$hasProduct = $this->dao->findByID($projectID)->from(TABLE_PROJECT)->fetch('hasProduct');
|
||||
if($hasProduct) $this->lang->modulePageNav = $this->product->select($products, $productID, 'project', 'testcase', $extra, $branch);
|
||||
|
||||
echo $this->fetch('testcase', 'browse', "productID=$productID&branch=$branch&browseType=$browseType¶m=$param&caseType=&orderBy=$orderBy&recTotal=$orderBy&recPerPage=$recPerPage&pageID=$pageID&projectID=$projectID");
|
||||
echo $this->fetch('testcase', 'browse', "productID=$productID&branch=$branch&browseType=$browseType¶m=$param&caseType=&orderBy=$orderBy&recTotal=$recTotal&recPerPage=$recPerPage&pageID=$pageID&projectID=$projectID");
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -1090,12 +1090,15 @@ class projectModel extends model
|
||||
{
|
||||
if(defined('TUTORIAL')) return $this->loadModel('tutorial')->getProjectPairs();
|
||||
|
||||
if($model == 'agileplus') $model = array('scrum', 'agileplus');
|
||||
if($model == 'waterfallplus') $model = array('waterfall', 'waterfallplus');
|
||||
|
||||
$projects = $this->dao->select('id, name, path')->from(TABLE_PROJECT)
|
||||
->where('type')->eq('project')
|
||||
->andWhere('deleted')->eq('0')
|
||||
->beginIF($programID)->andWhere('parent')->eq($programID)->fi()
|
||||
->beginIF($this->config->vision)->andWhere('vision')->eq($this->config->vision)->fi()
|
||||
->beginIF($model != 'all')->andWhere('model')->eq($model)->fi()
|
||||
->beginIF($model != 'all')->andWhere('model')->in($model)->fi()
|
||||
->beginIF(strpos($param, 'noclosed') !== false)->andWhere('status')->ne('closed')->fi()
|
||||
->beginIF(strpos($param, 'multiple') !== false)->andWhere('multiple')->eq('1')->fi()
|
||||
->beginIF(!$this->app->user->admin)->andWhere('id')->in($this->app->user->view->projects)->fi()
|
||||
@@ -1236,7 +1239,7 @@ class projectModel extends model
|
||||
->setIF($this->post->delta == 999, 'days', 0)
|
||||
->setIF($this->post->acl == 'open', 'whitelist', '')
|
||||
->setIF(!isset($_POST['whitelist']), 'whitelist', '')
|
||||
->setDefault('multiple', '1')
|
||||
->setIF(!isset($_POST['multiple']), 'multiple', '1')
|
||||
->setDefault('openedBy', $this->app->user->account)
|
||||
->setDefault('openedDate', helper::now())
|
||||
->setDefault('team', $this->post->name)
|
||||
|
||||
@@ -48,7 +48,7 @@
|
||||
<h2><?php echo $createTitle;?></h2>
|
||||
<?php if(!commonModel::isTutorialMode()): ?>
|
||||
<div class="pull-right btn-toolbar">
|
||||
<?php if($config->edition != 'max' || $model == 'kanban'):?>
|
||||
<?php if($config->edition != 'max' or $model == 'kanban'):?>
|
||||
<button type='button' class='btn btn-link' data-toggle='modal' data-target='#copyProjectModal'><?php echo html::icon($lang->icons['copy'], 'muted') . ' ' . $lang->project->copy;?></button>
|
||||
<?php else: ?>
|
||||
<button type='button' class='btn btn-link open-btn' data-toggle='modal' data-target='#maxCopyProjectModal'><?php echo html::icon($lang->icons['copy'], 'muted') . ' ' . $lang->project->copy;?></button>
|
||||
|
||||
@@ -44,7 +44,7 @@
|
||||
<?php if(common::hasPriv('execution', 'task')) echo html::checkbox('showTask', array('1' => $lang->programplan->stageCustom->task), '', $this->cookie->showTask ? 'checked=checked' : '');?>
|
||||
</div>
|
||||
<div class='btn-toolbar pull-right'>
|
||||
<?php if($project->model == 'waterfall' and $this->config->edition == 'max'):?>
|
||||
<?php if(($project->model == 'waterfall' or $project->model == 'waterfallplus') and $this->config->edition == 'max'):?>
|
||||
<div class="btn-group">
|
||||
<?php echo html::a($this->createLink('programplan', 'browse', "projectID=$projectID&productID=$productID&type=gantt"), "<i class='icon-gantt-alt'></i> ", '', "class='btn btn-icon switchBtn' title='{$lang->programplan->gantt}'");?>
|
||||
<?php echo html::a('', "<i class='icon-list'></i> ", '', "class='btn btn-icon text-primary switchBtn' title='{$lang->project->bylist}'");?>
|
||||
|
||||
@@ -95,4 +95,9 @@ $(function()
|
||||
{
|
||||
$('#planIdBox .chosen-container').find('div').css('width', $('#planIdBox').width())
|
||||
});
|
||||
|
||||
$('#parent_chosen').click(function()
|
||||
{
|
||||
$('#parent_chosen').find('div').css('width', $('#parent_chosen').width())
|
||||
});
|
||||
})
|
||||
|
||||
+11
-1
@@ -311,6 +311,15 @@ class task extends control
|
||||
}
|
||||
}
|
||||
|
||||
$lifetimeList = array();
|
||||
$attributeList = array();
|
||||
$executionList = $this->execution->getByIdList(array_keys($executions));
|
||||
foreach($executionList as $id => $object)
|
||||
{
|
||||
$lifetimeList[$id] = $object->lifetime;
|
||||
$attributeList[$id] = $object->attribute;
|
||||
}
|
||||
|
||||
$testStoryIdList = $this->loadModel('story')->getTestStories(array_keys($stories), $execution->id);
|
||||
/* Stories that can be used to create test tasks. */
|
||||
$testStories = array();
|
||||
@@ -330,7 +339,8 @@ class task extends control
|
||||
$this->view->gobackLink = (isset($output['from']) and $output['from'] == 'global') ? $this->createLink('execution', 'task', "executionID=$executionID") : '';
|
||||
$this->view->execution = $execution;
|
||||
$this->view->executions = $executions;
|
||||
$this->view->lifetimeList = $this->execution->getLifetimeByIdList(array_keys($executions));
|
||||
$this->view->lifetimeList = $lifetimeList;
|
||||
$this->view->attributeList = $attributeList;
|
||||
$this->view->task = $task;
|
||||
$this->view->users = $users;
|
||||
$this->view->storyID = $storyID;
|
||||
|
||||
@@ -63,14 +63,16 @@ function showTeamMenu()
|
||||
function loadAll(executionID)
|
||||
{
|
||||
lifetime = lifetimeList[executionID];
|
||||
attribute = attributeList[executionID];
|
||||
var fieldList = showFields + ',';
|
||||
if(lifetime == 'ops')
|
||||
if(lifetime == 'ops' || attribute == 'request' || attribute == 'review')
|
||||
{
|
||||
$('.storyBox').addClass('hidden');
|
||||
$('.storyBox,#selectTestStoryBox,#testStoryBox').addClass('hidden');
|
||||
}
|
||||
else if(fieldList.indexOf('story') >= 0)
|
||||
{
|
||||
$('.storyBox').removeClass('hidden');
|
||||
$('.storyBox,#selectTestStoryBox').removeClass('hidden');
|
||||
if($('#selectTestStory').prop('checked')) $('#testStoryBox').removeClass('hidden');
|
||||
}
|
||||
|
||||
loadModuleMenu(executionID);
|
||||
@@ -504,9 +506,10 @@ $(document).ready(function()
|
||||
var value = $select.val();
|
||||
$selector.find('.pri-text').html('<span class="label-pri label-pri-' + value + '" title="' + value + '">' + value + '</span>');
|
||||
});
|
||||
|
||||
$('#type').change(function()
|
||||
{
|
||||
if(lifetime != 'ops')
|
||||
if(lifetime != 'ops' && attribute != 'request' && attribute != 'review')
|
||||
{
|
||||
$('#selectTestStoryBox').toggleClass('hidden', $(this).val() != 'test');
|
||||
toggleSelectTestStory();
|
||||
|
||||
@@ -4087,16 +4087,23 @@ class taskModel extends model
|
||||
$today = helper::today();
|
||||
$showmore = $showmore ? 'showmore' : '';
|
||||
$trAttrs = "data-id='t$task->id'";
|
||||
|
||||
/* Remove projectID in execution path. */
|
||||
$executionPath = $execution->path;
|
||||
$executionPath = trim($executionPath, ',');
|
||||
$executionPath = substr($executionPath, strpos($executionPath, ',') + 1);
|
||||
|
||||
if(!$isChild)
|
||||
{
|
||||
$path = $execution->grade == 2 ? "$execution->parent,$execution->id,t$task->id," : ",$execution->id,t$task->id,";
|
||||
|
||||
$path = ",{$executionPath},t{$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,t$task->id," : ",$execution->id,$task->parent,t$task->id,";
|
||||
$path = ",{$executionPath},{$task->parent},t{$task->id},";
|
||||
$trClass = 'is-nest-child no-nest';
|
||||
$trAttrs .= " data-nested='false' data-parent='t$task->parent' data-nest-parent='t$task->parent' data-nest-path='$path'";
|
||||
}
|
||||
|
||||
@@ -22,7 +22,9 @@
|
||||
<?php js::set('requiredFields', $config->task->create->requiredFields);?>
|
||||
<?php js::set('estimateNotEmpty', sprintf($lang->error->gt, $lang->task->estimate, '0'))?>
|
||||
<?php js::set('lifetime', $execution->lifetime);?>
|
||||
<?php js::set('attribute', $execution->attribute);?>
|
||||
<?php js::set('lifetimeList', $lifetimeList);?>
|
||||
<?php js::set('attributeList', $attributeList);?>
|
||||
<?php js::set('hasProduct', $execution->hasProduct);?>
|
||||
<?php
|
||||
$requiredFields = array();
|
||||
|
||||
@@ -2490,34 +2490,6 @@ class executionTest
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Test Get lifetime by id list.
|
||||
*
|
||||
* @param array $idList
|
||||
* @access public
|
||||
* @return void
|
||||
*/
|
||||
public function getLifetimeByIdListTest($idList = '')
|
||||
{
|
||||
$result = $this->executionModel->getLifetimeByIdList($idList);
|
||||
|
||||
if(dao::isError())
|
||||
{
|
||||
$error = dao::getError();
|
||||
return $error;
|
||||
}
|
||||
else
|
||||
{
|
||||
if(!$result) return 'empty';
|
||||
|
||||
foreach($result as $id => $lifetime)
|
||||
{
|
||||
if(!$lifetime) $result[$id] = 'emptyLifetime';
|
||||
}
|
||||
return $result;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Test Update user view of execution and it's product.
|
||||
*
|
||||
@@ -2834,4 +2806,44 @@ class executionTest
|
||||
->andWhere('date')->eq($date)
|
||||
->orderBy('date DESC, id asc')->fetchGroup('name', 'date');
|
||||
}
|
||||
|
||||
/**
|
||||
* Reset execution sorts.
|
||||
*
|
||||
* @param int $projectID
|
||||
* @param string $type noParent
|
||||
* @access public
|
||||
* @return string
|
||||
*/
|
||||
public function resetExecutionSortsTest($projectID, $type = '')
|
||||
{
|
||||
$executions = array();
|
||||
$executionIDList = '';
|
||||
$firstGradeExecutions = array();
|
||||
if($projectID)
|
||||
{
|
||||
$executions = $this->executionModel->dao->select('*')->from(TABLE_EXECUTION)
|
||||
->where('deleted')->eq(0)
|
||||
->andWhere('project')->eq($projectID)
|
||||
->andWhere('type')->in('sprint,stage,kanban')
|
||||
->orderBy('order_asc')
|
||||
->fetchAll('id');
|
||||
|
||||
if($type == 'hasParent')
|
||||
{
|
||||
foreach($executions as $execution)
|
||||
{
|
||||
if($execution->grade == 1) $firstGradeExecutions[$execution->id] = $execution->id;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
$executions = $this->executionModel->resetExecutionSorts($executions, $firstGradeExecutions);
|
||||
if(!empty($executions))
|
||||
{
|
||||
$executionIDList = array_keys($executions);
|
||||
$executionIDList = implode(',', $executionIDList);
|
||||
}
|
||||
return $executionIDList;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,34 +0,0 @@
|
||||
#!/usr/bin/env php
|
||||
<?php
|
||||
include dirname(dirname(dirname(__FILE__))) . '/lib/init.php';
|
||||
include dirname(dirname(dirname(__FILE__))) . '/class/execution.class.php';
|
||||
zdTable('user')->gen(5);
|
||||
su('admin');
|
||||
|
||||
$execution = zdTable('project');
|
||||
$execution->id->range('1-5');
|
||||
$execution->name->range('项目集1,项目1,迭代1,阶段1,看板1');
|
||||
$execution->type->range('program,project,sprint,stage,kanban');
|
||||
$execution->parent->range('0,1,2{3}');
|
||||
$execution->status->range('wait{3},suspended,closed,doing');
|
||||
$execution->openedBy->range('admin,user1');
|
||||
$execution->begin->range('20220112 000000:0')->type('timestamp')->format('YY/MM/DD');
|
||||
$execution->end->range('20220212 000000:0')->type('timestamp')->format('YY/MM/DD');
|
||||
$execution->gen(5);
|
||||
|
||||
/**
|
||||
|
||||
title=测试executionModel->getLifetimeByIdList();
|
||||
cid=1
|
||||
pid=1
|
||||
|
||||
查询执行3和4 lifetime >> emptyLifetime
|
||||
查询空执行 lifetime >> empty
|
||||
|
||||
*/
|
||||
|
||||
$executionIDList = array(3, 4);
|
||||
|
||||
$executionTester = new executionTest();
|
||||
r($executionTester->getLifetimeByIdListTest($executionIDList)) && p('3') && e('emptyLifetime'); // 查询执行3和4 lifetime
|
||||
r($executionTester->getLifetimeByIdListTest(array('0'))) && p('') && e('empty'); // 查询空执行 lifetime
|
||||
@@ -0,0 +1,41 @@
|
||||
#!/usr/bin/env php
|
||||
<?php
|
||||
include dirname(dirname(dirname(__FILE__))) . '/lib/init.php';
|
||||
include dirname(dirname(dirname(__FILE__))) . '/class/execution.class.php';
|
||||
zdTable('user')->gen(5);
|
||||
su('admin');
|
||||
|
||||
$execution = zdTable('project');
|
||||
$execution->id->range('1-8');
|
||||
$execution->name->range('项目集1,项目1,需求阶段1,测试阶段1,需求子阶段1,需求子阶段2,需求子阶段1的迭代1,需求子阶段1的看板1');
|
||||
$execution->model->range('[],waterfallplus,[]{6}');
|
||||
$execution->type->range('program,project,stage{4},sprint,kanban');
|
||||
$execution->project->range('0{2},2{6}');
|
||||
$execution->parent->range('0,1,2{2},3{2},5{2}');
|
||||
$execution->grade->range('1{4},2{2},3{2}');
|
||||
$execution->path->range('`,1,`,`,1,2,`,`,1,2,3`,`,1,2,4,`,`,1,2,3,5,`,`,1,2,3,6,`,`,1,2,3,5,7,`,`1,2,3,5,8,`');
|
||||
$execution->order->range('5,10,15,20,25,30,35,40');
|
||||
$execution->status->range('doing');
|
||||
$execution->openedBy->range('admin');
|
||||
$execution->begin->range('20220112 000000:0')->type('timestamp')->format('YY/MM/DD');
|
||||
$execution->end->range('20220212 000000:0')->type('timestamp')->format('YY/MM/DD');
|
||||
$execution->gen(8);
|
||||
|
||||
/**
|
||||
|
||||
title=测试executionModel->resetExecutionSorts();
|
||||
cid=1
|
||||
pid=1
|
||||
|
||||
检查没有执行时的排序 >> 0
|
||||
检查有执行时的排序 >> 3,5,7,8,6,4
|
||||
检查有执行并且传parenExecutions时的排序 >> 3,5,7,8,6,4
|
||||
|
||||
*/
|
||||
|
||||
$projectList = array(0, 2);
|
||||
|
||||
$executionTester = new executionTest();
|
||||
r($executionTester->resetExecutionSortsTest($projectList[0])) && p() && e('0'); // 检查没有执行时的排序
|
||||
r($executionTester->resetExecutionSortsTest($projectList[1])) && p() && e('3,5,7,8,6,4'); // 检查有执行时的排序
|
||||
r($executionTester->resetExecutionSortsTest($projectList[1], 'hasParent')) && p() && e('3,5,7,8,6,4'); // 检查有执行并且传parenExecutions时的排序
|
||||
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
Binary file not shown.
@@ -257,6 +257,8 @@
|
||||
<glyph unicode="" glyph-name="download-alt" d="M492.405 52.544l-301.796 312.266c-16.137 16.312-4.61 46.607 18.442 46.607h117.376c16.137 0 27.663 11.652 27.663 27.964v291.293c0 16.312 11.526 27.964 27.663 27.964h255.882c16.137 0 27.664-11.652 27.664-27.964v-291.293c0-16.312 11.526-27.964 27.662-27.964h117.373c25.364 0 36.888-30.295 18.448-46.607l-299.493-312.266c-9.221-9.322-27.663-9.322-36.884 0zM957.869-173.497h-894.048c-25.358 0-48.41 20.968-48.41 48.939 0 25.632 20.747 48.931 48.41 48.931h896.356c25.356 0 48.412-20.968 48.412-48.931-2.308-27.971-23.056-48.939-50.72-48.939z" />
|
||||
<glyph unicode="" glyph-name="horn" horiz-adv-x="1081" d="M938.869 410.376c-20.69 298.501-137.33 262.5-137.33 262.5s-156.752-183.9-521.866-200v-257.998c0 0 155.167-7.504 256.077-34.503 100.913-26.999 168.679-42.2 260.725-116.998 0 0 165.507 12.698 142.393 346.998zM139.918 468.476h99.75v-251.697h-99.75v251.697zM490.046 52.575c-39.056 44.703-50.984 102.303-50.984 102.303h-93.628c0-91.5 87.189-207.002 105.661-230.201s41.589-12.8 94.683 0c52.989 12.8 9.923 63.898 9.923 63.898s-26.6 19.302-65.655 64z" />
|
||||
<glyph unicode="" glyph-name="design" d="M1022.95 548.083l-255.488 255.488-255.486-255.488-255.489 255.488-255.488-255.488 255.488-255.489-255.488-255.486v-255.488h255.488l255.489 255.488 255.486-255.488 255.488 255.488-255.488 255.486 255.488 255.489zM262.888 375.603l108.544 108.608-44.672 44.736-108.609-108.608-38.336 38.336 115.009 114.881-51.136 44.799-108.545-115.007-44.8 44.672 166.144 166.079 210.689-210.688-166.016-166.080-38.272 38.272zM64.872-154.507v127.744l127.743-127.744h-127.743zM256.488-128.971l-166.080 166.080 677.119 677.119 166.016-166.144-677.055-677.055zM933.606 37.109l-166.144-166.080-44.672 44.736 114.944 114.944-44.736 44.736-114.944-115.008-38.334 38.336 115.006 114.944-51.136 44.8-114.942-115.008-38.401 38.272 166.143 166.078 217.216-210.75z" />
|
||||
<glyph unicode="" glyph-name="waterfallplus" horiz-adv-x="956" d="M477.827 706.371c226.214 0 409.599-183.384 409.599-409.6h68.267c0 263.919-213.948 477.867-477.865 477.867h-68.267v-136.534h68.267v68.267zM477.827-181.097c-240.74 0-439.902 178.019-473.027 409.601h69.090c32.5-193.722 200.98-341.335 403.937-341.335v68.267h68.267v-136.533h-68.267zM136.533 467.437h341.333v-68.267h-341.333v68.267zM546.133 399.171v136.533h-477.867v-204.8h409.6v-68.267h-68.267v-204.801h477.867v204.801h-341.333v136.533zM477.867 194.371h341.333v-68.267h-341.333v68.267z" />
|
||||
<glyph unicode="" glyph-name="agileplus" horiz-adv-x="956" d="M887.467 296.771c0 226.216-183.385 409.6-409.6 409.6v-68.267h-68.267v136.534h68.267c263.919 0 477.867-213.948 477.867-477.867h-68.267zM0 296.771c0-263.92 213.948-477.868 477.867-477.868h68.267v136.533h-68.267v-68.267c-226.216 0-409.6 183.385-409.6 409.601h-68.267zM204.8 91.969v68.268h273.067c75.405 0 136.533 61.128 136.533 136.533s-61.128 136.533-136.533 136.533c-75.405 0-136.533-61.128-136.533-136.533h-68.267c0 113.108 91.692 204.8 204.8 204.8s204.8-91.692 204.8-204.8c0-52.453-19.719-100.3-52.148-136.533h120.415v-68.268h-546.133z" />
|
||||
<glyph unicode="" glyph-name="file, file-empty" horiz-adv-x="878" d="M838.857 587.428c21.143-21.143 38.857-63.429 38.857-93.714v-658.286c0-30.286-24.571-54.857-54.857-54.857h-768c-30.286 0-54.857 24.571-54.857 54.857v914.286c0 30.286 24.571 54.857 54.857 54.857h512c30.286 0 72.571-17.714 93.714-38.857zM585.143 726.857v-214.857h214.857c-3.429 9.714-8.571 19.429-12.571 23.429l-178.857 178.857c-4 4-13.714 9.143-23.429 12.571zM804.571-146.286v585.143h-237.714c-30.286 0-54.857 24.571-54.857 54.857v237.714h-438.857v-877.714h731.429z" />
|
||||
<glyph unicode="" glyph-name="book" d="M948.764 510.653c13.529-19.482 17.318-44.918 9.741-69.81l-148.822-490.3c-13.529-45.999-61.152-81.716-107.693-81.716h-499.501c-55.199 0-114.186 43.835-134.21 100.116-8.658 24.352-8.658 48.165-1.083 68.728 1.083 10.823 3.248 21.647 3.789 34.635 0.541 8.658-4.329 15.694-3.248 22.188 2.165 12.988 13.529 22.188 22.188 36.799 16.235 27.058 34.635 70.893 40.587 99.033 2.706 10.281-2.706 22.188 0 31.388 2.706 10.281 12.988 17.859 18.401 27.6 14.612 24.894 33.554 73.058 36.259 98.493 1.083 11.364-4.329 23.811-1.083 32.471 3.789 12.447 15.694 17.859 23.811 28.682 12.988 17.859 34.635 69.269 37.881 97.952 1.083 9.199-4.329 18.401-2.706 28.14 2.165 10.281 15.153 21.106 23.811 33.554 22.728 33.554 27.058 107.693 95.787 88.211l-0.541-1.623c9.199 2.165 18.401 4.871 27.6 4.871h411.831c25.434 0 48.165-11.364 61.694-30.306 14.070-19.482 17.318-44.918 9.741-70.352l-148.281-490.3c-25.434-83.34-39.505-101.74-108.235-101.74h-470.277c-7.035 0-15.694-1.623-20.565-8.117-4.329-6.495-4.871-11.364-0.541-23.269 10.823-31.388 48.165-37.881 77.93-37.881h499.501c20.024 0 43.293 11.364 49.247 30.846l162.352 534.135c3.248 10.281 3.248 21.106 2.706 30.846 12.447-4.871 23.811-12.447 31.929-23.269zM372.959 509.57c-3.248-9.741 2.165-17.318 11.905-17.318h329.032c9.199 0 19.482 7.576 22.728 17.318l11.364 34.635c3.248 9.741-2.165 17.318-11.905 17.318h-329.032c-9.199 0-19.482-7.576-22.728-17.318zM328.043 371.031c-3.248-9.741 2.165-17.318 11.905-17.318h329.032c9.199 0 19.482 7.576 22.728 17.318l11.364 34.635c3.248 9.741-2.165 17.318-11.905 17.318h-329.032c-9.199 0-19.482-7.576-22.728-17.318z" />
|
||||
<glyph unicode="" glyph-name="share" d="M960.285 412.526c0-8.506-3.502-16.511-9.505-22.514l-256.163-256.163c-6.003-6.003-14.008-9.505-22.514-9.505-17.512 0-32.020 14.509-32.020 32.020v128.082h-112.072c-215.638 0-357.227-41.527-357.227-280.178 0-20.513 1.001-41.025 2.501-61.54 0.5-8.005 2.501-17.011 2.501-25.015 0-9.505-6.003-17.512-16.010-17.512-7.004 0-10.506 3.502-14.008 8.506-7.505 10.506-13.009 26.518-18.511 38.025-28.517 64.041-63.54 155.598-63.54 225.643 0 56.036 5.504 113.572 26.518 166.606 69.545 172.609 273.673 201.628 437.778 201.628h112.072v128.082c0 17.512 14.509 32.020 32.020 32.020 8.506 0 16.511-3.502 22.514-9.505l256.163-256.163c6.003-6.003 9.505-14.008 9.505-22.514z" />
|
||||
|
||||
|
Before Width: | Height: | Size: 267 KiB After Width: | Height: | Size: 268 KiB |
Binary file not shown.
Binary file not shown.
Reference in New Issue
Block a user