Merge branch 'pailei2'
This commit is contained in:
+19
-17
@@ -113,6 +113,7 @@ $filter->project->browse = new stdclass();
|
||||
$filter->project->story = new stdclass();
|
||||
$filter->project->export = new stdclass();
|
||||
$filter->project->task = new stdclass();
|
||||
$filter->project->execution = new stdclass();
|
||||
$filter->projectstory->story = new stdclass();
|
||||
$filter->qa->default = new stdclass();
|
||||
$filter->story->create = new stdclass();
|
||||
@@ -244,23 +245,24 @@ $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['projectType'] = 'code';
|
||||
$filter->project->story->cookie['storyModuleParam'] = 'int';
|
||||
$filter->project->story->cookie['storyPreProjectID'] = 'int';
|
||||
$filter->project->story->cookie['storyProductParam'] = 'int';
|
||||
$filter->project->story->cookie['storyBranchParam'] = 'reg::checked';
|
||||
$filter->project->story->cookie['projectStoryOrder'] = 'reg::orderBy';
|
||||
$filter->project->task->cookie['moduleBrowseParam'] = 'int';
|
||||
$filter->project->task->cookie['preProjectID'] = 'int';
|
||||
$filter->project->task->cookie['productBrowseParam'] = 'int';
|
||||
$filter->project->task->cookie['projectTaskOrder'] = 'reg::orderBy';
|
||||
$filter->project->task->cookie['windowWidth'] = 'int';
|
||||
$filter->project->export->cookie['checkedItem'] = 'reg::checked';
|
||||
$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['projectType'] = 'code';
|
||||
$filter->project->story->cookie['storyModuleParam'] = 'int';
|
||||
$filter->project->story->cookie['storyPreProjectID'] = 'int';
|
||||
$filter->project->story->cookie['storyProductParam'] = 'int';
|
||||
$filter->project->story->cookie['storyBranchParam'] = 'reg::checked';
|
||||
$filter->project->story->cookie['projectStoryOrder'] = 'reg::orderBy';
|
||||
$filter->project->task->cookie['moduleBrowseParam'] = 'int';
|
||||
$filter->project->task->cookie['preProjectID'] = 'int';
|
||||
$filter->project->task->cookie['productBrowseParam'] = 'int';
|
||||
$filter->project->task->cookie['projectTaskOrder'] = 'reg::orderBy';
|
||||
$filter->project->task->cookie['windowWidth'] = 'int';
|
||||
$filter->project->export->cookie['checkedItem'] = 'reg::checked';
|
||||
$filter->project->execution->cookie['pagerExecutionAll'] = 'int';
|
||||
|
||||
$filter->projectstory->story->cookie['storyModuleParam'] = 'int';
|
||||
$filter->projectstory->story->cookie['pagerProductBrowse'] = 'int';
|
||||
|
||||
@@ -216,6 +216,7 @@ $config->openMethods[] = 'kanban.importexecution';
|
||||
$config->openMethods[] = 'kanban.importbuild';
|
||||
$config->openMethods[] = 'kanban.activatecard';
|
||||
$config->openMethods[] = 'kanban.finishcard';
|
||||
$config->openMethods[] = 'kanban.deleteobjectcard';
|
||||
|
||||
/* Define the tables. */
|
||||
define('TABLE_COMPANY', '`' . $config->db->prefix . 'company`');
|
||||
@@ -366,10 +367,11 @@ $config->objectTables['kanbancard'] = TABLE_KANBANCARD;
|
||||
$config->objectTables['sonarqube'] = TABLE_PIPELINE;
|
||||
$config->objectTables['gitlab'] = TABLE_PIPELINE;
|
||||
$config->objectTables['jebkins'] = TABLE_PIPELINE;
|
||||
$config->objectTables['stage'] = TABLE_STAGE;
|
||||
|
||||
$config->newFeatures = array('introduction', 'tutorial', 'youngBlueTheme', 'visions');
|
||||
|
||||
/* Program privs.*/
|
||||
$config->programPriv = new stdclass();
|
||||
$config->programPriv->scrum = array('story', 'projectstory', 'projectrelease', 'project', 'build', 'bug', 'testcase', 'testreport', 'doc', 'repo', 'meeting', 'stakeholder', 'testtask');
|
||||
$config->programPriv->scrum = array('story', 'projectstory', 'projectrelease', 'project', 'execution', 'build', 'bug', 'testcase', 'testreport', 'doc', 'repo', 'meeting', 'stakeholder', 'testtask');
|
||||
$config->programPriv->waterfall = array_merge($config->programPriv->scrum, array('workestimation', 'durationestimation', 'budget', 'programplan', 'review', 'reviewissue', 'weekly', 'cm', 'milestone', 'design', 'issue', 'risk', 'opportunity', 'measrecord', 'auditplan', 'trainplan', 'gapanalysis', 'pssp', 'researchplan', 'researchreport'));
|
||||
|
||||
+2
-2
@@ -244,8 +244,8 @@ INSERT INTO `zt_dept` (`id`, `name`, `parent`, `path`, `grade`, `order`, `positi
|
||||
INSERT INTO `zt_doclib` (`id`, `type`, `product`, `project`, `execution`, `name`, `acl`, `groups`, `users`, `main`, `collector`, `order`, `deleted`) VALUES
|
||||
(1, 'product', 1, 0, 0, '产品库', 'default', '', '', '1', '', 0, '0'),
|
||||
(2, 'product', 2, 0, 0, '产品库', 'default', '', '', '1', '', 0, '0'),
|
||||
(3, 'project', 0, 0, 1, '项目库', 'default', '', '', '1', '', 0, '0'),
|
||||
(4, 'project', 0, 0, 2, '项目库', 'default', '', '', '1', '', 0, '0'),
|
||||
(3, 'execution', 0, 0, 1, '项目库', 'default', '', '', '1', '', 0, '0'),
|
||||
(4, 'execution', 0, 0, 2, '项目库', 'default', '', '', '1', '', 0, '0'),
|
||||
(5, 'project', 0, 7, 0, '项目主库', 'default', '', '', '1', '', 0, '0');
|
||||
INSERT INTO `zt_history` (`id`, `action`, `field`, `old`, `new`, `diff`) VALUES
|
||||
(1, 14, 'version', '1', '2', ''),
|
||||
|
||||
@@ -42,6 +42,7 @@ $config->action->objectNameFields['kanban'] = 'name';
|
||||
$config->action->objectNameFields['kanbancard'] = 'name';
|
||||
$config->action->objectNameFields['sonarqube'] = 'name';
|
||||
$config->action->objectNameFields['gitlab'] = 'name';
|
||||
$config->action->objectNameFields['stage'] = 'name';
|
||||
|
||||
$config->action->commonImgSize = 870;
|
||||
|
||||
|
||||
@@ -645,6 +645,7 @@ $lang->action->label->kanbanlane = '看板泳道|execution|kanban|execution=%s
|
||||
$lang->action->label->kanbancard = '看板卡片|kanban|view|kanbanID=%s';
|
||||
$lang->action->label->mr = '合并请求|mr|view|id=%s';
|
||||
$lang->action->label->gitlab = 'GitLab服务器|gitlab|view|id=%s';
|
||||
$lang->action->label->stage = '瀑布模型的阶段|stage|browse|';
|
||||
|
||||
/* Object type. */
|
||||
$lang->action->search = new stdclass();
|
||||
|
||||
@@ -44,10 +44,8 @@
|
||||
<div class='col'>
|
||||
<div class='panel-content'>
|
||||
<div class='panel-heading not-move-handler'>
|
||||
<?php if($config->systemMode == 'new'):?>
|
||||
<?php $projectLabel = $project->model == 'waterfall' ? 'label-warning' : 'label-info';?>
|
||||
<span class="project-type-label label <?php echo $projectLabel;?> label-outline"><?php echo $lang->project->{$project->model};?></span>
|
||||
<?php endif;?>
|
||||
<?php $labelClass = $project->model == 'waterfall' ? 'label-warning' : 'label-info';?>
|
||||
<span class='project-type-label label <?php echo $labelClass;?> label-outline'><?php echo $lang->project->{$project->model};?></span>
|
||||
<strong class='project-name' title='<?php echo $project->name;?>'> <?php echo html::a($viewLink, $project->name);?> </strong>
|
||||
<nav class='panel-actions nav nav-default'>
|
||||
<li class='dropdown'>
|
||||
|
||||
+42
-6
@@ -322,6 +322,21 @@ class bug extends control
|
||||
if($this->app->tab == 'execution')
|
||||
{
|
||||
if(isset($output['executionID'])) $this->loadModel('execution')->setMenu($output['executionID']);
|
||||
$execution = $this->dao->findById((int)$output['executionID'])->from(TABLE_EXECUTION)->fetch();
|
||||
if($execution->type == 'kanban')
|
||||
{
|
||||
$this->loadModel('kanban');
|
||||
$regionPairs = $this->kanban->getRegionPairs($execution->id, 0, 'execution');
|
||||
$regionID = isset($output['regionID']) ? $output['regionID'] : key($regionPairs);
|
||||
$lanePairs = $this->kanban->getLanePairsByRegion($regionID, 'bug');
|
||||
$laneID = isset($output['laneID']) ? $output['laneID'] : key($lanePairs);
|
||||
|
||||
$this->view->executionType = $execution->type;
|
||||
$this->view->regionID = $regionID;
|
||||
$this->view->laneID = $laneID;
|
||||
$this->view->regionPairs = $regionPairs;
|
||||
$this->view->lanePairs = $lanePairs;
|
||||
}
|
||||
}
|
||||
else if($this->app->tab == 'project')
|
||||
{
|
||||
@@ -662,6 +677,9 @@ class bug extends control
|
||||
*/
|
||||
public function batchCreate($productID, $branch = '', $executionID = 0, $moduleID = 0, $extra = '')
|
||||
{
|
||||
$extra = str_replace(array(',', ' '), array('&', ''), $extra);
|
||||
parse_str($extra, $output);
|
||||
|
||||
if(!empty($_POST))
|
||||
{
|
||||
$actions = $this->bug->batchCreate($productID, $branch, $extra);
|
||||
@@ -675,9 +693,6 @@ class bug extends control
|
||||
|
||||
setcookie('bugModule', 0, 0, $this->config->webRoot, '', $this->config->cookieSecure, false);
|
||||
|
||||
$extra = str_replace(array(',', ' '), array('&', ''), $extra);
|
||||
parse_str($extra, $output);
|
||||
|
||||
/* If link from no head then reload. */
|
||||
if(isonlybody() and $executionID)
|
||||
{
|
||||
@@ -709,6 +724,20 @@ class bug extends control
|
||||
$builds = $this->loadModel('build')->getBuildPairs($productID, $branch, 'noempty', $executionID, 'execution');
|
||||
$stories = $this->story->getExecutionStoryPairs($executionID);
|
||||
$execution = $this->loadModel('execution')->getById($executionID);
|
||||
if($execution->type == 'kanban')
|
||||
{
|
||||
$this->loadModel('kanban');
|
||||
$regionPairs = $this->kanban->getRegionPairs($executionID, 0, 'execution');
|
||||
$regionID = isset($output['regionID']) ? $output['regionID'] : key($regionPairs);
|
||||
$lanePairs = $this->kanban->getLanePairsByRegion($regionID, 'bug');
|
||||
$laneID = isset($output['laneID']) ? $output['laneID'] : key($lanePairs);
|
||||
|
||||
$this->view->executionType = $execution->type;
|
||||
$this->view->regionID = $regionID;
|
||||
$this->view->laneID = $laneID;
|
||||
$this->view->regionPairs = $regionPairs;
|
||||
$this->view->lanePairs = $lanePairs;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
@@ -1672,7 +1701,7 @@ class bug extends control
|
||||
}
|
||||
else
|
||||
{
|
||||
return print(js::closeModal('parent.parent'));
|
||||
return print(js::closeModal('parent.parent', 'this', "function(){parent.parent.location.reload();}"));
|
||||
}
|
||||
}
|
||||
if(defined('RUN_MODE') && RUN_MODE == 'api')
|
||||
@@ -1835,15 +1864,16 @@ class bug extends control
|
||||
*
|
||||
* @param int $bugID
|
||||
* @param string $confirm yes|no
|
||||
* @param string $from taskkanban
|
||||
* @access public
|
||||
* @return void
|
||||
*/
|
||||
public function delete($bugID, $confirm = 'no')
|
||||
public function delete($bugID, $confirm = 'no', $from = '')
|
||||
{
|
||||
$bug = $this->bug->getById($bugID);
|
||||
if($confirm == 'no')
|
||||
{
|
||||
return print(js::confirm($this->lang->bug->confirmDelete, inlink('delete', "bugID=$bugID&confirm=yes")));
|
||||
return print(js::confirm($this->lang->bug->confirmDelete, inlink('delete', "bugID=$bugID&confirm=yes&from=$from")));
|
||||
}
|
||||
else
|
||||
{
|
||||
@@ -1864,6 +1894,9 @@ class bug extends control
|
||||
|
||||
if($this->viewType == 'json') return $this->send(array('result' => 'success', 'message' => $this->lang->saveSuccess));
|
||||
|
||||
if(isonlybody()) return print(js::reload('parent.parent'));
|
||||
if($from == 'taskkanban') return print(js::reload('parent'));
|
||||
|
||||
$locateLink = $this->session->bugList ? $this->session->bugList : inlink('browse', "productID={$bug->product}");
|
||||
return print(js::locate($locateLink, 'parent'));
|
||||
}
|
||||
@@ -1922,6 +1955,9 @@ class bug extends control
|
||||
{
|
||||
$executionMembers = $this->user->getTeamMemberPairs($executionID, 'execution', '', $selectedUser);
|
||||
|
||||
$execution = $this->loadModel('execution')->getByID($executionID);
|
||||
if(empty($selectedUser)) $selectedUser = $execution->QD;
|
||||
|
||||
return print(html::select('assignedTo', $executionMembers, $selectedUser, 'class="form-control"'));
|
||||
}
|
||||
|
||||
|
||||
@@ -4,6 +4,7 @@
|
||||
.confirm0 {color: gray;}
|
||||
.confirm1 {color: green;}
|
||||
td.delayed {color: #fff; background: #e84e0f !important;}
|
||||
#bugForm .setting {height: 25px;}
|
||||
|
||||
.datatable-wrapper .table-datatable .datatable-row td {height: 37px;}
|
||||
|
||||
|
||||
@@ -18,7 +18,6 @@ html[lang='en'] #deadlineTd .input-group-addon {padding: 5px 18px;}
|
||||
|
||||
.dropdown-pris > .btn {background-color: #fff; text-shadow: none;}
|
||||
|
||||
#contactListGroup .input-group-btn > .btn {margin-left: -1px !important;}
|
||||
#contactListGroup .chosen-container-single a {border-left-width: 0px;}
|
||||
|
||||
.minw-80px {min-width: 80px;}
|
||||
|
||||
@@ -38,6 +38,27 @@ function setOpenedBuilds(link, index)
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Set lane.
|
||||
*
|
||||
* @param int $regionID
|
||||
* @param int $num
|
||||
* @access public
|
||||
* @return void
|
||||
*/
|
||||
function setLane(regionID, num)
|
||||
{
|
||||
laneLink = createLink('kanban', 'ajaxGetLanes', 'regionID=' + regionID + '&type=bug&field=lanes&i=' + num);
|
||||
$.get(laneLink, function(lanes)
|
||||
{
|
||||
if(!lanes) lanes = '<select id="lanes' + num + '" name="lanes[' + num + ']" class="form-control"></select>';
|
||||
$('#lanes' + num).replaceWith(lanes);
|
||||
$("#lanes" + num + "_chosen").remove();
|
||||
$("#lanes" + num).next('.picker').remove();
|
||||
$("#lanes" + num).chosen();
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Load execution builds
|
||||
*
|
||||
|
||||
+21
-28
@@ -29,8 +29,6 @@ $(function()
|
||||
*/
|
||||
function loadAll(productID)
|
||||
{
|
||||
if(page == 'create') loadExecutionTeamMembers(productID, true);
|
||||
|
||||
if(typeof(changeProductConfirmed) != 'undefined' && !changeProductConfirmed)
|
||||
{
|
||||
firstChoice = confirm(confirmChangeProduct);
|
||||
@@ -50,9 +48,7 @@ function loadAll(productID)
|
||||
{
|
||||
$('#taskIdBox').innerHTML = '<select id="task"></select>'; // Reset the task.
|
||||
$('#task').chosen();
|
||||
var param = '';
|
||||
if(page == 'create') param = 'active';
|
||||
loadProductBranches(productID, param)
|
||||
loadProductBranches(productID)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -266,7 +262,7 @@ function loadProductProjects(productID)
|
||||
function loadProductExecutions(productID, projectID = 0)
|
||||
{
|
||||
required = $('#execution_chosen').hasClass('required');
|
||||
branch = $('#branch').val();
|
||||
branch = $('#branch').val();
|
||||
if(typeof(branch) == 'undefined') branch = 0;
|
||||
|
||||
link = createLink('product', 'ajaxGetExecutions', 'productID=' + productID + '&projectID=' + projectID + '&branch=' + branch);
|
||||
@@ -275,9 +271,10 @@ function loadProductExecutions(productID, projectID = 0)
|
||||
$(this).find('select').chosen();
|
||||
if(typeof(bugExecution) == 'string' && systemMode != 'classic') $('#executionIdBox').prepend("<span class='input-group-addon' id='executionBox' style='border-left-width: 0px;'>" + bugExecution + "</span>");
|
||||
if(required) $(this).addClass('required');
|
||||
changeExecutionName(projectID);
|
||||
changeAssignedTo(projectID);
|
||||
});
|
||||
loadProjectBuilds(projectID);
|
||||
|
||||
projectID != 0 ? loadProjectBuilds(projectID) : loadProductBuilds(productID);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -349,13 +346,16 @@ function loadExecutionRelated(executionID)
|
||||
}
|
||||
else
|
||||
{
|
||||
var currentProjectID = $('#project').val();
|
||||
var currentProductID = $('#product').val();
|
||||
|
||||
$('#taskIdBox').innerHTML = '<select id="task"></select>'; // Reset the task.
|
||||
loadProductStories($('#product').val());
|
||||
loadProductBuilds($('#product').val());
|
||||
loadTestTasks($('#product').val());
|
||||
loadProjectTeamMembers($('#project').val());
|
||||
loadProductStories(currentProductID);
|
||||
loadTestTasks(currentProductID);
|
||||
loadProjectTeamMembers(currentProjectID);
|
||||
|
||||
currentProjectID != 0 ? loadProjectBuilds(currentProjectID) : loadProductBuilds(currentProductID);
|
||||
}
|
||||
notice();
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -528,7 +528,8 @@ function loadProductBranches(productID, param)
|
||||
$('#branch_chosen').remove();
|
||||
$('#branch').next('.picker').remove();
|
||||
|
||||
var param = "productID=" + productID + "&oldBranch=0¶m=" + param;
|
||||
var branchStatus = page == 'create' ? 'active' : 'all';
|
||||
var param = "productID=" + productID + "&oldBranch=0¶m=" + branchStatus;
|
||||
if(typeof(tab) != 'undefined' && (tab == 'execution' || tab == 'project')) param += "&projectID=" + objectID;
|
||||
$.get(createLink('branch', 'ajaxGetBranches', param), function(data)
|
||||
{
|
||||
@@ -541,16 +542,11 @@ function loadProductBranches(productID, param)
|
||||
|
||||
loadProductModules(productID);
|
||||
loadProductProjects(productID);
|
||||
loadProductBuilds(productID);
|
||||
loadProductplans(productID);
|
||||
loadProductStories(productID);
|
||||
})
|
||||
}
|
||||
|
||||
|
||||
var oldAssignedToTitle = $("#assignedTo").find("option:selected").text();
|
||||
var oldAssignedTo = $("#assignedTo").find("option:selected").val();
|
||||
|
||||
/**
|
||||
* Load team members of the execution as assignedTo list.
|
||||
*
|
||||
@@ -564,18 +560,9 @@ function loadAssignedTo(executionID, selectedUser)
|
||||
link = createLink('bug', 'ajaxLoadAssignedTo', 'executionID=' + executionID + '&selectedUser=' + selectedUser);
|
||||
$.get(link, function(data)
|
||||
{
|
||||
var defaultOption = '<option title="' + oldAssignedToTitle + '" value="' + oldAssignedTo + '" selected="selected">' + oldAssignedToTitle + '</option>';
|
||||
var defaultAssignedTo = $('#assignedTo').val();
|
||||
|
||||
$('#assignedTo_chosen').remove();
|
||||
$('#assignedTo').next('.picker').remove();
|
||||
$('#assignedTo').replaceWith(data);
|
||||
|
||||
if(defaultAssignedTo !== oldAssignedTo && selectedUser == '')
|
||||
{
|
||||
if($('#assignedTo option[value="' + oldAssignedTo + '"]').length > 0) $('#assignedTo option[value="' + oldAssignedTo + '"]').remove();
|
||||
$('#assignedTo').append(defaultOption);
|
||||
}
|
||||
$('#assignedTo').chosen();
|
||||
});
|
||||
}
|
||||
@@ -593,6 +580,8 @@ var oldTestTask = $("#testtask").find("option:selected").val();
|
||||
*/
|
||||
function loadTestTasks(productID, executionID)
|
||||
{
|
||||
if(!$('#testtaskBox').length) return;
|
||||
|
||||
if(typeof(executionID) == 'undefined') executionID = 0;
|
||||
link = createLink('testtask', 'ajaxGetTestTasks', 'productID=' + productID + '&executionID=' + executionID);
|
||||
$.get(link, function(data)
|
||||
@@ -612,6 +601,9 @@ function loadTestTasks(productID, executionID)
|
||||
*/
|
||||
function notice()
|
||||
{
|
||||
if(page == 'edit') return;
|
||||
|
||||
$('#buildBoxActions').empty().hide();
|
||||
if($('#openedBuild').find('option').length <= 1)
|
||||
{
|
||||
var html = '';
|
||||
@@ -638,6 +630,7 @@ function notice()
|
||||
if($bba.length)
|
||||
{
|
||||
$bba.html(html);
|
||||
$bba.show();
|
||||
}
|
||||
else
|
||||
{
|
||||
|
||||
+33
-4
@@ -56,6 +56,27 @@ function loadModuleRelated()
|
||||
setStories(moduleID, productID, storyID);
|
||||
}
|
||||
|
||||
/**
|
||||
* Set lane.
|
||||
*
|
||||
* @param int $regionID
|
||||
* @access public
|
||||
* @return void
|
||||
*/
|
||||
function setLane(regionID)
|
||||
{
|
||||
console.log(regionID);
|
||||
laneLink = createLink('kanban', 'ajaxGetLanes', 'regionID=' + regionID + '&type=bug&field=lane');
|
||||
$.get(laneLink, function(lane)
|
||||
{
|
||||
if(!lane) lane = "<select id='lane' name='lane' class='form-control'></select>";
|
||||
$('#lane').replaceWith(lane);
|
||||
$("#lane" + "_chosen").remove();
|
||||
$("#lane").next('.picker').remove();
|
||||
$("#lane").chosen();
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the assignedTo field.
|
||||
*
|
||||
@@ -109,12 +130,16 @@ $(function()
|
||||
{
|
||||
loadExecutionRelated($('#execution').val());
|
||||
}
|
||||
else if(parseInt($('#project').val()))
|
||||
{
|
||||
loadProjectBuilds($('#project').val());
|
||||
loadProjectTeamMembers($('#project').val());
|
||||
}
|
||||
else
|
||||
{
|
||||
if(parseInt($('#project').val())) loadProjectTeamMembers($('#project').val());
|
||||
if(!assignedto) setTimeout(function(){setAssignedTo(moduleID, productID)}, 500);
|
||||
}
|
||||
|
||||
if(!assignedto) setTimeout(function(){setAssignedTo(moduleID, productID)}, 500);
|
||||
notice();
|
||||
|
||||
$('[data-toggle=tooltip]').tooltip();
|
||||
@@ -168,7 +193,7 @@ $(function()
|
||||
* @access public
|
||||
* @return void
|
||||
*/
|
||||
function changeExecutionName(projectID)
|
||||
function changeAssignedTo(projectID)
|
||||
{
|
||||
if(parseInt(projectID))
|
||||
{
|
||||
@@ -179,9 +204,13 @@ function changeExecutionName(projectID)
|
||||
$('#executionBox').html(executionLang);
|
||||
})
|
||||
}
|
||||
else if($('#execution').val() != 0)
|
||||
{
|
||||
loadAssignedTo($('#execution').val());
|
||||
}
|
||||
else
|
||||
{
|
||||
loadExecutionTeamMembers($('#product').val());
|
||||
setAssignedTo();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -21,25 +21,6 @@ $(function()
|
||||
}
|
||||
});
|
||||
|
||||
/**
|
||||
* Ajax change execution name.
|
||||
*
|
||||
* @param int projectID
|
||||
* @access public
|
||||
* @return void
|
||||
*/
|
||||
function changeExecutionName(projectID)
|
||||
{
|
||||
if(parseInt(projectID))
|
||||
{
|
||||
var link = createLink('bug', 'ajaxGetExecutionLang', 'projectID=' + projectID);
|
||||
$.post(link, function(executionLang)
|
||||
{
|
||||
$('#executionBox').html(executionLang);
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Set duplicate field.
|
||||
*
|
||||
|
||||
+26
-7
@@ -76,7 +76,7 @@ class bugModel extends model
|
||||
->trim('title')
|
||||
->join('openedBuild', ',')
|
||||
->join('mailto', ',')
|
||||
->remove('files, labels,uid,oldTaskID,contactListMenu')
|
||||
->remove('files,labels,uid,oldTaskID,contactListMenu,region,lane')
|
||||
->get();
|
||||
|
||||
if($bug->execution != 0) $bug->project = $this->dao->select('parent')->from(TABLE_EXECUTION)->where('id')->eq($bug->execution)->fetch('parent');
|
||||
@@ -107,8 +107,15 @@ class bugModel extends model
|
||||
if($bug->execution)
|
||||
{
|
||||
$this->loadModel('kanban');
|
||||
if(isset($output['laneID']) and isset($output['columnID'])) $this->kanban->addKanbanCell($bug->execution, $output['laneID'], $output['columnID'], 'bug', $bugID);
|
||||
if(!isset($output['laneID']) or !isset($output['columnID'])) $this->kanban->updateLane($bug->execution, 'bug');
|
||||
|
||||
$laneID = isset($output['laneID']) ? $output['laneID'] : 0;
|
||||
if(!empty($_POST['lane'])) $laneID = $_POST['lane'];
|
||||
|
||||
$columnID = $this->kanban->getColumnIDByLaneID($laneID, 'unconfirmed');
|
||||
if(empty($columnID)) $columnID = isset($output['columnID']) ? $output['columnID'] : 0;
|
||||
|
||||
if(!empty($laneID) and !empty($columnID)) $this->kanban->addKanbanCell($bug->execution, $laneID, $columnID, 'bug', $bugID);
|
||||
if(empty($laneID) or empty($columnID)) $this->kanban->updateLane($bug->execution, 'bug');
|
||||
}
|
||||
|
||||
/* Callback the callable method to process the related data for object that is transfered to bug. */
|
||||
@@ -201,6 +208,8 @@ class bugModel extends model
|
||||
$bug->browser = $data->browsers[$i];
|
||||
$bug->keywords = $data->keywords[$i];
|
||||
|
||||
if(isset($data->lanes[$i])) $bug->laneID = $data->lanes[$i];
|
||||
|
||||
if($bug->execution != 0) $bug->project = $this->dao->select('parent')->from(TABLE_EXECUTION)->where('id')->eq($bug->execution)->fetch('parent');
|
||||
|
||||
/* Assign the bug to the person in charge of the module. */
|
||||
@@ -236,6 +245,13 @@ class bugModel extends model
|
||||
/* When the bug is created by uploading an image, add the image to the step of the bug. */
|
||||
foreach($bugs as $i => $bug)
|
||||
{
|
||||
$laneID = isset($output['laneID']) ? $output['laneID'] : 0;
|
||||
if(isset($bug->laneID))
|
||||
{
|
||||
$laneID = $bug->laneID;
|
||||
unset($bug->laneID);
|
||||
}
|
||||
|
||||
if(!empty($data->uploadImage[$i]))
|
||||
{
|
||||
$fileName = $data->uploadImage[$i];
|
||||
@@ -274,8 +290,11 @@ class bugModel extends model
|
||||
|
||||
if($bug->execution)
|
||||
{
|
||||
if(isset($output['laneID']) and isset($output['columnID'])) $this->kanban->addKanbanCell($bug->execution, $output['laneID'], $output['columnID'], 'bug', $bugID);
|
||||
if(!isset($output['laneID']) or !isset($output['columnID'])) $this->kanban->updateLane($bug->execution, 'bug');
|
||||
$columnID = $this->kanban->getColumnIDByLaneID($laneID, 'unconfirmed');
|
||||
if(empty($columnID)) $columnID = isset($output['columnID']) ? $output['columnID'] : 0;
|
||||
|
||||
if(!empty($laneID) and !empty($columnID)) $this->kanban->addKanbanCell($bug->execution, $laneID, $columnID, 'bug', $bugID);
|
||||
if(empty($laneID) or empty($columnID)) $this->kanban->updateLane($bug->execution, 'bug');
|
||||
|
||||
}
|
||||
/* When the bug is created by uploading the image, add the image to the file of the bug. */
|
||||
@@ -290,7 +309,7 @@ class bugModel extends model
|
||||
unset($file);
|
||||
}
|
||||
|
||||
if(dao::isError()) return print(js::error('bug#' . ($i+1) . dao::getError(true)));
|
||||
if(dao::isError()) return print(js::error('bug#' . ($i) . dao::getError(true)));
|
||||
$actions[$bugID] = $this->action->create('bug', $bugID, 'Opened');
|
||||
}
|
||||
|
||||
@@ -2925,7 +2944,7 @@ class bugModel extends model
|
||||
echo $bug->activatedCount;
|
||||
break;
|
||||
case 'activatedDate':
|
||||
echo substr($bug->activatedDate, 5, 11);
|
||||
echo helper::isZeroDate($bug->activatedDate) ? '' : substr($bug->activatedDate, 5, 11);
|
||||
break;
|
||||
case 'keywords':
|
||||
echo $bug->keywords;
|
||||
|
||||
@@ -51,6 +51,10 @@
|
||||
<th class='c-execution<?php echo zget($visibleFields, 'execution', ' hidden') . zget($requiredFields, 'execution', '', ' required');?>'><?php echo (isset($project->model) and $project->model == 'kanban') ? $lang->bug->kanban : $lang->bug->execution;?></th>
|
||||
<th class='c-build required'><?php echo $lang->bug->openedBuild;?></th>
|
||||
<th class='c-title required'><?php echo $lang->bug->title;?></th>
|
||||
<?php if(isset($executionType) and $executionType == 'kanban'):?>
|
||||
<th class='c-execution'><?php echo $lang->kanbancard->region;?></th>
|
||||
<th class='c-execution'><?php echo $lang->kanbancard->lane;?></th>
|
||||
<?php endif;?>
|
||||
<th class='c-date<?php echo zget($visibleFields, 'deadline', ' hidden') . zget($requiredFields, 'deadline', '', ' required');?>'><?php echo $lang->bug->deadline;?></th>
|
||||
<th class='c-steps<?php echo zget($visibleFields, 'steps', ' hidden') . zget($requiredFields, 'steps', '', ' required');?>'><?php echo $lang->bug->steps;?></th>
|
||||
<th class='c-type<?php echo zget($visibleFields, 'type', ' hidden') . zget($requiredFields, 'type', '', ' required');?>'><?php echo $lang->typeAB;?></th>
|
||||
@@ -74,19 +78,19 @@
|
||||
$lang->bug->osList += array('ditto' => $lang->bug->ditto);
|
||||
$lang->bug->browserList += array('ditto' => $lang->bug->ditto);
|
||||
?>
|
||||
<?php $i = 0; ?>
|
||||
<?php $i = 1; ?>
|
||||
<?php if(!empty($titles)):?>
|
||||
<?php foreach($titles as $bugTitle => $fileName):?>
|
||||
<?php
|
||||
$moduleID = $i == 0 ? $moduleID : 'ditto';
|
||||
$executionID = $i == 0 ? $executionID : 'ditto';
|
||||
$type = $i == 0 ? '' : 'ditto';
|
||||
$pri = $i == 0 ? 0 : 'ditto';
|
||||
$os = $i == 0 ? '' : 'ditto';
|
||||
$browser = $i == 0 ? '' : 'ditto';
|
||||
$moduleID = $i == 1 ? $moduleID : 'ditto';
|
||||
$executionID = $i == 1 ? $executionID : 'ditto';
|
||||
$type = $i == 1 ? '' : 'ditto';
|
||||
$pri = $i == 1 ? 0 : 'ditto';
|
||||
$os = $i == 1 ? '' : 'ditto';
|
||||
$browser = $i == 1 ? '' : 'ditto';
|
||||
?>
|
||||
<tr>
|
||||
<td class='text-center'><?php echo $i+1;?></td>
|
||||
<td class='text-center'><?php echo $i;?></td>
|
||||
<td class='<?php echo zget($visibleFields, $product->type, ' hidden')?>' style='overflow:visible'><?php echo html::select("branches[$i]", $branches, $branch, "class='form-control chosen' onchange='setBranchRelated(this.value, $productID, $i)'");?></td>
|
||||
<td><?php echo html::select("modules[$i]", $moduleOptionMenu, $moduleID, "class='form-control chosen'");?></td>
|
||||
<td class='<?php echo zget($visibleFields, 'execution', ' hidden')?>' style='overflow:visible'><?php echo html::select("executions[$i]", $executions, $executionID, "class='form-control chosen' onchange='loadExecutionBuilds($productID, this.value, $i)'");?></td>
|
||||
@@ -105,6 +109,10 @@
|
||||
</div>
|
||||
</div>
|
||||
</td>
|
||||
<?php if(isset($executionType) and $executionType == 'kanban'):?>
|
||||
<td><?php echo html::select("regions[$i]", $regionPairs, $regionID, "class='form-control chosen'");?></td>
|
||||
<td><?php echo html::select("lanes[$i]", $lanePairs, $laneID, "class='form-control chosen'");?></td>
|
||||
<?php endif;?>
|
||||
<td class='<?php echo zget($visibleFields, 'deadline', 'hidden')?>'><?php echo html::input("deadlines[$i]", '', "class='form-control form-date'");?></td>
|
||||
<td class='<?php echo zget($visibleFields, 'steps', 'hidden')?>'><?php echo html::textarea("stepses[$i]", '', "rows='1' class='form-control autosize'");?></td>
|
||||
<td class='<?php echo zget($visibleFields, 'type', 'hidden')?>' style='overflow:visible'> <?php echo html::select("types[$i]", $lang->bug->typeList, $type, "class='form-control chosen'");?></td>
|
||||
@@ -119,7 +127,7 @@
|
||||
<?php endforeach;?>
|
||||
<?php endif;?>
|
||||
<?php $nextStart = $i;?>
|
||||
<?php for($i = $nextStart; $i < $config->bug->batchCreate; $i++):?>
|
||||
<?php for($i = $nextStart; $i <= $config->bug->batchCreate; $i++):?>
|
||||
<?php
|
||||
$moduleID = $i - $nextStart == 0 ? $moduleID : 'ditto';
|
||||
$executionID = $i - $nextStart == 0 ? $executionID : 'ditto';
|
||||
@@ -129,7 +137,7 @@
|
||||
$browser = $i - $nextStart == 0 ? '' : 'ditto';
|
||||
?>
|
||||
<tr>
|
||||
<td><?php echo $i+1;?></td>
|
||||
<td><?php echo $i;?></td>
|
||||
<td class='<?php echo zget($visibleFields, $product->type, ' hidden')?>' style='overflow:visible'><?php echo html::select("branches[$i]", $branches, $branch, "class='form-control chosen' onchange='setBranchRelated(this.value, $productID, $i)'");?></td>
|
||||
<td><?php echo html::select("modules[$i]", $moduleOptionMenu, $moduleID, "class='form-control chosen'");?></td>
|
||||
<td class='<?php echo zget($visibleFields, 'execution', ' hidden')?>' style='overflow:visible'><?php echo html::select("executions[$i]", $executions, $executionID, "class='form-control chosen' onchange='loadExecutionBuilds($productID, this.value, $i)'");?></td>
|
||||
@@ -148,6 +156,10 @@
|
||||
</div>
|
||||
</div>
|
||||
</td>
|
||||
<?php if(isset($executionType) and $executionType == 'kanban'):?>
|
||||
<td><?php echo html::select("regions[$i]", $regionPairs, $regionID, "class='form-control chosen' onchange='setLane(this.value, $i)'");?></td>
|
||||
<td><?php echo html::select("lanes[$i]", $lanePairs, $laneID, "class='form-control chosen'");?></td>
|
||||
<?php endif;?>
|
||||
<td class='<?php echo zget($visibleFields, 'deadline', 'hidden')?>'><?php echo html::input("deadlines[$i]", '', "class='form-control form-date'");?></td>
|
||||
<td class='<?php echo zget($visibleFields, 'steps', 'hidden')?>'><?php echo html::textarea("stepses[$i]", '', "rows='1' class='form-control autosize'");?></td>
|
||||
<td class='<?php echo zget($visibleFields, 'type', 'hidden')?>' style='overflow:visible'> <?php echo html::select("types[$i]", $lang->bug->typeList, $type, "class='form-control chosen'");?></td>
|
||||
|
||||
@@ -237,7 +237,7 @@ $currentBrowseType = isset($lang->bug->mySelects[$browseType]) && in_array($brow
|
||||
<form class='main-table table-bug' method='post' id='bugForm' <?php if(!$useDatatable) echo "data-ride='table'";?>>
|
||||
<?php endif;?>
|
||||
<div class="table-header fixed-right">
|
||||
<nav class="btn-toolbar pull-right"></nav>
|
||||
<nav class="btn-toolbar pull-right setting"></nav>
|
||||
</div>
|
||||
<?php
|
||||
$vars = "productID=$productID&branch=$branch&browseType=$browseType¶m=$param&orderBy=%s&recTotal={$pager->recTotal}&recPerPage={$pager->recPerPage}";
|
||||
|
||||
@@ -199,6 +199,18 @@ if($this->app->tab == 'project') js::set('objectID', $projectID);
|
||||
</td>
|
||||
</tr>
|
||||
<?php endif;?>
|
||||
<?php if(isset($executionType) and $executionType == 'kanban'):?>
|
||||
<tr>
|
||||
<th><?php echo $lang->kanbancard->region;?></th>
|
||||
<td><?php echo html::select('region', $regionPairs, $regionID, "onchange='setLane(this.value)' class='form-control chosen'");?></td>
|
||||
<td>
|
||||
<div class='input-group'>
|
||||
<div class="input-group-addon"><?php echo $lang->kanbancard->lane;?></div>
|
||||
<?php echo html::select('lane', $lanePairs, $laneID, "class='form-control chosen'");?>
|
||||
</div>
|
||||
</td>
|
||||
</tr>
|
||||
<?php endif;?>
|
||||
<tr>
|
||||
<th><?php echo $lang->bug->title;?></th>
|
||||
<td colspan='2'>
|
||||
|
||||
@@ -18,7 +18,7 @@
|
||||
<tr>
|
||||
<td style='padding: 10px; background-color: #F8FAFE; border: none; font-size: 14px; font-weight: 500; border-bottom: 1px solid #e5e5e5;'>
|
||||
<?php $color = empty($object->color) ? '#333' : $object->color;?>
|
||||
<?php echo html::a(zget($this->config->mail, 'domain', common::getSysURL()) . helper::createLink('bug', 'view', "bugID=$object->id", 'html'), $mailTitle, '', "style='color: {$color}; text-decoration: underline;'");?>
|
||||
<?php echo html::a($domain . helper::createLink('bug', 'view', "bugID=$object->id", 'html'), $mailTitle, '', "style='color: {$color}; text-decoration: underline;'");?>
|
||||
</td>
|
||||
</tr>
|
||||
</table>
|
||||
|
||||
@@ -117,7 +117,7 @@
|
||||
{
|
||||
common::printIcon('bug', 'create', $copyParams, $bug, 'button', 'copy');
|
||||
}
|
||||
common::printIcon('bug', 'delete', $params, $bug, 'button', 'trash', 'hiddenwin');
|
||||
common::printIcon('bug', 'delete', $params, $bug, 'button', 'trash', 'hiddenwin', 'showinonlybody');
|
||||
?>
|
||||
<?php endif;?>
|
||||
</div>
|
||||
|
||||
@@ -323,7 +323,7 @@ class buildModel extends model
|
||||
$buildID = (int)$buildID;
|
||||
$oldBuild = $this->dao->select('*')->from(TABLE_BUILD)->where('id')->eq($buildID)->fetch();
|
||||
$build = fixer::input('post')->stripTags($this->config->build->editor->edit['id'], $this->config->allowedTags)
|
||||
->setIF(!isset($this->post->branch), 'branch', $oldBuild->branch)
|
||||
->setIF(!isset($_POST['branch']), 'branch', $oldBuild->branch)
|
||||
->setDefault('product', $oldBuild->product)
|
||||
->cleanInt('product,branch,execution')
|
||||
->remove('allchecker,resolvedBy,files,labels,uid')
|
||||
|
||||
@@ -662,6 +662,7 @@ $lang->navGroup->entry = 'admin';
|
||||
$lang->navGroup->extension = 'admin';
|
||||
$lang->navGroup->action = 'admin';
|
||||
$lang->navGroup->convert = 'admin';
|
||||
$lang->navGroup->stage = 'admin';
|
||||
|
||||
$lang->navGroup->search = 'search';
|
||||
$lang->navGroup->index = 'index';
|
||||
|
||||
@@ -2708,12 +2708,12 @@ EOD;
|
||||
$response->errcode = $this->config->entry->errcode[$code];
|
||||
$response->errmsg = urlencode($this->lang->entry->errmsg[$code]);
|
||||
|
||||
return print(urldecode(json_encode($response)));
|
||||
die(urldecode(json_encode($response)));
|
||||
}
|
||||
else
|
||||
{
|
||||
$response->error = $code;
|
||||
return print(urldecode(json_encode($response)));
|
||||
die(urldecode(json_encode($response)));
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -34,7 +34,7 @@ $uid = uniqid('');
|
||||
'emoticons', 'image', 'insertfile', 'hr', '|', 'link', 'unlink', '/',
|
||||
'undo', 'redo', '|', 'selectall', 'cut', 'copy', 'paste', '|', 'plainpaste', 'wordpaste', '|', 'removeformat', 'clearhtml','quickformat', '|',
|
||||
'indent', 'outdent', 'subscript', 'superscript', '|',
|
||||
'table', 'code', '|', 'pagebreak', 'anchor', '|',
|
||||
'table', 'code', 'pagebreak',
|
||||
'fullscreen', 'source', 'preview', 'about'];
|
||||
var editorToolsMap = {fullTools: fullTools, simpleTools: simpleTools, bugTools: bugTools};
|
||||
|
||||
|
||||
@@ -1,4 +1,2 @@
|
||||
#whiteListBox .input-group:last-child {margin-top: 10px;}
|
||||
#mailtoGroup .input-group-btn > .btn {margin-left: -1px !important;}
|
||||
#mailtoGroup .chosen-container-single a {border-left-width: 0px;}
|
||||
.fullscreen-save, .markdown-fullscreen-save {position: fixed; top: 10px; right: 30px; z-index: 999999;}
|
||||
|
||||
@@ -588,6 +588,7 @@ class docModel extends model
|
||||
{
|
||||
$now = helper::now();
|
||||
$doc = fixer::input('post')
|
||||
->callFunc('title', 'trim')
|
||||
->add('addedBy', $this->app->user->account)
|
||||
->add('addedDate', $now)
|
||||
->add('editedBy', $this->app->user->account)
|
||||
@@ -684,6 +685,7 @@ class docModel extends model
|
||||
|
||||
$now = helper::now();
|
||||
$doc = fixer::input('post')->setDefault('module', 0)
|
||||
->callFunc('title', 'trim')
|
||||
->stripTags($this->config->doc->editor->edit['id'], $this->config->allowedTags)
|
||||
->setDefault('users', '')
|
||||
->setDefault('groups', '')
|
||||
|
||||
@@ -18,7 +18,7 @@
|
||||
<tr>
|
||||
<td style='padding: 10px; background-color: #F8FAFE; border: none; font-size: 14px; font-weight: 500; border-bottom: 1px solid #e5e5e5;'>
|
||||
<?php $color = empty($object->color) ? '#333' : $object->color;?>
|
||||
<?php echo html::a(zget($this->config->mail, 'domain', common::getSysURL()) . helper::createLink('doc', 'view', "docID=$object->id", 'html'), $mailTitle, '', "style='color: {$color}; text-decoration: underline;'");?>
|
||||
<?php echo html::a($domain . helper::createLink('doc', 'view', "docID=$object->id", 'html'), $mailTitle, '', "style='color: {$color}; text-decoration: underline;'");?>
|
||||
</td>
|
||||
</tr>
|
||||
</table>
|
||||
|
||||
@@ -773,12 +773,20 @@ class execution extends control
|
||||
{
|
||||
foreach($products as $product) $productModules += $this->tree->getOptionMenu($product->id, 'story', 0, $product->branches);
|
||||
}
|
||||
foreach($productModules as $branchID => $moduleList)
|
||||
|
||||
if(defined('TUTORIAL'))
|
||||
{
|
||||
foreach($moduleList as $moduleID => $moduleName)
|
||||
$modules = $this->loadModel('tutorial')->getModulePairs();
|
||||
}
|
||||
else
|
||||
{
|
||||
foreach($productModules as $branchID => $moduleList)
|
||||
{
|
||||
if($moduleID and !isset($executionModules[$moduleID])) continue;
|
||||
$modules[$moduleID] = ((count($products) >= 2 and $moduleID) ? $product->name : '') . $moduleName;
|
||||
foreach($moduleList as $moduleID => $moduleName)
|
||||
{
|
||||
if($moduleID and !isset($executionModules[$moduleID])) continue;
|
||||
$modules[$moduleID] = ((count($products) >= 2 and $moduleID) ? $product->name : '') . $moduleName;
|
||||
}
|
||||
}
|
||||
}
|
||||
$actionURL = $this->createLink('execution', 'story', "executionID=$executionID&orderBy=$orderBy&type=bySearch&queryID=myQueryID");
|
||||
@@ -1304,11 +1312,12 @@ class execution extends control
|
||||
}
|
||||
}
|
||||
|
||||
if(!empty($projectID) and $project->model == 'kanban' and $this->app->tab == 'project') return $this->send(array('result' => 'success', 'message' => $this->lang->saveSuccess, 'locate' => $this->createLink('project', 'index', "projectID=$projectID")));
|
||||
if(!empty($projectID) and $project->model == 'kanban') return $this->send(array('result' => 'success', 'message' => $this->lang->saveSuccess, 'locate' => inlink('kanban', "executionID=$executionID")));
|
||||
if(!empty($projectID) and $project->model == 'kanban' and $this->app->tab == 'project') return $this->send(array('result' => 'success', 'locate' => $this->createLink('project', 'index', "projectID=$projectID")));
|
||||
if(!empty($projectID) and $project->model == 'kanban') return $this->send(array('result' => 'success', 'locate' => inlink('kanban', "executionID=$executionID")));
|
||||
|
||||
$this->view->title = $this->lang->execution->tips;
|
||||
$this->view->tips = $this->fetch('execution', 'tips', "executionID=$executionID");
|
||||
$this->view->defaultURL = isset($this->session->closeTipsList) ? $this->session->closeTipsList : $this->createLink('execution', 'task', 'executionID=' . $executionID);
|
||||
$this->view->executionID = $executionID;
|
||||
$this->view->projectID = $projectID;
|
||||
$this->view->project = $project;
|
||||
@@ -1402,13 +1411,6 @@ class execution extends control
|
||||
{
|
||||
$execution = $this->execution->getById($executionID);
|
||||
$this->loadModel('kanban')->createRDKanban($execution);
|
||||
|
||||
if(dao::isError()) return $this->send(array('result' => 'fail', 'message' => dao::getError()));
|
||||
|
||||
$link= $this->config->vision != 'lite' ? $this->createLink('project', 'index', "projectID=$projectID") : $this->createLink('project', 'execution', "status=all&projectID=$projectID");
|
||||
if($this->app->tab == 'project') return $this->send(array('result' => 'success', 'message' => $this->lang->saveSuccess, 'locate' => $link));
|
||||
|
||||
return $this->send(array('result' => 'success', 'message' => $this->lang->saveSuccess, 'locate' => inlink('kanban', "executionID=$executionID")));
|
||||
}
|
||||
|
||||
if(!empty($planID))
|
||||
@@ -1417,8 +1419,15 @@ class execution extends control
|
||||
}
|
||||
else
|
||||
{
|
||||
if(!empty($projectID) and $project->model == 'kanban' and $this->app->tab == 'project') return $this->send(array('result' => 'success', 'message' => $this->lang->saveSuccess, 'locate' => $this->createLink('project', 'index', "projectID=$projectID")));
|
||||
if(!empty($projectID) and $project->model == 'kanban') return $this->send(array('result' => 'success', 'message' => $this->lang->saveSuccess, 'locate' => inlink('kanban', "executionID=$executionID")));
|
||||
if(!empty($projectID) and $project->model == 'kanban')
|
||||
{
|
||||
if(dao::isError()) return $this->send(array('result' => 'fail', 'message' => dao::getError()));
|
||||
|
||||
$link = $this->config->vision != 'lite' ? $this->createLink('project', 'index', "projectID=$projectID") : $this->createLink('project', 'execution', "status=all&projectID=$projectID");
|
||||
if($this->app->tab == 'project') return $this->send(array('result' => 'success', 'message' => $this->lang->saveSuccess, 'locate' => $link));
|
||||
|
||||
return $this->send(array('result' => 'success', 'message' => $this->lang->saveSuccess, 'locate' => inlink('kanban', "executionID=$executionID")));
|
||||
}
|
||||
return $this->send(array('result' => 'success', 'message' => $this->lang->saveSuccess, 'locate' => inlink('create', "projectID=$projectID&executionID=$executionID")));
|
||||
}
|
||||
}
|
||||
@@ -1565,7 +1574,8 @@ class execution extends control
|
||||
$position[] = html::a($browseExecutionLink, $execution->name);
|
||||
$position[] = $this->lang->execution->edit;
|
||||
|
||||
$allProducts = array(0 => '') + $this->product->getProducts($execution->project, 'noclosed', '', false);
|
||||
$allProducts = $this->config->systemMode == 'classic' ? $this->product->getPairs('noclosed') : $this->product->getProducts($execution->project, 'noclosed', '', false);
|
||||
$allProducts = array(0 => '') + $allProducts;
|
||||
|
||||
$this->loadModel('productplan');
|
||||
$productPlans = array(0 => '');
|
||||
@@ -1609,6 +1619,8 @@ class execution extends control
|
||||
$rdUsers = $this->user->getPairs('noclosed|nodeleted|devfirst', $execution->RD, $this->config->maxCount);
|
||||
if(!empty($this->config->user->moreLink)) $this->config->moreLinks["RD"] = $this->config->user->moreLink;
|
||||
|
||||
$project = $this->project->getById($execution->project);
|
||||
|
||||
$this->view->title = $title;
|
||||
$this->view->position = $position;
|
||||
$this->view->executions = $executions;
|
||||
@@ -1618,8 +1630,7 @@ class execution extends control
|
||||
$this->view->qdUsers = $qdUsers;
|
||||
$this->view->rdUsers = $rdUsers;
|
||||
$this->view->users = $this->user->getPairs('nodeleted|noclosed');
|
||||
$this->view->allProjects = $this->project->getPairsByModel('all', 0, 'noclosed');
|
||||
$this->view->project = $this->project->getById($execution->project);
|
||||
$this->view->project = $project;
|
||||
$this->view->groups = $this->loadModel('group')->getPairs();
|
||||
$this->view->allProducts = $allProducts;
|
||||
$this->view->linkedProducts = $linkedProducts;
|
||||
@@ -1631,6 +1642,7 @@ class execution extends control
|
||||
$this->view->productPlans = $productPlans;
|
||||
$this->view->branchGroups = $this->execution->getBranchByProduct(array_keys($linkedProducts), $this->config->systemMode == 'new' ? $execution->project : 0, 'noclosed', $linkedBranchList);
|
||||
$this->view->teamMembers = $this->execution->getTeamMembers($executionID);
|
||||
if($this->config->systemMode == 'new') $this->view->allProjects = $this->project->getPairsByModel($project->model, 0, 'noclosed');
|
||||
$this->display();
|
||||
}
|
||||
|
||||
@@ -1648,6 +1660,8 @@ class execution extends control
|
||||
if($this->post->names)
|
||||
{
|
||||
$allChanges = $this->execution->batchUpdate();
|
||||
if(dao::isError()) return print(js::error(dao::getError()));
|
||||
|
||||
if(!empty($allChanges))
|
||||
{
|
||||
foreach($allChanges as $executionID => $changes)
|
||||
@@ -2718,6 +2732,8 @@ class execution extends control
|
||||
{
|
||||
$this->loadModel('story');
|
||||
$this->loadModel('product');
|
||||
$this->loadModel('tree');
|
||||
$this->loadModel('branch');
|
||||
|
||||
/* Init objectID */
|
||||
$originObjectID = $objectID;
|
||||
@@ -2733,6 +2749,7 @@ class execution extends control
|
||||
$object = $this->project->getByID($objectID, $this->app->tab == 'project' ? 'project' : 'sprint,stage,kanban');
|
||||
$products = $this->product->getProducts($objectID);
|
||||
$browseLink = $this->createLink($this->app->tab == 'project' ? 'projectstory' : 'execution', 'story', "objectID=$objectID");
|
||||
$queryID = ($browseType == 'bySearch') ? (int)$param : 0;
|
||||
|
||||
$this->session->set('storyList', $this->app->getURI(true), $this->app->tab); // Save session.
|
||||
|
||||
@@ -2770,33 +2787,37 @@ class execution extends control
|
||||
{
|
||||
$this->project->setMenu($object->id);
|
||||
}
|
||||
else if($object->type == 'sprint' or $object->type == 'stage')
|
||||
elseif($object->type == 'sprint' or $object->type == 'stage')
|
||||
{
|
||||
$this->execution->setMenu($object->id);
|
||||
}
|
||||
|
||||
$queryID = ($browseType == 'bySearch') ? (int)$param : 0;
|
||||
|
||||
/* Set modules and branches. */
|
||||
$modules = array();
|
||||
$branchIDList = array(BRANCH_MAIN);
|
||||
$branches = $this->project->getBranchesByProject($objectID);
|
||||
$productType = 'normal';
|
||||
$this->loadModel('tree');
|
||||
$this->loadModel('branch');
|
||||
foreach($products as $product)
|
||||
|
||||
if(defined('TUTORIAL'))
|
||||
{
|
||||
$productModules = $this->tree->getOptionMenu($product->id, 'story', 0, defined('TUTORIAL') ? array(0 => 0) : array_keys($branches[$product->id]));
|
||||
foreach($productModules as $branch => $branchModules)
|
||||
$modules = $this->loadModel('tutorial')->getModulePairs();
|
||||
}
|
||||
else
|
||||
{
|
||||
foreach($products as $product)
|
||||
{
|
||||
foreach($branchModules as $moduleID => $moduleName) $modules[$moduleID] = ((count($products) >= 2 and $moduleID != 0) ? $product->name : '') . $moduleName;
|
||||
}
|
||||
if($product->type != 'normal')
|
||||
{
|
||||
$productType = $product->type;
|
||||
if(isset($branches[$product->id]))
|
||||
$productModules = $this->tree->getOptionMenu($product->id, 'story', 0, array_keys($branches[$product->id]));
|
||||
foreach($productModules as $branch => $branchModules)
|
||||
{
|
||||
foreach($branches[$product->id] as $branchID => $branch) $branchIDList[$branchID] = $branchID;
|
||||
foreach($branchModules as $moduleID => $moduleName) $modules[$moduleID] = ((count($products) >= 2 and $moduleID != 0) ? $product->name : '') . $moduleName;
|
||||
}
|
||||
if($product->type != 'normal')
|
||||
{
|
||||
$productType = $product->type;
|
||||
if(isset($branches[$product->id]))
|
||||
{
|
||||
foreach($branches[$product->id] as $branchID => $branch) $branchIDList[$branchID] = $branchID;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -3246,6 +3267,8 @@ class execution extends control
|
||||
*/
|
||||
public function all($status = 'all', $projectID = 0, $orderBy = 'order_asc', $productID = 0, $recTotal = 0, $recPerPage = 10, $pageID = 1)
|
||||
{
|
||||
$this->session->set('closeTipsList', $this->app->getURI(true));
|
||||
|
||||
$this->app->loadLang('my');
|
||||
$this->app->loadLang('product');
|
||||
$this->app->loadLang('stage');
|
||||
|
||||
@@ -0,0 +1 @@
|
||||
#importBugForm {min-height: 250px;}
|
||||
@@ -34,12 +34,12 @@
|
||||
.region .kanban-header {border-bottom: none!important; min-width: max-content; min-width: -moz-max-content;}
|
||||
.region .kanban-header-col > .title {max-width: 80% !important;}
|
||||
.region .kanban-header-col > .title {margin: 0}
|
||||
.region .kanban-header-col > .title > span {display: inline-block; overflow: hidden; padding-right:2px; position: initial; max-width: 140px !important;}
|
||||
.region .kanban-header-col > .title > span {display: inline-block; overflow: hidden; padding-right:2px; position: initial; max-width: 85px !important;}
|
||||
.region .kanban-header-col > .title > .text-grey {opacity: .5; font-weight: bold; color: #8b91a2;}
|
||||
.region .kanban-header-col > .title > .count {opacity: .5; font-weight: bold; color: #8b91a2;}
|
||||
.region .kanban-header-col > .title > .error {color: #333333; padding-left: 2px; font-size: 10px; padding-top: 1px; padding-right: 2px;}
|
||||
.kanban-affixed .kanban-header-col > .title > .text {color: #fff!important}
|
||||
.region .kanban-header-col > .actions {position: relative; right: -30px;}
|
||||
.region .kanban-header-col > .actions {position: relative; right: 5px;}
|
||||
.region .kanban-header-parent-col > .actions {position: absolute; right: 0px;}
|
||||
.region .kanban-header-sub-cols .actions {position: absolute; right: 0px;}
|
||||
|
||||
@@ -66,6 +66,7 @@
|
||||
|
||||
.kanban-col[data-type=ADD] {display: none;}
|
||||
.kanban-col[data-type=EMPTY] {display: none;}
|
||||
.kanban-col {padding-right: 0px !important;}
|
||||
.kanban-item:hover .title {padding-right: 10px;}
|
||||
.gray .actions {display:none;}
|
||||
|
||||
|
||||
@@ -28,6 +28,7 @@
|
||||
|
||||
.kanban-affixed .kanban-header-col > .title > .text,
|
||||
.kanban-affixed .kanban-header-col > .title > .count {color: #fff!important;}
|
||||
.kanban-header-col > .title > .text {max-width: 110px !important;}
|
||||
|
||||
#kanbanContainer {margin: 0;}
|
||||
#kanbanContainer > .panel-body {overflow: auto;}
|
||||
|
||||
@@ -265,31 +265,32 @@ function createColumnMenu(options)
|
||||
*/
|
||||
function createColumnCreateMenu(options)
|
||||
{
|
||||
var $col = options.$trigger.closest('.kanban-col');
|
||||
var col = $col.data('col');
|
||||
var items = [];
|
||||
var laneID = col.$kanbanData.lanes[0].id ? col.$kanbanData.lanes[0].id : 0;
|
||||
var $col = options.$trigger.closest('.kanban-col');
|
||||
var col = $col.data('col');
|
||||
var items = [];
|
||||
var laneID = col.$kanbanData.lanes[0].id ? col.$kanbanData.lanes[0].id : 0;
|
||||
var regionID = col.$kanbanData.region;
|
||||
|
||||
if(col.type == 'backlog')
|
||||
{
|
||||
if(priv.canCreateStory) items.push({label: storyLang.create, url: $.createLink('story', 'create', 'productID=' + productID + '&branch=0&moduleID=0&storyID=0&objectID=' + executionID + '&bugID=0&planID=0&todoID=0&extra=laneID=' + laneID + ',columnID=' + col.id, '', true), className: 'iframe', attrs: {'data-toggle': 'modal', 'data-width': '80%'}});
|
||||
if(priv.canBatchCreateStory) items.push({label: executionLang.batchCreateStory, url: productCount > 1 ? '#batchCreateStory' : $.createLink('story', 'batchcreate', 'productID=' + productID + '&branch=0&moduleID=0&storyID=0&executionID=' + executionID + '&plan=0&type=story&extra=laneID=' + laneID + ',columnID=' + col.id, '', true), className: 'iframe',attrs: {'data-toggle': 'modal', 'data-width': '90%'}});
|
||||
if(priv.canCreateStory) items.push({label: storyLang.create, url: $.createLink('story', 'create', 'productID=' + productID + '&branch=0&moduleID=0&storyID=0&objectID=' + executionID + '&bugID=0&planID=0&todoID=0&extra=regionID=' + regionID + ',laneID=' + laneID + ',columnID=' + col.id, '', true), className: 'iframe', attrs: {'data-toggle': 'modal', 'data-width': '80%'}});
|
||||
if(priv.canBatchCreateStory) items.push({label: executionLang.batchCreateStory, url: productCount > 1 ? '#batchCreateStory' : $.createLink('story', 'batchcreate', 'productID=' + productID + '&branch=0&moduleID=0&storyID=0&executionID=' + executionID + '&plan=0&type=story&extra=regionID=' + regionID + ',laneID=' + laneID + ',columnID=' + col.id, '', true), className: 'iframe',attrs: {'data-toggle': 'modal', 'data-width': '90%'}});
|
||||
if(priv.canLinkStory) items.push({label: executionLang.linkStory, url: $.createLink('execution', 'linkStory', 'executionID=' + executionID + '&browseType=¶m=0&recTotal=0&recPerPage=50,&pageID=1&extra=laneID=' + laneID + ',columnID=' + col.id, '', true), className: 'iframe', attrs: {'data-toggle': 'modal', 'data-width': '90%'}});
|
||||
if(priv.canLinkStoryByPlan) items.push({label: executionLang.linkStoryByPlan, url: '#linkStoryByPlan', 'attrs' : {'data-toggle': 'modal', 'data-target': '#linkStoryByPlan','data-col' : col.id, 'data-lane' : laneID, 'class' : 'linkStoryByPlanButton'}});
|
||||
}
|
||||
else if(col.type == 'unconfirmed')
|
||||
{
|
||||
if(priv.canCreateBug) items.push({label: bugLang.create, url: $.createLink('bug', 'create', 'productID=0&moduleID=0&extra=laneID=' + laneID + ',columnID=' + col.id + ',executionID=' + executionID, '', true), className: 'iframe', attrs: {'data-toggle': 'modal', 'data-width': '80%'}});
|
||||
if(priv.canCreateBug) items.push({label: bugLang.create, url: $.createLink('bug', 'create', 'productID=' + productID + '&moduleID=0&extra=regionID=' + regionID + ',laneID=' + laneID + ',columnID=' + col.id + ',executionID=' + executionID, '', true), className: 'iframe', attrs: {'data-toggle': 'modal', 'data-width': '80%'}});
|
||||
if(priv.canBatchCreateBug)
|
||||
{
|
||||
if(productNum > 1) items.push({label: bugLang.batchCreate, url: '#batchCreateBug', 'attrs' : {'data-toggle': 'modal'}});
|
||||
else items.push({label: bugLang.batchCreate, url: $.createLink('bug', 'batchcreate', 'productID=' + productID + '&branch=&executionID=' + executionID + '&module=0&extra=laneID=' + laneID + ',columnID=' + col.id, '', true), className: 'iframe', attrs: {'data-toggle': 'modal', 'data-width': '90%'}});
|
||||
else items.push({label: bugLang.batchCreate, url: $.createLink('bug', 'batchcreate', 'productID=' + productID + '&branch=&executionID=' + executionID + '&module=0&extra=regionID=' + regionID + ',laneID=' + laneID + ',columnID=' + col.id, '', true), className: 'iframe', attrs: {'data-toggle': 'modal', 'data-width': '90%'}});
|
||||
}
|
||||
}
|
||||
else if(col.type == 'wait')
|
||||
{
|
||||
if(priv.canCreateTask) items.push({label: taskLang.create, url: $.createLink('task', 'create', 'executionID=' + executionID + "&storyID=0&moduleID=0&taskID=0&todoID=0&extra=laneID=" + laneID + ",columnID=" + col.id, '', true), className: 'iframe', attrs: {'data-toggle': 'modal', 'data-width': '80%'}});
|
||||
if(priv.canBatchCreateTask) items.push({label: taskLang.batchCreate, url: $.createLink('task', 'batchcreate', 'executionID=' + executionID + "&storyID=0&moduleID=0&taskID=0&iframe=0&extra=laneID=" + laneID + ",columnID=" + col.id, '', true), className: 'iframe', attrs: {'data-toggle': 'modal', 'data-width': '80%'}});
|
||||
if(priv.canCreateTask) items.push({label: taskLang.create, url: $.createLink('task', 'create', 'executionID=' + executionID + "&storyID=0&moduleID=0&taskID=0&todoID=0&extra=regionID=" + regionID + ",laneID=" + laneID + ",columnID=" + col.id, '', true), className: 'iframe', attrs: {'data-toggle': 'modal', 'data-width': '80%'}});
|
||||
if(priv.canBatchCreateTask) items.push({label: taskLang.batchCreate, url: $.createLink('task', 'batchcreate', 'executionID=' + executionID + "&storyID=0&moduleID=0&taskID=0&iframe=0&extra=regionID=" + regionID + ",laneID=" + laneID + ",columnID=" + col.id, '', true), className: 'iframe', attrs: {'data-toggle': 'modal', 'data-width': '80%'}});
|
||||
if(priv.canImportBug && vision == 'rnd') items.push({label: executionLang.importBug, url: $.createLink('execution', 'importBug', 'executionID=' + executionID + "&storyID=0&moduleID=0&taskID=0&todoID=0&extra=laneID=" + laneID + ",columnID=" + col.id, '', true), className: 'iframe', attrs: {'data-toggle': 'modal', 'data-width': '80%'}});
|
||||
}
|
||||
return items;
|
||||
@@ -548,7 +549,7 @@ function renderBugItem(item, $item, col)
|
||||
if(scaleSize <= 1)
|
||||
{
|
||||
var $actions = $item.find('.actions');
|
||||
if(!$actions.length && (priv.canEditBug || priv.canResolveBug || priv.canConfirmBug || priv.canCopyBug || priv.canToStoryBug))
|
||||
if(!$actions.length && (priv.canEditBug || priv.canResolveBug || priv.canConfirmBug || priv.canCopyBug || priv.canToStoryBug || priv.canDeleteBug))
|
||||
{
|
||||
$actions = $([
|
||||
'<div class="actions">',
|
||||
@@ -862,11 +863,16 @@ function changeCardColType(cardID, fromColID, toColID, fromLaneID, toLaneID, car
|
||||
}
|
||||
else if(toColType == 'developing')
|
||||
{
|
||||
if((fromColType == 'pause' || fromColType == 'canceled' || fromColType == 'closed' || fromColType == 'developed') && priv.canActivateTask)
|
||||
if((fromColType == 'canceled' || fromColType == 'closed' || fromColType == 'developed') && priv.canActivateTask)
|
||||
{
|
||||
var link = createLink('task', 'activate', 'taskID=' + objectID + '&extra=fromColID=' + fromColID + ',toColID=' + toColID + ',fromLaneID=' + fromLaneID + ',toLaneID=' + toLaneID + ',regionID=' + regionID, '', true);
|
||||
showIframe = true;
|
||||
}
|
||||
if(fromColType == 'pause' && priv.canActivateTask)
|
||||
{
|
||||
var link = createLink('task', 'restart', 'taskID=' + objectID, '', true);
|
||||
showIframe = true;
|
||||
}
|
||||
if(fromColType == 'wait' && priv.canStartTask)
|
||||
{
|
||||
var link = createLink('task', 'start', 'taskID=' + objectID + '&extra=fromColID=' + fromColID + ',toColID=' + toColID + ',fromLaneID=' + fromLaneID + ',toLaneID=' + toLaneID + ',regionID=' + regionID, '', true);
|
||||
@@ -971,6 +977,36 @@ function changeCardColType(cardID, fromColID, toColID, fromLaneID, toLaneID, car
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Delete a card.
|
||||
*
|
||||
* @param string objectType
|
||||
* @param int objectID
|
||||
* @param int regionID
|
||||
* @access public
|
||||
* @return void
|
||||
*/
|
||||
function deleteCard(objectType, objectID, regionID)
|
||||
{
|
||||
var objectLang = objectType + 'Lang';
|
||||
var result = confirm(window[objectLang].confirmDelete) ? true : false;
|
||||
|
||||
if(!result) return false;
|
||||
if(!objectID) return false;
|
||||
|
||||
var url = createLink('kanban', 'deleteObjectCard', 'objectType=' + objectType + '&objectID=' + objectID + '®ionID=' + regionID);
|
||||
return $.ajax(
|
||||
{
|
||||
method: 'post',
|
||||
dataType: 'json',
|
||||
url: url,
|
||||
success: function(data)
|
||||
{
|
||||
updateRegion(regionID, data[regionID]);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Close modal and update kanban data.
|
||||
*
|
||||
@@ -1071,6 +1107,7 @@ function createStoryMenu(options)
|
||||
if(priv.canBatchCreateTask && showAction) items.push({label: executionLang.batchWBS, icon: 'pluses', url: createLink('task', 'batchCreate', 'executionID=' + execution.id + '&storyID=' + story.id, '', 'true'), className: 'iframe', attrs: {'data-toggle': 'modal', 'data-width': '80%'}});
|
||||
if(priv.canActivateStory && story.$col.type == 'closed') items.push({label: executionLang.activate, icon: 'magic', url: createLink('story', 'activate', 'storyID=' + story.id, '', 'true'), className: 'iframe', attrs: {'data-toggle': 'modal', 'data-width': '80%'}});
|
||||
if(priv.canUnlinkStory) items.push({label: executionLang.unlinkStory, icon: 'unlink', url: createLink('execution', 'unlinkStory', 'executionID=' + execution.id + '&storyID=' + story.id, '', 'false'), attrs: {target: 'hiddenwin'}});
|
||||
if(priv.canDeleteStory) items.push({label: storyLang.delete, icon: 'trash', onClick: function(){deleteCard('story', story.id, story.$lane.region)}});
|
||||
return items;
|
||||
}
|
||||
|
||||
@@ -1090,6 +1127,7 @@ function createTaskMenu(options)
|
||||
if(priv.canActivateTask && (task.$col.type == 'developed' || task.$col.type == 'canceled' || task.$col.type == 'closed')) items.push({label: executionLang.activate, icon: 'magic', url: createLink('task', 'activate', 'taskID=' + task.id, '', 'true'), className: 'iframe', attrs: {'data-toggle': 'modal', 'data-width': '80%'}});
|
||||
if(priv.canCreateTask) items.push({label: taskLang.copy, icon: 'copy', url: createLink('task', 'create', 'executionID=' + executionID + '&storyID=' + '0' + '&moduleID=' + '0' + '&taskID=' + task.id, '', 'true'), className: 'iframe', attrs: {'data-toggle': 'modal', 'data-width': '80%'}});
|
||||
if(priv.canCancelTask && (task.$col.type == 'wait' || task.$col.type == 'developing' || task.$col.type == 'pause')) items.push({label: taskLang.cancel, icon: 'cancel', url: createLink('task', 'cancel', 'taskID=' + task.id, '', 'true'), className: 'iframe', attrs: {'data-toggle': 'modal', 'data-width': '80%'}});
|
||||
if(priv.canDeleteTask) items.push({label: taskLang.delete, icon: 'trash', onClick: function(){deleteCard('task', task.id, task.$lane.region)}});
|
||||
return items;
|
||||
}
|
||||
|
||||
@@ -1109,6 +1147,7 @@ function createBugMenu(options)
|
||||
if(priv.canCopyBug) items.push({label: bugLang.copy, icon: 'copy', url: createLink('bug', 'create', 'productID=' + productID + '&branch=' + '' + '&extras=bugID=' + bug.id, '', 'true'), className: 'iframe', attrs: {'data-toggle': 'modal', 'data-width': '80%'}});
|
||||
if(priv.canToStoryBug && (bug.$col.type != 'closed')) items.push({label: bugLang.toStory, icon: 'lightbulb', url: createLink('story', 'create', 'product=' + productID + '&branch=' + '0' + '&module=' + '0' + '&story=' + '0' + '&execution=' + '0' + '&bugID=' + bug.id, '', 'true'), className: 'iframe', attrs: {'data-toggle': 'modal', 'data-width': '80%'}});
|
||||
if(priv.canActivateBug && (bug.$col.type == 'fixed') || bug.$col.type == 'testing' || bug.$col.type == 'tested' || bug.$col.type == 'closed') items.push({label: bugLang.activate, icon: 'magic', url: createLink('bug', 'activate', 'bugID=' + bug.id, '', 'true'), className: 'iframe', attrs: {'data-toggle': 'modal', 'data-width': '80%'}});
|
||||
if(priv.canDeleteBug) items.push({label: bugLang.delete, icon: 'trash', onClick: function(){deleteCard('bug', bug.id, bug.$lane.region)}});
|
||||
return items;
|
||||
}
|
||||
|
||||
|
||||
@@ -23,9 +23,9 @@ function setRole(account, roleID)
|
||||
|
||||
function addItem(obj)
|
||||
{
|
||||
var item = $('#addItem').html().replace(/%i%/g, i);
|
||||
$(obj).closest('tr').after('<tr class="addedItem">' + item + '</tr>');
|
||||
var $accounts = $('#hours' + i).closest('tr').find('select:first')
|
||||
var item = $('#addItem').html().replace(/%i%/g, itemIndex);
|
||||
$('<tr class="addedItem">' + item + '</tr>').insertAfter($(obj).closest('tr'));
|
||||
var $accounts = $('#hours' + itemIndex).closest('tr').find('select:first')
|
||||
|
||||
if($accounts.attr('data-pickertype') != 'remote')
|
||||
{
|
||||
@@ -37,7 +37,7 @@ function addItem(obj)
|
||||
var pickerremote = $accounts.attr('data-pickerremote');
|
||||
$accounts.picker({chosenMode: true, remote: pickerremote});
|
||||
}
|
||||
i ++;
|
||||
itemIndex ++;
|
||||
}
|
||||
|
||||
function deleteItem(obj)
|
||||
|
||||
@@ -315,11 +315,15 @@ function renderHeaderCol($col, col, $header, kanban)
|
||||
].join(''));
|
||||
}
|
||||
|
||||
$actions.append([
|
||||
'<a data-contextmenu="column" title="' + kanbanLang.moreAction + '" data-type="' + col.type + '" data-kanban="' + kanban.id + '" data-parent="' + (col.parentType || '') + '">',
|
||||
'<i class="icon icon-ellipsis-v"></i>',
|
||||
'</a>'
|
||||
].join(''));
|
||||
if(priv.canSetWIP || priv.canEditName)
|
||||
{
|
||||
$actions.append([
|
||||
'<a data-contextmenu="column" title="' + kanbanLang.moreAction + '" data-type="' + col.type + '" data-kanban="' + kanban.id + '" data-parent="' + (col.parentType || '') + '">',
|
||||
'<i class="icon icon-ellipsis-v"></i>',
|
||||
'</a>'
|
||||
].join(''));
|
||||
}
|
||||
|
||||
$actions.appendTo($col);
|
||||
}
|
||||
|
||||
@@ -571,11 +575,16 @@ function changeCardColType(cardID, fromColID, toColID, fromLaneID, toLaneID, car
|
||||
}
|
||||
else if(toColType == 'developing')
|
||||
{
|
||||
if((fromColType == 'pause' || fromColType == 'canceled' || fromColType == 'closed' || fromColType == 'developed') && priv.canActivateTask)
|
||||
if((fromColType == 'canceled' || fromColType == 'closed' || fromColType == 'developed') && priv.canActivateTask)
|
||||
{
|
||||
var link = createLink('task', 'activate', 'taskID=' + objectID, '', true);
|
||||
showIframe = true;
|
||||
}
|
||||
if(fromColType == 'pause' && priv.canActivateTask)
|
||||
{
|
||||
var link = createLink('task', 'restart', 'taskID=' + objectID, '', true);
|
||||
showIframe = true;
|
||||
}
|
||||
if(fromColType == 'wait' && priv.canStartTask)
|
||||
{
|
||||
var link = createLink('task', 'start', 'taskID=' + objectID, '', true);
|
||||
@@ -861,7 +870,7 @@ function createStoryMenu(options)
|
||||
var item = {label: this.label, icon: this.icon, url: this.url, attrs: {'data-toggle': 'modal', 'data-type': 'iframe'}};
|
||||
if(this.size) item.attrs['data-width'] = this.size;
|
||||
|
||||
if(this.icon == 'unlink') item = {label: this.label, icon: this.icon, url: this.url, attrs: {'target': 'hiddenwin'}};
|
||||
if(this.icon == 'unlink' || this.icon == 'trash') item = {label: this.label, icon: this.icon, url: this.url, attrs: {'target': 'hiddenwin'}};
|
||||
items.push(item);
|
||||
});
|
||||
|
||||
@@ -883,6 +892,7 @@ function createBugMenu(options)
|
||||
var item = {label: this.label, icon: this.icon, url: this.url, attrs: {'data-toggle': 'modal', 'data-type': 'iframe'}};
|
||||
if(this.size) item.attrs['data-width'] = this.size;
|
||||
|
||||
if(this.icon == 'trash') item = {label: this.label, icon: this.icon, url: this.url, attrs: {'target': 'hiddenwin'}};
|
||||
items.push(item);
|
||||
});
|
||||
|
||||
@@ -904,6 +914,7 @@ function createTaskMenu(options)
|
||||
var item = {label: this.label, icon: this.icon, url: this.url, attrs: {'data-toggle': 'modal', 'data-type': 'iframe'}};
|
||||
if(this.size) item.attrs['data-width'] = this.size;
|
||||
|
||||
if(this.icon == 'trash') item = {label: this.label, icon: this.icon, url: this.url, attrs: {'target': 'hiddenwin'}};
|
||||
items.push(item);
|
||||
});
|
||||
|
||||
|
||||
@@ -14,11 +14,11 @@ $lang->execution->allExecutions = 'All ' . $lang->execution->common . 's';
|
||||
$lang->execution->allExecutionAB = 'Execution List';
|
||||
$lang->execution->id = $lang->executionCommon . ' ID';
|
||||
$lang->execution->type = $lang->executionCommon . 'Type';
|
||||
$lang->execution->name = $lang->executionCommon . 'Name';
|
||||
$lang->execution->code = $lang->executionCommon . 'Code';
|
||||
$lang->execution->name = "{$lang->executionCommon} Name";
|
||||
$lang->execution->code = "{$lang->executionCommon} Code";
|
||||
$lang->execution->projectName = 'Project';
|
||||
$lang->execution->execName = 'Execution Name';
|
||||
$lang->execution->execCode = 'Execution Code';
|
||||
$lang->execution->execName = "{$lang->execution->common} Name";
|
||||
$lang->execution->execCode = "{$lang->execution->common} Code";
|
||||
$lang->execution->execType = 'Execution Type';
|
||||
$lang->execution->stage = 'Stage';
|
||||
$lang->execution->pri = 'Priority';
|
||||
@@ -45,7 +45,7 @@ $lang->execution->totalDays = ' Days';
|
||||
$lang->execution->status = $lang->executionCommon . 'Status';
|
||||
$lang->execution->execStatus = 'Status';
|
||||
$lang->execution->subStatus = 'Sub Status';
|
||||
$lang->execution->desc = $lang->executionCommon . 'Description';
|
||||
$lang->execution->desc = "{$lang->executionCommon} Description";
|
||||
$lang->execution->execDesc = 'Description';
|
||||
$lang->execution->owner = 'Owner';
|
||||
$lang->execution->PO = "{$lang->executionCommon} Owner";
|
||||
@@ -221,8 +221,8 @@ $lang->execution->treeAction = "Execution Tree View";
|
||||
$lang->execution->exportAction = "Export Execution";
|
||||
$lang->execution->computeBurnAction = "Update Burndown";
|
||||
$lang->execution->create = "Create {$lang->executionCommon}";
|
||||
$lang->execution->createExec = "Create Execution";
|
||||
$lang->execution->copyExec = "Copy Execution";
|
||||
$lang->execution->createExec = "Create {$lang->execution->common}";
|
||||
$lang->execution->copyExec = "Copy {$lang->execution->common}";
|
||||
$lang->execution->copy = "Copy {$lang->executionCommon}";
|
||||
$lang->execution->delete = "Delete {$lang->executionCommon}";
|
||||
$lang->execution->deleteAB = "Delete Execution";
|
||||
@@ -347,6 +347,8 @@ $lang->execution->errorSameProducts = "{$lang->executionCommon} cannot
|
||||
$lang->execution->errorSameBranches = "{$lang->executionCommon} cannot be linked to the same branch twice";
|
||||
$lang->execution->errorBegin = "The start time of {$lang->executionCommon} cannot be less than the start time of the project %s.";
|
||||
$lang->execution->errorEnd = "The end time of {$lang->executionCommon} cannot be greater than the end time %s of the project.";
|
||||
$lang->execution->errorLetterProject = "The start time of stage cannot be less than the start time of the project %s.";
|
||||
$lang->execution->errorGreaterProject = "The end time of stage cannot be greater than the end time %s of the project.";
|
||||
$lang->execution->accessDenied = "Your access to {$lang->executionCommon} is denied!";
|
||||
$lang->execution->tips = 'Note';
|
||||
$lang->execution->afterInfo = "{$lang->executionCommon} is created. Next you can ";
|
||||
|
||||
@@ -347,6 +347,8 @@ $lang->execution->errorSameProducts = "{$lang->executionCommon}不能
|
||||
$lang->execution->errorSameBranches = "{$lang->executionCommon}不能关联多个相同的分支。";
|
||||
$lang->execution->errorBegin = "{$lang->executionCommon}的开始时间不能小于所属项目的开始时间%s。";
|
||||
$lang->execution->errorEnd = "{$lang->executionCommon}的截止时间不能大于所属项目的结束时间%s。";
|
||||
$lang->execution->errorLetterProject = "阶段的计划开始时间不能小于所属项目的计划开始时间%s。";
|
||||
$lang->execution->errorGreaterProject = "阶段的计划完成时间不能大于所属项目的计划完成时间%s。";
|
||||
$lang->execution->accessDenied = "您无权访问该{$lang->executionCommon}!";
|
||||
$lang->execution->tips = '提示';
|
||||
$lang->execution->afterInfo = "{$lang->executionCommon}添加成功,您现在可以进行以下操作:";
|
||||
|
||||
+44
-21
@@ -252,6 +252,10 @@ class executionModel extends model
|
||||
if(!isset($executions[$executionID]))
|
||||
{
|
||||
$this->session->set('execution', key($executions), $this->app->tab);
|
||||
|
||||
$execution = $this->dao->select('*')->from(TABLE_EXECUTION)->where('id')->eq($executionID)->andWhere('type')->in('sprint,stage,kanban')->fetch();
|
||||
if(empty($execution)) return js::error($this->lang->notFound);
|
||||
|
||||
if($executionID && strpos(",{$this->app->user->view->sprints},", ",{$executionID},") === false) $this->accessDenied();
|
||||
}
|
||||
|
||||
@@ -448,18 +452,12 @@ class executionModel extends model
|
||||
}
|
||||
|
||||
$products = array_filter($this->post->products);
|
||||
if($oldExecution->type == 'stage' and empty($products))
|
||||
$noLinkTip = $oldExecution->type != 'kanban' ? $this->lang->execution->noLinkProduct : $this->lang->execution->kanbanNoLinkProduct;
|
||||
if(empty($products))
|
||||
{
|
||||
dao::$errors['message'][] = $this->lang->execution->noLinkProduct;
|
||||
dao::$errors['message'][] = $noLinkTip;
|
||||
return false;
|
||||
}
|
||||
|
||||
if($oldExecution->type == 'kanban' and empty($products))
|
||||
{
|
||||
dao::$errors['message'][] = $this->lang->execution->kanbanNoLinkProduct;
|
||||
return false;
|
||||
}
|
||||
|
||||
/* Get the data from the post. */
|
||||
$execution = fixer::input('post')
|
||||
->setDefault('lastEditedBy', $this->app->user->account)
|
||||
@@ -547,11 +545,8 @@ class executionModel extends model
|
||||
->exec();
|
||||
if(isset($execution->project) and $execution->project) $this->addProjectMembers($execution->project, $teamMembers);
|
||||
|
||||
if(!empty($execution->whitelist))
|
||||
{
|
||||
$whitelist = explode(',', $execution->whitelist);
|
||||
$this->loadModel('personnel')->updateWhitelist($whitelist, 'sprint', $executionID);
|
||||
}
|
||||
$whitelist = explode(',', $execution->whitelist);
|
||||
$this->loadModel('personnel')->updateWhitelist($whitelist, 'sprint', $executionID);
|
||||
|
||||
/* Fix bug#3074, Update views for team members. */
|
||||
if($execution->acl != 'open') $this->updateUserView($executionID, 'sprint', $changedAccounts);
|
||||
@@ -579,6 +574,7 @@ class executionModel extends model
|
||||
public function batchUpdate()
|
||||
{
|
||||
$this->loadModel('user');
|
||||
$this->loadModel('project');
|
||||
|
||||
$executions = array();
|
||||
$allChanges = array();
|
||||
@@ -634,11 +630,16 @@ class executionModel extends model
|
||||
if($projectModel == 'scrum' and empty($executionCode))
|
||||
{
|
||||
dao::$errors['code'][] = 'execution#' . $executionID . sprintf($this->lang->error->notempty, $this->lang->project->code);
|
||||
return false;
|
||||
}
|
||||
elseif(!empty($executionCode))
|
||||
{
|
||||
/* Check unique code for edited executions. */
|
||||
if(isset($codeList[$executionCode])) dao::$errors['code'][] = 'execution#' . $executionID . sprintf($this->lang->error->unique, $this->lang->project->code, $executionCode);
|
||||
if(isset($codeList[$executionCode]))
|
||||
{
|
||||
dao::$errors['code'][] = 'execution#' . $executionID . sprintf($this->lang->error->unique, $this->lang->project->code, $executionCode);
|
||||
return false;
|
||||
}
|
||||
$codeList[$executionCode] = $executionCode;
|
||||
}
|
||||
|
||||
@@ -649,29 +650,44 @@ class executionModel extends model
|
||||
|
||||
$executions[$executionID]->{$extendField->field} = htmlSpecialString($executions[$executionID]->{$extendField->field});
|
||||
$message = $this->checkFlowRule($extendField, $executions[$executionID]->{$extendField->field});
|
||||
if($message) return print(js::alert($message));
|
||||
|
||||
if($message)
|
||||
{
|
||||
dao::$errors['message'][] = $message;
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
if(dao::isError()) return print(js::error(dao::getError()));
|
||||
|
||||
foreach($executions as $executionID => $execution)
|
||||
{
|
||||
$oldExecution = $oldExecutions[$executionID];
|
||||
$team = $this->loadModel('user')->getTeamMemberPairs($executionID, 'execution');
|
||||
$projectID = isset($execution->project) ? $execution->project : $oldExecution->project;
|
||||
$project = $this->project->getByID($projectID);
|
||||
|
||||
if($execution->begin < $project->begin)
|
||||
{
|
||||
dao::$errors['begin'] = sprintf($this->lang->execution->errorLetterProject, $project->begin);
|
||||
return false;
|
||||
}
|
||||
if($execution->end > $project->end)
|
||||
{
|
||||
dao::$errors['end'] = sprintf($this->lang->execution->errorGreaterProject, $project->end);
|
||||
return false;
|
||||
}
|
||||
|
||||
$this->dao->update(TABLE_EXECUTION)->data($execution)
|
||||
->autoCheck($skipFields = 'begin,end')
|
||||
->batchcheck($this->config->execution->edit->requiredFields, 'notempty')
|
||||
->checkIF($execution->begin != '', 'begin', 'date')
|
||||
->checkIF($execution->end != '', 'end', 'date')
|
||||
->checkIF($execution->end != '', 'end', 'gt', $execution->begin)
|
||||
->checkIF($execution->end != '', 'end', 'ge', $execution->begin)
|
||||
->checkIF((!empty($execution->name) and $this->config->systemMode == 'new'), 'name', 'unique', "id != $executionID and type in ('sprint','stage') and `project` = $projectID")
|
||||
->checkIF(!empty($execution->code), 'code', 'unique', "id != $executionID and type in ('sprint','stage')")
|
||||
->where('id')->eq($executionID)
|
||||
->limit(1)
|
||||
->exec();
|
||||
if(dao::isError()) return print(js::error('execution#' . $executionID . dao::getError(true)));
|
||||
|
||||
if(!empty($execution->project) and $oldExecution->project != $execution->project)
|
||||
{
|
||||
@@ -2269,11 +2285,12 @@ class executionModel extends model
|
||||
* @param array $stories
|
||||
* @param array $products
|
||||
* @param string $extra
|
||||
* @param array $lanes
|
||||
*
|
||||
* @access public
|
||||
* @return bool
|
||||
*/
|
||||
public function linkStory($executionID, $stories = array(), $products = array(), $extra = '')
|
||||
public function linkStory($executionID, $stories = array(), $products = array(), $extra = '', $lanes = array())
|
||||
{
|
||||
if(empty($executionID)) return false;
|
||||
if(empty($stories)) $stories = $this->post->stories;
|
||||
@@ -2296,7 +2313,13 @@ class executionModel extends model
|
||||
if(strpos($notAllowedStatus, $storyList[$storyID]->status) !== false) continue;
|
||||
if(isset($linkedStories[$storyID])) continue;
|
||||
|
||||
if(isset($output['laneID']) and isset($output['columnID'])) $this->kanban->addKanbanCell($executionID, $output['laneID'], $output['columnID'], 'story', $storyID);
|
||||
$laneID = isset($output['laneID']) ? $output['laneID'] : 0;
|
||||
if(!empty($lanes[$storyID])) $laneID = $lanes[$storyID];
|
||||
|
||||
$columnID = $this->kanban->getColumnIDByLaneID($laneID, 'backlog');
|
||||
if(empty($columnID)) $columnID = isset($output['columnID']) ? $output['columnID'] : 0;
|
||||
|
||||
if(!empty($laneID) and !empty($columnID)) $this->kanban->addKanbanCell($executionID, $laneID, $columnID, 'story', $storyID);
|
||||
|
||||
$data = new stdclass();
|
||||
$data->project = $executionID;
|
||||
|
||||
@@ -11,7 +11,6 @@
|
||||
*/
|
||||
?>
|
||||
<?php if(isset($tips)):?>
|
||||
<?php $defaultURL = $this->createLink('execution', 'task', 'executionID=' . $executionID);?>
|
||||
<?php include '../../common/view/header.html.php';?>
|
||||
<body>
|
||||
<div class='modal-dialog mw-500px' id='tipsModal'>
|
||||
@@ -145,7 +144,7 @@
|
||||
<?php endforeach;?>
|
||||
<div class='col-sm-4'>
|
||||
<div class="input-group <?php if(in_array($project->model, array('kanban', 'waterfall'))) echo 'required';?>">
|
||||
<?php echo html::select("products[$i]", $allProducts, '', "class='form-control chosen' onchange='loadBranches(this)'");?>
|
||||
<?php echo html::select("products[$i]", $allProducts, '', "class='form-control chosen' required onchange='loadBranches(this)'");?>
|
||||
<span class='input-group-addon fix-border'></span>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@@ -159,7 +159,7 @@
|
||||
<?php endforeach;?>
|
||||
<div class='col-sm-4'>
|
||||
<div class="input-group">
|
||||
<?php echo html::select("products[$i]", $allProducts, '', "class='form-control chosen' onchange='loadBranches(this)'");?>
|
||||
<?php echo html::select("products[$i]", $allProducts, '', "class='form-control chosen' required onchange='loadBranches(this)'");?>
|
||||
<span class='input-group-addon fix-border'></span>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@@ -75,7 +75,7 @@
|
||||
</div>
|
||||
<div class='btn-toolbar'>
|
||||
<?php if(isonlybody()):?>
|
||||
<?php echo html::submitButton('<i class="icon icon-back icon-sm"></i> ' . $lang->goback, 'onclick="goback()"', 'btn');?>
|
||||
<?php echo html::commonButton('<i class="icon icon-sm"></i> ' . $lang->goback, 'onclick="goback()"', 'btn');?>
|
||||
<?php else:?>
|
||||
<?php echo html::backButton('','','btn');?>
|
||||
<?php endif;?>
|
||||
|
||||
@@ -85,6 +85,7 @@ js::set('priv',
|
||||
'canResolveBug' => common::hasPriv('bug', 'resolve'),
|
||||
'canCopyBug' => common::hasPriv('bug', 'create'),
|
||||
'canEditBug' => common::hasPriv('bug', 'edit'),
|
||||
'canDeleteBug' => common::hasPriv('bug', 'delete'),
|
||||
'canActivateBug' => common::hasPriv('bug', 'activate'),
|
||||
'canAssignTask' => common::hasPriv('task', 'assignto'),
|
||||
'canFinishTask' => common::hasPriv('task', 'finish'),
|
||||
@@ -96,10 +97,12 @@ js::set('priv',
|
||||
'canStartTask' => common::hasPriv('task', 'start'),
|
||||
'canRestartTask' => common::hasPriv('task', 'restart'),
|
||||
'canEditTask' => common::hasPriv('task', 'edit'),
|
||||
'canDeleteTask' => common::hasPriv('task', 'delete'),
|
||||
'canRecordEstimateTask' => common::hasPriv('task', 'recordEstimate'),
|
||||
'canToStoryBug' => common::hasPriv('story', 'create'),
|
||||
'canAssignStory' => common::hasPriv('story', 'assignto'),
|
||||
'canEditStory' => common::hasPriv('story', 'edit'),
|
||||
'canDeleteStory' => common::hasPriv('story', 'delete'),
|
||||
'canChangeStory' => common::hasPriv('story', 'change'),
|
||||
'canUnlinkStory' => common::hasPriv('execution', 'unlinkStory'),
|
||||
)
|
||||
|
||||
@@ -122,7 +122,7 @@
|
||||
</tbody>
|
||||
<tfoot><tr><td colspan='6' class='text-center form-actions'><?php echo html::submitButton() . ' ' . html::backButton(); ?></td></tr></tfoot>
|
||||
</table>
|
||||
<?php js::set('i', $i);?>
|
||||
<?php js::set('itemIndex', $i);?>
|
||||
</form>
|
||||
</div>
|
||||
<div>
|
||||
|
||||
@@ -372,6 +372,9 @@ class groupModel extends model
|
||||
if(isset($_POST['allchecker']))$actions['views'] = array();
|
||||
if(!isset($actions['actions']))$actions['actions'] = array();
|
||||
|
||||
if(isset($actions['actions']['project']['started'])) $actions['actions']['project']['syncproject'] = 'syncproject';
|
||||
if(isset($actions['actions']['execution']['started'])) $actions['actions']['execution']['syncexecution'] = 'syncexecution';
|
||||
|
||||
$dynamic = $actions['actions'];
|
||||
if(!isset($_POST['allchecker']))
|
||||
{
|
||||
|
||||
@@ -156,7 +156,7 @@ class kanban extends control
|
||||
{
|
||||
if($confirm == 'no')
|
||||
{
|
||||
return print(js::confirm($this->lang->kanban->confirmDelete, $this->createLink('kanban', 'deleteSpace', "spaceID=$spaceID&confirm=yes")));
|
||||
return print(js::confirm($this->lang->kanban->confirmDeleteSpace, $this->createLink('kanban', 'deleteSpace', "spaceID=$spaceID&confirm=yes")));
|
||||
}
|
||||
else
|
||||
{
|
||||
@@ -324,7 +324,7 @@ class kanban extends control
|
||||
{
|
||||
if($confirm == 'no')
|
||||
{
|
||||
return print(js::confirm($this->lang->kanban->confirmDelete, $this->createLink('kanban', 'delete', "kanbanID=$kanbanID&confirm=yes")));
|
||||
return print(js::confirm($this->lang->kanban->confirmDeleteKanban, $this->createLink('kanban', 'delete', "kanbanID=$kanbanID&confirm=yes")));
|
||||
}
|
||||
else
|
||||
{
|
||||
@@ -830,13 +830,9 @@ class kanban extends control
|
||||
$kanbanUsers = $kanbanID == 0 ? ',' : trim($kanban->owner) . ',' . trim($kanban->team);
|
||||
$users = $this->loadModel('user')->getPairs('noclosed|nodeleted', '', 0, $kanbanUsers);
|
||||
|
||||
$lanePairs = $this->kanban->getLanePairsByGroup($groupID);
|
||||
|
||||
$lanePairs['ditto'] = $this->lang->kanbancard->ditto;
|
||||
|
||||
$this->view->title = $this->lang->kanban->batchCreateCard;
|
||||
$this->view->users = $users;
|
||||
$this->view->lanePairs = $lanePairs;
|
||||
$this->view->lanePairs = $this->kanban->getLanePairsByGroup($groupID);
|
||||
|
||||
$this->display();
|
||||
}
|
||||
@@ -1341,8 +1337,11 @@ class kanban extends control
|
||||
{
|
||||
if($confirm == 'no')
|
||||
{
|
||||
$card = $this->kanban->getCardByID($cardID);
|
||||
$column = $this->dao->select('*')->from(TABLE_KANBANCOLUMN)->where('id')->eq($card->column)->fetch();
|
||||
$column = $this->dao->select('t2.*')->from(TABLE_KANBANCELL)->alias('t1')
|
||||
->leftJoin(TABLE_KANBANCOLUMN)->alias('t2')->on('t1.column=t2.id')
|
||||
->where('t1.cards')->like("%,$cardID,%")
|
||||
->andWhere('t1.type')->eq('common')
|
||||
->fetch();
|
||||
if($column->archived or $column->deleted) return print(js::alert(sprintf($this->lang->kanbancard->confirmRestoreTip, $column->name)));
|
||||
|
||||
return print(js::confirm(sprintf($this->lang->kanbancard->confirmRestore, $column->name), $this->createLink('kanban', 'restoreCard', "cardID=$cardID&confirm=yes"), ''));
|
||||
@@ -1384,6 +1383,28 @@ class kanban extends control
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Delete a card.
|
||||
*
|
||||
* @param string $objectType story|task|bug
|
||||
* @param int $objectID
|
||||
* @param int $regionID
|
||||
* @access public
|
||||
* @return void
|
||||
*/
|
||||
public function deleteObjectCard($objectType, $objectID, $regionID)
|
||||
{
|
||||
if(!($objectType == 'task' or $objectType == 'story' or $objectType == 'bug')) return false;
|
||||
$table = 'TABLE_' . strtoupper($objectType);
|
||||
$this->loadModel($objectType)->delete(constant($table), $objectID);
|
||||
if(dao::isError()) return $this->send(array('result' => 'fail', 'message' => dao::getError()));
|
||||
|
||||
$kanbanID = $this->kanban->getKanbanIDByregion($regionID);
|
||||
$kanbanGroup = $this->kanban->getRDKanban($kanbanID);
|
||||
|
||||
return print(json_encode($kanbanGroup));
|
||||
}
|
||||
|
||||
/**
|
||||
* Set WIP.
|
||||
*
|
||||
|
||||
@@ -1 +1 @@
|
||||
#c-name {width: 110px}
|
||||
#c-name {width: 90px}
|
||||
|
||||
@@ -2,6 +2,7 @@
|
||||
.c-WIPTitle {width: 80px; padding-left: 15px !important; padding-right: 0px !important;}
|
||||
.c-color {width: 320px;}
|
||||
.c-WIPCount {width: 240px;}
|
||||
.c-WIPTitle {width: 85px;}
|
||||
td.required:after {right: -1px;}
|
||||
.c-action {width: 80px;}
|
||||
.c-action > a {padding-top: 10px;}
|
||||
|
||||
@@ -23,7 +23,7 @@
|
||||
.region .kanban-header-sub-cols .kanban-header-col > .title {max-width: 100% !important;min-width:240px;}
|
||||
.region .sort .region-header {cursor: move;}
|
||||
|
||||
.region .kanban {padding: 0px 10px 10px 10px; min-height: unset; overflow:auto; width: 100%}
|
||||
.region .kanban {padding: 0px 5px 10px 10px; min-height: unset; overflow:auto; width: 100%}
|
||||
.region .kanban .form-actions {margin: 0;}
|
||||
.region .kanban .form-actions .btn {margin-right: 10px; min-width: 50px;}
|
||||
|
||||
@@ -35,12 +35,12 @@
|
||||
.region .kanban-header {border-bottom: none!important; min-width: max-content; min-width: -moz-max-content;}
|
||||
.region .kanban-header-col > .title {max-width: 80% !important;}
|
||||
.region .kanban-header-col > .title {margin: 0}
|
||||
.region .kanban-header-col > .title > span {display: inline-block; overflow: hidden; padding-right:2px; position: initial; max-width: 140px !important;}
|
||||
.region .kanban-header-col > .title > span {display: inline-block; overflow: hidden; padding-right:2px; position: initial; max-width:95px !important;}
|
||||
.region .kanban-header-col > .title > .text-grey {opacity: .5; font-weight: bold; color: #8b91a2;}
|
||||
.region .kanban-header-col > .title > .count {opacity: .5; font-weight: bold; color: #8b91a2;}
|
||||
.region .kanban-header-col > .title > .error {color: #333333; padding-left: 2px; font-size: 10px; padding-top: 1px; padding-right: 2px;}
|
||||
.kanban-affixed .kanban-header-col > .title > .text {color: #fff!important}
|
||||
.region .kanban-header-col > .actions {position: relative; right: -30px;}
|
||||
.region .kanban-header-col > .actions {position: relative; right: -5px;}
|
||||
.region .kanban-header-parent-col > .actions {position: absolute; right: 0px;}
|
||||
.region .kanban-header-sub-cols .actions {position: absolute; right: 0px;}
|
||||
|
||||
@@ -98,6 +98,7 @@
|
||||
|
||||
.kanban-col[data-type=ADD] {display: none;}
|
||||
.kanban-col[data-type=EMPTY] {display: none;}
|
||||
.kanban-col {padding-right: 0px !important;}
|
||||
.kanban-item .title {padding-right: 10px;}
|
||||
.gray .actions {display:none;}
|
||||
|
||||
|
||||
@@ -85,3 +85,26 @@ function locateView(module, objectID)
|
||||
if(module == 'build') dataApp = 'project';
|
||||
parent.$.apps.open(createLink(module, 'view', 'objectID=' + objectID), dataApp);
|
||||
}
|
||||
|
||||
/**
|
||||
* When type change.
|
||||
*
|
||||
* @param string type
|
||||
* @access public
|
||||
* @return void
|
||||
*/
|
||||
function changeType(type)
|
||||
{
|
||||
if(type == 'private')
|
||||
{
|
||||
$('#ownerBox').addClass('hidden');
|
||||
$('#teamBox').addClass('hidden');
|
||||
$('#whitelistBox').removeClass('hidden');
|
||||
}
|
||||
else
|
||||
{
|
||||
$('#ownerBox').removeClass('hidden');
|
||||
$('#teamBox').removeClass('hidden');
|
||||
$('#whitelistBox').addClass('hidden');
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,12 +0,0 @@
|
||||
/**
|
||||
* When type change.
|
||||
*
|
||||
* @param string type
|
||||
* @access public
|
||||
* @return void
|
||||
*/
|
||||
function changeType(type)
|
||||
{
|
||||
location.href = createLink('kanban', 'createSpace', 'type=' + type);
|
||||
}
|
||||
|
||||
@@ -1,12 +0,0 @@
|
||||
/**
|
||||
* When type change.
|
||||
*
|
||||
* @param int spaceID
|
||||
* @param string type
|
||||
* @access public
|
||||
* @return void
|
||||
*/
|
||||
function changeType(spaceID, type)
|
||||
{
|
||||
location.href = createLink('kanban', 'editSpace', 'spaceID=' + spaceID + '&type=' + type);
|
||||
}
|
||||
@@ -27,16 +27,3 @@ function setWIPLimit()
|
||||
|
||||
$('#limit').val(count);
|
||||
}
|
||||
|
||||
/**
|
||||
* When WIPCount value change.
|
||||
*
|
||||
* @param int value
|
||||
* @access public
|
||||
* @return void
|
||||
*/
|
||||
function wipValueChange(value)
|
||||
{
|
||||
if(value == '') $('#submit').addClass('disabled');
|
||||
if(value) $('#submit').removeClass('disabled');
|
||||
}
|
||||
|
||||
@@ -1490,7 +1490,7 @@ function initSortable()
|
||||
var groupID = e.element.closest('.kanban-board').data('id');
|
||||
e.list.each(function(index, data)
|
||||
{
|
||||
if(data.item.hasClass('kanban-col') && data.item.hasClass('sort') && groupID == data.item.data().col.group) orders.push(data.item.data('id'));
|
||||
if(data.item.hasClass('kanban-col') && (data.item.hasClass('sort') || data.item.children().hasClass('sort')) && groupID == data.item.data().col.group) orders.push(data.item.data('id'));
|
||||
});
|
||||
|
||||
regionID = e.element.closest('.region').data('id');
|
||||
|
||||
@@ -101,9 +101,10 @@ $lang->kanban->cardCount = 'Card Count';
|
||||
$lang->kanban->createColumnOnLeft = 'Create Column On Left';
|
||||
$lang->kanban->createColumnOnRight = 'Create Column On Right';
|
||||
|
||||
$lang->kanban->accessDenied = "You have no access to the kanban.";
|
||||
$lang->kanban->confirmDelete = 'Do you want to delete this?';
|
||||
$lang->kanban->cardCountTip = 'Please enter the number of cards';
|
||||
$lang->kanban->accessDenied = "You have no access to the kanban.";
|
||||
$lang->kanban->confirmDeleteSpace = 'Do you want to delete this Space?';
|
||||
$lang->kanban->confirmDeleteKanban = 'Do you want to delete this Kanban?';
|
||||
$lang->kanban->cardCountTip = 'Please enter the number of cards';
|
||||
|
||||
$lang->kanban->selectedKanban = 'Please select Kanban';
|
||||
$lang->kanban->selectedProduct = 'Please select Product';
|
||||
@@ -188,6 +189,7 @@ $lang->kanban->error->mustBeInt = 'The WIPs must be positive integer.';
|
||||
$lang->kanban->error->parentLimitNote = 'The WIPs in the parent column cannot be < the sum of the WIPs in the child column.';
|
||||
$lang->kanban->error->childLimitNote = 'The sum of products in the child column cannot be > the number of products in the parent column.';
|
||||
$lang->kanban->error->importObjNotEmpty = 'Please select at least one import object.';
|
||||
$lang->kanban->error->childLimitEmpty = 'Please set the WIP quantity of the sub column before operation.';
|
||||
|
||||
$lang->kanban->importList = array();
|
||||
$lang->kanban->importList['off'] = 'Import is not enabled';
|
||||
@@ -332,6 +334,7 @@ $lang->kanbancard->name = 'Card Name';
|
||||
$lang->kanbancard->legendBasicInfo = 'Basic Info';
|
||||
$lang->kanbancard->legendLifeTime = 'Card Life';
|
||||
$lang->kanbancard->space = 'Space';
|
||||
$lang->kanbancard->region = 'Region';
|
||||
$lang->kanbancard->kanban = 'Kanban';
|
||||
$lang->kanbancard->lane = 'Lane';
|
||||
$lang->kanbancard->column = 'Column';
|
||||
|
||||
@@ -101,9 +101,10 @@ $lang->kanban->cardCount = '卡片数量';
|
||||
$lang->kanban->createColumnOnLeft = '在左侧添加看板列';
|
||||
$lang->kanban->createColumnOnRight = '在右侧添加看板列';
|
||||
|
||||
$lang->kanban->accessDenied = '您无权访问该看板';
|
||||
$lang->kanban->confirmDelete = '您确认删除吗?';
|
||||
$lang->kanban->cardCountTip = '请输入卡片数量';
|
||||
$lang->kanban->accessDenied = '您无权访问该看板';
|
||||
$lang->kanban->confirmDeleteSpace = '您确认要删除该空间吗?';
|
||||
$lang->kanban->confirmDeleteKanban = '您确认要删除该看板吗?';
|
||||
$lang->kanban->cardCountTip = '请输入卡片数量';
|
||||
|
||||
$lang->kanban->selectedKanban = '请选择看板';
|
||||
$lang->kanban->selectedProduct = '请选择产品';
|
||||
@@ -188,6 +189,7 @@ $lang->kanban->error->mustBeInt = '在制品数量必须是正整数。'
|
||||
$lang->kanban->error->parentLimitNote = '父列的在制品数量不能小于子列在制品数量之和';
|
||||
$lang->kanban->error->childLimitNote = '子列在制品数量之和不能大于父列的在制品数量';
|
||||
$lang->kanban->error->importObjNotEmpty = '请至少选择一个导入对象';
|
||||
$lang->kanban->error->childLimitEmpty = '请先设置子列的在制品数量后再操作';
|
||||
|
||||
$lang->kanban->importList = array();
|
||||
$lang->kanban->importList['off'] = '不启用导入功能';
|
||||
@@ -332,6 +334,7 @@ $lang->kanbancard->name = '卡片名称';
|
||||
$lang->kanbancard->legendBasicInfo = '基本信息';
|
||||
$lang->kanbancard->legendLifeTime = '卡片的一生';
|
||||
$lang->kanbancard->space = '所属空间';
|
||||
$lang->kanbancard->region = '所属区域';
|
||||
$lang->kanbancard->kanban = '所属看板';
|
||||
$lang->kanbancard->lane = '所属泳道';
|
||||
$lang->kanbancard->column = '所属看板列';
|
||||
|
||||
@@ -77,8 +77,9 @@ $lang->kanban->teamSumCount = '共%s人';
|
||||
$lang->kanban->createColumnOnLeft = '在左側添加看板列';
|
||||
$lang->kanban->createColumnOnRight = '在右側添加看板列';
|
||||
|
||||
$lang->kanban->accessDenied = '您無權訪問該看板';
|
||||
$lang->kanban->confirmDelete = '您確認刪除嗎?';
|
||||
$lang->kanban->accessDenied = '您無權訪問該看板';
|
||||
$lang->kanban->confirmDeleteSpace = '您確認要删除該空間嗎?';
|
||||
$lang->kanban->confirmDeleteKanban = '您確認要删除該看板嗎?';
|
||||
|
||||
$lang->kanban->aclGroup['open'] = '公開';
|
||||
$lang->kanban->aclGroup['private'] = '私有';
|
||||
@@ -266,6 +267,7 @@ $lang->kanbancard->name = '卡片名稱';
|
||||
$lang->kanbancard->legendBasicInfo = '基本信息';
|
||||
$lang->kanbancard->legendLifeTime = '卡片的一生';
|
||||
$lang->kanbancard->space = '所屬空間';
|
||||
$lang->kanbancard->region = '所屬區域';
|
||||
$lang->kanbancard->kanban = '所屬看板';
|
||||
$lang->kanbancard->lane = '所屬泳道';
|
||||
$lang->kanbancard->column = '所屬看板列';
|
||||
|
||||
+66
-26
@@ -412,27 +412,15 @@ class kanbanModel extends model
|
||||
/**
|
||||
* Create a kanban card.
|
||||
*
|
||||
* @param int $kanbanID
|
||||
* @param int $regionID
|
||||
* @param int $groupID
|
||||
* @param int $columnID
|
||||
* @param int $kanbanID
|
||||
* @param int $regionID
|
||||
* @param int $groupID
|
||||
* @param int $columnID
|
||||
* @access public
|
||||
* @return void
|
||||
* @return bool|int
|
||||
*/
|
||||
public function createCard($kanbanID, $regionID, $groupID, $columnID)
|
||||
{
|
||||
if($this->post->estimate < 0)
|
||||
{
|
||||
dao::$errors[] = $this->lang->kanbancard->error->recordMinus;
|
||||
return false;
|
||||
}
|
||||
|
||||
if($this->post->end && $this->post->begin > $this->post->end)
|
||||
{
|
||||
dao::$errors[] = $this->lang->kanbancard->error->endSmall;
|
||||
return false;
|
||||
}
|
||||
|
||||
$now = helper::now();
|
||||
$card = fixer::input('post')
|
||||
->add('kanban', $kanbanID)
|
||||
@@ -442,7 +430,7 @@ class kanbanModel extends model
|
||||
->add('createdDate', $now)
|
||||
->add('assignedDate', $now)
|
||||
->add('color', '#fff')
|
||||
->trim('name')
|
||||
->trim('name,estimate')
|
||||
->setDefault('estimate', 0)
|
||||
->stripTags($this->config->kanban->editor->createcard['id'], $this->config->allowedTags)
|
||||
->join('assignedTo', ',')
|
||||
@@ -450,6 +438,18 @@ class kanbanModel extends model
|
||||
->remove('uid,lane')
|
||||
->get();
|
||||
|
||||
if($card->estimate < 0)
|
||||
{
|
||||
dao::$errors['estimate'] = $this->lang->kanbancard->error->recordMinus;
|
||||
return false;
|
||||
}
|
||||
|
||||
if($card->end && $card->begin > $card->end)
|
||||
{
|
||||
dao::$errors['end'] = $this->lang->kanbancard->error->endSmall;
|
||||
return false;
|
||||
}
|
||||
|
||||
$card = $this->loadModel('file')->processImgURL($card, $this->config->kanban->editor->createcard['id'], $this->post->uid);
|
||||
|
||||
$this->dao->insert(TABLE_KANBANCARD)->data($card)->autoCheck()
|
||||
@@ -553,10 +553,15 @@ class kanbanModel extends model
|
||||
return false;
|
||||
}
|
||||
|
||||
/*
|
||||
/**
|
||||
* Batch create kanban cards.
|
||||
*
|
||||
* @param int $kanbanID
|
||||
* @param int $regionID
|
||||
* @param int $groupID
|
||||
* @param int $columnID
|
||||
* @access public
|
||||
* @return void
|
||||
* @return bool
|
||||
*/
|
||||
public function batchCreateCard($kanbanID, $regionID, $groupID, $columnID)
|
||||
{
|
||||
@@ -564,6 +569,9 @@ class kanbanModel extends model
|
||||
{
|
||||
if($_POST['name'][$index] and isset($_POST['assignedTo'][$index])) $_POST['assignedTo'][$index] = implode(',', $_POST['assignedTo'][$index]);
|
||||
if(!isset($_POST['assignedTo'][$index])) $_POST['assignedTo'][$index] = '';
|
||||
|
||||
$_POST['estimate'][$index] = trim($_POST['estimate'][$index]);
|
||||
if(empty($_POST['estimate'][$index])) $_POST['estimate'][$index] = 0;
|
||||
}
|
||||
$cards = fixer::input('post')->get();
|
||||
|
||||
@@ -888,6 +896,18 @@ class kanbanModel extends model
|
||||
->fetchPairs();
|
||||
}
|
||||
|
||||
/**
|
||||
* Get kanban id by region id.
|
||||
*
|
||||
* @param int $regionID
|
||||
* @access public
|
||||
* @return int
|
||||
*/
|
||||
public function getKanbanIDByRegion($regionID)
|
||||
{
|
||||
return $this->dao->select('kanban')->from(TABLE_KANBANREGION)->where('id')->eq($regionID)->fetch('kanban');
|
||||
}
|
||||
|
||||
/**
|
||||
* Get kanban group by regions.
|
||||
*
|
||||
@@ -1423,7 +1443,7 @@ class kanbanModel extends model
|
||||
->leftJoin(TABLE_KANBANCOLUMN)->alias('t2')->on('t1.`column` = t2.id')
|
||||
->where('t1.kanban')->eq($executionID)
|
||||
->andWhere('t1.`type`')->eq($browseType)
|
||||
->fetchAll();
|
||||
->fetchAll('columnType');
|
||||
|
||||
$cardGroup = array();
|
||||
foreach($columns as $column)
|
||||
@@ -1671,11 +1691,10 @@ class kanbanModel extends model
|
||||
->where('deleted')->eq(0)
|
||||
->beginIF(strpos($param, 'noclosed') !== false)->andWhere('status')->ne('closed')->fi()
|
||||
->fetchAll('id');
|
||||
if($this->app->user->admin) return array_keys($objects);
|
||||
|
||||
$spaceList = $objectType == 'kanban' ? $this->dao->select('id,owner,type')->from(TABLE_KANBANSPACE)->fetchAll('id') : array();
|
||||
|
||||
if($this->app->user->admin and $param != 'involved') return array_keys($objects);
|
||||
if($this->app->user->admin and strpos('private,involved', $param) === false) return array_keys($objects);
|
||||
|
||||
$account = $this->app->user->account;
|
||||
foreach($objects as $objectID => $object)
|
||||
@@ -1825,8 +1844,8 @@ class kanbanModel extends model
|
||||
/**
|
||||
* Get lane pairs by region id.
|
||||
*
|
||||
* @param array $regionID
|
||||
* @param string $type all|story|task|bug|common
|
||||
* @param array|int $regionID
|
||||
* @param string $type all|story|task|bug|common
|
||||
* @access public
|
||||
* @return array
|
||||
*/
|
||||
@@ -2769,7 +2788,7 @@ class kanbanModel extends model
|
||||
{
|
||||
if($childColumn->limit == -1)
|
||||
{
|
||||
dao::$errors['limit'] = $this->lang->kanban->error->parentLimitNote;
|
||||
dao::$errors['limit'] = $this->lang->kanban->error->childLimitEmpty;
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -2898,6 +2917,7 @@ class kanbanModel extends model
|
||||
->where('t1.kanban')->eq($kanban->id)
|
||||
->andWhere('t1.deleted')->eq(0)
|
||||
->andWhere('t2.deleted')->eq(0)
|
||||
->andWhere('t2.type')->eq('common')
|
||||
->fetch('count');
|
||||
|
||||
if($laneCount > 1) $printSetHeightBtn = true;
|
||||
@@ -3322,6 +3342,23 @@ class kanbanModel extends model
|
||||
->fetchAll('id');
|
||||
}
|
||||
|
||||
/**
|
||||
* Get column ID by lane ID.
|
||||
*
|
||||
* @param int $laneID
|
||||
* @param string $columnType
|
||||
* @access public
|
||||
* @return int
|
||||
*/
|
||||
public function getColumnIDByLaneID($laneID, $columnType)
|
||||
{
|
||||
return $this->dao->select('t1.column')->from(TABLE_KANBANCELL)->alias('t1')
|
||||
->leftJoin(TABLE_KANBANCOLUMN)->alias('t2')->on('t1.column = t2.id')
|
||||
->where('t1.lane')->eq($laneID)
|
||||
->andWhere('t2.type')->eq($columnType)
|
||||
->fetch('column');
|
||||
}
|
||||
|
||||
/**
|
||||
* Get lane by id.
|
||||
*
|
||||
@@ -3474,6 +3511,7 @@ class kanbanModel extends model
|
||||
if(common::hasPriv('task', 'batchCreate') and $toTaskPriv) $menu[] = array('label' => $this->lang->execution->batchWBS, 'icon' => 'pluses', 'url' => helper::createLink('task', 'batchCreate', "executionID=$executionID&storyID=$story->id&moduleID=0&taskID=0&iframe=true", '', true), 'size' => '95%');
|
||||
if(common::hasPriv('story', 'activate') and $this->story->isClickable($story, 'activate')) $menu[] = array('label' => $this->lang->story->activate, 'icon' => 'magic', 'url' => helper::createLink('story', 'activate', "storyID=$story->id", '', true));
|
||||
if(common::hasPriv('execution', 'unlinkStory')) $menu[] = array('label' => $this->lang->execution->unlinkStory, 'icon' => 'unlink', 'url' => helper::createLink('execution', 'unlinkStory', "executionID=$executionID&storyID=$story->story&confirm=no", '', true));
|
||||
if(common::hasPriv('story', 'delete')) $menu[] = array('label' => $this->lang->story->delete, 'icon' => 'trash', 'url' => helper::createLink('story', 'delete', "storyID=$story->id&confirm=no&from=taskkanban"));
|
||||
|
||||
$menus[$story->id] = $menu;
|
||||
}
|
||||
@@ -3492,6 +3530,7 @@ class kanbanModel extends model
|
||||
if(common::hasPriv('bug', 'create') and $this->bug->isClickable($bug, 'create')) $menu[] = array('label' => $this->lang->bug->copy, 'icon' => 'copy', 'url' => helper::createLink('bug', 'create', "productID=$bug->product&branch=$bug->branch&extras=bugID=$bug->id", '', true), 'size' => '95%');
|
||||
if(common::hasPriv('bug', 'activate') and $this->bug->isClickable($bug, 'activate')) $menu[] = array('label' => $this->lang->bug->activate, 'icon' => 'magic', 'url' => helper::createLink('bug', 'activate', "bugID=$bug->id", '', true));
|
||||
if(common::hasPriv('story', 'create') and $bug->status != 'closed') $menu[] = array('label' => $this->lang->bug->toStory, 'icon' => 'lightbulb', 'url' => helper::createLink('story', 'create', "product=$bug->product&branch=$bug->branch&module=0&story=0&execution=0&bugID=$bug->id", '', true), 'size' => '95%');
|
||||
if(common::hasPriv('bug', 'delete')) $menu[] = array('label' => $this->lang->bug->delete, 'icon' => 'trash', 'url' => helper::createLink('bug', 'delete', "bugID=$bug->id&confirm=no&from=taskkanban"));
|
||||
|
||||
$menus[$bug->id] = $menu;
|
||||
}
|
||||
@@ -3511,6 +3550,7 @@ class kanbanModel extends model
|
||||
if(common::hasPriv('task', 'batchCreate') and $this->task->isClickable($task, 'batchCreate')) $menu[] = array('label' => $this->lang->task->children, 'icon' => 'split', 'url' => helper::createLink('task', 'batchCreate', "execution=$task->execution&storyID=$task->story&moduleID=$task->module&taskID=$task->id", '', true), 'size' => '95%');
|
||||
if(common::hasPriv('task', 'create') and $this->task->isClickable($task, 'create')) $menu[] = array('label' => $this->lang->task->copy, 'icon' => 'copy', 'url' => helper::createLink('task', 'create', "projctID=$task->execution&storyID=$task->story&moduleID=$task->module&taskID=$task->id", '', true), 'size' => '95%');
|
||||
if(common::hasPriv('task', 'cancel') and $this->task->isClickable($task, 'cancel')) $menu[] = array('label' => $this->lang->task->cancel, 'icon' => 'ban-circle', 'url' => helper::createLink('task', 'cancel', "taskID=$task->id", '', true));
|
||||
if(common::hasPriv('task', 'delete')) $menu[] = array('label' => $this->lang->task->delete, 'icon' => 'trash', 'url' => helper::createLink('task', 'delete', "executionID=$task->execution&taskID=$task->id&confirm=no&from=taskkanban"));
|
||||
|
||||
$menus[$task->id] = $menu;
|
||||
}
|
||||
|
||||
@@ -39,7 +39,8 @@
|
||||
<tr>
|
||||
<td class='text-center'><?php echo $i + 1;?></td>
|
||||
<td class='text-center'><?php echo html::input("name[$i]", '', "class='form-control title-import'");?></td>
|
||||
<td style='overflow:visible'><?php echo html::select("lane[$i]", $lanePairs, key($lanePairs), "class='form-control chosen'")?></td>
|
||||
<?php if($i > 0) $lanePairs['ditto'] = $this->lang->kanbancard->ditto;?>
|
||||
<td style='overflow:visible'><?php echo html::select("lane[$i]", $lanePairs, $i > 0 ? 'ditto' : key($lanePairs), "class='form-control chosen'")?></td>
|
||||
<td style='overflow:visible'><?php echo html::select("assignedTo[$i][]", $users, $app->user->account, "class='form-control chosen' multiple");?></td>
|
||||
<td><?php echo html::input("estimate[$i]", '', "class='form-control text-center'");?></td>
|
||||
<td>
|
||||
|
||||
@@ -27,12 +27,11 @@
|
||||
<th><?php echo $lang->kanbanspace->name;?></th>
|
||||
<td><?php echo html::input('name', '', "class='form-control'");?></td>
|
||||
</tr>
|
||||
<?php if($type != 'private'):?>
|
||||
<tr>
|
||||
<tr id='ownerBox' class="<?php echo $type == 'private' ? 'hidden' : '';?>">
|
||||
<th><?php echo $lang->kanbanspace->owner;?></th>
|
||||
<td><?php echo html::select('owner', $users, '', "class='form-control chosen'");?></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<tr id='teamBox' class="<?php echo $type == 'private' ? 'hidden' : '';?>">
|
||||
<th><?php echo $lang->kanbanspace->team;?></th>
|
||||
<td colspan='2'>
|
||||
<div class="input-group">
|
||||
@@ -41,7 +40,6 @@
|
||||
</div>
|
||||
</td>
|
||||
</tr>
|
||||
<?php endif;?>
|
||||
<tr>
|
||||
<th><?php echo $lang->kanbanspace->desc;?></th>
|
||||
<td colspan='2'>
|
||||
@@ -49,12 +47,10 @@
|
||||
<?php echo html::textarea('desc', '', "rows='10' class='form-control'");?>
|
||||
</td>
|
||||
</tr>
|
||||
<?php if($type == 'private'):?>
|
||||
<tr id="whitelistBox">
|
||||
<tr id="whitelistBox" class="<?php echo $type == 'private' ? '' : 'hidden';?>">
|
||||
<th><?php echo $lang->whitelist;?></th>
|
||||
<td><?php echo html::select('whitelist[]', $users, '', 'class="form-control chosen" multiple');?></td>
|
||||
</tr>
|
||||
<?php endif;?>
|
||||
<tr>
|
||||
<td colspan='3' class='text-center form-actions'>
|
||||
<?php echo html::submitButton();?>
|
||||
|
||||
@@ -20,7 +20,7 @@
|
||||
<table class='table table-form'>
|
||||
<tr>
|
||||
<th><?php echo $lang->kanbanspace->type;?></th>
|
||||
<td><?php echo html::select('type', $typeList, $defaultType, "onchange='changeType($spaceID, this.value)' class='form-control chosen'");?></td>
|
||||
<td><?php echo html::select('type', $typeList, $defaultType, "onchange='changeType(this.value)' class='form-control chosen'");?></td>
|
||||
<td></td>
|
||||
</tr>
|
||||
<tr>
|
||||
@@ -28,12 +28,11 @@
|
||||
<td><?php echo html::input('name', $space->name, "class='form-control'");?></td>
|
||||
<td></td>
|
||||
</tr>
|
||||
<?php if($space->type != 'private' or $type == 'cooperation' or $type == 'public'):?>
|
||||
<tr>
|
||||
<tr id='ownerBox' class="<?php echo $space->type == 'private' ? 'hidden' : '';?>">
|
||||
<th><?php echo $lang->kanbanspace->owner;?></th>
|
||||
<td><?php echo html::select('owner', $users, $space->owner, "class='form-control chosen'");?></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<tr id='teamBox' class="<?php echo $space->type == 'private' ? 'hidden' : '';?>">
|
||||
<th><?php echo $lang->kanbanspace->team;?></th>
|
||||
<td colspan='2'>
|
||||
<div class="input-group">
|
||||
@@ -42,7 +41,6 @@
|
||||
</div>
|
||||
</td>
|
||||
</tr>
|
||||
<?php endif;?>
|
||||
<tr>
|
||||
<th><?php echo $lang->kanbanspace->desc;?></th>
|
||||
<td colspan='2'>
|
||||
@@ -50,12 +48,10 @@
|
||||
<?php echo html::textarea('desc', $space->desc, "rows='10' class='form-control'");?>
|
||||
</td>
|
||||
</tr>
|
||||
<?php if($space->type == 'private' and $type != 'cooperation' and $type != 'public'):?>
|
||||
<tr id="whitelistBox">
|
||||
<tr id="whitelistBox" class="<?php echo $space->type == 'private' ? '' : 'hidden';?>">
|
||||
<th><?php echo $lang->whitelist;?></th>
|
||||
<td><?php echo html::select('whitelist[]', $users, $space->whitelist, 'class="form-control chosen" multiple');?></td>
|
||||
</tr>
|
||||
<?php endif;?>
|
||||
<tr>
|
||||
<td colspan='3' class='text-center form-actions'>
|
||||
<?php echo html::submitButton();?>
|
||||
|
||||
@@ -44,7 +44,7 @@
|
||||
<td colspan='2'>
|
||||
<div class="table-col">
|
||||
<?php $attr = $column->limit == -1 ? 'disabled' : '';?>
|
||||
<?php echo html::input('WIPCount', $column->limit != -1 ? $column->limit : '', "class='form-control' $attr onchange='wipValueChange(this.value)'");?>
|
||||
<?php echo html::input('WIPCount', $column->limit != -1 ? $column->limit : '', "class='form-control' $attr");?>
|
||||
</div>
|
||||
<div class="table-col w-50px">
|
||||
<?php echo html::hidden('limit', $column->limit, "class='form-control'");?>
|
||||
|
||||
@@ -691,6 +691,7 @@ class mailModel extends model
|
||||
$nameFields = $this->config->action->objectNameFields[$objectType];
|
||||
$title = zget($object, $nameFields, '');
|
||||
$subject = $this->getSubject($objectType, $object, $title, $action->action);
|
||||
$domain = (defined('RUN_MODE') and RUN_MODE == 'api') ? '' : zget($this->config->mail, 'domain', common::getSysURL());
|
||||
|
||||
if($objectType == 'review' and empty($object->auditedBy)) return;
|
||||
|
||||
|
||||
@@ -72,8 +72,15 @@ class messageModel extends model
|
||||
$actions = $messageSetting['mail']['setting'];
|
||||
if(isset($actions[$objectType]) and in_array($actionType, $actions[$objectType]))
|
||||
{
|
||||
/* If it is an api call, get the request method set by the user. */
|
||||
global $config;
|
||||
$requestType = $config->requestType;
|
||||
if(defined('RUN_MODE') and RUN_MODE == 'api') include $this->app->getConfigRoot() . 'config.php';
|
||||
|
||||
$moduleName = $objectType == 'case' ? 'testcase' : $objectType;
|
||||
$this->loadModel('mail')->sendmail($objectID, $actionID);
|
||||
|
||||
if(defined('RUN_MODE') and RUN_MODE == 'api') $config->requestType = $requestType;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -170,7 +170,7 @@ class my extends control
|
||||
$riskCount = $pager->recTotal;
|
||||
|
||||
/* Get the number of reviews assigned to me. */
|
||||
$reviewList = $this->review->getUserReviews('wait', 'id_desc', $pager);
|
||||
$reviewList = $this->review->getUserReviews('needreview', 'id_desc', $pager);
|
||||
$reviewCount = $pager->recTotal;
|
||||
|
||||
/* Get the number of nc assigned to me. */
|
||||
@@ -803,7 +803,7 @@ EOF;
|
||||
* @access public
|
||||
* @return void
|
||||
*/
|
||||
public function audit($browseType = 'wait', $orderBy = 't1.id_desc', $recTotal = 0, $recPerPage = 15, $pageID = 1)
|
||||
public function audit($browseType = 'needreview', $orderBy = 't1.id_desc', $recTotal = 0, $recPerPage = 15, $pageID = 1)
|
||||
{
|
||||
$this->loadModel('datatable');
|
||||
$this->loadModel('baseline');
|
||||
|
||||
@@ -634,13 +634,13 @@ class product extends control
|
||||
$this->lang->program->switcherMenu = $this->loadModel('program')->getSwitcher($programID, true);
|
||||
|
||||
$this->loadModel('user');
|
||||
$poUsers = $this->user->getPairs('nodeleted|pofirst', $appendPoUsers);
|
||||
$poUsers = $this->user->getPairs('nodeleted|noclosed|pofirst', $appendPoUsers);
|
||||
if(!empty($this->config->user->moreLink)) $this->config->moreLinks["PO"] = $this->config->user->moreLink;
|
||||
|
||||
$qdUsers = $this->user->getPairs('nodeleted|qdfirst', $appendQdUsers);
|
||||
$qdUsers = $this->user->getPairs('nodeleted|noclosed|qdfirst', $appendQdUsers);
|
||||
if(!empty($this->config->user->moreLink)) $this->config->moreLinks["QD"] = $this->config->user->moreLink;
|
||||
|
||||
$rdUsers = $this->user->getPairs('nodeleted|devfirst', $appendRdUsers);
|
||||
$rdUsers = $this->user->getPairs('nodeleted|noclosed|devfirst', $appendRdUsers);
|
||||
if(!empty($this->config->user->moreLink)) $this->config->moreLinks["RD"] = $this->config->user->moreLink;
|
||||
|
||||
$programs = array();
|
||||
@@ -994,7 +994,7 @@ class product extends control
|
||||
|
||||
if($number === '')
|
||||
{
|
||||
return print(html::select('execution', array('' => '') + $executions, empty($executionID) ? key(array_filter($executions)) : $executionID, "class='form-control' onchange='loadExecutionRelated(this.value)'"));
|
||||
return print(html::select('execution', array('' => '') + $executions, $executionID, "class='form-control' onchange='loadExecutionRelated(this.value)'"));
|
||||
}
|
||||
else
|
||||
{
|
||||
|
||||
@@ -9,6 +9,7 @@
|
||||
.dropdown-list > li > a {display: block; padding: 3px 20px; clear: both; font-weight: normal; line-height: 1.53846154; color: #141414; white-space: nowrap;}
|
||||
.dropdown-list > li > a:hover,
|
||||
.dropdown-list > li > a:focus {color: #1a4f85; text-decoration: none; background-color: #ddd;}
|
||||
#productStoryForm .setting {height: 25px;}
|
||||
|
||||
.pl-5px {padding-left: 5px;}
|
||||
.popoverStage {position: relative;}
|
||||
|
||||
@@ -572,6 +572,7 @@ class productModel extends model
|
||||
public function create()
|
||||
{
|
||||
$product = fixer::input('post')
|
||||
->callFunc('name', 'trim')
|
||||
->setDefault('status', 'normal')
|
||||
->setDefault('line', 0)
|
||||
->setDefault('createdBy', $this->app->user->account)
|
||||
@@ -653,6 +654,7 @@ class productModel extends model
|
||||
if($oldProduct->bind) $this->config->product->edit->requiredFields = 'name';
|
||||
|
||||
$product = fixer::input('post')
|
||||
->callFunc('name', 'trim')
|
||||
->setDefault('line', 0)
|
||||
->join('whitelist', ',')
|
||||
->join('reviewer', ',')
|
||||
@@ -1005,12 +1007,14 @@ class productModel extends model
|
||||
*/
|
||||
public function getProjectPairsByProduct($productID, $branch = 0, $appendProject = 0)
|
||||
{
|
||||
$product = $this->getById($productID);
|
||||
|
||||
$projects = $this->dao->select('t2.id,t2.name')->from(TABLE_PROJECTPRODUCT)->alias('t1')
|
||||
->leftJoin(TABLE_PROJECT)->alias('t2')->on('t1.project = t2.id')
|
||||
->where('t1.product')->eq($productID)
|
||||
->andWhere('t2.type')->eq('project')
|
||||
->beginIF(!$this->app->user->admin)->andWhere('t2.id')->in($this->app->user->view->projects)->fi()
|
||||
->beginIF($branch !== '')->andWhere('t1.branch')->in($branch)->fi()
|
||||
->beginIF($product->type != 'normal' and $branch !== '')->andWhere('t1.branch')->in($branch)->fi()
|
||||
->andWhere('t2.deleted')->eq('0')
|
||||
->orderBy('order_asc')
|
||||
->fetchPairs('id', 'name');
|
||||
|
||||
@@ -269,14 +269,14 @@ $projectIDParam = $isProjectStory ? "projectID=$projectID&" : '';
|
||||
<p>
|
||||
<span class="text-muted"><?php echo $storyType == 'story' ? $lang->story->noStory : $lang->story->noRequirement;?></span>
|
||||
<?php if(common::canModify('product', $product) and common::hasPriv('story', 'create')):?>
|
||||
<?php echo html::a($this->createLink('story', 'create', "productID={$productID}&branch={$branch}&moduleID={$moduleID}&storyID=0&projectID=$projectID&bugID=0&planID=0&todoID=0&extra=&type=$storyType"), "<i class='icon icon-plus'></i> " . $lang->story->createCommon, '', "class='btn btn-info' data-app='$from'");?>
|
||||
<?php echo html::a($this->createLink('story', 'create', "productID={$productID}&branch={$branch}&moduleID={$moduleID}&storyID=0&projectID=$projectID&bugID=0&planID=0&todoID=0&extra=&type=$storyType"), "<i class='icon icon-plus'></i> " . $lang->story->create, '', "class='btn btn-info' data-app='$from'");?>
|
||||
<?php endif;?>
|
||||
</p>
|
||||
</div>
|
||||
<?php else:?>
|
||||
<form class="main-table table-story skip-iframe-modal" method="post" id='productStoryForm'>
|
||||
<div class="table-header fixed-right">
|
||||
<nav class="btn-toolbar pull-right"></nav>
|
||||
<nav class="btn-toolbar pull-right setting"></nav>
|
||||
</div>
|
||||
<?php
|
||||
$datatableId = $this->moduleName . ucfirst($this->methodName);
|
||||
@@ -510,7 +510,7 @@ $projectIDParam = $isProjectStory ? "projectID=$projectID&" : '';
|
||||
{
|
||||
$searchKey = $withSearch ? ('data-key="' . zget($modulesPinYin, $module, '') . '"') : '';
|
||||
$actionLink = $this->createLink('story', 'batchChangeModule', "moduleID=$moduleId");
|
||||
echo html::a('#', empty($module) ? '/' : $module, '', "$searchKey onclick=\"setFormAction('$actionLink', 'hiddenwin', '#productStoryForm')\"");
|
||||
echo html::a('#', empty($module) ? '/' : $module, '', "$searchKey title='{$module}' onclick=\"setFormAction('$actionLink', 'hiddenwin', '#productStoryForm')\"");
|
||||
}
|
||||
?>
|
||||
</div>
|
||||
|
||||
@@ -444,14 +444,14 @@ class productplan extends control
|
||||
{
|
||||
if($confirm == 'no')
|
||||
{
|
||||
die(js::confirm($this->lang->productplan->confirmStart, $this->createLink('productplan', 'start', "planID=$planID&confirm=yes"), 'parent'));
|
||||
return print(js::confirm($this->lang->productplan->confirmStart, $this->createLink('productplan', 'start', "planID=$planID&confirm=yes")));
|
||||
}
|
||||
else
|
||||
{
|
||||
$this->productplan->updateStatus($planID, 'doing', 'started');
|
||||
|
||||
if(dao::isError()) die(js::error(dao::getError()));
|
||||
die(js::reload('parent'));
|
||||
if(dao::isError()) return print(js::error(dao::getError()));
|
||||
return print(js::reload('parent'));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -467,14 +467,14 @@ class productplan extends control
|
||||
{
|
||||
if($confirm == 'no')
|
||||
{
|
||||
die(js::confirm($this->lang->productplan->confirmFinish, $this->createLink('productplan', 'finish', "planID=$planID&confirm=yes"), 'parent'));
|
||||
return print(js::confirm($this->lang->productplan->confirmFinish, $this->createLink('productplan', 'finish', "planID=$planID&confirm=yes")));
|
||||
}
|
||||
else
|
||||
{
|
||||
$this->productplan->updateStatus($planID, 'done', 'finished');
|
||||
|
||||
if(dao::isError()) die(js::error(dao::getError()));
|
||||
die(js::reload('parent'));
|
||||
if(dao::isError()) return print(js::error(dao::getError()));
|
||||
return print(js::reload('parent'));
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -15,7 +15,7 @@ $(function()
|
||||
{
|
||||
var $content = $(this).find('td.content');
|
||||
var content = $content.find('div').html();
|
||||
if(content.indexOf('<br') >= 0)
|
||||
if(content.indexOf('<br') >= 0 || content.indexOf('<img') >= 0)
|
||||
{
|
||||
$content.append("<a href='###' class='more'><i class='icon icon-chevron-double-down'></i></a>");
|
||||
}
|
||||
|
||||
@@ -45,17 +45,10 @@
|
||||
|
||||
if($plan->parent >= 0)
|
||||
{
|
||||
$attr = "target='hiddenwin'";
|
||||
$isOnlyBody = false;
|
||||
$class = '';
|
||||
if($plan->begin == $config->productplan->future or $plan->end == $config->productplan->future)
|
||||
{
|
||||
$class = 'iframe';
|
||||
$attr = "data-toggle='modal' data-id='{$plan->id}' data-width='550px'";
|
||||
$isOnlyBody = true;
|
||||
}
|
||||
$class = $plan->status == 'wait' ? $class : 'disabled';
|
||||
common::printLink('productplan', 'start', "planID=$plan->id", "<i class='icon-play'></i>{$lang->productplan->startAB}", '', "class='btn btn-link {$class}'{$attr} title='{$lang->productplan->start}'", '', $isOnlyBody, $plan);
|
||||
$attr = "target='hiddenwin'";
|
||||
$class = $plan->status == 'wait' ? '' : 'disabled';
|
||||
|
||||
common::printLink('productplan', 'start', "planID=$plan->id", "<i class='icon-play'></i>{$lang->productplan->startAB}", '', "class='btn btn-link {$class}'{$attr} title='{$lang->productplan->start}'", '', false, $plan);
|
||||
$class = $plan->status == 'doing' ? '' : 'disabled';
|
||||
common::printLink('productplan', 'finish', "planID=$plan->id", "<i class='icon-checked'></i>{$lang->productplan->finishAB}", '', "class='btn btn-link {$class}' target='hiddenwin' title='{$lang->productplan->finish}'", '', false, $plan);
|
||||
$class = $plan->status !== 'closed' ? 'iframe' : 'disabled';
|
||||
|
||||
@@ -679,7 +679,7 @@ class programModel extends model
|
||||
->setIF($this->post->delta == 999, 'end', LONG_TIME)
|
||||
->setIF($this->post->future, 'budget', 0)
|
||||
->setIF($this->post->budget != 0, 'budget', round($this->post->budget, 2))
|
||||
->setIF(!isset($this->post->budgetUnit), 'budgetUnit', $oldProgram->budgetUnit)
|
||||
->setIF(!isset($_POST['budgetUnit']), 'budgetUnit', $oldProgram->budgetUnit)
|
||||
->join('whitelist', ',')
|
||||
->stripTags($this->config->program->editor->edit['id'], $this->config->allowedTags)
|
||||
->remove('uid,delta,future,syncPRJUnit,exchangeRate,contactListMenu')
|
||||
|
||||
@@ -7,15 +7,15 @@
|
||||
*/
|
||||
function addItem(obj)
|
||||
{
|
||||
var item = $('#addItem').html().replace(/%i%/g, i);
|
||||
var item = $('#addItem').html().replace(/%i%/g, itemIndex);
|
||||
$(obj).closest('tr').after('<tr class="addedItem">' + item + '</tr>');
|
||||
var newItem = $('#names' + i).closest('tr');
|
||||
var newItem = $('#names' + itemIndex).closest('tr');
|
||||
newItem.find('.form-date').datepicker();
|
||||
$("#output" + i).chosen();
|
||||
$("#output" + itemIndex).chosen();
|
||||
$("#PM_i__chosen").remove();
|
||||
$("#PM" + i).chosen();
|
||||
$("#PM" + itemIndex).chosen();
|
||||
$("#output_i__chosen").remove();
|
||||
i ++;
|
||||
itemIndex ++;
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -598,7 +598,7 @@ class programplanModel extends model
|
||||
$member->account = $account;
|
||||
$member->role = $this->lang->user->roleList[$this->app->user->role];
|
||||
$member->join = $now;
|
||||
$member->type = $data->type;
|
||||
$member->type = 'execution';
|
||||
$member->days = $data->days;
|
||||
$member->hours = $this->config->execution->defaultWorkhours;
|
||||
$this->dao->insert(TABLE_TEAM)->data($member)->exec();
|
||||
|
||||
@@ -170,7 +170,7 @@
|
||||
</tfoot>
|
||||
</table>
|
||||
</div>
|
||||
<?php js::set('i', $i);?>
|
||||
<?php js::set('itemIndex', $i);?>
|
||||
</form>
|
||||
</div>
|
||||
<div>
|
||||
|
||||
@@ -133,6 +133,7 @@ $config->project->maxCheckList->scrum = array('bug', 'execution', 'build', '
|
||||
$config->project->maxCheckList->waterfall = array('execution', 'design', 'doc', 'bug', 'case', 'build', 'release', 'testtask', 'review', 'build', 'researchplan', 'issue', 'risk', 'opportunity', 'auditplan', 'gapanalysis', 'meeting');
|
||||
|
||||
$config->project->excludedPriv['project'] = array('index', 'browse', 'kanban', 'create', 'batchEdit', 'qa', 'updateOrder', 'createGuide', 'programTitle', 'export');
|
||||
$config->project->excludedPriv['execution'] = array('view', 'browse', 'edit', 'batchedit', 'start', 'activate', 'putoff', 'suspend', 'close', 'delete', 'task', 'grouptask', 'importtask', 'importplanstories', 'importBug', 'story', 'build', 'testtask', 'testcase', 'bug', 'testreport', 'burn', 'computeBurn', 'fixFirst', 'burnData', 'team', 'doc', 'dynamic', 'manageProducts', 'manageMembers', 'unlinkMember', 'linkStory', 'unlinkStory', 'batchUnlinkStory', 'updateOrder', 'taskKanban', 'printKanban', 'tree', 'treeTask', 'treeStory', 'all', 'kanbanHideCols', 'kanbanColsColor', 'export', 'storyKanban', 'storySort', 'whitelist', 'addWhitelist', 'unbindWhitelist', 'storyEstimate', 'executionkanban', 'kanban');
|
||||
$config->project->excludedPriv['story'] = array('report', 'linkStory', 'batchChangeBranch', 'batchChangeModule', 'batchToTask', 'processStoryChange', 'track', 'tasks', 'bugs', 'cases');
|
||||
$config->project->excludedPriv['bug'] = array('browse', 'batchChangePlan', 'batchCreate', 'batchEdit', 'batchConfirm', 'batchResolve', 'batchClose', 'batchActivate', 'report', 'batchChangeModule', 'batchChangeBranch');
|
||||
$config->project->excludedPriv['testcase'] = array('browse', 'batchChangeModule', 'batchChangeBranch');
|
||||
|
||||
@@ -1342,6 +1342,8 @@ class project extends control
|
||||
if(!empty($_POST))
|
||||
{
|
||||
$this->project->manageMembers($projectID);
|
||||
if(dao::isError()) $this->send(array('result' => 'fail', 'message' => dao::getError()));
|
||||
|
||||
$this->loadModel('action')->create('team', $projectID, 'ManagedTeam');
|
||||
|
||||
$link = $this->createLink('project', 'team', "projectID=$projectID");
|
||||
|
||||
@@ -62,12 +62,12 @@ function setRole(account, roleID)
|
||||
*/
|
||||
function addItem(obj)
|
||||
{
|
||||
var item = $('#addItem').html().replace(/%i%/g, i);
|
||||
var item = $('#addItem').html().replace(/%i%/g, itemIndex);
|
||||
var $tr = $('<tr class="addedItem">' + item + '</tr>').insertAfter($(obj).closest('tr'));
|
||||
$tr.find('select:first')
|
||||
.trigger('liszt:updated')
|
||||
.picker({type: 'user'});
|
||||
i++;
|
||||
itemIndex++;
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
+57
-55
@@ -1,60 +1,62 @@
|
||||
<?php
|
||||
/* Actions. */
|
||||
$lang->project->createGuide = 'Select Template';
|
||||
$lang->project->index = 'Dashboard';
|
||||
$lang->project->home = 'Home';
|
||||
$lang->project->create = 'Create Project';
|
||||
$lang->project->edit = 'Edit';
|
||||
$lang->project->batchEdit = 'Batch Edit Projects';
|
||||
$lang->project->view = 'Project View';
|
||||
$lang->project->batchEdit = 'Batch Edit';
|
||||
$lang->project->browse = 'Projects';
|
||||
$lang->project->all = 'All';
|
||||
$lang->project->start = 'Start';
|
||||
$lang->project->finish = 'Finish';
|
||||
$lang->project->suspend = 'Suspend';
|
||||
$lang->project->delete = 'Delete';
|
||||
$lang->project->close = 'Close';
|
||||
$lang->project->activate = 'Activate';
|
||||
$lang->project->group = 'Privilege Group';
|
||||
$lang->project->createGroup = 'Create Group';
|
||||
$lang->project->editGroup = 'Edit Group';
|
||||
$lang->project->copyGroup = 'Copy Group';
|
||||
$lang->project->manageView = 'Manage View';
|
||||
$lang->project->managePriv = 'Manage Privilege';
|
||||
$lang->project->manageMembers = 'Manage Team';
|
||||
$lang->project->export = 'Export';
|
||||
$lang->project->addProduct = 'Add Product';
|
||||
$lang->project->manageGroupMember = 'Manage Group';
|
||||
$lang->project->moduleSetting = 'List Settings';
|
||||
$lang->project->moduleOpen = 'Program Name';
|
||||
$lang->project->dynamic = 'Dynamic';
|
||||
$lang->project->execution = 'Execution';
|
||||
$lang->project->qa = 'QA';
|
||||
$lang->project->bug = 'Bug List';
|
||||
$lang->project->testcase = 'Case List';
|
||||
$lang->project->testtask = 'Test Task';
|
||||
$lang->project->build = 'Build';
|
||||
$lang->project->updateOrder = 'Order';
|
||||
$lang->project->sort = 'Order';
|
||||
$lang->project->whitelist = 'Project Whitelist';
|
||||
$lang->project->addWhitelist = 'Project Add Whitelist';
|
||||
$lang->project->unbindWhitelist = 'Project Remove Whitelist';
|
||||
$lang->project->manageProducts = 'Manage Products';
|
||||
$lang->project->copyTitle = 'Please select an project to copy';
|
||||
$lang->project->errorSameProducts = 'Project cannot be associated with multiple identical products.';
|
||||
$lang->project->errorSameBranches = 'Project cannot be associated with multiple identical branches.';
|
||||
$lang->project->errorNoProducts = 'At least one product is associated';
|
||||
$lang->project->copyNoProject = 'There are no items available to copy.';
|
||||
$lang->project->searchByName = 'Enter the project name to retrieve';
|
||||
$lang->project->deleted = 'Deleted';
|
||||
$lang->project->linkedProducts = "Linked {$lang->productCommon}s";
|
||||
$lang->project->unlinkedProducts = "Unlinked {$lang->productCommon}s";
|
||||
$lang->project->testreport = 'Test Report';
|
||||
$lang->project->selectProgram = 'Program filtering';
|
||||
$lang->project->teamMember = 'Team Member';
|
||||
$lang->project->unlinkMember = 'Remove Member';
|
||||
$lang->project->copyTeamTitle = 'Select a project team to copy';
|
||||
$lang->project->createGuide = 'Select Template';
|
||||
$lang->project->index = 'Dashboard';
|
||||
$lang->project->home = 'Home';
|
||||
$lang->project->create = 'Create Project';
|
||||
$lang->project->edit = 'Edit';
|
||||
$lang->project->batchEdit = 'Batch Edit Projects';
|
||||
$lang->project->view = 'Project View';
|
||||
$lang->project->batchEdit = 'Batch Edit';
|
||||
$lang->project->browse = 'Projects';
|
||||
$lang->project->all = 'All';
|
||||
$lang->project->start = 'Start';
|
||||
$lang->project->finish = 'Finish';
|
||||
$lang->project->suspend = 'Suspend';
|
||||
$lang->project->delete = 'Delete';
|
||||
$lang->project->close = 'Close';
|
||||
$lang->project->activate = 'Activate';
|
||||
$lang->project->group = 'Privilege Group';
|
||||
$lang->project->createGroup = 'Create Group';
|
||||
$lang->project->editGroup = 'Edit Group';
|
||||
$lang->project->copyGroup = 'Copy Group';
|
||||
$lang->project->manageView = 'Manage View';
|
||||
$lang->project->managePriv = 'Manage Privilege';
|
||||
$lang->project->manageMembers = 'Manage Team';
|
||||
$lang->project->export = 'Export';
|
||||
$lang->project->addProduct = 'Add Product';
|
||||
$lang->project->manageGroupMember = 'Manage Group';
|
||||
$lang->project->moduleSetting = 'List Settings';
|
||||
$lang->project->moduleOpen = 'Program Name';
|
||||
$lang->project->dynamic = 'Dynamic';
|
||||
$lang->project->execution = 'Execution';
|
||||
$lang->project->qa = 'QA';
|
||||
$lang->project->bug = 'Bug List';
|
||||
$lang->project->testcase = 'Case List';
|
||||
$lang->project->testtask = 'Test Task';
|
||||
$lang->project->build = 'Build';
|
||||
$lang->project->updateOrder = 'Order';
|
||||
$lang->project->sort = 'Order';
|
||||
$lang->project->whitelist = 'Project Whitelist';
|
||||
$lang->project->addWhitelist = 'Project Add Whitelist';
|
||||
$lang->project->unbindWhitelist = 'Project Remove Whitelist';
|
||||
$lang->project->manageProducts = 'Manage Products';
|
||||
$lang->project->copyTitle = 'Please select an project to copy';
|
||||
$lang->project->errorSameProducts = 'Project cannot be associated with multiple identical products.';
|
||||
$lang->project->errorSameBranches = 'Project cannot be associated with multiple identical branches.';
|
||||
$lang->project->errorNoProducts = 'At least one product is associated';
|
||||
$lang->project->copyNoProject = 'There are no items available to copy.';
|
||||
$lang->project->searchByName = 'Enter the project name to retrieve';
|
||||
$lang->project->deleted = 'Deleted';
|
||||
$lang->project->linkedProducts = "Linked {$lang->productCommon}s";
|
||||
$lang->project->unlinkedProducts = "Unlinked {$lang->productCommon}s";
|
||||
$lang->project->testreport = 'Test Report';
|
||||
$lang->project->selectProgram = 'Program filtering';
|
||||
$lang->project->teamMember = 'Team Member';
|
||||
$lang->project->unlinkMember = 'Remove Member';
|
||||
$lang->project->copyTeamTitle = 'Select a project team to copy';
|
||||
$lang->project->daysGreaterProject = 'Days cannot be greater than days of project『%s』';
|
||||
$lang->project->errorHours = 'Hours/Day cannot be greater than『24』';
|
||||
|
||||
/* Fields. */
|
||||
$lang->project->common = 'Project';
|
||||
|
||||
@@ -1,60 +1,62 @@
|
||||
<?php
|
||||
/* Actions. */
|
||||
$lang->project->createGuide = '选择项目模板';
|
||||
$lang->project->index = '项目仪表盘';
|
||||
$lang->project->home = '项目主页';
|
||||
$lang->project->create = '创建项目';
|
||||
$lang->project->edit = '编辑项目';
|
||||
$lang->project->batchEdit = '批量编辑项目';
|
||||
$lang->project->view = '项目概况';
|
||||
$lang->project->batchEdit = '批量编辑';
|
||||
$lang->project->browse = '项目列表';
|
||||
$lang->project->all = '所有项目';
|
||||
$lang->project->start = '启动项目';
|
||||
$lang->project->finish = '完成项目';
|
||||
$lang->project->suspend = '挂起项目';
|
||||
$lang->project->delete = '删除项目';
|
||||
$lang->project->close = '关闭项目';
|
||||
$lang->project->activate = '激活项目';
|
||||
$lang->project->group = '项目权限分组';
|
||||
$lang->project->createGroup = '项目创建分组';
|
||||
$lang->project->editGroup = '项目编辑分组';
|
||||
$lang->project->copyGroup = '项目复制分组';
|
||||
$lang->project->manageView = '项目维护视野';
|
||||
$lang->project->managePriv = '项目维护权限';
|
||||
$lang->project->manageMembers = '团队管理';
|
||||
$lang->project->export = '导出';
|
||||
$lang->project->addProduct = '新建产品';
|
||||
$lang->project->manageGroupMember = '维护分组用户';
|
||||
$lang->project->moduleSetting = '列表设置';
|
||||
$lang->project->moduleOpen = '显示项目集名';
|
||||
$lang->project->dynamic = '动态';
|
||||
$lang->project->execution = '执行列表';
|
||||
$lang->project->qa = '测试仪表盘';
|
||||
$lang->project->bug = 'Bug列表';
|
||||
$lang->project->testcase = '用例列表';
|
||||
$lang->project->testtask = '测试单';
|
||||
$lang->project->build = '版本';
|
||||
$lang->project->updateOrder = '排序';
|
||||
$lang->project->sort = '项目排序';
|
||||
$lang->project->whitelist = '项目白名单';
|
||||
$lang->project->addWhitelist = '项目添加白名单';
|
||||
$lang->project->unbindWhitelist = '项目删除白名单';
|
||||
$lang->project->manageProducts = '关联产品';
|
||||
$lang->project->copyTitle = '请选择要复制的项目';
|
||||
$lang->project->errorSameProducts = '项目不能关联多个相同的产品。';
|
||||
$lang->project->errorSameBranches = '项目不能关联多个相同的分支。';
|
||||
$lang->project->errorNoProducts = '最少关联一个产品';
|
||||
$lang->project->copyNoProject = '没有可用的项目来复制';
|
||||
$lang->project->searchByName = '输入项目名称进行检索';
|
||||
$lang->project->deleted = '已删除';
|
||||
$lang->project->linkedProducts = '已关联产品';
|
||||
$lang->project->unlinkedProducts = '未关联';
|
||||
$lang->project->testreport = '测试报告';
|
||||
$lang->project->selectProgram = '项目集筛选';
|
||||
$lang->project->teamMember = '团队成员';
|
||||
$lang->project->unlinkMember = '移除成员';
|
||||
$lang->project->copyTeamTitle = '选择一个项目团队来复制';
|
||||
$lang->project->createGuide = '选择项目模板';
|
||||
$lang->project->index = '项目仪表盘';
|
||||
$lang->project->home = '项目主页';
|
||||
$lang->project->create = '创建项目';
|
||||
$lang->project->edit = '编辑项目';
|
||||
$lang->project->batchEdit = '批量编辑项目';
|
||||
$lang->project->view = '项目概况';
|
||||
$lang->project->batchEdit = '批量编辑';
|
||||
$lang->project->browse = '项目列表';
|
||||
$lang->project->all = '所有项目';
|
||||
$lang->project->start = '启动项目';
|
||||
$lang->project->finish = '完成项目';
|
||||
$lang->project->suspend = '挂起项目';
|
||||
$lang->project->delete = '删除项目';
|
||||
$lang->project->close = '关闭项目';
|
||||
$lang->project->activate = '激活项目';
|
||||
$lang->project->group = '项目权限分组';
|
||||
$lang->project->createGroup = '项目创建分组';
|
||||
$lang->project->editGroup = '项目编辑分组';
|
||||
$lang->project->copyGroup = '项目复制分组';
|
||||
$lang->project->manageView = '项目维护视野';
|
||||
$lang->project->managePriv = '项目维护权限';
|
||||
$lang->project->manageMembers = '团队管理';
|
||||
$lang->project->export = '导出';
|
||||
$lang->project->addProduct = '新建产品';
|
||||
$lang->project->manageGroupMember = '维护分组用户';
|
||||
$lang->project->moduleSetting = '列表设置';
|
||||
$lang->project->moduleOpen = '显示项目集名';
|
||||
$lang->project->dynamic = '动态';
|
||||
$lang->project->execution = '执行列表';
|
||||
$lang->project->qa = '测试仪表盘';
|
||||
$lang->project->bug = 'Bug列表';
|
||||
$lang->project->testcase = '用例列表';
|
||||
$lang->project->testtask = '测试单';
|
||||
$lang->project->build = '版本';
|
||||
$lang->project->updateOrder = '排序';
|
||||
$lang->project->sort = '项目排序';
|
||||
$lang->project->whitelist = '项目白名单';
|
||||
$lang->project->addWhitelist = '项目添加白名单';
|
||||
$lang->project->unbindWhitelist = '项目删除白名单';
|
||||
$lang->project->manageProducts = '关联产品';
|
||||
$lang->project->copyTitle = '请选择要复制的项目';
|
||||
$lang->project->errorSameProducts = '项目不能关联多个相同的产品。';
|
||||
$lang->project->errorSameBranches = '项目不能关联多个相同的分支。';
|
||||
$lang->project->errorNoProducts = '最少关联一个产品';
|
||||
$lang->project->copyNoProject = '没有可用的项目来复制';
|
||||
$lang->project->searchByName = '输入项目名称进行检索';
|
||||
$lang->project->deleted = '已删除';
|
||||
$lang->project->linkedProducts = '已关联产品';
|
||||
$lang->project->unlinkedProducts = '未关联';
|
||||
$lang->project->testreport = '测试报告';
|
||||
$lang->project->selectProgram = '项目集筛选';
|
||||
$lang->project->teamMember = '团队成员';
|
||||
$lang->project->unlinkMember = '移除成员';
|
||||
$lang->project->copyTeamTitle = '选择一个项目团队来复制';
|
||||
$lang->project->daysGreaterProject = '可用工日不能大于项目的可用工日『%s』';
|
||||
$lang->project->errorHours = '可用工时/天不能大于『24』';
|
||||
|
||||
/* Fields. */
|
||||
$lang->project->common = '项目';
|
||||
|
||||
@@ -790,6 +790,7 @@ class projectModel extends model
|
||||
public function create()
|
||||
{
|
||||
$project = fixer::input('post')
|
||||
->callFunc('name', 'trim')
|
||||
->setDefault('status', 'wait')
|
||||
->setIF($this->post->delta == 999, 'end', LONG_TIME)
|
||||
->setIF($this->post->delta == 999, 'days', 0)
|
||||
@@ -1035,6 +1036,7 @@ class projectModel extends model
|
||||
$_POST['products'] = isset($_POST['products']) ? array_filter($_POST['products']) : $linkedProducts;
|
||||
|
||||
$project = fixer::input('post')
|
||||
->callFunc('name', 'trim')
|
||||
->setDefault('team', substr($this->post->name, 0, 30))
|
||||
->setDefault('lastEditedBy', $this->app->user->account)
|
||||
->setDefault('lastEditedDate', helper::now())
|
||||
@@ -1530,20 +1532,35 @@ class projectModel extends model
|
||||
$projectID = (int)$projectID;
|
||||
$projectType = 'project';
|
||||
$accounts = array_unique($accounts);
|
||||
$limited = array_values($limited);
|
||||
$oldJoin = $this->dao->select('`account`, `join`')->from(TABLE_TEAM)->where('root')->eq($projectID)->andWhere('type')->eq($projectType)->fetchPairs();
|
||||
$this->dao->delete()->from(TABLE_TEAM)->where('root')->eq($projectID)->andWhere('type')->eq($projectType)->exec();
|
||||
|
||||
foreach($accounts as $key => $account)
|
||||
{
|
||||
if(empty($account)) continue;
|
||||
|
||||
if((int)$days[$key] > $project->days)
|
||||
{
|
||||
dao::$errors['message'][] = sprintf($this->lang->project->daysGreaterProject, $project->days);
|
||||
return false;
|
||||
}
|
||||
if((float)$hours[$key] > 24)
|
||||
{
|
||||
dao::$errors['message'][] = $this->lang->project->errorHours;
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
$projectMember = array();
|
||||
foreach($accounts as $key => $account)
|
||||
{
|
||||
if(empty($account)) continue;
|
||||
|
||||
$member = new stdclass();
|
||||
$member = new stdclass();
|
||||
$member->role = $roles[$key];
|
||||
$member->days = $days[$key];
|
||||
$member->hours = $hours[$key];
|
||||
$member->limited = $limited[$key];
|
||||
$member->limited = isset($limited[$key]) ? $limited[$key] : 'no';
|
||||
|
||||
$member->root = $projectID;
|
||||
$member->account = $account;
|
||||
|
||||
@@ -125,14 +125,14 @@
|
||||
</tr>
|
||||
</tfoot>
|
||||
</table>
|
||||
<?php js::set('i', $i);?>
|
||||
<?php js::set('itemIndex', $i);?>
|
||||
</form>
|
||||
</div>
|
||||
<div>
|
||||
<?php $i = '%i%';?>
|
||||
<table class='hidden'>
|
||||
<tr id='addItem' class='hidden'>
|
||||
<td><?php echo html::select("accounts[]", $users, '', "class='form-control' onchange='setRole(this.value, $i)'");?></td>
|
||||
<td><?php echo html::select("accounts[$i]", $users, '', "class='form-control' onchange='setRole(this.value, $i)'");?></td>
|
||||
<td><?php echo html::input("roles[$i]", '', "class='form-control'");?></td>
|
||||
<td><?php echo html::input("days[$i]", $project->days, "class='form-control'");?></td>
|
||||
<td><?php echo html::input("hours[$i]", $config->execution->defaultWorkhours, "class='form-control'");?></td>
|
||||
|
||||
@@ -51,7 +51,7 @@ class projectrelease extends control
|
||||
|
||||
$this->view->products = $this->products;
|
||||
$this->view->product = $product;
|
||||
$this->view->branches = (isset($product->type) and $product->type == 'normal') ? array() : $this->loadModel('branch')->getPairs($productID);
|
||||
$this->view->branches = (isset($product->type) and $product->type == 'normal') ? array() : $this->loadModel('branch')->getPairs($productID, 'active');
|
||||
$this->view->branch = $branch;
|
||||
$this->view->project = $this->project->getByID($projectID);
|
||||
}
|
||||
|
||||
@@ -27,7 +27,7 @@ function loadBranches(productID)
|
||||
{
|
||||
$('#branch').remove();
|
||||
$('#branch_chosen').remove();
|
||||
$.get(createLink('branch', 'ajaxGetBranches', "productID=" + productID), function(data)
|
||||
$.get(createLink('branch', 'ajaxGetBranches', "productID=" + productID + '&oldBranch=0¶ms=active'), function(data)
|
||||
{
|
||||
var $product = $('#product');
|
||||
var $inputGroup = $product.closest('.input-group');
|
||||
|
||||
@@ -9,3 +9,4 @@
|
||||
#tabsNav .nav-tabs > li.active + li.pull-right {margin-right: 0;}
|
||||
ol, ul {padding-left: 20px;}
|
||||
.body-modal #mainContent {min-height: 240px;}
|
||||
.c-id {width: 110px;}
|
||||
|
||||
@@ -77,7 +77,7 @@
|
||||
<?php $vars = "releaseID={$release->id}&type=story&link=$link¶m=$param&orderBy=%s";?>
|
||||
<thead>
|
||||
<tr>
|
||||
<th class='c-id text-left w-110px'>
|
||||
<th class='c-id text-left'>
|
||||
<?php if(($canBatchUnlink or $canBatchClose) and $canBeChanged):?>
|
||||
<div class="checkbox-primary check-all" title="<?php echo $lang->selectAll?>">
|
||||
<label></label>
|
||||
@@ -172,7 +172,7 @@
|
||||
<?php $vars = "releaseID={$release->id}&type=bug&link=$link¶m=$param&orderBy=%s";?>
|
||||
<thead>
|
||||
<tr class='text-center'>
|
||||
<th class='c-id text-left w-110px'>
|
||||
<th class='c-id text-left'>
|
||||
<?php if($canBatchUnlink and $canBeChanged):?>
|
||||
<div class="checkbox-primary check-all" title="<?php echo $lang->selectAll?>">
|
||||
<label></label>
|
||||
|
||||
@@ -151,6 +151,7 @@ class repo extends control
|
||||
$this->view->products = $products;
|
||||
$this->view->productID = $productID;
|
||||
$this->view->gitlabHosts = $this->loadModel('gitlab')->getPairs();
|
||||
$this->view->objectID = $objectID;
|
||||
|
||||
$this->display();
|
||||
}
|
||||
|
||||
@@ -25,7 +25,7 @@
|
||||
<table class='table table-form'>
|
||||
<tr>
|
||||
<th><?php echo $lang->repo->product; ?></th>
|
||||
<td class='required'><?php echo html::select('product[]', $products, $productID, "class='form-control chosen' multiple"); ?></td>
|
||||
<td class='required'><?php echo html::select('product[]', $products, empty($objectID) ? '' : array_keys($products), "class='form-control chosen' multiple"); ?></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<th class='thWidth'><?php echo $lang->repo->type; ?></th>
|
||||
|
||||
@@ -31,7 +31,7 @@
|
||||
<td><?php echo $i;?></td>
|
||||
<td><?php echo html::input("name[$i]", '', "class='form-control'");?></td>
|
||||
<td><?php echo html::input("percent[$i]", '', "class='form-control'");?></td>
|
||||
<td><?php echo html::select("type[$i]", $lang->stage->typeList, '', "class='form-control chosen'");?></td>
|
||||
<td><?php echo html::select("type[$i]", array('' => '') + $lang->stage->typeList, '', "class='form-control chosen'");?></td>
|
||||
</tr>
|
||||
<?php endfor;?>
|
||||
<tr>
|
||||
|
||||
+51
-10
@@ -46,6 +46,10 @@ class story extends control
|
||||
*/
|
||||
public function create($productID = 0, $branch = 0, $moduleID = 0, $storyID = 0, $objectID = 0, $bugID = 0, $planID = 0, $todoID = 0, $extra = '', $type = 'story')
|
||||
{
|
||||
/* Whether there is a object to transfer story, for example feedback. */
|
||||
$extra = str_replace(array(',', ' '), array('&', ''), $extra);
|
||||
parse_str($extra, $output);
|
||||
|
||||
if($productID == 0 and $objectID == 0) $this->locate($this->createLink('product', 'create'));
|
||||
|
||||
/* Get product id according to the project id when lite vision todo transfer story */
|
||||
@@ -71,11 +75,23 @@ class story extends control
|
||||
{
|
||||
$objectID = empty($objectID) ? $this->session->execution : $objectID;
|
||||
$this->execution->setMenu($objectID);
|
||||
$execution = $this->dao->findById((int)$objectID)->from(TABLE_EXECUTION)->fetch();
|
||||
if($execution->type == 'kanban')
|
||||
{
|
||||
$this->loadModel('kanban');
|
||||
$regionPairs = $this->kanban->getRegionPairs($execution->id, 0, 'execution');
|
||||
$regionID = isset($output['regionID']) ? $output['regionID'] : key($regionPairs);
|
||||
$lanePairs = $this->kanban->getLanePairsByRegion($regionID, 'story');
|
||||
$laneID = isset($output['laneID']) ? $output['laneID'] : key($lanePairs);
|
||||
|
||||
$this->view->executionType = $execution->type;
|
||||
$this->view->regionID = $regionID;
|
||||
$this->view->laneID = $laneID;
|
||||
$this->view->regionPairs = $regionPairs;
|
||||
$this->view->lanePairs = $lanePairs;
|
||||
}
|
||||
}
|
||||
|
||||
/* Whether there is a object to transfer story, for example feedback. */
|
||||
$extra = str_replace(array(',', ' '), array('&', ''), $extra);
|
||||
parse_str($extra, $output);
|
||||
foreach($output as $paramKey => $paramValue)
|
||||
{
|
||||
if(isset($this->config->story->fromObjects[$paramKey]))
|
||||
@@ -401,6 +417,20 @@ class story extends control
|
||||
}
|
||||
else
|
||||
{
|
||||
if($execution->type == 'kanban')
|
||||
{
|
||||
$this->loadModel('kanban');
|
||||
$regionPairs = $this->kanban->getRegionPairs($executionID, 0, 'execution');
|
||||
$regionID = isset($output['regionID']) ? $output['regionID'] : key($regionPairs);
|
||||
$lanePairs = $this->kanban->getLanePairsByRegion($regionID, 'story');
|
||||
$laneID = isset($output['laneID']) ? $output['laneID'] : key($lanePairs);
|
||||
|
||||
$this->view->regionID = $regionID;
|
||||
$this->view->laneID = $laneID;
|
||||
$this->view->regionPairs = $regionPairs;
|
||||
$this->view->lanePairs = $lanePairs;
|
||||
}
|
||||
|
||||
$this->execution->setMenu($executionID);
|
||||
$this->app->rawModule = 'execution';
|
||||
$this->lang->navGroup->story = 'execution';
|
||||
@@ -433,12 +463,18 @@ class story extends control
|
||||
$stories = array();
|
||||
foreach($mails as $mail) $stories[] = $mail->storyID;
|
||||
|
||||
$lanes = array();
|
||||
if(isset($_POST['lanes']))
|
||||
{
|
||||
foreach($mails as $i => $mail) $lanes[$mail->storyID] = $_POST['lanes'][$i];
|
||||
}
|
||||
|
||||
/* Project or execution linked stories. */
|
||||
if($executionID)
|
||||
{
|
||||
$products = array();
|
||||
foreach($mails as $story) $products[$story->storyID] = $productID;
|
||||
$this->execution->linkStory($executionID, $stories, $products, $extra);
|
||||
$this->execution->linkStory($executionID, $stories, $products, $extra, $lanes);
|
||||
if($executionID != $this->session->project) $this->execution->linkStory($this->session->project, $stories, $products);
|
||||
}
|
||||
|
||||
@@ -725,8 +761,6 @@ class story extends control
|
||||
$productReviewers = $product->reviewer;
|
||||
if(!$productReviewers and $product->acl != 'open') $productReviewers = $this->loadModel('user')->getProductViewListUsers($product, '', '', '');
|
||||
|
||||
$this->story->replaceURLang($story->type);
|
||||
|
||||
/* Process the module when branch products are switched to normal products. */
|
||||
if($product->type == 'normal' and !empty($story->branch)) $this->view->moduleOptionMenu += $this->tree->getModulesName($story->module);
|
||||
|
||||
@@ -1120,7 +1154,9 @@ class story extends control
|
||||
}
|
||||
|
||||
$reviewers = $this->story->getReviewerPairs($storyID, $story->version);
|
||||
$checkSuperReviewed = strpos(',' . trim(zget($this->config->story, 'superReviewers', ''), ',') . ',', ',' . trim($story->reviewedBy, ',') . ',');
|
||||
$reviewedBy = trim($story->reviewedBy, ',');
|
||||
$superReviewers = trim(zget($this->config->story, 'superReviewers', ''), ',');
|
||||
$checkSuperReviewed = empty($reviewedBy) ? false : strpos(",$superReviewers,", ",$reviewedBy,");
|
||||
|
||||
$this->executeHooks($storyID);
|
||||
|
||||
@@ -1162,17 +1198,18 @@ class story extends control
|
||||
*
|
||||
* @param int $storyID
|
||||
* @param string $confirm yes|no
|
||||
* @param string $from taskkanban
|
||||
* @access public
|
||||
* @return void
|
||||
*/
|
||||
public function delete($storyID, $confirm = 'no')
|
||||
public function delete($storyID, $confirm = 'no', $from = '')
|
||||
{
|
||||
$story = $this->story->getById($storyID);
|
||||
if($story->parent < 0) return print(js::alert($this->lang->story->cannotDeleteParent));
|
||||
|
||||
if($confirm == 'no')
|
||||
{
|
||||
return print(js::confirm($this->lang->story->confirmDelete, $this->createLink('story', 'delete', "story=$storyID&confirm=yes"), ''));
|
||||
return print(js::confirm($this->lang->story->confirmDelete, $this->createLink('story', 'delete', "story=$storyID&confirm=yes&from=$from"), ''));
|
||||
}
|
||||
else
|
||||
{
|
||||
@@ -1187,6 +1224,10 @@ class story extends control
|
||||
|
||||
if(defined('RUN_MODE') && RUN_MODE == 'api') return $this->send(array('status' => 'success'));
|
||||
|
||||
if($this->app->tab == 'execution' and $from == 'taskkanban') return print(js::reload('parent'));
|
||||
|
||||
if(isonlybody()) return print(js::reload('parent.parent'));
|
||||
|
||||
$locateLink = $this->session->storyList ? $this->session->storyList : $this->createLink('product', 'browse', "productID={$story->product}");
|
||||
return print(js::locate($locateLink, 'parent'));
|
||||
}
|
||||
@@ -1345,7 +1386,7 @@ class story extends control
|
||||
}
|
||||
else
|
||||
{
|
||||
return print(js::closeModal('parent.parent', 'this'));
|
||||
return print(js::closeModal('parent.parent', 'this', "function(){parent.parent.location.reload();}"));
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -115,3 +115,24 @@ function toggleCheck(obj)
|
||||
$ditto.closest('.input-group-addon').hide();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Set lane.
|
||||
*
|
||||
* @param int $regionID
|
||||
* @param int $num
|
||||
* @access public
|
||||
* @return void
|
||||
*/
|
||||
function setLane(regionID, num)
|
||||
{
|
||||
laneLink = createLink('kanban', 'ajaxGetLanes', 'regionID=' + regionID + '&type=story&field=lanes&i=' + num);
|
||||
$.get(laneLink, function(lanes)
|
||||
{
|
||||
if(!lanes) lanes = '<select id="lanes' + num + '" name="lanes[' + num + ']" class="form-control"></select>';
|
||||
$('#lanes' + num).replaceWith(lanes);
|
||||
$("#lanes" + num + "_chosen").remove();
|
||||
$("#lanes" + num).next('.picker').remove();
|
||||
$("#lanes" + num).chosen();
|
||||
});
|
||||
}
|
||||
|
||||
@@ -48,6 +48,26 @@ function refreshPlan()
|
||||
$('a.refresh').click();
|
||||
}
|
||||
|
||||
/**
|
||||
* Set lane.
|
||||
*
|
||||
* @param int $regionID
|
||||
* @access public
|
||||
* @return void
|
||||
*/
|
||||
function setLane(regionID)
|
||||
{
|
||||
laneLink = createLink('kanban', 'ajaxGetLanes', 'regionID=' + regionID + '&type=story&field=lane');
|
||||
$.get(laneLink, function(lane)
|
||||
{
|
||||
if(!lane) lane = "<select id='lane' name='lane' class='form-control'></select>";
|
||||
$('#lane').replaceWith(lane);
|
||||
$('#lane' + "_chosen").remove();
|
||||
$('#lane').next('.picker').remove();
|
||||
$('#lane').chosen();
|
||||
});
|
||||
}
|
||||
|
||||
$(window).unload(function(){
|
||||
if(blockID) window.parent.refreshBlock($('#block' + blockID));
|
||||
});
|
||||
|
||||
+26
-8
@@ -44,7 +44,7 @@ class storyModel extends model
|
||||
if($setImgSize) $story->spec = $this->file->setImgSize($story->spec);
|
||||
if($setImgSize) $story->verify = $this->file->setImgSize($story->verify);
|
||||
|
||||
$story->executions = $this->dao->select('t1.project, t2.name, t2.status')->from(TABLE_PROJECTSTORY)->alias('t1')
|
||||
$story->executions = $this->dao->select('t1.project, t2.name, t2.status, t2.type')->from(TABLE_PROJECTSTORY)->alias('t1')
|
||||
->leftJoin(TABLE_EXECUTION)->alias('t2')->on('t1.project = t2.id')
|
||||
->where('t1.story')->eq($storyID)
|
||||
->andWhere('t2.type')->in('sprint,stage,kanban')
|
||||
@@ -220,7 +220,7 @@ class storyModel extends model
|
||||
->setIF($bugID > 0, 'fromBug', $bugID)
|
||||
->join('mailto', ',')
|
||||
->stripTags($this->config->story->editor->create['id'], $this->config->allowedTags)
|
||||
->remove('files,labels,reviewer,needNotReview,newStory,uid,contactListMenu,URS')
|
||||
->remove('files,labels,reviewer,needNotReview,newStory,uid,contactListMenu,URS,region,lane')
|
||||
->get();
|
||||
|
||||
/* Check repeat story. */
|
||||
@@ -289,8 +289,15 @@ class storyModel extends model
|
||||
if($this->config->systemMode == 'new' and $executionID != $this->session->project) $this->linkStory($this->session->project, $this->post->product, $storyID);
|
||||
|
||||
$this->loadModel('kanban');
|
||||
if(isset($output['laneID']) and isset($output['columnID'])) $this->kanban->addKanbanCell($executionID, $output['laneID'], $output['columnID'], 'story', $storyID);
|
||||
if(!isset($output['laneID']) or !isset($output['columnID'])) $this->kanban->updateLane($executionID, 'story');
|
||||
|
||||
$laneID = isset($output['laneID']) ? $output['laneID'] : 0;
|
||||
if(isset($_POST['lane'])) $laneID = $_POST['lane'];
|
||||
|
||||
$columnID = $this->kanban->getColumnIDByLaneID($laneID, 'backlog');
|
||||
if(empty($columnID)) $columnID = isset($output['columnID']) ? $output['columnID'] : 0;
|
||||
|
||||
if(!empty($laneID) and !empty($columnID)) $this->kanban->addKanbanCell($executionID, $laneID, $columnID, 'story', $storyID);
|
||||
if(empty($laneID) or empty($columnID)) $this->kanban->updateLane($executionID, 'story');
|
||||
}
|
||||
|
||||
if(is_array($this->post->URS))
|
||||
@@ -1273,7 +1280,6 @@ class storyModel extends model
|
||||
*/
|
||||
public function review($storyID)
|
||||
{
|
||||
if($this->post->result == false) return print(js::alert($this->lang->story->mustChooseResult));
|
||||
if($this->post->result == 'revert' and $this->post->preVersion == false) return print(js::alert($this->lang->story->mustChoosePreVersion));
|
||||
|
||||
if(strpos($this->config->story->review->requiredFields, 'comment') !== false and !$this->post->comment)
|
||||
@@ -1282,6 +1288,12 @@ class storyModel extends model
|
||||
return false;
|
||||
}
|
||||
|
||||
if($this->post->result == false)
|
||||
{
|
||||
dao::$errors[] = $this->lang->story->mustChooseResult;
|
||||
return false;
|
||||
}
|
||||
|
||||
$oldStory = $this->dao->findById($storyID)->from(TABLE_STORY)->fetch();
|
||||
$now = helper::now();
|
||||
$date = helper::today();
|
||||
@@ -1533,8 +1545,11 @@ class storyModel extends model
|
||||
->where('id')->eq($storyID)->exec();
|
||||
|
||||
/* Update parent story status and stage. */
|
||||
if($oldStory->parent > 0) $this->updateParentStatus($storyID, $oldStory->parent);
|
||||
$this->setStage($oldStory->parent);
|
||||
if($oldStory->parent > 0)
|
||||
{
|
||||
$this->updateParentStatus($storyID, $oldStory->parent);
|
||||
$this->setStage($oldStory->parent);
|
||||
}
|
||||
if(!dao::isError()) $this->loadModel('score')->create('story', 'close', $storyID);
|
||||
return common::createChanges($oldStory, $story);
|
||||
}
|
||||
@@ -1982,6 +1997,9 @@ class storyModel extends model
|
||||
->remove('comment')
|
||||
->get();
|
||||
$this->dao->update(TABLE_STORY)->data($story)->autoCheck()->where('id')->eq($storyID)->exec();
|
||||
|
||||
if($this->post->status == 'active') $this->dao->delete()->from(TABLE_STORYREVIEW)->where('story')->eq($storyID)->exec();
|
||||
|
||||
$this->setStage($storyID);
|
||||
|
||||
/* Update parent story status. */
|
||||
@@ -2849,7 +2867,7 @@ class storyModel extends model
|
||||
->beginIF($moduleIdList)->andWhere('t2.module')->in($moduleIdList)->fi()
|
||||
->beginIF($status == 'unclosed')->andWhere('t2.status')->ne('closed')->fi()
|
||||
->orderBy('t1.`order` desc')
|
||||
->fetchAll();
|
||||
->fetchAll('id');
|
||||
return empty($stories) ? array() : $this->formatStories($stories, $type);
|
||||
}
|
||||
|
||||
|
||||
@@ -48,6 +48,10 @@
|
||||
<?php if(!isonlybody()):?>
|
||||
<th class='c-plan<?php echo zget($visibleFields, 'plan', ' hidden') . zget($requiredFields, 'plan', '', ' required');?>'><?php echo $lang->story->plan;?></th>
|
||||
<?php endif;?>
|
||||
<?php if(isset($execution) and $execution->type == 'kanban'):?>
|
||||
<th class='c-branch'><?php echo $lang->kanbancard->region;?></th>
|
||||
<th class='c-branch'><?php echo $lang->kanbancard->lane;?></th>
|
||||
<?php endif;?>
|
||||
<th class='c-name required has-btn'><?php echo $lang->story->title;?></th>
|
||||
<th class='c-spec<?php echo zget($visibleFields, 'spec', ' hidden') . zget($requiredFields, 'spec', '', ' required');?>'><?php echo $lang->story->spec;?></th>
|
||||
<th class='c-source<?php echo zget($visibleFields, 'source', ' hidden') . zget($requiredFields, 'source', '', ' required');?>'><?php echo $lang->story->source;?></th>
|
||||
@@ -71,6 +75,10 @@
|
||||
<?php if(!isonlybody()):?>
|
||||
<td class='text-left<?php echo zget($visibleFields, 'plan', ' hidden')?>' style='overflow:visible'><?php echo html::select('plan[$id]', $plans, $planID, "class='form-control chosen'");?></td>
|
||||
<?php endif;?>
|
||||
<?php if(isset($execution) and $execution->type == 'kanban'):?>
|
||||
<td class='text-left'><?php echo html::select('regions[$id]', $regionPairs, $regionID, "class='form-control chosen' onchange='setLane(this.value, \$id)'");?>
|
||||
<td class='text-left'><?php echo html::select('lanes[$id]', $lanePairs, $laneID, "class='form-control chosen'");?>
|
||||
<?php endif;?>
|
||||
<td style='overflow:visible'>
|
||||
<div class="input-group">
|
||||
<div class="input-control has-icon-right">
|
||||
@@ -125,15 +133,16 @@ $(function()
|
||||
|
||||
$('#batchCreateForm').batchActionForm(
|
||||
{
|
||||
idEnd: <?php echo max((empty($titles) ? 0 : count($titles)), 9)?>,
|
||||
idStart: 1,
|
||||
idEnd: <?php echo max((empty($titles) ? 1 : count($titles)), 10)?>,
|
||||
rowCreator: function($row, index)
|
||||
{
|
||||
$row.find('select.chosen,select.picker-select').each(function()
|
||||
{
|
||||
var $select = $(this);
|
||||
if($select.hasClass('picker-select')) $select.parent().find('.picker').remove();
|
||||
if(index == 0) $select.find("option[value='ditto']").remove();
|
||||
if(index > 0) $select.val('ditto');
|
||||
if(index == 1) $select.find("option[value='ditto']").remove();
|
||||
if(index > 1) $select.val('ditto');
|
||||
if($select.attr('id').indexOf('branch') >= 0) $select.val('<?php echo $branch;?>')
|
||||
$select.chosen();
|
||||
setTimeout(function()
|
||||
|
||||
@@ -155,9 +155,9 @@
|
||||
<div class='input-group' id='moduleIdBox'>
|
||||
<div class="input-group-addon"><?php echo $lang->story->parent;?></div>
|
||||
<?php echo html::select('parent', $stories, '', "class='form-control chosen'");?>
|
||||
</div>
|
||||
</div>
|
||||
</td>
|
||||
</tr>
|
||||
</tr>
|
||||
<?php else:?>
|
||||
<tr>
|
||||
<th><?php echo $lang->story->parent;?></th>
|
||||
@@ -165,6 +165,18 @@
|
||||
</tr>
|
||||
<?php endif;?>
|
||||
<?php endif;?>
|
||||
<?php if (isset($executionType) and $executionType == 'kanban'):?>
|
||||
<tr>
|
||||
<th><?php echo $lang->kanbancard->region;?>
|
||||
<td colspan="2"><?php echo html::select('region', $regionPairs, $regionID, "onchange='setLane(this.value)' class='form-control chosen'");?></td>
|
||||
<td colspan="2">
|
||||
<div class='input-group'>
|
||||
<div class="input-group-addon"><?php echo $lang->kanbancard->lane;?></div>
|
||||
<?php echo html::select('lane', $lanePairs, $laneID, "class='form-control chosen'");?>
|
||||
</div>
|
||||
</td>
|
||||
</tr>
|
||||
<?php endif;?>
|
||||
<tr>
|
||||
<th><?php echo $lang->story->title;?></th>
|
||||
<td colspan="4">
|
||||
|
||||
@@ -18,7 +18,7 @@
|
||||
<tr>
|
||||
<td style='padding: 10px; background-color: #F8FAFE; border: none; font-size: 14px; font-weight: 500; border-bottom: 1px solid #e5e5e5;'>
|
||||
<?php $color = empty($object->color) ? '#333' : $object->color;?>
|
||||
<?php echo html::a(zget($this->config->mail, 'domain', common::getSysURL()) . helper::createLink('story', 'view', "storyID=$object->id", 'html'), $mailTitle, '', "style='color: {$color}; text-decoration: underline;'");?>
|
||||
<?php echo html::a($domain . helper::createLink('story', 'view', "storyID=$object->id", 'html'), $mailTitle, '', "style='color: {$color}; text-decoration: underline;'");?>
|
||||
</td>
|
||||
</tr>
|
||||
</table>
|
||||
|
||||
@@ -244,7 +244,7 @@
|
||||
echo "<div class='divider'></div>";
|
||||
common::printIcon('story', 'edit', "storyID=$story->id", $story);
|
||||
common::printIcon('story', 'create', "productID=$story->product&branch=$story->branch&moduleID=$story->module&storyID=$story->id&executionID=0&bugID=0&planID=0&todoID=0&extra=&type=$story->type", $story, 'button', 'copy', '', '', '', "data-width='1050'");
|
||||
common::printIcon('story', 'delete', "storyID=$story->id", $story, 'button', 'trash', 'hiddenwin');
|
||||
common::printIcon('story', 'delete', "storyID=$story->id", $story, 'button', 'trash', 'hiddenwin', 'showinonlybody',true);
|
||||
?>
|
||||
<?php endif;?>
|
||||
</div>
|
||||
@@ -492,7 +492,8 @@
|
||||
{
|
||||
foreach($story->executions as $executionID => $execution)
|
||||
{
|
||||
echo "<li title='$execution->name'>" . html::a($this->createLink('execution', 'browse', "executionID=$executionID"), $execution->name, '', "class='text-muted'") . '</li>';
|
||||
$execName = ($execution->type == 'kanban' and isonlybody()) ? $execution->name : html::a($this->createLink('execution', 'browse', "executionID=$executionID"), $execution->name, '', "class='text-muted'");
|
||||
echo "<li title='$execution->name'>" . $execName . '</li>';
|
||||
}
|
||||
}
|
||||
?>
|
||||
|
||||
@@ -35,7 +35,7 @@ $config->task->exportFields = '
|
||||
openedBy, openedDate, assignedTo, assignedDate,
|
||||
finishedBy, finishedDate, canceledBy, canceledDate,
|
||||
closedBy, closedDate, closedReason,
|
||||
lastEditedBy, lastEditedDate,files
|
||||
lastEditedBy, lastEditedDate, avtivatedDate, files
|
||||
';
|
||||
|
||||
$config->task->customCreateFields = 'story,estStarted,deadline,mailto,pri,estimate';
|
||||
|
||||
+49
-13
@@ -86,6 +86,20 @@ class task extends control
|
||||
$execution = $this->execution->getById($executionID);
|
||||
$taskLink = $this->createLink('execution', 'browse', "executionID=$executionID&tab=task");
|
||||
|
||||
$this->loadModel('kanban');
|
||||
if($execution->type == 'kanban')
|
||||
{
|
||||
$regionPairs = $this->kanban->getRegionPairs($execution->id, 0, 'execution');
|
||||
$regionID = isset($output['regionID']) ? $output['regionID'] : key($regionPairs);
|
||||
$lanePairs = $this->kanban->getLanePairsByRegion($regionID, 'task');
|
||||
$laneID = isset($output['laneID']) ? $output['laneID'] : key($lanePairs);
|
||||
|
||||
$this->view->regionID = $regionID;
|
||||
$this->view->laneID = $laneID;
|
||||
$this->view->regionPairs = $regionPairs;
|
||||
$this->view->lanePairs = $lanePairs;
|
||||
}
|
||||
|
||||
/* Set menu. */
|
||||
$this->execution->setMenu($execution->id);
|
||||
|
||||
@@ -129,11 +143,19 @@ class task extends control
|
||||
$this->action->create('task', $taskID, 'Opened', '');
|
||||
}
|
||||
|
||||
$this->loadModel('kanban');
|
||||
/* Create task in kanban. */
|
||||
$kanbanID = $execution->type == 'kanban' ? $executionID : $_POST['execution'];
|
||||
if(isset($output['laneID']) and isset($output['columnID'])) $this->kanban->addKanbanCell($kanbanID, $output['laneID'], $output['columnID'], 'task', $taskID);
|
||||
if(!isset($output['laneID']) or !isset($output['columnID'])) $this->kanban->updateLane($kanbanID, 'task');
|
||||
|
||||
$laneID = isset($output['laneID']) ? $output['laneID'] : 0;
|
||||
if(!empty($_POST['lane'])) $laneID = $_POST['lane'];
|
||||
|
||||
$columnID = $this->kanban->getColumnIDByLaneID($laneID, 'wait');
|
||||
if(empty($columnID)) $columnID = isset($output['columnID']) ? $output['columnID'] : 0;
|
||||
|
||||
if(!empty($laneID) and !empty($columnID)) $this->kanban->addKanbanCell($kanbanID, $laneID, $columnID, 'task', $taskID);
|
||||
if(empty($laneID) or empty($columnID)) $this->kanban->updateLane($kanbanID, 'task');
|
||||
|
||||
/* To do status. */
|
||||
if($todoID > 0)
|
||||
{
|
||||
$this->dao->update(TABLE_TODO)->set('status')->eq('done')->where('id')->eq($todoID)->exec();
|
||||
@@ -210,14 +232,7 @@ class task extends control
|
||||
if(!isset($moduleOptionMenu[$task->module])) $task->module = 0;
|
||||
}
|
||||
|
||||
/* Fix bug #2737. When moduleID is not story module. */
|
||||
$moduleIdList = array();
|
||||
if($task->module)
|
||||
{
|
||||
$moduleID = $this->tree->getStoryModule($task->module);
|
||||
$moduleIdList = $this->tree->getAllChildID($moduleID);
|
||||
}
|
||||
$stories = $this->story->getExecutionStoryPairs($executionID, 0, 'all', $moduleIdList, 'full', 'unclosed');
|
||||
$stories = $this->story->getExecutionStoryPairs($executionID, 0, 'all', '', 'full', 'unclosed');
|
||||
|
||||
if($this->config->vision == 'lite') $stories = $stories + array('', '');
|
||||
|
||||
@@ -364,6 +379,23 @@ class task extends control
|
||||
$showAllModule = isset($this->config->execution->task->allModule) ? $this->config->execution->task->allModule : '';
|
||||
$modules = $this->loadModel('tree')->getTaskOptionMenu($executionID, 0, 0, $showAllModule ? 'allModule' : '');
|
||||
|
||||
if($execution->type == 'kanban')
|
||||
{
|
||||
$extra = str_replace(array(',', ' '), array('&', ''), $extra);
|
||||
parse_str($extra, $output);
|
||||
|
||||
$this->loadModel('kanban');
|
||||
$regionPairs = $this->kanban->getRegionPairs($executionID, 0, 'execution');
|
||||
$regionID = isset($output['regionID']) ? $output['regionID'] : key($regionPairs);
|
||||
$lanePairs = $this->kanban->getLanePairsByRegion($regionID, 'task');
|
||||
$laneID = isset($output['laneID']) ? $output['laneID'] : key($lanePairs);
|
||||
|
||||
$this->view->regionID = $regionID;
|
||||
$this->view->laneID = $laneID;
|
||||
$this->view->regionPairs = $regionPairs;
|
||||
$this->view->lanePairs = $lanePairs;
|
||||
}
|
||||
|
||||
$title = $execution->name . $this->lang->colon . $this->lang->task->batchCreate;
|
||||
$position[] = html::a($taskLink, $execution->name);
|
||||
$position[] = $this->lang->task->common;
|
||||
@@ -1560,17 +1592,18 @@ class task extends control
|
||||
* @param int $executionID
|
||||
* @param int $taskID
|
||||
* @param string $confirm yes|no
|
||||
* @param string $from taskkanban
|
||||
* @access public
|
||||
* @return void
|
||||
*/
|
||||
public function delete($executionID, $taskID, $confirm = 'no')
|
||||
public function delete($executionID, $taskID, $confirm = 'no', $from = '')
|
||||
{
|
||||
$task = $this->task->getById($taskID);
|
||||
if($task->parent < 0) return print(js::alert($this->lang->task->cannotDeleteParent));
|
||||
|
||||
if($confirm == 'no')
|
||||
{
|
||||
return print(js::confirm($this->lang->task->confirmDelete, inlink('delete', "executionID=$executionID&taskID=$taskID&confirm=yes")));
|
||||
return print(js::confirm($this->lang->task->confirmDelete, inlink('delete', "executionID=$executionID&taskID=$taskID&confirm=yes&from=$from")));
|
||||
}
|
||||
else
|
||||
{
|
||||
@@ -1585,6 +1618,9 @@ class task extends control
|
||||
|
||||
$this->executeHooks($taskID);
|
||||
|
||||
if(isonlybody()) return print(js::reload('parent.parent'));
|
||||
if($from == 'taskkanban') return print(js::reload('parent'));
|
||||
|
||||
$locateLink = $this->session->taskList ? $this->session->taskList : $this->createLink('execution', 'task', "executionID={$task->execution}");
|
||||
return print(js::locate($locateLink, 'parent'));
|
||||
}
|
||||
|
||||
@@ -19,3 +19,7 @@
|
||||
.chosen-results > li.has-new-test {position: relative; color: #388E3C;}
|
||||
.chosen-results > li.has-test.highlighted,
|
||||
.chosen-results > li.has-new-test.highlighted {color: #fff;}
|
||||
|
||||
.c-multipleTask {width: 110px;}
|
||||
.c-modulel {width: 110px;}
|
||||
.c-selectStory {width: 120px;}
|
||||
|
||||
@@ -0,0 +1,3 @@
|
||||
.c-multipleTask {width: 120px;}
|
||||
.c-modulel {width: 110px;}
|
||||
.c-selectStory {width: 150px;}
|
||||
@@ -87,7 +87,7 @@ function copyStoryTitle(num)
|
||||
function setStoryRelated(num)
|
||||
{
|
||||
var storyID = $('#story' + num).val();
|
||||
if(storyID && storyID != 'ditto')
|
||||
if(storyID != 0 && storyID != 'ditto')
|
||||
{
|
||||
var link = createLink('story', 'ajaxGetInfo', 'storyID=' + storyID);
|
||||
$.getJSON(link, function(storyInfo)
|
||||
@@ -184,6 +184,27 @@ function markStoryTask()
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Set lane.
|
||||
*
|
||||
* @param int $regionID
|
||||
* @param int $num
|
||||
* @access public
|
||||
* @return void
|
||||
*/
|
||||
function setLane(regionID, num)
|
||||
{
|
||||
laneLink = createLink('kanban', 'ajaxGetLanes', 'regionID=' + regionID + '&type=task&field=lanes&i=' + num);
|
||||
$.get(laneLink, function(lanes)
|
||||
{
|
||||
if(!lanes) lanes = '<select id="lanes' + num + '" name="lanes[' + num + ']" class="form-control"></select>';
|
||||
$('#lanes' + num).replaceWith(lanes);
|
||||
$("#lanes" + num + "_chosen").remove();
|
||||
$("#lanes" + num).next('.picker').remove();
|
||||
$("#lanes" + num).chosen();
|
||||
});
|
||||
}
|
||||
|
||||
$(document).on('chosen:showing_dropdown', 'select[name^="story"],.chosen-with-drop', function()
|
||||
{
|
||||
var select = $(this).closest('td').find('select');
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user