diff --git a/module/block/config.php b/module/block/config.php index cce425b4f7..f633f2f1a8 100644 --- a/module/block/config.php +++ b/module/block/config.php @@ -21,6 +21,7 @@ $config->block->moduleIndex['project'] = 'execution'; $config->block->longBlock = array(); $config->block->longBlock['']['flowchart'] = 'flowchart'; $config->block->longBlock['']['welcome'] = 'welcome'; +$config->block->longBlock['']['assigntome'] = 'assigntome'; $config->block->longBlock['product']['statistic'] = 'statistic'; $config->block->longBlock['execution']['statistic'] = 'statistic'; $config->block->longBlock['qa']['statistic'] = 'statistic'; diff --git a/module/block/control.php b/module/block/control.php index 9378ba0f6d..a442a81bab 100644 --- a/module/block/control.php +++ b/module/block/control.php @@ -1832,6 +1832,8 @@ class block extends control /* Get projects. */ $this->app->loadLang('task'); + $this->app->loadLang('program'); + $this->app->loadLang('execution'); $this->view->projects = $this->loadModel('project')->getOverviewList('byStatus', $status, $orderBy, $count); } diff --git a/module/block/js/dashboard.js b/module/block/js/dashboard.js index 71cfd9d810..b230dc7f5f 100644 --- a/module/block/js/dashboard.js +++ b/module/block/js/dashboard.js @@ -235,11 +235,31 @@ $(function() }); // Init dashboard + var sortMessager = new $.zui.Messager({close: false}); $('#dashboard').sortable( { selector: '.panel', trigger: '.panel-heading:not(.not-move-handler),.panel-move-handler', containerSelector: '.col-main,.col-side', + canMoveHere: function($ele, $target) + { + var fixedCol = $ele.data('fixed'); + if(fixedCol) + { + var $targetCol = $target.closest('.col-main,.col-side'); + var targetCol = $targetCol.hasClass('col-main') ? 'main' : 'side'; + if(targetCol !== fixedCol) + { + !sortMessager.isShow && sortMessager.show(fixedCol === 'main' ? config.cannotPlaceInRight : config.cannotPlaceInRight); + return false; + } + else + { + sortMessager.isShow && sortMessager.hide(); + } + return true; + } + }, start: function() { $('body').css('overflow', 'hidden'); @@ -259,7 +279,8 @@ $(function() }); e.element.toggleClass('block-sm', isSideCol); - } + }, + always: function(){sortMessager.isShow && sortMessager.hide();} }).on('click', '.refresh-panel', function() { refreshBlock($(this).closest('.panel')); diff --git a/module/block/lang/de.php b/module/block/lang/de.php index 7992ff1b06..24cc122e5b 100644 --- a/module/block/lang/de.php +++ b/module/block/lang/de.php @@ -93,6 +93,8 @@ $lang->block->refresh = 'Aktualisieren'; $lang->block->nbsp = ''; $lang->block->hidden = 'Verstecken'; $lang->block->dynamicInfo = "%s %s %s %s %s"; +$lang->block->cannotPlaceInLeft = 'Kann den Block nicht auf der linken Seite platzieren.'; +$lang->block->cannotPlaceInRight = 'Kann den Block nicht auf der rechten Seite platzieren.'; $lang->block->productName = $lang->productCommon . ' Name'; $lang->block->totalStory = 'The Total ' . $lang->SRCommon; diff --git a/module/block/lang/en.php b/module/block/lang/en.php index d3dc6dd148..f60c95a5cf 100644 --- a/module/block/lang/en.php +++ b/module/block/lang/en.php @@ -93,6 +93,8 @@ $lang->block->refresh = 'Refresh'; $lang->block->nbsp = ' '; $lang->block->hidden = 'Hide'; $lang->block->dynamicInfo = "%s %s %s %s %s"; +$lang->block->cannotPlaceInLeft = 'Cannot place the block at left side.'; +$lang->block->cannotPlaceInRight = 'Cannot place the block at right side.'; $lang->block->productName = $lang->productCommon . ' Name'; $lang->block->totalStory = 'The Total ' . $lang->SRCommon; diff --git a/module/block/lang/fr.php b/module/block/lang/fr.php index e8d6a3ef0b..f3fe6e569c 100644 --- a/module/block/lang/fr.php +++ b/module/block/lang/fr.php @@ -93,6 +93,8 @@ $lang->block->refresh = 'Rafraichir'; $lang->block->nbsp = ' '; $lang->block->hidden = 'Masquer'; $lang->block->dynamicInfo = "%s %s %s %s %s"; +$lang->block->cannotPlaceInLeft = 'Impossible de placer le bloc à gauche.'; +$lang->block->cannotPlaceInRight = 'Impossible de placer le bloc à droite.'; $lang->block->productName = $lang->productCommon . ' Name'; $lang->block->totalStory = 'The Total ' . $lang->SRCommon; diff --git a/module/block/lang/vi.php b/module/block/lang/vi.php index a2a8ffedcf..7d80c07ad3 100644 --- a/module/block/lang/vi.php +++ b/module/block/lang/vi.php @@ -93,6 +93,8 @@ $lang->block->refresh = 'Refresh'; $lang->block->nbsp = ' '; $lang->block->hidden = 'Ẩn'; $lang->block->dynamicInfo = "%s %s %s %s %s"; +$lang->block->cannotPlaceInLeft = 'Khối này không thể được đặt ở bên trái.'; +$lang->block->cannotPlaceInRight = 'Khối này không thể được đặt ở bên phải.'; $lang->block->productName = $lang->productCommon . ' Name'; $lang->block->totalStory = 'The Total ' . $lang->SRCommon; diff --git a/module/block/lang/zh-cn.php b/module/block/lang/zh-cn.php index f96eac4a08..c323af5727 100644 --- a/module/block/lang/zh-cn.php +++ b/module/block/lang/zh-cn.php @@ -93,6 +93,8 @@ $lang->block->refresh = '刷新'; $lang->block->nbsp = ''; $lang->block->hidden = '隐藏'; $lang->block->dynamicInfo = "%s %s %s %s %s"; +$lang->block->cannotPlaceInLeft = '此区块无法放置在左侧。'; +$lang->block->cannotPlaceInRight = '此区块无法放置在右侧。'; $lang->block->productName = $lang->productCommon . '名称'; $lang->block->totalStory = '总' . $lang->SRCommon; diff --git a/module/block/lang/zh-tw.php b/module/block/lang/zh-tw.php index 1f1fa7978d..d764317cd9 100644 --- a/module/block/lang/zh-tw.php +++ b/module/block/lang/zh-tw.php @@ -93,6 +93,8 @@ $lang->block->refresh = '刷新'; $lang->block->nbsp = ''; $lang->block->hidden = '隱藏'; $lang->block->dynamicInfo = "%s %s %s %s %s"; +$lang->block->cannotPlaceInLeft = '此區塊無法放置在左側。'; +$lang->block->cannotPlaceInRight = '此區塊無法放置在右側。'; $lang->block->productName = $lang->productCommon . '名稱'; $lang->block->totalStory = '總' . $lang->SRCommon; diff --git a/module/block/view/dashboard.html.php b/module/block/view/dashboard.html.php index 2603308dcb..ccca29da24 100644 --- a/module/block/view/dashboard.html.php +++ b/module/block/view/dashboard.html.php @@ -101,8 +101,11 @@ $useGuest = $this->app->user->account == 'guest'; diff --git a/module/custom/config.php b/module/custom/config.php index 4b000df4ce..29873486f9 100644 --- a/module/custom/config.php +++ b/module/custom/config.php @@ -53,7 +53,7 @@ $config->custom->fieldList['task']['edit'] = 'pri,estimate,estStarted, $config->custom->fieldList['task']['finish'] = 'comment'; $config->custom->fieldList['task']['activate'] = 'assignedTo,comment'; $config->custom->fieldList['build'] = 'scmPath,filePath,desc'; -$config->custom->fieldList['bug']['create'] = 'module,project,deadline,type,os,browser,severity,pri,steps,keywords'; +$config->custom->fieldList['bug']['create'] = 'module,deadline,type,os,browser,severity,pri,steps,keywords'; $config->custom->fieldList['bug']['edit'] = 'plan,assignedTo,deadline,type,os,browser,severity,pri,steps,keywords'; $config->custom->fieldList['bug']['resolve'] = 'resolvedBuild,resolvedDate,assignedTo,comment'; $config->custom->fieldList['testcase']['create'] = 'stage,story,pri,precondition,keywords'; diff --git a/module/execution/js/edit.js b/module/execution/js/edit.js index 3b1a920272..e17d014f62 100644 --- a/module/execution/js/edit.js +++ b/module/execution/js/edit.js @@ -19,4 +19,10 @@ $(function() $(this).siblings('div').find('span').attr('title', tip); } }); + + oldProject = $("#project").val(); + $('#project').change(function() + { + if(!confirm('修改所属项目后,执行关联的原项目需求如果要更改所属项目,需手动修改到新项目,是否继续修改?')) $("#project").val(oldProject).trigger("chosen:updated"); + }); }) diff --git a/module/product/control.php b/module/product/control.php index d99757534c..ea4efb0274 100644 --- a/module/product/control.php +++ b/module/product/control.php @@ -1261,6 +1261,22 @@ class product extends control $product->closedBugs = (int)$product->closedBugs; $product->bugFixedRate = (($product->unResolved + $product->fixedBugs) == 0 ? 0 : round($product->fixedBugs / ($product->unResolved + $product->fixedBugs), 3) * 100) . '%'; $product->program = $product->programName; + + /* get rowspan data */ + if($lastProgram == '' or $product->program != $lastProgram) + { + $rowspan[$i]['rows']['program'] = 1; + $programI = $i; + } + else $rowspan[$programI]['rows']['program']++; + if($lastLine == '' or $product->line != $lastLine) + { + $rowspan[$i]['rows']['line'] = 1; + $lineI = $i; + } + else $rowspan[$lineI]['rows']['line']++; + $lastProgram = $product->program; + $lastLine = $product->line; if($this->post->exportType == 'selected') { @@ -1270,6 +1286,7 @@ class product extends control } if(isset($this->config->bizVersion)) list($fields, $productStats) = $this->loadModel('workflowfield')->appendDataFromFlow($fields, $productStats); + if(isset($rowspan)) $this->post->set('rowspan', $rowspan); $this->post->set('fields', $fields); $this->post->set('rows', $productStats); $this->post->set('kind', 'product'); diff --git a/module/report/lang/de.php b/module/report/lang/de.php index c9719d9154..7caec42dfa 100644 --- a/module/report/lang/de.php +++ b/module/report/lang/de.php @@ -37,7 +37,7 @@ $lang->report->assign['assign'] = 'Zugeordnet'; $lang->report->singleColor[] = 'F6BD0F'; -$lang->report->projectDeviation = 'Projektabweichungsbericht'; +$lang->report->projectDeviation = "{$lang->execution->common}abweichungsbericht"; $lang->report->productSummary = $lang->productCommon . ' Zusammenfassung'; $lang->report->bugCreate = 'Bug gemeldet'; $lang->report->bugAssign = 'Bug zugeordnet'; @@ -56,7 +56,7 @@ $lang->reportList->product = new stdclass(); $lang->reportList->test = new stdclass(); $lang->reportList->staff = new stdclass(); -$lang->reportList->project->lists[10] = 'Durchgeführt Abweichnung|reportprojectdeviation'; +$lang->reportList->project->lists[10] = "{$lang->execution->common} Abweichnung|reportprojectdeviation"; $lang->reportList->product->lists[10] = $lang->productCommon . ' Zusammenfassung|report|productsummary'; $lang->reportList->test->lists[10] = 'Bugs gemeldet|report|bugcreate'; $lang->reportList->test->lists[13] = 'Bugs zugeordnet|report|bugassign'; diff --git a/module/report/lang/en.php b/module/report/lang/en.php index 1a73ab0066..8c9ea28fa9 100644 --- a/module/report/lang/en.php +++ b/module/report/lang/en.php @@ -37,7 +37,7 @@ $lang->report->assign['assign'] = 'Assigned'; $lang->report->singleColor[] = 'F6BD0F'; -$lang->report->projectDeviation = 'Project Deviation'; +$lang->report->projectDeviation = "{$lang->execution->common} Deviation"; $lang->report->productSummary = $lang->productCommon . ' Summary'; $lang->report->bugCreate = 'Bug Reported Summary'; $lang->report->bugAssign = 'Bug Assigned Summary'; @@ -56,7 +56,7 @@ $lang->reportList->product = new stdclass(); $lang->reportList->test = new stdclass(); $lang->reportList->staff = new stdclass(); -$lang->reportList->project->lists[10] = 'Execution Deviation|report|projectdeviation'; +$lang->reportList->project->lists[10] = "{$lang->execution->common} Deviation|report|projectdeviation"; $lang->reportList->product->lists[10] = $lang->productCommon . ' Summary|report|productsummary'; $lang->reportList->test->lists[10] = 'Bug Reported Summary|report|bugcreate'; $lang->reportList->test->lists[13] = 'Bug Assigned Summary|report|bugassign'; diff --git a/module/report/lang/fr.php b/module/report/lang/fr.php index 187aa4b7af..f7731d193b 100644 --- a/module/report/lang/fr.php +++ b/module/report/lang/fr.php @@ -37,7 +37,7 @@ $lang->report->assign['assign'] = 'Affecté'; $lang->report->singleColor[] = 'F6BD0F'; -$lang->report->projectDeviation = 'Rapport de déviation du projet'; +$lang->report->projectDeviation = "Rapport de déviation du{$lang->execution->common}"; $lang->report->productSummary = 'Résumé ' . $lang->productCommon; $lang->report->bugCreate = 'Résumé remontée Bugs'; $lang->report->bugAssign = 'Résumé affectation Bugs'; @@ -56,7 +56,7 @@ $lang->reportList->product = new stdclass(); $lang->reportList->test = new stdclass(); $lang->reportList->staff = new stdclass(); -$lang->reportList->project->lists[10] = 'Dériv Effectué|report|projectdeviation'; +$lang->reportList->project->lists[10] = "Dérv {$lang->execution->common}|report|projectdeviation"; $lang->reportList->product->lists[10] = 'Résumé ' . $lang->productCommon . '|report|productsummary'; $lang->reportList->test->lists[10] = 'Résumé remontée Bugs|report|bugcreate'; $lang->reportList->test->lists[13] = 'Résumé affectation Bugs|report|bugassign'; diff --git a/module/report/lang/zh-cn.php b/module/report/lang/zh-cn.php index 56d4bcf32d..24535ab660 100644 --- a/module/report/lang/zh-cn.php +++ b/module/report/lang/zh-cn.php @@ -37,7 +37,7 @@ $lang->report->assign['assign'] = '已指派'; $lang->report->singleColor[] = 'F6BD0F'; -$lang->report->projectDeviation = '项目偏差报表'; +$lang->report->projectDeviation = "{$lang->execution->common}偏差报表"; $lang->report->productSummary = $lang->productCommon . '汇总表'; $lang->report->bugCreate = 'Bug创建表'; $lang->report->bugAssign = 'Bug指派表'; @@ -56,7 +56,7 @@ $lang->reportList->product = new stdclass(); $lang->reportList->test = new stdclass(); $lang->reportList->staff = new stdclass(); -$lang->reportList->project->lists[10] = '项目偏差报表|report|projectdeviation'; +$lang->reportList->project->lists[10] = "{$lang->execution->common}偏差报表|report|projectdeviation"; $lang->reportList->product->lists[10] = $lang->productCommon . '汇总表|report|productsummary'; $lang->reportList->test->lists[10] = 'Bug创建表|report|bugcreate'; $lang->reportList->test->lists[13] = 'Bug指派表|report|bugassign'; diff --git a/module/story/model.php b/module/story/model.php index b3d8dbcaf9..848f0d7aa2 100644 --- a/module/story/model.php +++ b/module/story/model.php @@ -4005,9 +4005,25 @@ class storyModel extends model if(count($tracks) < $pager->recPerPage) { + /* Show of child story */ + $storiesCopy = array(); + foreach($stories as $id => $story) + { + $storiesCopy[$id] = $story; + if(isset($story->children) and count($story->children) > 0) + { + foreach($story->children as $childID => $children) + { + $storiesCopy[$childID] = $children; + } + } + } + $stories = $storiesCopy; + foreach($stories as $id => $story) { $stories[$id] = new stdclass(); + $stories[$id]->parent = $story->parent; $stories[$id]->title = $story->title; $stories[$id]->cases = $this->loadModel('testcase')->getStoryCases($id); $stories[$id]->bugs = $this->loadModel('bug')->getStoryBugs($id); diff --git a/module/story/view/track.html.php b/module/story/view/track.html.php index 7b4e2dbbc6..3429e5af0a 100644 --- a/module/story/view/track.html.php +++ b/module/story/view/track.html.php @@ -69,7 +69,10 @@ $story):?> ';?> - createLink($module, 'view', "storyID=$storyID"), $story->title, '',"title='$story->title' data-app='$openApp'");?> + + parent > 0):?>lang->story->childrenAB;?> + createLink($module, 'view', "storyID=$storyID"), $story->title, '',"title='$story->title' data-app='$openApp'");?> + tasks as $taskID => $task):?> createLink('task', 'view', "taskID=$taskID"), $task->name, '', "title='$task->name'") . '
';?> diff --git a/module/task/model.php b/module/task/model.php index db89381a78..a55e8124b4 100644 --- a/module/task/model.php +++ b/module/task/model.php @@ -169,11 +169,11 @@ class taskModel extends model $childTaskID = $this->dao->lastInsertID(); $this->action->create('task', $childTaskID, 'Opened'); } - } - $this->computeWorkingHours($taskID); - $this->computeBeginAndEnd($taskID); - $this->dao->update(TABLE_TASK)->set('parent')->eq(-1)->where('id')->eq($taskID)->exec(); + $this->computeWorkingHours($taskID); + $this->computeBeginAndEnd($taskID); + $this->dao->update(TABLE_TASK)->set('parent')->eq(-1)->where('id')->eq($taskID)->exec(); + } } $this->file->updateObjectID($this->post->uid, $taskID, 'task'); if(!empty($taskFiles)) diff --git a/module/testtask/view/groupcase.html.php b/module/testtask/view/groupcase.html.php index 978aa62f55..b5af67b4ab 100644 --- a/module/testtask/view/groupcase.html.php +++ b/module/testtask/view/groupcase.html.php @@ -65,7 +65,7 @@ ?> case);?> pri;?>' title='testcase->priList, $run->pri, $run->pri);?>'>testcase->priList, $run->pri, $run->pri);?> - case", $run->title)) echo $run->title;?> + case&version=$run->version&from=testtask&taskID=$run->task", $run->title)) echo $run->title;?> testcase->typeList, $run->type, '');?> assignedTo);?> lastRunner);?> diff --git a/module/upgrade/control.php b/module/upgrade/control.php index bab1934572..92134bff08 100644 --- a/module/upgrade/control.php +++ b/module/upgrade/control.php @@ -582,6 +582,8 @@ class upgrade extends control $products = $this->dao->select('id, name')->from(TABLE_PRODUCT)->where('deleted')->eq(0)->fetchPairs(); if(empty($repos) or empty($products)) { + $this->dao->delete()->from(TABLE_BLOCK)->exec(); + $this->dao->delete()->from(TABLE_CONFIG)->where('`key`')->eq('blockInited')->exec(); $this->loadModel('setting')->deleteItems('owner=system&module=common§ion=global&key=upgradeStep'); die(js::locate($this->createLink('upgrade', 'afterExec', "fromVersion=&processed=no"))); } diff --git a/module/upgrade/model.php b/module/upgrade/model.php index cea6fb429d..420225e28f 100644 --- a/module/upgrade/model.php +++ b/module/upgrade/model.php @@ -696,6 +696,11 @@ class upgradeModel extends model $this->processProductDoc(); $this->adjustPriv15_3(); $this->appendExec('15_2'); + case '15_3': + $this->saveLogs('Execute 15_3'); + $this->execSQL($this->getUpgradeFile('15.3')); + $this->adjustBugRequired(); + $this->appendExec('15_3'); } $this->deletePatch(); @@ -5199,4 +5204,24 @@ class upgradeModel extends model } return true; } + + /** + * Required to adjust the bug. + * + * @access public + * @return void + */ + public function adjustBugRequired() + { + $data = $this->dao->select('*')->from(TABLE_CONFIG) + ->where('owner')->eq('system') + ->andWhere('module')->eq('bug') + ->andWhere('section')->eq('create') + ->andWhere('`key`')->eq('requiredFields') + ->fetch(); + + $data->value = ',' . $data->value . ','; + $data->value = str_replace(',project,', ',', $data->value); + $this->dao->update(TABLE_CONFIG)->set('value')->eq(trim($data->value, ','))->where('id')->eq($data->id)->exec(); + } } diff --git a/module/user/model.php b/module/user/model.php index 9a46f5c0e6..b2b69e53d2 100644 --- a/module/user/model.php +++ b/module/user/model.php @@ -1614,6 +1614,10 @@ class userModel extends model while($stakeholder = $stmt->fetch()) $stakeholders[$stakeholder->objectID][$stakeholder->user] = $stakeholder->user; } + /* Compute parent stakeholders. */ + $programStakeholderGroup = $this->loadModel('stakeholder')->getParentStakeholderGroup(array_keys($allPrograms)); + $projectStakeholderGroup = $this->loadModel('stakeholder')->getParentStakeholderGroup(array_keys($allProjects)); + list($productTeams, $productStakeholders) = $this->getProductMembers($allProducts); /* Init user view. */ @@ -1637,7 +1641,9 @@ class userModel extends model $programs = array(); foreach($allPrograms as $id => $program) { - if($this->checkProgramPriv($program, $account, zget($stakeholders, $id, array()), zget($whiteList, $id, array()))) $programs[$id] = $id; + $programStakeholders = zget($stakeholders, $id, array()); + if($program->acl == 'program') $programStakeholders += zget($programStakeholderGroup, $id, array()); + if($this->checkProgramPriv($program, $account, $programStakeholders, zget($whiteList, $id, array()))) $programs[$id] = $id; } $userView->programs = join(',', $programs); @@ -1655,6 +1661,7 @@ class userModel extends model { $projectTeams = zget($teams, $id, array()); $projectStakeholders = zget($stakeholders, $id, array()); + if($project->acl == 'program') $projectStakeholders += zget($projectStakeholderGroup, $id, array()); if($this->checkProjectPriv($project, $account, $projectStakeholders, $projectTeams, zget($whiteList, $id, array()))) $projects[$id] = $id; } $userView->projects = join(',', $projects);