Merge branch 'sprint/244' into sprint/244_wangzemei_70009
This commit is contained in:
+13
-7
@@ -97,6 +97,7 @@ $filter->mail->batchdelete = new stdclass();
|
||||
$filter->misc->checkupdate = new stdclass();
|
||||
$filter->file->download = new stdclass();
|
||||
$filter->product->browse = new stdclass();
|
||||
$filter->product->all = new stdclass();
|
||||
$filter->product->default = new stdclass();
|
||||
$filter->product->index = new stdclass();
|
||||
$filter->product->export = new stdclass();
|
||||
@@ -108,6 +109,7 @@ $filter->program->default = new stdclass();
|
||||
$filter->program->pgmproject = new stdclass();
|
||||
$filter->program->prjbrowse = new stdclass();
|
||||
$filter->program->project = new stdclass();
|
||||
$filter->program->product = new stdclass();
|
||||
$filter->program->browse = new stdclass();
|
||||
$filter->program->export = new stdclass();
|
||||
$filter->program->pgmbrowse = new stdclass();
|
||||
@@ -236,6 +238,7 @@ $filter->product->browse->cookie['productStoryOrder'] = 'reg::orderBy';
|
||||
$filter->product->browse->cookie['storyModule'] = 'int';
|
||||
$filter->product->browse->cookie['storyBranch'] = 'int';
|
||||
$filter->product->browse->cookie['treeBranch'] = 'reg::word';
|
||||
$filter->product->all->cookie['showProductBatchEdit'] = 'int';
|
||||
$filter->product->default->cookie['lastProduct'] = 'int';
|
||||
$filter->product->default->cookie['preProductID'] = 'int';
|
||||
$filter->product->index->cookie['preBranch'] = 'reg::word';
|
||||
@@ -247,19 +250,22 @@ $filter->product->dynamic->cookie['preBranch'] = 'reg::word';
|
||||
|
||||
$filter->branch->default->cookie['preBranch'] = 'reg::word';
|
||||
|
||||
$filter->program->default->cookie['lastPGM'] = 'int';
|
||||
$filter->program->default->cookie['lastPRJ'] = 'int';
|
||||
$filter->program->prjbrowse->cookie['programType'] = 'code';
|
||||
$filter->program->project->cookie['involved'] = 'code';
|
||||
$filter->program->browse->cookie['showClosed'] = 'code';
|
||||
$filter->program->export->cookie['checkedItem'] = 'reg::checked';
|
||||
$filter->program->ajaxgetdropmenu->cookie['showClosed'] = 'code';
|
||||
$filter->program->default->cookie['lastPGM'] = 'int';
|
||||
$filter->program->default->cookie['lastPRJ'] = 'int';
|
||||
$filter->program->prjbrowse->cookie['programType'] = 'code';
|
||||
$filter->program->project->cookie['involved'] = 'code';
|
||||
$filter->program->project->cookie['showProjectBatchEdit'] = 'int';
|
||||
$filter->program->product->cookie['showProductBatchEdit'] = 'int';
|
||||
$filter->program->browse->cookie['showClosed'] = 'code';
|
||||
$filter->program->export->cookie['checkedItem'] = 'reg::checked';
|
||||
$filter->program->ajaxgetdropmenu->cookie['showClosed'] = 'code';
|
||||
|
||||
$filter->project->default->cookie['lastProject'] = 'int';
|
||||
$filter->project->default->cookie['lastPRJ'] = 'int';
|
||||
$filter->project->default->cookie['projectMode'] = 'code';
|
||||
$filter->project->default->cookie['kanbanview'] = 'code';
|
||||
$filter->project->browse->cookie['involved'] = 'code';
|
||||
$filter->project->browse->cookie['showProjectBatchEdit'] = 'int';
|
||||
$filter->project->export->cookie['involved'] = 'code';
|
||||
$filter->project->browse->cookie['projectType'] = 'code';
|
||||
$filter->project->story->cookie['storyModuleParam'] = 'int';
|
||||
|
||||
@@ -18,6 +18,7 @@ body {margin-bottom: 25px;}
|
||||
#mainMenu .btn-toolbar .btn-group .dropdown-menu .btn-active-text:hover .text:after {border-bottom: unset;}
|
||||
.body-modal #mainMenu>.btn-toolbar {width: auto;}
|
||||
.assignedTo{border-radius: 4px !important;}
|
||||
#productStoryForm table tbody tr td.c-actions .dividing-line {width: 1px; height: 16px; display: inline-block; vertical-align: middle; background: #F4F5F7; margin: 0 4px 0 0;}
|
||||
</style>
|
||||
<?php js::set('browseType', $browseType);?>
|
||||
<?php js::set('productID', $productID);?>
|
||||
|
||||
@@ -300,11 +300,11 @@ $config->bug->datatable->fieldList['openedBuild']['required'] = 'no';
|
||||
$config->bug->datatable->fieldList['openedBuild']['control'] = 'multiple';
|
||||
$config->bug->datatable->fieldList['openedBuild']['dataSource'] = array('module' => 'build', 'method' =>'getBuildPairs', 'params' => '$productID&$branch&noempty,noterminate,nodone,withbranch');
|
||||
|
||||
$config->bug->datatable->fieldList['assignedTo']['title'] = 'assignedToAB';
|
||||
$config->bug->datatable->fieldList['assignedTo']['fixed'] = 'no';
|
||||
$config->bug->datatable->fieldList['assignedTo']['width'] = '120';
|
||||
$config->bug->datatable->fieldList['assignedTo']['required'] = 'no';
|
||||
$config->bug->datatable->fieldList['assignedTo']['dataSource'] = array('module' => 'bug', 'method' =>'getProductMemberPairs', 'params' => '$productID&$branch');
|
||||
$config->bug->datatable->fieldList['assignedTo']['title'] = 'assignedToAB';
|
||||
$config->bug->datatable->fieldList['assignedTo']['fixed'] = 'no';
|
||||
$config->bug->datatable->fieldList['assignedTo']['width'] = '120';
|
||||
$config->bug->datatable->fieldList['assignedTo']['required'] = 'no';
|
||||
$config->bug->datatable->fieldList['assignedTo']['dataSource'] = array('module' => 'user', 'method' =>'getPairs', 'params' => 'noclosed|noletter');
|
||||
|
||||
$config->bug->datatable->fieldList['assignedDate']['title'] = 'assignedDate';
|
||||
$config->bug->datatable->fieldList['assignedDate']['fixed'] = 'no';
|
||||
|
||||
@@ -2149,6 +2149,8 @@ EOD;
|
||||
{
|
||||
if(strpos($orderBy, 'priOrder') !== false) $select .= ", IF(`pri` = 0, {$this->config->maxPriValue}, `pri`) as priOrder";
|
||||
if(strpos($orderBy, 'severityOrder') !== false) $select .= ", IF(`severity` = 0, {$this->config->maxPriValue}, `severity`) as severityOrder";
|
||||
$queryCondition = str_replace('t4.status', 'status', $queryCondition);
|
||||
|
||||
$sql = $this->dao->select("*$select")->from($table)
|
||||
->where($queryCondition)
|
||||
->beginIF($orderBy != false)->orderBy($orderBy)->fi()
|
||||
|
||||
@@ -50,7 +50,7 @@
|
||||
?>
|
||||
</nobr>
|
||||
</td>
|
||||
<td class='w-300px'>
|
||||
<td class='w-500px'>
|
||||
<?php
|
||||
$maxOrder = 0;
|
||||
foreach($sons as $sonDept)
|
||||
@@ -174,39 +174,37 @@ $(function()
|
||||
e.stopPropagation();
|
||||
});
|
||||
|
||||
$("#dataForm").submit(function(e)
|
||||
|
||||
$("input[name*='depts']").change(function ()
|
||||
{
|
||||
var postDept = new Array();
|
||||
var depts = new Array();
|
||||
var depts = new Array();
|
||||
var modifyData = $(this).val();
|
||||
var changedInput = $(this);
|
||||
|
||||
$.each($('input[name*="depts[]"]'), function(index, value)
|
||||
{
|
||||
if($(this).val()) postDept.push($(this).val());
|
||||
});
|
||||
changedInput.wrap('<span>');
|
||||
changedInput.closest('span').addClass('dataField');
|
||||
|
||||
$.each($('input[name*="depts[id"]'), function(index, value)
|
||||
$('input[name^="depts"]').not($(this)).each(function()
|
||||
{
|
||||
if($(this).val()) depts.push($(this).val());
|
||||
});
|
||||
|
||||
for(var i = 0; i < postDept.length; i++)
|
||||
if(depts.indexOf(modifyData) > -1)
|
||||
{
|
||||
if(depts.indexOf(postDept[i]) > -1 || postDept[i] == postDept[i + 1])
|
||||
{
|
||||
if(confirm(repeatDepart))
|
||||
{
|
||||
var link = createLink('dept', 'manageChild');
|
||||
break;
|
||||
}
|
||||
else
|
||||
{
|
||||
setTimeout(function()
|
||||
{
|
||||
$('#submit').removeAttr('disabled');
|
||||
},10)
|
||||
return false;
|
||||
}
|
||||
}
|
||||
$('.dataField #depts\\[\\]').addClass('intro');
|
||||
$('.intro').css({"margin" : "5px 0px 5px 0px", "display" : "inline", "width" : "50%"});
|
||||
changedInput.after('<span style="padding-left: 15px;color: #1183fb" class="tips">' + repeatDepart + '</span>');
|
||||
}
|
||||
});
|
||||
|
||||
$("input[name*='depts']").focus(function ()
|
||||
{
|
||||
if($('.dataField').length)
|
||||
{
|
||||
$('.intro').removeAttr('style');
|
||||
$('.intro').unwrap();
|
||||
$('#depts\\[\\]').removeClass('intro');
|
||||
$('.tips').remove();
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
@@ -629,6 +629,18 @@ class doc extends control
|
||||
if($this->config->systemMode == 'classic' and $objectType == 'project') $objectType = 'execution';
|
||||
$this->doc->delete(TABLE_DOC, $docID);
|
||||
|
||||
/* Delete doc files. */
|
||||
$this->loadModel('file');
|
||||
foreach($doc->files as $fileID => $file)
|
||||
{
|
||||
$file = $this->file->getById($fileID);
|
||||
$this->dao->delete()->from(TABLE_FILE)->where('id')->eq($fileID)->exec();
|
||||
$this->loadModel('action')->create($file->objectType, $file->objectID, 'deletedFile', '', $extra=$file->title);
|
||||
|
||||
$fileRecord = $this->dao->select('id')->from(TABLE_FILE)->where('pathname')->eq($file->pathname)->fetch();
|
||||
if(empty($fileRecord)) @unlink($file->realPath);
|
||||
}
|
||||
|
||||
/* if ajax request, send result. */
|
||||
if($this->server->ajax)
|
||||
{
|
||||
|
||||
@@ -62,7 +62,7 @@ $(function()
|
||||
|
||||
if($(".createCustomLib").length == 1) $(".createCustomLib").click(); // Fix bug #15139.
|
||||
|
||||
if(!fromGlobal && textType.indexOf(docType) != -1)
|
||||
if(!fromGlobal && textType.indexOf(docType) != -1 && from == 'doc')
|
||||
{
|
||||
var basicInfo = JSON.parse(sessionStorage.getItem('docBasicInfo'));
|
||||
|
||||
|
||||
@@ -10,6 +10,7 @@
|
||||
* @link http://www.zentao.net
|
||||
*/
|
||||
?>
|
||||
<?php js::set('from', $from);?>
|
||||
<?php if(strpos($config->doc->textTypes, $docType) !== false and $from == 'doc'):?>
|
||||
<?php include 'createtexttype.html.php';?>
|
||||
<?php else:?>
|
||||
|
||||
@@ -20,3 +20,4 @@ th.c-pri{width:50px;}
|
||||
.switchBtn {background-color: #fff !important;}
|
||||
.switchBtn > i {padding-left: 7px;}
|
||||
#main>.container {padding: 0 20px 20px 23px;}
|
||||
#executionStoryForm table tbody tr td.c-actions .dividing-line {width: 1px; height: 16px; display: inline-block; vertical-align: middle; background: #F4F5F7; margin: 0 4px 0 0;}
|
||||
|
||||
@@ -467,7 +467,7 @@ $lang->execution->kanban = "Kanban";
|
||||
$lang->execution->kanbanSetting = "Kanban Einstellung";
|
||||
$lang->execution->setKanban = "Kanban Einstellung";
|
||||
$lang->execution->resetKanban = "Einstellungen zurücksetzen";
|
||||
$lang->execution->printKanban = "Kanban drucken";
|
||||
$lang->execution->printKanban = "drucken Kanban";
|
||||
$lang->execution->fullScreen = "Full Screen";
|
||||
$lang->execution->bugList = "Bugs";
|
||||
|
||||
@@ -487,7 +487,7 @@ $lang->kanbanSetting->optionList['0'] = 'Verstecken';
|
||||
$lang->kanbanSetting->optionList['1'] = 'Anzeigen';
|
||||
|
||||
$lang->printKanban = new stdclass();
|
||||
$lang->printKanban->common = 'Kanban drucken';
|
||||
$lang->printKanban->common = 'drucken Kanban';
|
||||
$lang->printKanban->content = 'Inhanlt';
|
||||
$lang->printKanban->print = 'Drucken';
|
||||
|
||||
|
||||
@@ -467,7 +467,7 @@ $lang->execution->kanban = "Kanban";
|
||||
$lang->execution->kanbanSetting = "Settings";
|
||||
$lang->execution->setKanban = "Set Kanban";
|
||||
$lang->execution->resetKanban = "Reset";
|
||||
$lang->execution->printKanban = "Print";
|
||||
$lang->execution->printKanban = "Print Kanban";
|
||||
$lang->execution->fullScreen = "Full Screen";
|
||||
$lang->execution->bugList = "Bugs";
|
||||
|
||||
|
||||
@@ -467,7 +467,7 @@ $lang->execution->kanban = "Kanban";
|
||||
$lang->execution->kanbanSetting = "Paramétrage";
|
||||
$lang->execution->setKanban = "Paramétrage";
|
||||
$lang->execution->resetKanban = "Réinitialiser";
|
||||
$lang->execution->printKanban = "Impression";
|
||||
$lang->execution->printKanban = "Imprimer Kanban";
|
||||
$lang->execution->fullScreen = "Full Screen";
|
||||
$lang->execution->bugList = "Bugs";
|
||||
|
||||
|
||||
@@ -487,7 +487,7 @@ $lang->kanbanSetting->optionList['0'] = '隐藏';
|
||||
$lang->kanbanSetting->optionList['1'] = '显示';
|
||||
|
||||
$lang->printKanban = new stdclass();
|
||||
$lang->printKanban->common = '看板打印';
|
||||
$lang->printKanban->common = '打印看板';
|
||||
$lang->printKanban->content = '内容';
|
||||
$lang->printKanban->print = '打印';
|
||||
|
||||
|
||||
@@ -410,7 +410,7 @@ $lang->kanbanSetting->optionList['0'] = '隱藏';
|
||||
$lang->kanbanSetting->optionList['1'] = '顯示';
|
||||
|
||||
$lang->printKanban = new stdclass();
|
||||
$lang->printKanban->common = '看板打印';
|
||||
$lang->printKanban->common = '打印看板';
|
||||
$lang->printKanban->content = '內容';
|
||||
$lang->printKanban->print = '打印';
|
||||
|
||||
|
||||
@@ -185,3 +185,4 @@
|
||||
.region.active.notAll {margin-top: -5px;}
|
||||
.region.active.notAll .region-header {display: none;}
|
||||
.region.active.notAll .kanban, .region.active.notAll .kanban .kanban-header {background-color: #efefef;}
|
||||
.kanban-card a[disabled] {color: #313c52;}
|
||||
|
||||
@@ -1507,6 +1507,7 @@ $(function()
|
||||
$(window).on('resize', function(a)
|
||||
{
|
||||
adjustAddBtnPosition();
|
||||
initRegionTabs();
|
||||
});
|
||||
|
||||
resetLaneHeight();
|
||||
@@ -1558,8 +1559,6 @@ $(function()
|
||||
|
||||
distance = 0;
|
||||
radiusWidth = 10;
|
||||
$(window).on('resize', initRegionTabs);
|
||||
initRegionTabs();
|
||||
|
||||
$('.leftBtn').click(function()
|
||||
{
|
||||
|
||||
+13
-2
@@ -686,7 +686,7 @@ class mrModel extends model
|
||||
}
|
||||
|
||||
$mergeResult = json_decode(commonModel::http($url, $MRObject));
|
||||
if(isset($mergeResult->number)) $mergeResult->iid = $host->type == 'gitea' ? $mergeResult->number : $mergeResult->id;
|
||||
if(isset($mergeResult->number)) $mergeResult->iid = $mergeResult->number;
|
||||
if(isset($mergeResult->mergeable))
|
||||
{
|
||||
if($mergeResult->mergeable) $mergeResult->merge_status = 'can_be_merged';
|
||||
@@ -867,7 +867,16 @@ class mrModel extends model
|
||||
*/
|
||||
public function apiGetMRCommits($hostID, $projectID, $MRID)
|
||||
{
|
||||
$url = sprintf($this->gitlab->getApiRoot($hostID), "/projects/$projectID/merge_requests/$MRID/commits");
|
||||
$host = $this->loadModel('pipeline')->getByID($hostID);
|
||||
if($host->type == 'gitlab')
|
||||
{
|
||||
$url = sprintf($this->gitlab->getApiRoot($hostID), "/projects/$projectID/merge_requests/$MRID/commits");
|
||||
}
|
||||
else
|
||||
{
|
||||
$url = sprintf($this->loadModel($host->type)->getApiRoot($hostID), "/repos/$projectID/pulls/$MRID/commits");
|
||||
}
|
||||
|
||||
return json_decode(commonModel::http($url));
|
||||
}
|
||||
|
||||
@@ -1797,6 +1806,8 @@ class mrModel extends model
|
||||
|
||||
/* Get commits by MR. */
|
||||
$commits = $this->apiGetMRCommits($MR->hostID, $MR->targetProject, $MR->mriid);
|
||||
if(empty($commits)) return true;
|
||||
|
||||
foreach($commits as $commit)
|
||||
{
|
||||
$objects = $this->repo->parseComment($commit->message);
|
||||
|
||||
@@ -8,3 +8,4 @@
|
||||
.dropdown-list > li > a:focus {color: #1a4f85; text-decoration: none; background-color: #ddd;}
|
||||
|
||||
.btn-toolbar .nav-title {float: left; display: inline-block; padding: 6px 12px; margin-bottom: 0; font-size: 13px; font-weight: bolder; line-height: 18px; text-align: center; white-space: nowrap; vertical-align: middle;}
|
||||
#myStoryForm table tbody tr td.c-actions .dividing-line {width: 1px; height: 16px; display: inline-block; vertical-align: middle; background: #F4F5F7; margin: 0 4px 0 0;}
|
||||
|
||||
@@ -10,3 +10,4 @@
|
||||
.table td.c-hours {padding-right: 12px;}
|
||||
.main-table tbody > tr.table-children > td:first-child::before {width: 3px;}
|
||||
@-moz-document url-prefix() {.main-table tbody > tr.table-children > td:first-child::before {width: 4px;};}
|
||||
.c-actions-6 {width: 185px;}
|
||||
|
||||
@@ -51,12 +51,7 @@
|
||||
<tr>
|
||||
<td class='c-id'><?php printf('%03d', $project->id);?></td>
|
||||
<td class='c-name text-left' title='<?php echo $project->name?>'>
|
||||
<?php
|
||||
if($project->model === 'waterfall') echo "<span class='project-type-label label label-outline label-warning'>{$lang->project->waterfall}</span> ";
|
||||
if($project->model === 'scrum') echo "<span class='project-type-label label label-outline label-info'>{$lang->project->scrum}</span> ";
|
||||
if($project->model === 'kanban') echo "<span class='project-type-label label label-outline label-info'>{$lang->project->kanban}</span> ";
|
||||
echo html::a($this->createLink('project', 'index', "projectID=$project->id", '', '', $project->id), $project->name, '', "data-group='project'");
|
||||
?>
|
||||
<?php echo html::a($this->createLink('project', 'index', "projectID=$project->id", '', '', $project->id), $project->name, '', "data-group='project' title='{$project->name} ({$this->lang->project->{$project->model}})'");?>
|
||||
</td>
|
||||
<?php if($status == 'openedbyme'):?>
|
||||
<td class='c-status'><span class="status-project status-<?php echo $project->status?>"><?php echo zget($lang->project->statusList, $project->status, '');?></span></td>
|
||||
|
||||
@@ -114,8 +114,21 @@
|
||||
echo common::buildIconButton('story', 'review', "$vars&from=product&storyType=requirement", $story, 'list', 'search', '', 'iframe', true);
|
||||
}
|
||||
echo common::buildIconButton('story', 'recall', "$vars&from=list&storyType=requirement", $story, 'list', 'undo', 'hiddenwin', '', '', '', $lang->story->recall);
|
||||
echo common::buildIconButton('story', 'close', "$vars&from=&storyType=requirement", $story, 'list', '', '', 'iframe', true);
|
||||
echo common::buildIconButton('story', 'edit', "$vars&from=default&storyType=requirement", $story, 'list', '', '', 'iframe', true, "data-width='95%'");
|
||||
|
||||
$storyType = 'storyType=requirement';
|
||||
$canChange = common::hasPriv('story', 'change', '', $storyType);
|
||||
$canSubmitReview = (strpos('draft,changing', $story->status) !== false and common::hasPriv('story', 'submitReview', '', $storyType));
|
||||
$canReview = (strpos('draft,changing', $story->status) === false and common::hasPriv('story', 'review', '', $storyType));
|
||||
$canRecall = common::hasPriv('story', 'recall', '', $storyType);
|
||||
$canEdit = common::hasPriv('story', 'edit', '', $storyType);
|
||||
$canClose = common::hasPriv('story', 'close', '', $storyType);
|
||||
if(($canChange or $canSubmitReview or $canReview or $canRecall or $canEdit) and $canClose)
|
||||
{
|
||||
echo "<div class='dividing-line'></div>";
|
||||
}
|
||||
|
||||
echo common::buildIconButton('story', 'close', "$vars&from=&storyType=requirement", $story, 'list', '', '', 'iframe', true);
|
||||
}
|
||||
?>
|
||||
</td>
|
||||
@@ -163,8 +176,19 @@
|
||||
}
|
||||
|
||||
common::printIcon('story', 'recall', "$vars&from=list&storyType=story", $child, 'list', 'undo', 'hiddenwin', '', '', '', $lang->story->recall);
|
||||
common::printIcon('story', 'close', "$vars&from=&storyType=story", $child, 'list', '', '', 'iframe', true);
|
||||
common::printIcon('story', 'edit', "$vars&from=default&storyType=story", $child, 'list');
|
||||
$storyType = 'storyType=story';
|
||||
$canChange = common::hasPriv('story', 'change', '', $storyType);
|
||||
$canSubmitReview = (strpos('draft,changing', $child->status) !== false and common::hasPriv('story', 'submitReview', '', $storyType));
|
||||
$canReview = (strpos('draft,draft', $child->status) === false and common::hasPriv('story', 'review', '', $storyType));
|
||||
$canRecall = common::hasPriv('story', 'recall', '', $storyType);
|
||||
$canEdit = common::hasPriv('story', 'edit', '', $storyType);
|
||||
$canClose = common::hasPriv('story', 'close', '', $storyType);
|
||||
if(($canChange or $canSubmitReview or $canReview or $canRecall or $canEdit) and $canClose)
|
||||
{
|
||||
echo "<div class='dividing-line'></div>";
|
||||
}
|
||||
common::printIcon('story', 'close', "$vars&from=&storyType=story", $child, 'list', '', '', 'iframe', true);
|
||||
}
|
||||
}
|
||||
?>
|
||||
|
||||
@@ -50,6 +50,11 @@
|
||||
$canBatchReview = common::hasPriv('story', 'batchReview');
|
||||
$canBatchAssignTo = common::hasPriv('story', 'batchAssignTo');
|
||||
$canBatchAction = ($canBatchEdit or $canBatchClose or $canBatchReview or $canBatchAssignTo);
|
||||
$canChange = common::hasPriv('story', 'change');
|
||||
$canRecall = common::hasPriv('story', 'recall');
|
||||
$canEdit = common::hasPriv('story', 'edit');
|
||||
$canCreateCase = common::hasPriv('testcase', 'create');
|
||||
$canClose = common::hasPriv('story', 'close');
|
||||
?>
|
||||
<thead>
|
||||
<tr>
|
||||
@@ -116,9 +121,21 @@
|
||||
}
|
||||
|
||||
echo common::buildIconButton('story', 'recall', $vars, $story, 'list', 'undo', 'hiddenwin', '', '', '', $lang->story->recall);
|
||||
echo common::buildIconButton('story', 'close', $vars, $story, 'list', '', '', 'iframe', true);
|
||||
echo common::buildIconButton('story', 'edit', $vars, $story, 'list', '', '', 'iframe', true, "data-width='95%'");
|
||||
echo common::buildIconButton('story', 'createCase', "productID=$story->product&branch=$story->branch&module=0&from=¶m=0&$vars", $story, 'list', 'sitemap', '', 'iframe', true, "data-width='95%'");
|
||||
|
||||
$canSubmitReview = (strpos('draft,changing', $story->status) !== false and common::hasPriv('story', 'submitReview'));
|
||||
$canReview = (strpos('draft,changing', $story->status) === false and common::hasPriv('story', 'review'));
|
||||
|
||||
if(($canChange or $canSubmitReview or $canReview or $canRecall or $canEdit) and ($canCreateCase or $canClose))
|
||||
{
|
||||
echo "<div class='dividing-line'></div>";
|
||||
}
|
||||
|
||||
echo common::buildIconButton('testcase', 'create', "productID=$story->product&branch=$story->branch&module=0&from=¶m=0&$vars", $story, 'list', 'sitemap', '', 'iframe', true, "data-width='95%'");
|
||||
|
||||
if($canCreateCase and $canClose) echo "<div class='dividing-line'></div>";
|
||||
|
||||
echo common::buildIconButton('story', 'close', $vars, $story, 'list', '', '', 'iframe', true);
|
||||
}
|
||||
?>
|
||||
</td>
|
||||
@@ -165,9 +182,21 @@
|
||||
common::printIcon('story', 'review', $vars, $child, 'list', 'search', '', 'iframe', true);
|
||||
}
|
||||
common::printIcon('story', 'recall', $vars, $child, 'list', 'undo', 'hiddenwin', '', '', '', $lang->story->recall);
|
||||
common::printIcon('story', 'close', $vars, $child, 'list', '', '', 'iframe', true);
|
||||
common::printIcon('story', 'edit', $vars, $child, 'list', '', '', 'iframe', true, "data-width='95%'");
|
||||
common::printIcon('story', 'createCase', "productID=$child->product&branch=$child->branch&module=0&from=¶m=0&$vars", $child, 'list', 'sitemap', '', 'iframe', true, "data-width='95%'");
|
||||
|
||||
$canSubmitReview = (strpos('draft,changing', $child->status) !== false and common::hasPriv('story', 'submitReview'));
|
||||
$canReview = (strpos('draft,changing', $child->status) === false and common::hasPriv('story', 'review'));
|
||||
|
||||
if(($canChange or $canSubmitReview or $canReview or $canRecall or $canEdit) and ($canCreateCase or $canClose))
|
||||
{
|
||||
echo "<div class='dividing-line'></div>";
|
||||
}
|
||||
|
||||
common::printIcon('testcase', 'create', "productID=$child->product&branch=$child->branch&module=0&from=¶m=0&$vars", $child, 'list', 'sitemap', '', 'iframe', true, "data-width='95%'");
|
||||
|
||||
if($canCreateCase and $canClose) echo "<div class='dividing-line'></div>";
|
||||
|
||||
common::printIcon('story', 'close', $vars, $child, 'list', '', '', 'iframe', true);
|
||||
}
|
||||
?>
|
||||
</td>
|
||||
|
||||
@@ -1292,6 +1292,7 @@ class product extends control
|
||||
$this->view->orderBy = $orderBy;
|
||||
$this->view->browseType = $browseType;
|
||||
$this->view->pager = $pager;
|
||||
$this->view->showBatchEdit = $this->cookie->showProductBatchEdit;
|
||||
|
||||
$this->display();
|
||||
}
|
||||
|
||||
@@ -40,13 +40,12 @@
|
||||
th.c-name {width: 400px;}
|
||||
th.c-PO {width: 100px;}
|
||||
th.c-story {width: 290px;}
|
||||
th.c-bug {width: 200px;}
|
||||
th.c-bug {width: 150px;}
|
||||
th.c-plan {width: 45px;}
|
||||
th.c-release {width: 50px;}
|
||||
th.c-actions {width: 50px;}
|
||||
[lang='en'] .en-wrap-text {white-space: normal; height: 24px; line-height: 1; font-size: 12px;}
|
||||
|
||||
|
||||
#productListForm thead>tr>th,
|
||||
#productListForm tbody>tr>td {text-align: center; text-overflow: unset!important}
|
||||
#productListForm thead>tr>th {padding: 0; line-height: 24px;}
|
||||
@@ -86,9 +85,11 @@ th.c-actions {width: 50px;}
|
||||
[lang^='zh-'] th.c-story {width: 220px;}
|
||||
}
|
||||
|
||||
#productTableList .c-name > span.table-nest-icon {width: 0; visibility: hidden;}
|
||||
#productTableList > tr.row-line.is-nest-child > td.text-left.table-nest-title > span.table-nest-icon.icon:before{content: '\e6f2'; background-color: white; display: inline;}
|
||||
#productTableList > tr.row-line.no-nest > td.text-left.table-nest-title > span.table-nest-icon.icon:before{content: '\e6f2'; background-color: white; display: inline;}
|
||||
.statistic {margin-left: 10px; color: #838a9d; float: left; position: relative; line-height: 28px;}
|
||||
.table-footer.fixed-footer .statistic {color: #fff;}
|
||||
#productTableList .c-manager {padding-left: 14px;}
|
||||
#productTableList .c-manager a {top: 7px; left: 22px;}
|
||||
.checkbox-primary {margin-right: 10px;}
|
||||
|
||||
@@ -1,6 +1,13 @@
|
||||
$("#" + browseType + "Tab").addClass('btn-active-text');
|
||||
$(function()
|
||||
{
|
||||
$('input[name^="showEdit"]').click(function()
|
||||
{
|
||||
$.cookie('showProductBatchEdit', $(this).is(':checked') ? 1 : 0, {expires: config.cookieLife, path: config.webRoot});
|
||||
setCheckbox();
|
||||
});
|
||||
setCheckbox();
|
||||
|
||||
/* Init table sort. */
|
||||
$('#productTableList').addClass('sortable').sortable(
|
||||
{
|
||||
@@ -36,6 +43,23 @@ $(function()
|
||||
}
|
||||
});
|
||||
|
||||
/**
|
||||
* Set batch edit checkbox.
|
||||
*
|
||||
* @access public
|
||||
* @return void
|
||||
*/
|
||||
function setCheckbox()
|
||||
{
|
||||
$('#productListForm .c-checkbox, #productListForm .check-all').hide();
|
||||
$('.c-name').css('border-left', 'none');
|
||||
if($.cookie('showProductBatchEdit') == 1)
|
||||
{
|
||||
$('#productListForm .c-checkbox, #productListForm .check-all').show();
|
||||
$('.c-name').css('border-left', '1px solid #ddd');
|
||||
}
|
||||
}
|
||||
|
||||
/* Update parent checkbox */
|
||||
function updatePrarentCheckbox($parent)
|
||||
{
|
||||
@@ -69,17 +93,21 @@ $(function()
|
||||
function addStatistic()
|
||||
{
|
||||
var checkedLength = $(":checkbox[name^='productIDList']:checked").length;
|
||||
var summary = checkedProducts.replace('%s', checkedLength);
|
||||
if(cilentLang == "en" && checkedLength < 2) summary = summary.replace('products', 'product');
|
||||
var statistic = "<div id='productsSummary' class='statistic'>" + summary + "</div>";
|
||||
|
||||
if(checkedLength > 0)
|
||||
{
|
||||
var summary = checkedProducts.replace('%s', checkedLength);
|
||||
if(cilentLang == "en" && checkedLength < 2) summary = summary.replace('products', 'product');
|
||||
|
||||
var statistic = "<div id='productsSummary' class='statistic'>" + summary + "</div>";
|
||||
$('#productsCount').hide();
|
||||
$('#productsSummary').remove();
|
||||
$('#editBtn').after(statistic);
|
||||
$('.table-actions').show();
|
||||
}
|
||||
else
|
||||
{
|
||||
$('.table-actions').hide();
|
||||
$('#productsCount').show();
|
||||
$('#productsSummary').addClass('hidden');
|
||||
}
|
||||
}
|
||||
|
||||
@@ -37,6 +37,8 @@ $lang->product->addWhitelist = 'Add Whitelist';
|
||||
$lang->product->unbindWhitelist = 'Remove Whitelist';
|
||||
$lang->product->track = 'View Stories Matrix';
|
||||
$lang->product->checkedProducts = '%s products selected';
|
||||
$lang->product->pageSummary = 'Total products: %s.';
|
||||
$lang->product->lineSummary = 'Total product lines: %s, Total products: %s.';
|
||||
|
||||
$lang->product->indexAction = "All {$lang->productCommon}";
|
||||
$lang->product->closeAction = "Close {$lang->productCommon}";
|
||||
|
||||
@@ -37,6 +37,8 @@ $lang->product->addWhitelist = 'Add Whitelist';
|
||||
$lang->product->unbindWhitelist = 'Unbind Whitelist';
|
||||
$lang->product->track = 'View Stories Matrix';
|
||||
$lang->product->checkedProducts = '%s products selected';
|
||||
$lang->product->pageSummary = 'Total products: %s.';
|
||||
$lang->product->lineSummary = 'Total product lines: %s, Total products: %s.';
|
||||
|
||||
$lang->product->indexAction = "All {$lang->productCommon}";
|
||||
$lang->product->closeAction = "Close {$lang->productCommon}";
|
||||
|
||||
@@ -37,6 +37,8 @@ $lang->product->addWhitelist = 'Add Whitelist';
|
||||
$lang->product->unbindWhitelist = 'Remove Whitelist';
|
||||
$lang->product->track = 'Consulter Stories Matrice';
|
||||
$lang->product->checkedProducts = '%s produits s électionnés';
|
||||
$lang->product->pageSummary = 'Total products: %s.';
|
||||
$lang->product->lineSummary = 'Total product lines: %s, Total products: %s.';
|
||||
|
||||
$lang->product->indexAction = "All {$lang->productCommon}";
|
||||
$lang->product->closeAction = "Fermer {$lang->productCommon}";
|
||||
|
||||
@@ -37,6 +37,8 @@ $lang->product->addWhitelist = '添加白名单';
|
||||
$lang->product->unbindWhitelist = '移除白名单';
|
||||
$lang->product->track = "查看需求矩阵";
|
||||
$lang->product->checkedProducts = '已选择%s项产品';
|
||||
$lang->product->pageSummary = '本页共%s个产品。';
|
||||
$lang->product->lineSummary = '本页共%s个产品线,%s个产品。';
|
||||
|
||||
$lang->product->indexAction = "所有{$lang->productCommon}仪表盘";
|
||||
$lang->product->closeAction = "关闭{$lang->productCommon}";
|
||||
|
||||
@@ -11,13 +11,16 @@
|
||||
?>
|
||||
<?php include '../../common/view/header.html.php';?>
|
||||
<?php include '../../common/view/sortable.html.php';?>
|
||||
<?php js::set('productLines', $productLines); ?>
|
||||
<?php $canBatchEdit = common::hasPriv('product', 'batchEdit'); ?>
|
||||
<div id="mainMenu" class="clearfix">
|
||||
<div class="btn-toolbar pull-left">
|
||||
<div class="btn-toolBar pull-left">
|
||||
<?php common::sortFeatureMenu();?>
|
||||
<?php foreach($lang->product->featureBar['all'] as $key => $label):?>
|
||||
<?php $recTotalLabel = $browseType == $key ? " <span class='label label-light label-badge'>{$recTotal}</span>" : '';?>
|
||||
<?php echo html::a(inlink("all", "browseType=$key&orderBy=$orderBy"), "<span class='text'>{$label}</span>" . $recTotalLabel, '', "class='btn btn-link' id='{$key}Tab'");?>
|
||||
<?php endforeach;?>
|
||||
<?php if($canBatchEdit) echo html::checkbox('showEdit', array('1' => $lang->product->edit), $showBatchEdit);?>
|
||||
<a class="btn btn-link querybox-toggle" id='bysearchTab'><i class="icon icon-search muted"></i> <?php echo $lang->product->searchStory;?></a>
|
||||
</div>
|
||||
<div class="btn-toolbar pull-right">
|
||||
@@ -36,7 +39,6 @@
|
||||
<div class="main-col">
|
||||
<div class="cell<?php if($browseType == 'bySearch') echo ' show';?>" id="queryBox" data-module='product'></div>
|
||||
<form class="main-table table-product" data-ride="table" data-nested='true' id="productListForm" method="post" action='<?php echo inLink('batchEdit', '');?>' data-preserve-nested='true' data-expand-nest-child='true'>
|
||||
<?php $canBatchEdit = common::hasPriv('product', 'batchEdit'); ?>
|
||||
<table id="productList" class="table has-sort-head table-nested table-fixed">
|
||||
<?php $vars = "browseType=$browseType&orderBy=%s";?>
|
||||
<thead>
|
||||
@@ -54,7 +56,7 @@
|
||||
<?php common::printOrderLink('PO', $orderBy, $vars, $lang->product->manager);?>
|
||||
</th>
|
||||
<th class="c-story" colspan="5"><?php echo $lang->story->story;?></th>
|
||||
<th class="c-bug" colspan="3"><?php echo $lang->bug->common;?></th>
|
||||
<th class="c-bug" colspan="2"><?php echo $lang->bug->common;?></th>
|
||||
<th class="c-plan" rowspan="2"><?php echo $lang->product->plan;?></th>
|
||||
<th class="c-release" rowspan="2"><?php echo $lang->product->release;?></th>
|
||||
<?php
|
||||
@@ -70,7 +72,6 @@
|
||||
<th><?php echo $lang->story->statusList['reviewing'];?></th>
|
||||
<th><div class='en-wrap-text'><?php echo $lang->story->completeRate;?></div></th>
|
||||
<th style="border-left: 1px solid #ddd;"><?php echo $lang->bug->activate;?></th>
|
||||
<th><?php echo $lang->close;?></th>
|
||||
<th><?php echo $lang->bug->fixedRate;?></th>
|
||||
</tr>
|
||||
</thead>
|
||||
@@ -124,7 +125,6 @@
|
||||
<td><?php echo $program['reviewingStories'];?></td>
|
||||
<td><?php echo $program['totalStories'] == 0 ? 0 : round($program['closedStories'] / $program['totalStories'], 3) * 100;?>%</td>
|
||||
<td><?php echo $program['unResolvedBugs'];?></td>
|
||||
<td><?php echo $program['closedBugs'];?></td>
|
||||
<td><?php echo ($program['unResolvedBugs'] + $program['fixedBugs']) == 0 ? 0 : round($program['fixedBugs'] / ($program['unResolvedBugs'] + $program['fixedBugs']), 3) * 100;?>%</td>
|
||||
<td><?php echo $program['plans'];?></td>
|
||||
<td><?php echo $program['releases'];?></td>
|
||||
@@ -165,7 +165,6 @@
|
||||
<td><?php echo isset($line['reviewingStories']) ? $line['reviewingStories'] : 0;?></td>
|
||||
<td><?php echo (isset($line['totalStories']) and $line['totalStories'] != 0) ? round($line['closedStories'] / $line['totalStories'], 3) * 100 : 0;?>%</td>
|
||||
<td><?php echo isset($line['unResolvedBugs']) ? $line['unResolvedBugs'] : 0;?></td>
|
||||
<td><?php echo isset($line['closedBugs']) ? $line['closedBugs'] : 0;?></td>
|
||||
<td><?php echo (isset($line['fixedBugs']) and ($line['unResolvedBugs'] + $line['fixedBugs'] != 0)) ? round($line['fixedBugs'] / ($line['unResolvedBugs'] + $line['fixedBugs']), 3) * 100 : 0;?>%</td>
|
||||
<td><?php echo isset($line['plans']) ? $line['plans'] : 0;?></td>
|
||||
<td><?php echo isset($line['releases']) ? $line['releases'] : 0;?></td>
|
||||
@@ -208,8 +207,7 @@
|
||||
<?php endif;?>
|
||||
<td class="c-name text-left sort-handler table-nest-title" title='<?php echo $product->name?>'>
|
||||
<?php
|
||||
$productLink = html::a($this->createLink('product', 'browse', 'productID=' . $product->id), $product->name);
|
||||
echo "<span class='table-nest-icon icon icon-product'></span>" . $productLink;
|
||||
echo html::a($this->createLink('product', 'browse', 'productID=' . $product->id), $product->name);
|
||||
?>
|
||||
</td>
|
||||
<td class='c-manager'>
|
||||
@@ -230,7 +228,6 @@
|
||||
<td><?php echo $product->stories['reviewing'];?></td>
|
||||
<td><?php echo $totalStories == 0 ? 0 : round($product->stories['closed'] / $totalStories, 3) * 100;?>%</td>
|
||||
<td><?php echo $product->unResolved;?></td>
|
||||
<td><?php echo $product->closedBugs;?></td>
|
||||
<td><?php echo ($product->unResolved + $product->fixedBugs) == 0 ? 0 : round($product->fixedBugs / ($product->unResolved + $product->fixedBugs), 3) * 100;?>%</td>
|
||||
<td><?php echo $product->plans;?></td>
|
||||
<td><?php echo $product->releases;?></td>
|
||||
@@ -247,13 +244,17 @@
|
||||
<?php echo $pager->show('left', 'pagerjs');?>
|
||||
<?php if(!empty($product) and $canBatchEdit):?>
|
||||
<div class="checkbox-primary check-all"><label><?php echo $lang->selectAll?></label></div>
|
||||
<?php
|
||||
$summary = empty($productLines) ? sprintf($lang->product->pageSummary, count($productStats)) : sprintf($lang->product->lineSummary, count($lineNames), count($productStats));
|
||||
echo "<div id='productsCount' class='statistic'>$summary</div>";
|
||||
?>
|
||||
<div class="table-actions btn-toolbar">
|
||||
<?php
|
||||
$actionLink = $this->createLink('product', 'batchEdit');
|
||||
echo html::commonButton($lang->edit, "id='editBtn' data-form-action='$actionLink'");
|
||||
?>
|
||||
<?php endif;?>
|
||||
</div>
|
||||
<?php endif;?>
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
||||
|
||||
@@ -43,7 +43,7 @@ $projectIDParam = $isProjectStory ? "projectID=$projectID&" : '';
|
||||
.btn-group button.dropdown-toggle.btn-secondary, .btn-group button.dropdown-toggle.btn-primary {padding:6px;}
|
||||
|
||||
#productStoryForm table tbody tr td.c-actions {overflow: visible;}
|
||||
#productStoryForm table tbody tr td.c-actions .dividing-line {width: 1px; height: 16px; display: inline-block; vertical-align: middle; background: #E4E4E4; margin: 0 4px 0 0;}
|
||||
#productStoryForm table tbody tr td.c-actions .dividing-line {width: 1px; height: 16px; display: inline-block; vertical-align: middle; background: #F4F5F7; margin: 0 4px 0 0;}
|
||||
</style>
|
||||
<div id="mainMenu" class="clearfix">
|
||||
<?php if(!$isProjectStory):?>
|
||||
@@ -347,11 +347,11 @@ $projectIDParam = $isProjectStory ? "projectID=$projectID&" : '';
|
||||
{
|
||||
if($value->id == 'title' || $value->id == 'id' || $value->id == 'pri' || $value->id == 'status')
|
||||
{
|
||||
$this->story->printCell($value, $story, $users, $branchOption, $storyStages, $modulePairs, $storyTasks, $storyBugs, $storyCases, $useDatatable ? 'datatable' : 'table');
|
||||
$this->story->printCell($value, $story, $users, $branchOption, $storyStages, $modulePairs, $storyTasks, $storyBugs, $storyCases, $useDatatable ? 'datatable' : 'table', $storyType);
|
||||
}
|
||||
}?>
|
||||
<?php else:?>
|
||||
<?php foreach($setting as $key => $value) $this->story->printCell($value, $story, $users, $branchOption, $storyStages, $modulePairs, $storyTasks, $storyBugs, $storyCases, $useDatatable ? 'datatable' : 'table');?>
|
||||
<?php foreach($setting as $key => $value) $this->story->printCell($value, $story, $users, $branchOption, $storyStages, $modulePairs, $storyTasks, $storyBugs, $storyCases, $useDatatable ? 'datatable' : 'table', $storyType);?>
|
||||
<?php endif;?>
|
||||
</tr>
|
||||
<?php if(!empty($story->children)):?>
|
||||
|
||||
+18
-16
@@ -163,16 +163,17 @@ class program extends control
|
||||
$this->view->program = $program;
|
||||
}
|
||||
|
||||
$this->view->title = $this->lang->program->product;
|
||||
$this->view->position[] = $this->lang->program->product;
|
||||
$this->view->programID = $programID;
|
||||
$this->view->browseType = $browseType;
|
||||
$this->view->orderBy = $orderBy;
|
||||
$this->view->pager = $pager;
|
||||
$this->view->users = $this->loadModel('user')->getPairs('noletter');
|
||||
$this->view->userIdPairs = $this->user->getPairs('noletter|showid');
|
||||
$this->view->usersAvatar = $this->user->getAvatarPairs('');
|
||||
$this->view->products = $this->loadModel('product')->getStats($orderBy, $pager, $browseType, '', 'story', $programID);
|
||||
$this->view->title = $this->lang->program->product;
|
||||
$this->view->position[] = $this->lang->program->product;
|
||||
$this->view->programID = $programID;
|
||||
$this->view->browseType = $browseType;
|
||||
$this->view->orderBy = $orderBy;
|
||||
$this->view->pager = $pager;
|
||||
$this->view->users = $this->loadModel('user')->getPairs('noletter');
|
||||
$this->view->products = $this->loadModel('product')->getStats($orderBy, $pager, $browseType, '', 'story', $programID);
|
||||
$this->view->userIdPairs = $this->user->getPairs('noletter|showid');
|
||||
$this->view->usersAvatar = $this->user->getAvatarPairs('');
|
||||
$this->view->showBatchEdit = $this->cookie->showProductBatchEdit;
|
||||
|
||||
$this->display();
|
||||
}
|
||||
@@ -481,12 +482,13 @@ class program extends control
|
||||
$this->view->title = $this->lang->program->project;
|
||||
$this->view->position[] = $this->lang->program->project;
|
||||
|
||||
$this->view->projectStats = $projectStats;
|
||||
$this->view->pager = $pager;
|
||||
$this->view->programID = $programID;
|
||||
$this->view->users = $this->loadModel('user')->getPairs('noletter|pofirst|nodeleted');
|
||||
$this->view->browseType = $browseType;
|
||||
$this->view->orderBy = $orderBy;
|
||||
$this->view->projectStats = $projectStats;
|
||||
$this->view->pager = $pager;
|
||||
$this->view->programID = $programID;
|
||||
$this->view->users = $this->loadModel('user')->getPairs('noletter|pofirst|nodeleted');
|
||||
$this->view->browseType = $browseType;
|
||||
$this->view->orderBy = $orderBy;
|
||||
$this->view->showBatchEdit = $this->cookie->showProjectBatchEdit;
|
||||
|
||||
$this->display();
|
||||
}
|
||||
|
||||
@@ -10,3 +10,4 @@ tbody.sortable > tr > td > span.sort-handler {color: #999;}
|
||||
.c-actions {width: 70px;}
|
||||
#productList .c-manager {padding-left: 20px;}
|
||||
#productList .c-manager a {top: 7px; left: 26px;}
|
||||
.statistic {margin-left: 10px; color: #838a9d; float: left; position: relative; line-height: 28px;}
|
||||
|
||||
@@ -0,0 +1,105 @@
|
||||
$(function()
|
||||
{
|
||||
$('input[name^="showEdit"]').click(function()
|
||||
{
|
||||
$.cookie('showProductBatchEdit', $(this).is(':checked') ? 1 : 0, {expires: config.cookieLife, path: config.webRoot});
|
||||
setCheckbox();
|
||||
});
|
||||
setCheckbox();
|
||||
|
||||
$(":checkbox[name^='productIDList']").on('click', function()
|
||||
{
|
||||
updateStatistic()
|
||||
});
|
||||
|
||||
$(".check-all").on('click', function()
|
||||
{
|
||||
if($(":checkbox[name^='productIDList']:not(:checked)").length == 0)
|
||||
{
|
||||
$(":checkbox[name^='productIDList']").prop('checked', false);
|
||||
}
|
||||
else
|
||||
{
|
||||
$(":checkbox[name^='productIDList']").prop('checked', true);
|
||||
}
|
||||
updateStatistic()
|
||||
});
|
||||
});
|
||||
|
||||
|
||||
/**
|
||||
* Set batch edit checkbox.
|
||||
*
|
||||
* @access public
|
||||
* @return void
|
||||
*/
|
||||
function setCheckbox()
|
||||
{
|
||||
$('#productListForm .checkbox-primary, #productListForm .check-all').hide();
|
||||
$('#productListForm .product-id').addClass('hidden');
|
||||
if($.cookie('showProductBatchEdit') == 1)
|
||||
{
|
||||
$('#productListForm .checkbox-primary, #productListForm .check-all').show();
|
||||
}
|
||||
else
|
||||
{
|
||||
$('#productListForm .product-id').removeClass('hidden');
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Add a statistics prompt statement after the Edit button.
|
||||
*
|
||||
* @access public
|
||||
* @return void
|
||||
*/
|
||||
function addStatistic()
|
||||
{
|
||||
var checkedLength = $(":checkbox[name^='productIDList']:checked").length;
|
||||
if(checkedLength > 0)
|
||||
{
|
||||
var summary = checkedProducts.replace('%s', checkedLength);
|
||||
if(cilentLang == "en" && checkedLength < 2) summary = summary.replace('products', 'product');
|
||||
|
||||
var statistic = "<div id='productsSummary' class='statistic'>" + summary + "</div>";
|
||||
$('#productsCount').hide();
|
||||
$('#productsSummary').remove();
|
||||
$('#editBtn').after(statistic);
|
||||
$('.table-actions').show();
|
||||
}
|
||||
else
|
||||
{
|
||||
$('.table-actions').hide();
|
||||
$('#productsCount').show();
|
||||
$('#productsSummary').addClass('hidden');
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Anti shake operation for jquery.
|
||||
*
|
||||
* @param fn $fn
|
||||
* @param delay $delay
|
||||
* @access public
|
||||
* @return void
|
||||
*/
|
||||
function debounce(fn, delay)
|
||||
{
|
||||
var timer = null;
|
||||
return function()
|
||||
{
|
||||
if(timer) clearTimeout(timer);
|
||||
timer = setTimeout(fn, delay)
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Update statistics.
|
||||
*
|
||||
* @access public
|
||||
* @return void
|
||||
*/
|
||||
function updateStatistic()
|
||||
{
|
||||
debounce(addStatistic(), 200)
|
||||
}
|
||||
@@ -0,0 +1,21 @@
|
||||
$(function()
|
||||
{
|
||||
$('input[name^="showEdit"]').click(function()
|
||||
{
|
||||
$.cookie('showProjectBatchEdit', $(this).is(':checked') ? 1 : 0, {expires: config.cookieLife, path: config.webRoot});
|
||||
setCheckbox();
|
||||
});
|
||||
setCheckbox();
|
||||
});
|
||||
|
||||
/**
|
||||
* Set batch edit checkbox.
|
||||
*
|
||||
* @access public
|
||||
* @return void
|
||||
*/
|
||||
function setCheckbox()
|
||||
{
|
||||
$('#projectsForm .checkbox-primary').hide();
|
||||
if($.cookie('showProjectBatchEdit') == 1) $('#projectsForm .checkbox-primary').show();
|
||||
}
|
||||
@@ -61,7 +61,8 @@
|
||||
<span class="icon icon-cards-view" style="color: #888fa1;"></span>
|
||||
<?php echo ($app->user->admin or strpos(",{$app->user->view->programs},", ",$program->id,") !== false) ? html::a($this->createLink('program', 'product', "programID=$program->id"), $program->name) : $program->name;?>
|
||||
<?php else:?>
|
||||
<?php echo html::a($this->createLink('project', 'index', "projectID=$program->id", '', '', $program->id), $program->name, '', 'class="text-ellipsis text-primary"');?>
|
||||
<?php $projectType = $lang->project->{$program->model};?>
|
||||
<?php echo html::a($this->createLink('project', 'index', "projectID=$program->id", '', '', $program->id), $program->name, '', "class='text-ellipsis text-primary' title='{$program->name} ($projectType)'");?>
|
||||
<?php
|
||||
if($program->status != 'done' and $program->status != 'closed' and $program->status != 'suspended')
|
||||
{
|
||||
|
||||
@@ -11,14 +11,18 @@
|
||||
?>
|
||||
<?php include '../../common/view/header.html.php';?>
|
||||
<?php include '../../common/view/sortable.html.php';?>
|
||||
<?php js::set('checkedProducts', $lang->product->checkedProducts);?>
|
||||
<?php js::set('cilentLang', $this->app->getClientLang());?>
|
||||
<?php $canBatchEdit = common::hasPriv('product', 'batchEdit');?>
|
||||
<div id="mainMenu" class="clearfix">
|
||||
<?php if(!isonlybody()):?>
|
||||
<div class="btn-toolbar pull-left">
|
||||
<div class="btn-toolBar pull-left">
|
||||
<?php foreach($lang->product->featureBar['all'] as $key => $label):?>
|
||||
<?php $active = $key == $browseType ? 'btn-active-text' : '';?>
|
||||
<?php if($key == $browseType) $label .= " <span class='label label-light label-badge'>{$pager->recTotal}</span>";?>
|
||||
<?php echo html::a(inlink("product", "programID=$programID&browseType=$key&orderBy=$orderBy"), "<span class='text'>{$label}</span>", '', "class='btn btn-link $active'");?>
|
||||
<?php endforeach;?>
|
||||
<?php if($canBatchEdit) echo html::checkbox('showEdit', array('1' => $lang->product->edit), $showBatchEdit);?>
|
||||
</div>
|
||||
<div class="btn-toolbar pull-right">
|
||||
<?php common::printLink('product', 'create', "programID=$programID", '<i class="icon icon-plus"></i> ' . $lang->product->create, '', 'class="btn btn-primary"');?>
|
||||
@@ -34,7 +38,6 @@
|
||||
<div class="main-col">
|
||||
<form class="main-table table-product" data-ride="table" id="productListForm" method="post" action='<?php echo $this->createLink('product', 'batchEdit', "programID=$programID");?>'>
|
||||
<?php $canOrder = common::hasPriv('product', 'updateOrder');?>
|
||||
<?php $canBatchEdit = common::hasPriv('product', 'batchEdit');?>
|
||||
<table id="productList" class="table has-sort-head table-bordered table-fixed">
|
||||
<?php $vars = "programID=$programID&browseType=$browseType&orderBy=%s&recTotal={$pager->recTotal}&recPerPage={$pager->recPerPage}&pageID={$pager->pageID}";?>
|
||||
<thead>
|
||||
@@ -73,10 +76,9 @@
|
||||
<tr class="text-center" data-id='<?php echo $product->id ?>' data-order='<?php echo $product->code;?>'>
|
||||
<td class='c-id text-left'>
|
||||
<?php if($canBatchEdit):?>
|
||||
<?php echo html::checkbox('productIDList', array($product->id => sprintf('%03d', $product->id)));?>
|
||||
<?php else:?>
|
||||
<?php printf('%03d', $product->id);?>
|
||||
<?php echo html::checkbox('productIDList', array($product->id => sprintf('%03d', $product->id)), '', 'class="id-checkbox ' . (!$showBatchEdit ? 'hidden"' : '"'));?>
|
||||
<?php endif;?>
|
||||
<span class="product-id <?php if($canBatchEdit && $showBatchEdit) echo 'hidden';?>"><?php printf('%03d', $product->id);?></span>
|
||||
</td>
|
||||
<td class="c-name" title='<?php echo $product->name?>'><?php echo html::a($this->createLink('product', 'browse', 'product=' . $product->id), $product->name);?></td>
|
||||
<td class='c-manager'>
|
||||
@@ -114,8 +116,15 @@
|
||||
<?php if($canBatchEdit):?>
|
||||
<div class="checkbox-primary check-all"><label><?php echo $lang->selectAll?></label></div>
|
||||
<div class="table-actions btn-toolbar">
|
||||
<?php echo html::submitButton($lang->edit, '', 'btn');?>
|
||||
<?php
|
||||
$actionLink = $this->createLink('product', 'batchEdit');
|
||||
echo html::commonButton($lang->edit, "id='editBtn' data-form-action='$actionLink'");
|
||||
?>
|
||||
</div>
|
||||
<?php
|
||||
$summary = sprintf($lang->product->pageSummary, count($products));
|
||||
echo "<div id='productsCount' class='statistic'>$summary</div>";
|
||||
?>
|
||||
<?php endif;?>
|
||||
<?php $pager->show('right', 'pagerjs');?>
|
||||
</div>
|
||||
|
||||
@@ -14,6 +14,7 @@
|
||||
<?php
|
||||
js::set('programID', $programID);
|
||||
js::set('browseType', $browseType);
|
||||
$canBatchEdit = common::hasPriv('project', 'batchEdit');
|
||||
?>
|
||||
<div id="mainMenu" class="clearfix">
|
||||
<div class="btn-toolBar pull-left">
|
||||
@@ -24,6 +25,7 @@ js::set('browseType', $browseType);
|
||||
<?php if($browseType == $key) $label .= " <span class='label label-light label-badge'>{$pager->recTotal}</span>";?>
|
||||
<?php echo html::a(inlink('project', "programID=$programID&browseType=$key"), $label, '', "class='btn btn-link $active'");?>
|
||||
<?php endforeach;?>
|
||||
<?php if($canBatchEdit) echo html::checkbox('showEdit', array('1' => $lang->project->edit), $showBatchEdit);?>
|
||||
<?php echo html::checkbox('involved ', array('1' => $lang->project->mine), '', $this->cookie->involved ? 'checked=checked' : '');?>
|
||||
</div>
|
||||
<div class="btn-toolbar pull-right">
|
||||
@@ -46,7 +48,6 @@ js::set('browseType', $browseType);
|
||||
$setting = $this->datatable->getSetting('program');
|
||||
?>
|
||||
<table class='table has-sort-head'>
|
||||
<?php $canBatchEdit = common::hasPriv('project', 'batchEdit');?>
|
||||
<thead>
|
||||
<tr>
|
||||
<?php
|
||||
|
||||
@@ -378,6 +378,7 @@ class project extends control
|
||||
$this->view->recTotal = $recTotal;
|
||||
$this->view->recPerPage = $recPerPage;
|
||||
$this->view->pageID = $pageID;
|
||||
$this->view->showBatchEdit = $this->cookie->showProjectBatchEdit;
|
||||
$this->view->allProjectsNum = $this->loadModel('program')->getProjectStats($programID, 'all');
|
||||
|
||||
$this->display();
|
||||
|
||||
@@ -3,20 +3,39 @@ $(function()
|
||||
$('input[name^="involved"]').click(function()
|
||||
{
|
||||
var involved = $(this).is(':checked') ? 1 : 0;
|
||||
$.cookie('involved', involved, {expires:config.cookieLife, path:config.webRoot});
|
||||
$.cookie('involved', involved, {expires: config.cookieLife, path: config.webRoot});
|
||||
window.location.reload();
|
||||
});
|
||||
|
||||
$('[id="switchButton"]').click(function()
|
||||
{
|
||||
var projectType = $(this).attr('data-type');
|
||||
$.cookie('projectType', projectType, {expires:config.cookieLife, path:config.webRoot});
|
||||
$.cookie('projectType', projectType, {expires: config.cookieLife, path: config.webRoot});
|
||||
window.location.reload();
|
||||
});
|
||||
|
||||
$('input[name^="showEdit"]').click(function()
|
||||
{
|
||||
$.cookie('showProjectBatchEdit', $(this).is(':checked') ? 1 : 0, {expires: config.cookieLife, path: config.webRoot});
|
||||
setCheckbox();
|
||||
});
|
||||
setCheckbox();
|
||||
|
||||
if(!useDatatable) resetNameWidth();
|
||||
});
|
||||
|
||||
/**
|
||||
* Set batch edit checkbox.
|
||||
*
|
||||
* @access public
|
||||
* @return void
|
||||
*/
|
||||
function setCheckbox()
|
||||
{
|
||||
$('#projectForm .checkbox-primary').hide();
|
||||
if($.cookie('showProjectBatchEdit') == 1) $('#projectForm .checkbox-primary').show();
|
||||
}
|
||||
|
||||
function resetNameWidth()
|
||||
{
|
||||
$name = $('#projectForm thead th.c-name');
|
||||
|
||||
@@ -1978,7 +1978,7 @@ class projectModel extends model
|
||||
elseif($id == 'name')
|
||||
{
|
||||
$class .= ' text-left';
|
||||
$title = "title='{$project->name}'";
|
||||
$title = "title='{$project->name}" . ($this->config->vision == 'lite' ? "'" : "({$this->lang->project->{$project->model}})'");
|
||||
}
|
||||
elseif($id == 'PM')
|
||||
{
|
||||
@@ -2021,9 +2021,6 @@ class projectModel extends model
|
||||
case 'name':
|
||||
$prefix = '';
|
||||
$suffix = '';
|
||||
if($project->model === 'waterfall') $prefix = "<span class='project-type-label label label-outline label-warning'>{$this->lang->project->waterfall}</span> ";
|
||||
if($project->model === 'scrum') $prefix = "<span class='project-type-label label label-outline label-info'>{$this->lang->project->scrum}</span> ";
|
||||
if($project->model === 'kanban') $prefix = "<span class='project-type-label label label-outline label-info'>{$this->lang->project->kanban}</span> ";
|
||||
if(isset($project->delay)) $suffix = "<span class='label label-danger label-badge'>{$this->lang->project->statusList['delay']}</span>";
|
||||
if(!empty($suffix) or !empty($prefix)) echo '<div class="project-name' . (empty($prefix) ? '' : ' has-prefix') . (empty($suffix) ? '' : ' has-suffix') . '">';
|
||||
if(!empty($prefix)) echo $prefix;
|
||||
|
||||
@@ -23,6 +23,7 @@
|
||||
.project-name.has-prefix > a {padding-left: 5px;}
|
||||
.project-name.has-suffix > a {padding-right: 5px;}
|
||||
</style>
|
||||
<?php $canBatchEdit = common::hasPriv('project', 'batchEdit');?>
|
||||
<div id="mainMenu" class="clearfix">
|
||||
<?php if($this->config->systemMode == 'new'):?>
|
||||
<div id="sidebarHeader">
|
||||
@@ -40,6 +41,7 @@
|
||||
<?php if($browseType == $key) $label .= " <span class='label label-light label-badge'>{$pager->recTotal}</span>";?>
|
||||
<?php echo html::a(inlink('browse', "programID=$programID&browseType=$key"), $label, '', "class='btn btn-link $active'");?>
|
||||
<?php endforeach;?>
|
||||
<?php if($canBatchEdit) echo html::checkbox('showEdit', array('1' => $lang->project->edit), $showBatchEdit);?>
|
||||
<?php if($browseType != 'bysearch') echo html::checkbox('involved', array('1' => $lang->project->mine), '', $this->cookie->involved ? 'checked=checked' : '');?>
|
||||
<a class="btn btn-link querybox-toggle" id='bysearchTab'><i class="icon icon-search muted"></i> <?php echo $lang->search->common;?></a>
|
||||
</div>
|
||||
@@ -99,7 +101,6 @@
|
||||
?>
|
||||
<?php if(!$useDatatable) echo '<div class="table-responsive">';?>
|
||||
<table class='table has-sort-head <?php if($useDatatable) echo 'datatable';?>' data-fixed-left-width='<?php echo $fixedFieldsWidth['leftWidth']?>' data-fixed-right-width='<?php echo $fixedFieldsWidth['rightWidth']?>'>
|
||||
<?php $canBatchEdit = $this->config->systemMode == 'new' ? common::hasPriv('project', 'batchEdit') : common::hasPriv('project', 'batchEdit');?>
|
||||
<thead>
|
||||
<tr>
|
||||
<?php
|
||||
|
||||
@@ -254,5 +254,5 @@ $config->story->datatable->fieldList['caseCount']['name'] = $lang->story->ca
|
||||
|
||||
$config->story->datatable->fieldList['actions']['title'] = 'actions';
|
||||
$config->story->datatable->fieldList['actions']['fixed'] = 'right';
|
||||
$config->story->datatable->fieldList['actions']['width'] = $app->tab == 'project' ? '220' : '200';
|
||||
$config->story->datatable->fieldList['actions']['width'] = $app->tab == 'project' ? '220' : '210';
|
||||
$config->story->datatable->fieldList['actions']['required'] = 'yes';
|
||||
|
||||
+73
-32
@@ -4193,7 +4193,6 @@ class storyModel extends model
|
||||
if($action == 'close') return $story->status != 'closed';
|
||||
if($action == 'activate') return $story->status == 'closed';
|
||||
if($action == 'assignto') return $story->status != 'closed';
|
||||
if($action == 'createcase') return $story->type != 'requirement';
|
||||
if($action == 'batchcreate' and $story->parent > 0) return false;
|
||||
if($action == 'batchcreate' and $story->type == 'requirement' and $story->status != 'closed') return strpos('draft,reviewing,changing', $story->status) === false;
|
||||
if($action == 'batchcreate' and $config->vision == 'lite' and ($story->status == 'active' and ($story->stage == 'wait' or $story->stage == 'projected'))) return true;
|
||||
@@ -4207,10 +4206,12 @@ class storyModel extends model
|
||||
*
|
||||
* @param object $story
|
||||
* @param string $type
|
||||
* @param object $execution
|
||||
* @param string $storyType story|requirement
|
||||
* @access public
|
||||
* @return string
|
||||
*/
|
||||
public function buildOperateMenu($story, $type = 'view', $execution = '')
|
||||
public function buildOperateMenu($story, $type = 'view', $execution = '', $storyType = 'story')
|
||||
{
|
||||
$menu = '';
|
||||
$params = "storyID=$story->id";
|
||||
@@ -4255,30 +4256,38 @@ class storyModel extends model
|
||||
$isClick = $this->isClickable($story, 'recall');
|
||||
$title = $story->status == 'changing' ? $this->lang->story->recallChange : $this->lang->story->recall;
|
||||
$title = $isClick ? $title : $this->lang->story->recallTip['actived'];
|
||||
$storyPriv = array(common::hasPriv('story', 'change'), common::hasPriv('story', 'submitReview'), common::hasPriv('story', 'review'), common::hasPriv('story', 'close'));
|
||||
$storyPrivCount = array_sum($storyPriv);
|
||||
if($this->app->tab == 'product' and common::hasPriv('story', 'recall') && ($storyPrivCount > 1))
|
||||
$menu .= $this->buildMenu('story', 'recall', $params . "&from=list&confirm=no&storyType=$story->type", $story, $type, 'undo', 'hiddenwin', 'showinonlybody', false, '', $title);
|
||||
$menu .= $this->buildMenu('story', 'edit', $params . "&kanbanGroup=default&storyType=$story->type", $story, $type, '', '', 'showinonlybody');
|
||||
|
||||
$vars = "storyType={$story->type}";
|
||||
$canChange = common::hasPriv('story', 'change', '', $vars);
|
||||
$canRecall = common::hasPriv('story', 'recall', '', $vars);
|
||||
$canSubmitReview = (strpos('draft,changing', $story->status) !== false and common::hasPriv('story', 'submitReview', '', $vars));
|
||||
$canReview = (strpos('draft,changing', $story->status) === false and common::hasPriv('story', 'review', '', $vars));
|
||||
$canEdit = common::hasPriv('story', 'edit', '', $vars);
|
||||
$canBatchCreate = ($this->app->tab == 'product' and (common::hasPriv('story', 'batchCreate', '', 'storyType=story')));
|
||||
$canCreateCase = ($story->type == 'story' and common::hasPriv('testcase', 'create'));
|
||||
$canClose = common::hasPriv('story', 'close', '', $vars);
|
||||
$canUnlinkStory = ($this->app->tab == 'project' and common::hasPriv('projectstory', 'unlinkStory'));
|
||||
|
||||
if(in_array($this->app->tab, array('product', 'project')))
|
||||
{
|
||||
$menu .= "<div class='btn-group dropup' style='margin-left:-5px;'>";
|
||||
$menu .= "<button type='button' class='btn icon-caret-down dropdown-toggle' data-toggle='dropdown' title='{$this->lang->more}' style='width: 16px; padding-left: 0px;'></button>";
|
||||
$menu .= "<ul class='dropdown-menu pull-right text-center' role='menu' style='min-width:auto; padding: 5px;'>";
|
||||
$menu .= $this->buildMenu('story', 'recall', $params . "&from=list&confirm=no&storyType=$story->type", $story, $type, 'undo', 'hiddenwin', 'showinonlybody', false, '', $title);
|
||||
$menu .= "</ul>";
|
||||
$menu .= "</div>";
|
||||
} else {
|
||||
$menu .= $this->buildMenu('story', 'recall', $params . "&from=list&confirm=no&storyType=$story->type", $story, $type, 'undo', 'hiddenwin', 'showinonlybody', false, '', $title);
|
||||
if(($canChange or $canRecall or $canSubmitReview or $canReview or $canEdit) and ($canCreateCase or $canBatchCreate or $canClose or $canUnlinkStory))
|
||||
{
|
||||
$menu .= "<div class='dividing-line'></div>";
|
||||
}
|
||||
}
|
||||
|
||||
$menu .= $this->buildMenu('story', 'close', $params . "&from=&storyType=$story->type", $story, $type, '', '', 'iframe', true);
|
||||
if($this->app->tab == 'product' and (common::hasPriv('story', 'recall') or $storyPrivCount > 0) and (common::hasPriv('story', 'edit') or common::hasPriv('story', 'createCase') or common::hasPriv('story', 'batchCreate')))
|
||||
if($this->app->tab == 'product' and $storyType == 'requirement')
|
||||
{
|
||||
$menu .= "<div class='dividing-line'></div>";
|
||||
$menu .= $this->buildMenu('story', 'close', $params . "&from=&storyType=$story->type", $story, $type, '', '', 'iframe', true);
|
||||
if($canClose and ($canBatchCreate or $canCreateCase)) $menu .= "<div class='dividing-line'></div>";
|
||||
}
|
||||
|
||||
$menu .= $this->buildMenu('story', 'edit', $params . "&kanbanGroup=default&storyType=$story->type", $story, $type, '', '', 'showinonlybody');
|
||||
if($storyType == 'requirement') $menu .= $this->buildMenu('story', 'batchCreate', "productID=$story->product&branch=$story->branch&module=$story->module&$params&executionID=0&plan=0&storyType=story", $story, $type, 'split', '', 'showinonlybody', '', '', $title);
|
||||
|
||||
$tab = $this->app->tab == 'project' ? 'project' : 'qa';
|
||||
if($story->type != 'requirement' and $this->config->vision != 'lite') $menu .= $this->buildMenu('story', 'createCase', "productID=$story->product&branch=$story->branch&module=0&from=¶m=0&$params", $story, $type, 'sitemap', '', 'showinonlybody', false, "data-app='$tab'");
|
||||
if($story->type != 'requirement' and $this->config->vision != 'lite') $menu .= $this->buildMenu('testcase', 'create', "productID=$story->product&branch=$story->branch&module=0&from=¶m=0&$params", $story, $type, 'sitemap', '', 'showinonlybody', false, "data-app='$tab'");
|
||||
|
||||
if($this->app->rawModule != 'projectstory' OR $this->config->vision == 'lite')
|
||||
{
|
||||
@@ -4296,9 +4305,24 @@ class storyModel extends model
|
||||
if($story->status == 'active' and $story->stage != 'wait') $title = sprintf($this->lang->story->subDivideTip['notWait'], zget($this->lang->story->stageList, $story->stage));
|
||||
}
|
||||
}
|
||||
$menu .= $this->buildMenu('story', 'batchCreate', "productID=$story->product&branch=$story->branch&module=$story->module&$params&executionID=0&plan=0&storyType=story", $story, $type, 'split', '', 'showinonlybody', '', '', $title);
|
||||
|
||||
if($storyType == 'story') $menu .= $this->buildMenu('story', 'batchCreate', "productID=$story->product&branch=$story->branch&module=$story->module&$params&executionID=0&plan=0&storyType=story", $story, $type, 'split', '', 'showinonlybody', '', '', $title);
|
||||
}
|
||||
|
||||
if($this->app->rawModule == 'projectstory' and $this->config->vision != 'lite')
|
||||
{
|
||||
if($canCreateCase and ($canClose or $canUnlinkStory)) $menu .= "<div class='dividing-line'></div>";
|
||||
|
||||
$menu .= $this->buildMenu('story', 'close', $params . "&from=&storyType=$story->type", $story, $type, '', '', 'iframe', true);
|
||||
$menu .= $this->buildMenu('projectstory', 'unlinkStory', "projectID={$this->session->project}&$params", $story, $type, 'unlink', 'hiddenwin', 'showinonlybody');
|
||||
}
|
||||
|
||||
if($this->app->tab == 'product' and $storyType == 'story')
|
||||
{
|
||||
if(($canBatchCreate or $canCreateCase) and $canClose) $menu .= "<div class='dividing-line'></div>";
|
||||
|
||||
$menu .= $this->buildMenu('story', 'close', $params . "&from=&storyType=$story->type", $story, $type, '', '', 'iframe', true);
|
||||
}
|
||||
if($this->app->rawModule == 'projectstory' and $this->config->vision != 'lite') $menu .= $this->buildMenu('projectstory', 'unlinkStory', "projectID={$this->session->project}&$params", $story, $type, 'unlink', 'hiddenwin', 'showinonlybody');
|
||||
|
||||
}
|
||||
else
|
||||
@@ -4374,13 +4398,22 @@ class storyModel extends model
|
||||
$story->reviewer = isset($story->reviewer) ? $story->reviewer : array();
|
||||
$story->notReview = isset($story->notReview) ? $story->notReview : array();
|
||||
|
||||
$canSubmitReview = (strpos('draft,changing', $story->status) !== false and common::hasPriv('story', 'submitReview'));
|
||||
$canReview = (strpos('draft,changing', $story->status) === false and common::hasPriv('story', 'review'));
|
||||
$canRecall = common::hasPriv('story', 'recall');
|
||||
$canCreateTask = common::hasPriv('task', 'create');
|
||||
$canBatchCreateTask = common::hasPriv('task', 'batchCreate');
|
||||
$canCreateCase = ($hasDBPriv and common::hasPriv('testcase', 'create'));
|
||||
$canEstimate = common::hasPriv('execution', 'storyEstimate', $execution);
|
||||
$canUnlinkStory = common::hasPriv('execution', 'unlinkStory', $execution);
|
||||
|
||||
if(strpos('draft,changing', $story->status) !== false)
|
||||
{
|
||||
if(common::hasPriv('story', 'submitReview')) $menu .= common::printIcon('story', 'submitReview', "storyID=$story->id&from=story", $story, 'list', 'confirm', '', 'iframe', true, "data-width='50%'");
|
||||
if($canSubmitReview) $menu .= common::printIcon('story', 'submitReview', "storyID=$story->id&from=story", $story, 'list', 'confirm', '', 'iframe', true, "data-width='50%'");
|
||||
}
|
||||
else
|
||||
{
|
||||
if(common::hasPriv('story', 'review'))
|
||||
if($canReview)
|
||||
{
|
||||
$reviewDisabled = in_array($this->app->user->account, $story->notReview) and ($story->status == 'draft' or $story->status == 'changing') ? '' : 'disabled';
|
||||
$story->from = 'execution';
|
||||
@@ -4388,7 +4421,7 @@ class storyModel extends model
|
||||
}
|
||||
}
|
||||
|
||||
if(common::hasPriv('story', 'recall'))
|
||||
if($canRecall)
|
||||
{
|
||||
$recallDisabled = empty($story->reviewedBy) and strpos('draft,changing', $story->status) !== false and !empty($story->reviewer) ? '' : 'disabled';
|
||||
$title = $story->status == 'changing' ? $this->lang->story->recallChange : $this->lang->story->recall;
|
||||
@@ -4410,21 +4443,29 @@ class storyModel extends model
|
||||
$this->lang->task->batchCreate = $this->lang->execution->batchWBS;
|
||||
if($hasDBPriv) $menu .= common::printIcon('task', 'batchCreate', "executionID=$executionID&story={$story->id}", '', 'list', 'pluses', '', $toTaskDisabled);
|
||||
|
||||
if(($canSubmitReview or $canReview or $canRecall or $canCreateTask or $canBatchCreateTask) and ($canCreateCase or $canEstimate or $canUnlinkStory))
|
||||
{
|
||||
$menu .= "<div class='dividing-line'></div>";
|
||||
}
|
||||
|
||||
if($canEstimate)
|
||||
{
|
||||
$menu .= common::buildIconButton('execution', 'storyEstimate', "executionID=$executionID&storyID=$story->id", '', 'list', 'estimate', '', 'iframe', true, "data-width='470px'");
|
||||
}
|
||||
|
||||
$this->lang->testcase->batchCreate = $this->lang->testcase->create;
|
||||
if($hasDBPriv and common::hasPriv('testcase', 'create'))
|
||||
if($canCreateCase)
|
||||
{
|
||||
$menu .= html::a(helper::createLink('testcase', 'create', "productID=$story->product&branch=$story->branch&moduleID=$story->module&form=¶m=0&storyID=$story->id"), '<i class="icon-testcase-create icon-sitemap"></i>', '', "class='btn' title='{$this->lang->testcase->create}' data-app='qa'");
|
||||
$menu .= common::buildIconButton('testcase', 'create', "productID=$story->product&branch=$story->branch&moduleID=$story->module&form=¶m=0&storyID=$story->id", '', 'list', 'sitemap', '', '', '', "data-app='qa'");
|
||||
}
|
||||
|
||||
if($canBeChanged and common::hasPriv('execution', 'storyEstimate', $execution))
|
||||
if(($canEstimate or $canCreateCase) and $canUnlinkStory) $menu .= "<div class='dividing-line'></div>";
|
||||
|
||||
if($canUnlinkStory)
|
||||
{
|
||||
$menu .= common::printIcon('execution', 'storyEstimate', "executionID=$executionID&storyID=$story->id", '', 'list', 'estimate', '', 'iframe', true, "data-width='470px'");
|
||||
$menu .= common::buildIconButton('execution', 'unlinkStory', "executionID=$executionID&storyID=$story->id&confirm=no", '', 'list', 'unlink', 'hiddenwin');
|
||||
}
|
||||
|
||||
if($canBeChanged and common::hasPriv('execution', 'unlinkStory', $execution))
|
||||
{
|
||||
$menu .= common::printIcon('execution', 'unlinkStory', "executionID=$executionID&storyID=$story->id&confirm=no", '', 'list', 'unlink', 'hiddenwin');
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -4889,7 +4930,7 @@ class storyModel extends model
|
||||
$menuType = 'browse';
|
||||
$execution = '';
|
||||
}
|
||||
echo $this->buildOperateMenu($story, $menuType, $execution);
|
||||
echo $this->buildOperateMenu($story, $menuType, $execution, $storyType);
|
||||
break;
|
||||
}
|
||||
echo '</td>';
|
||||
|
||||
@@ -174,7 +174,7 @@
|
||||
common::printIcon('story', 'close', "storyID=$child->id&from=&storyType=$child->type", $child, 'list', '', '', 'iframe showinonlybody', true);
|
||||
common::printIcon('story', 'activate', "storyID=$child->id&storyType=$child->type", $child, 'list', '', '', 'iframe showinonlybody', true);
|
||||
common::printIcon('story', 'edit', "storyID=$child->id&kanbanGroup=default&storyType=$child->type", $child, 'list');
|
||||
common::printIcon('story', 'createCase', "productID=$child->product&branch=$child->branch&module=0&from=¶m=0&story={$child->id}", $child, 'list', 'sitemap');
|
||||
common::printIcon('testcase', 'create', "productID=$child->product&branch=$child->branch&module=0&from=¶m=0&story={$child->id}", $child, 'list', 'sitemap');
|
||||
?>
|
||||
</td>
|
||||
</tr>
|
||||
|
||||
@@ -1112,10 +1112,11 @@ class task extends control
|
||||
*
|
||||
* @param int $taskID
|
||||
* @param string $from
|
||||
* @param string $orderBy
|
||||
* @access public
|
||||
* @return void
|
||||
*/
|
||||
public function recordEstimate($taskID, $from = '')
|
||||
public function recordEstimate($taskID, $from = '', $orderBy = '')
|
||||
{
|
||||
$this->commonAction($taskID);
|
||||
|
||||
@@ -1174,12 +1175,14 @@ class task extends control
|
||||
$this->session->set('estimateList', $uri, 'execution');
|
||||
if(isonlybody()) $this->session->set('estimateList', $uri . (strpos($uri, '?') === false ? '?' : '&') . 'onlybody=yes', 'execution');
|
||||
|
||||
$task = $this->task->getById($taskID);
|
||||
$orderBy = 'date,id';
|
||||
if(!empty($task->team) and $task->mode == 'linear') $orderBy = 'order,date,id';
|
||||
$task = $this->task->getById($taskID);
|
||||
if(!empty($task->team) and $task->mode == 'linear' and !$orderBy) $orderBy = 'order_asc';
|
||||
if(!$orderBy) $orderBy = 'date_asc';
|
||||
|
||||
$this->view->title = $this->lang->task->record;
|
||||
$this->view->task = $task;
|
||||
$this->view->from = $from;
|
||||
$this->view->orderBy = $orderBy;
|
||||
$this->view->efforts = $this->task->getTaskEstimate($taskID, '', '', $orderBy);
|
||||
$this->view->users = $this->loadModel('user')->getPairs('noclosed|noletter');
|
||||
$this->display();
|
||||
|
||||
@@ -8,7 +8,7 @@
|
||||
.nav > li.divider {margin: 0 10px 0 5px; background-color: #000; opacity: 0.06; width: 1px ; height: 15px; padding: 0 !important;}
|
||||
.table-bordered td, .table-bordered th { border: 1px solid #EEEEEE; }
|
||||
.table-recorded thead { background: #F5F6F8}
|
||||
.table>thead>tr>th{ border-bottom: 1px solid #EEEEEE}
|
||||
.table>thead>tr>th{border-bottom: 1px solid #EEEEEE; font-weight: 400;}
|
||||
#linearefforts .nav li.active a{color: #0c64eb !important}
|
||||
.input-group-addon {background: #fff}
|
||||
.icon-calendar {color: rgb(22, 168, 248)}
|
||||
@@ -18,3 +18,6 @@
|
||||
.main-header ul.hours:after{content:")"}
|
||||
.body-modal .main-header>h2 { max-width: 70% !important; margin-right:0px;}
|
||||
.table-record .form-date {border-right: none;}
|
||||
|
||||
.table.has-sort-head thead>tr>th>a:after, .table.has-sort-head thead>tr>th>a:before {top: -7px;}
|
||||
.table.has-sort-head thead>tr>th>a:hover, .table.has-sort-head thead>tr>th>a:hover:after, .table.has-sort-head thead>tr>th>a:hover:before {color: #000;}
|
||||
|
||||
@@ -1,5 +1,24 @@
|
||||
$(function()
|
||||
{
|
||||
/* Set default tab. */
|
||||
if($.cookie('recordEstimateType') == 'all')
|
||||
{
|
||||
$('#recordForm').addClass('hidden');
|
||||
$('.my-effort, #legendMyEffort').removeClass('active');
|
||||
$('.all-effort, #legendAllEffort').addClass('active');
|
||||
}
|
||||
else
|
||||
{
|
||||
$('.my-effort, #legendMyEffort').addClass('active');
|
||||
$('#recordForm').removeClass('hidden');
|
||||
}
|
||||
$.cookie('recordEstimateType', null);
|
||||
|
||||
$('.order-btn').on('click', function()
|
||||
{
|
||||
$.cookie('recordEstimateType', 'all');
|
||||
});
|
||||
|
||||
/* Hide creation logs when displaying team logs. */
|
||||
$('#linearefforts .tabs ul > li').click(function()
|
||||
{
|
||||
@@ -7,7 +26,6 @@ $(function()
|
||||
$('#recordForm').toggleClass('hidden', tab == '#legendAllEffort');
|
||||
});
|
||||
|
||||
|
||||
$('.form-date').datetimepicker('setEndDate', today);
|
||||
|
||||
$("#recordForm #submit").click(function(e, confirmed)
|
||||
|
||||
@@ -2910,13 +2910,14 @@ class taskModel extends model
|
||||
->where('id')->eq((int)$estimateID)
|
||||
->exec();
|
||||
|
||||
$consumed = $task->consumed + $estimate->consumed - $oldEstimate->consumed;
|
||||
$left = ($lastEstimate and $estimateID == $lastEstimate->id) ? $estimate->left : $task->left;
|
||||
$lastEstimate = $this->dao->select('*')->from(TABLE_EFFORT)
|
||||
->where('objectID')->eq($task->id)
|
||||
->andWhere('objectType')->eq('task')
|
||||
->orderBy('date_desc,id_desc')->limit(1)->fetch();
|
||||
|
||||
$consumed = $task->consumed + $estimate->consumed - $oldEstimate->consumed;
|
||||
$left = ($lastEstimate and $estimateID == $lastEstimate->id) ? $estimate->left : $task->left;
|
||||
|
||||
$now = helper::now();
|
||||
$data = new stdClass();
|
||||
$data->consumed = $consumed;
|
||||
|
||||
@@ -16,33 +16,45 @@ foreach($task->team as $team) $teamOrders[$team->order] = $team->account;
|
||||
$myOrders = array();
|
||||
$allEfforts = array();
|
||||
$recorders = array();
|
||||
foreach($efforts as $effort)
|
||||
$index = 0;
|
||||
$allOrders = array();
|
||||
$efforts = array_values($efforts);
|
||||
foreach($efforts as $key => $effort)
|
||||
{
|
||||
$order = $effort->order;
|
||||
$account = $effort->account;
|
||||
$allEfforts[$order][] = $effort;
|
||||
$prevEffort = $key > 0 ? $efforts[$key - 1] : null;
|
||||
$order = (!$prevEffort or $prevEffort->order == $effort->order) ? $index : ++$index;
|
||||
$account = $effort->account;
|
||||
|
||||
$allEfforts[$order][] = $effort;
|
||||
$recorders[$order][$account] = $account;
|
||||
if($app->user->account == $account)
|
||||
{
|
||||
if(!isset($myOrders[$order])) $myOrders[$order] = 0;
|
||||
$myOrders[$order] += 1;
|
||||
}
|
||||
$allOrders[$order] = $effort->order + 1;
|
||||
}
|
||||
?>
|
||||
<div id='linearefforts'>
|
||||
<div class='tabs'>
|
||||
<ul class='nav nav-tabs'>
|
||||
<li class='active'><a href='#legendMyEffort' data-toggle='tab'><?php echo $lang->task->myEffort;?></a></li>
|
||||
<li><a href='#legendAllEffort' data-toggle='tab'><?php echo $lang->task->allEffort;?></a></li>
|
||||
<li class='my-effort'><a href='#legendMyEffort' data-toggle='tab'><?php echo $lang->task->myEffort;?></a></li>
|
||||
<li class='all-effort'><a href='#legendAllEffort' data-toggle='tab'><?php echo $lang->task->allEffort;?></a></li>
|
||||
</ul>
|
||||
<div class='tab-content'>
|
||||
<div class='tab-pane active' id='legendMyEffort'>
|
||||
<div class='tab-pane' id='legendMyEffort'>
|
||||
<?php if(!empty($myOrders)):?>
|
||||
<table class='table table-bordered table-fixed table-recorded'>
|
||||
<table class='table table-bordered table-fixed table-recorded has-sort-head'>
|
||||
<thead>
|
||||
<tr class='text-center'>
|
||||
<th class="w-60px"> <?php echo $lang->task->teamOrder;?></th>
|
||||
<th class="w-120px"><?php echo $lang->task->date;?></th>
|
||||
<?php
|
||||
$vars = (isset($objectType) ? "objectType=$objectType&" : '') . "taskID=$task->id&from=$from&orderBy=%s";
|
||||
$sort = explode(',', $orderBy);
|
||||
$orderBy = zget($sort, '0', '');
|
||||
if(!strpos($orderBy, '_')) $orderBy .= '_asc';
|
||||
?>
|
||||
<th class="w-60px"><?php common::printOrderLink('order', $orderBy, $vars, $lang->task->teamOrder);?></th>
|
||||
<th class="w-120px"><?php common::printOrderLink('date', $orderBy, $vars, $lang->task->date);?></th>
|
||||
<th class="w-120px"><?php echo $lang->task->recordedBy;?></th>
|
||||
<th><?php echo $lang->task->work;?></th>
|
||||
<th class="thWidth"><?php echo $lang->task->consumedAB;?></th>
|
||||
@@ -58,7 +70,7 @@ foreach($efforts as $effort)
|
||||
<?php if($effort->account != $this->app->user->account) continue;?>
|
||||
<tr class="text-center">
|
||||
<?php if(!$showOrder):?>
|
||||
<td rowspan='<?php echo $count;?>'><?php echo $order + 1;?></td>
|
||||
<td rowspan='<?php echo $count;?>'><?php echo $allOrders[$order];?></td>
|
||||
<?php $showOrder = true;?>
|
||||
<?php endif;?>
|
||||
<td><?php echo $effort->date;?></td>
|
||||
@@ -84,11 +96,12 @@ foreach($efforts as $effort)
|
||||
<?php endif;?>
|
||||
</div>
|
||||
<div class='tab-pane' id='legendAllEffort'>
|
||||
<table class='table table-bordered table-fixed table-recorded'>
|
||||
<table class='table table-bordered table-fixed table-recorded has-sort-head'>
|
||||
<thead>
|
||||
<tr class='text-center'>
|
||||
<th class="w-60px"> <?php echo $lang->task->teamOrder;?></th>
|
||||
<th class="w-120px"><?php echo $lang->task->date;?></th>
|
||||
<?php $vars = (isset($objectType) ? "objectType=$objectType&" : '') . "taskID=$task->id&from=$from&orderBy=%s";?>
|
||||
<th class="w-60px order-btn"><?php common::printOrderLink('order', $orderBy, $vars, $lang->task->teamOrder);?></th>
|
||||
<th class="w-120px order-btn"><?php common::printOrderLink('date', $orderBy, $vars, $lang->task->date);?></th>
|
||||
<th class="w-120px"><?php echo $lang->task->recordedBy;?></th>
|
||||
<th><?php echo $lang->task->work;?></th>
|
||||
<th class="thWidth"><?php echo $lang->task->consumedAB;?></th>
|
||||
@@ -103,7 +116,7 @@ foreach($efforts as $effort)
|
||||
<?php foreach($allEfforts[$order] as $effort):?>
|
||||
<tr class="text-center">
|
||||
<?php if(!$showOrder):?>
|
||||
<td rowspan='<?php echo $count;?>'><?php echo $order + 1;?></td>
|
||||
<td rowspan='<?php echo $count;?>'><?php echo $allOrders[$order];?></td>
|
||||
<?php $showOrder = true;?>
|
||||
<?php endif;?>
|
||||
<td><?php echo $effort->date;?></td>
|
||||
|
||||
@@ -12,6 +12,9 @@
|
||||
?>
|
||||
<?php include '../../common/view/header.lite.html.php';?>
|
||||
<?php include '../../common/view/datepicker.html.php';?>
|
||||
<?php if(!$this->task->canOperateEffort($task) and empty($myOrders)):?>
|
||||
<style>#mainContent {min-height: unset;}</style>
|
||||
<?php endif;?>
|
||||
<?php $members = $task->members;?>
|
||||
<?php
|
||||
$confirmRecord = $lang->task->confirmRecord;
|
||||
@@ -56,10 +59,11 @@ if(!empty($members) && $task->mode == 'linear')
|
||||
<?php if(!empty($task->team) and $task->mode == 'linear'):?>
|
||||
<?php include __DIR__ . '/lineareffort.html.php';?>
|
||||
<?php else:?>
|
||||
<table class='table table-bordered table-fixed table-recorded'>
|
||||
<table class='table table-bordered table-fixed table-recorded has-sort-head'>
|
||||
<thead>
|
||||
<tr class='text-center'>
|
||||
<th class="w-120px"><?php echo $lang->task->date;?></th>
|
||||
<?php $vars = "taskID=$task->id&from=$from&orderBy=%s";?>
|
||||
<th class="w-120px"><?php common::printOrderLink('date', !strpos($orderBy, ',') ? $orderBy : 'date_asc', $vars, $lang->task->date);?></th>
|
||||
<th class="w-120px"><?php echo $lang->task->recordedBy;?></th>
|
||||
<th><?php echo $lang->task->work;?></th>
|
||||
<th class="thWidth"><?php echo $lang->task->consumed;?></th>
|
||||
@@ -100,7 +104,7 @@ if(!empty($members) && $task->mode == 'linear')
|
||||
</div>
|
||||
</div>
|
||||
<?php else:?>
|
||||
<form id="recordForm" method='post' target='hiddenwin'>
|
||||
<form id="recordForm" class='hidden' method='post' target='hiddenwin'>
|
||||
<?php
|
||||
$readonly = '';
|
||||
$left = '';
|
||||
|
||||
@@ -975,13 +975,16 @@ class testcase extends control
|
||||
$moduleIdList = $case->module;
|
||||
if($case->module) $moduleIdList = $this->tree->getAllChildID($case->module);
|
||||
|
||||
$moduleIdList = (!in_array($this->app->tab, array('execution', 'project')) and empty($stories)) ? 0 : $moduleIdList;
|
||||
$stories = $this->story->getProductStoryPairs($productID, $case->branch, $moduleIdList, 'all','id_desc', 0, 'full', 'story', false);
|
||||
|
||||
$this->view->productID = $productID;
|
||||
$this->view->product = $product;
|
||||
$this->view->products = $this->products;
|
||||
$this->view->branchTagOption = $branchTagOption;
|
||||
$this->view->productName = $this->products[$productID];
|
||||
$this->view->moduleOptionMenu = $moduleOptionMenu;
|
||||
$this->view->stories = $this->story->getProductStoryPairs($productID, $case->branch, $moduleIdList, 'all','id_desc', 0, 'full', 'story', false);
|
||||
$this->view->stories = $stories;
|
||||
}
|
||||
$forceNotReview = $this->testcase->forceNotReview();
|
||||
if($forceNotReview) unset($this->lang->testcase->statusList['wait']);
|
||||
|
||||
@@ -114,6 +114,7 @@ js::set('suiteID', $suiteID);
|
||||
<tr data-id='<?php echo $case->id?>'>
|
||||
<?php foreach($setting as $key => $value) $this->testcase->printCell($value, $case, $users, $branchOption, $modulePairs, $browseType, $useDatatable ? 'datatable' : 'table');?>
|
||||
</tr>
|
||||
<?php $caseProductIds[$case->product] = $case->product;?>
|
||||
<?php endforeach;?>
|
||||
</tbody>
|
||||
</table>
|
||||
@@ -129,8 +130,9 @@ js::set('suiteID', $suiteID);
|
||||
$misc = $canBatchRun ? "onclick=\"setFormAction('$actionLink', '', '#caseList')\"" : "disabled='disabled'";
|
||||
echo html::commonButton($lang->testtask->runCase, $misc);
|
||||
|
||||
$actionLink = $this->createLink('testcase', 'batchEdit', "productID=$productID&branch=$branch");
|
||||
$misc = $canBatchEdit ? "onclick=\"setFormAction('$actionLink', '', '#caseList')\"" : "disabled='disabled'";
|
||||
$caseProductID = count($caseProductIds) > 1 ? 0 : $productID;
|
||||
$actionLink = $this->createLink('testcase', 'batchEdit', "productID=$caseProductID&branch=$branch");
|
||||
$misc = $canBatchEdit ? "onclick=\"setFormAction('$actionLink', '', '#caseList')\"" : "disabled='disabled'";
|
||||
echo html::commonButton($lang->edit, $misc);
|
||||
?>
|
||||
<button type='button' class='btn dropdown-toggle' data-toggle='dropdown'><span class='caret'></span></button>
|
||||
|
||||
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
Reference in New Issue
Block a user