diff --git a/db/update17.0.beta1.sql b/db/update17.0.beta1.sql index a916d02ba7..7f67f4c88c 100644 --- a/db/update17.0.beta1.sql +++ b/db/update17.0.beta1.sql @@ -3,3 +3,6 @@ ALTER TABLE `zt_kanbanspace` ADD COLUMN `activatedDate` datetime NOT NULL AFTER ALTER TABLE `zt_kanban` ADD COLUMN `activatedBy` char(30) NOT NULL AFTER `closedDate`; ALTER TABLE `zt_kanban` ADD COLUMN `activatedDate` datetime NOT NULL AFTER `activatedBy`; + +ALTER TABLE `zt_task` ADD COLUMN `mode` varchar(10) NOT NULL AFTER `type`; +UPDATE `zt_task` SET mode = 'linear' WHERE `id` IN (SELECT root FROM `zt_team` WHERE type = 'task'); diff --git a/db/zentao.sql b/db/zentao.sql index 0ec6975287..618c17016a 100644 --- a/db/zentao.sql +++ b/db/zentao.sql @@ -1463,6 +1463,7 @@ CREATE TABLE IF NOT EXISTS `zt_task` ( `fromBug` mediumint(8) unsigned NOT NULL default '0', `name` varchar(255) NOT NULL, `type` varchar(20) NOT NULL, + `mode` varchar(10) NOT NULL, `pri` tinyint(3) unsigned NOT NULL default '0', `estimate` float unsigned NOT NULL, `consumed` float unsigned NOT NULL, diff --git a/module/task/control.php b/module/task/control.php index 6a8a17aa23..5dc5243ab3 100644 --- a/module/task/control.php +++ b/module/task/control.php @@ -824,7 +824,7 @@ class task extends control $this->loadModel('action'); foreach($tasks as $taskID => $task) { - if(isset($muletipleTasks[$taskID]) and $task->assignedTo != $this->app->user->account) continue; + if(isset($muletipleTasks[$taskID]) and $task->assignedTo != $this->app->user->account and $task->mode == 'linear') continue; if(isset($muletipleTasks[$taskID]) and !isset($muletipleTasks[$taskID][$this->post->assignedTo])) continue; $changes = $this->task->assign($taskID); @@ -1207,7 +1207,7 @@ class task extends control } $task = $this->view->task; - $members = $this->loadModel('user')->getTeamMemberPairs($task->execution, 'execution', 'nodeleted'); + $members = $task->team ? $this->task->getMemberPairs($task) : $this->loadModel('user')->getTeamMemberPairs($task->execution, 'execution', 'nodeleted'); $task->nextBy = $task->openedBy; $this->view->users = $members; diff --git a/module/task/js/create.js b/module/task/js/create.js index 1511c7354d..a942920439 100644 --- a/module/task/js/create.js +++ b/module/task/js/create.js @@ -23,6 +23,7 @@ function loadExecutionMembers(executionID) { $("#multipleBox").removeAttr("checked"); $('.team-group').addClass('hidden'); + $(".modeBox").addClass("hidden"); $.get(createLink('execution', 'ajaxGetMembers', 'executionID=' + executionID + '&assignedTo=' + $('#assignedTo').val()), function(data) { $('#assignedTo_chosen').remove(); @@ -141,6 +142,7 @@ function setOwners(result) { $("#multipleBox").removeAttr("checked"); $('.team-group').addClass('hidden'); + $('.modeBox').addClass('hidden'); $('#assignedTo, #assignedTo_chosen').removeClass('hidden'); $('#assignedTo').next('.picker').removeClass('hidden'); if(result == 'affair') @@ -150,6 +152,7 @@ function setOwners(result) $('#assignedTo').chosen(); $('.affair').hide(); $('.team-group').addClass('hidden'); + $('.modeBox').addClass('hidden'); $('#selectAllUser').removeClass('hidden'); } else if($('#assignedTo').attr('multiple') == 'multiple') @@ -421,7 +424,7 @@ $(document).ready(function() $(window).resize(); - /* show team menu. */ + /* Show team menu. */ $('[name^=multiple]').change(function() { if($(this).prop('checked')) @@ -429,6 +432,7 @@ $(document).ready(function() $('#assignedTo, #assignedTo_chosen').addClass('hidden'); $('#assignedTo').next('.picker').addClass('hidden'); $('.team-group').removeClass('hidden'); + $('.modeBox').removeClass('hidden'); $('#estimate').attr('readonly', true); } else @@ -436,6 +440,7 @@ $(document).ready(function() $('#assignedTo, #assignedTo_chosen').removeClass('hidden'); $('#assignedTo').next('.picker').removeClass('hidden'); $('.team-group').addClass('hidden'); + $('.modeBox').addClass('hidden'); $('#estimate').attr('readonly', false); } $('#dataPlanGroup').fixInputGroup(); diff --git a/module/task/js/edit.js b/module/task/js/edit.js index 0a49d29468..9e2a46d744 100644 --- a/module/task/js/edit.js +++ b/module/task/js/edit.js @@ -82,17 +82,29 @@ $(document).ready(function() if(checked) { $('#teamTr').removeClass('hidden'); + $('.modeBox').removeClass('hidden'); + $('#mode').removeAttr('disabled').trigger('chosen:updated'); $('#parent').val(''); $('#parent').trigger('chosen:updated'); $('#parent').closest('tr').addClass('hidden'); $('#estimate').attr('disabled', 'disabled'); + $('#left').attr('disabled', 'disabled'); + + var mode = $('#mode').val(); + if((mode == 'linear' && currentUser != oldAssignedTo) || !team[currentUser]) $('[name=assignedTo]').attr('disabled', 'disabled').trigger('chosen:updated'); } else { $('#teamTr').addClass('hidden'); + $('.modeBox').addClass('hidden'); + $('#mode').attr('disabled', 'disabled').trigger('chosen:updated'); $('#parent').closest('tr').removeClass('hidden'); $('#estimate').removeAttr('disabled'); + $('#left').removeAttr('disabled'); + $('[name=assignedTo]').removeAttr('disabled').trigger('chosen:updated'); } + + updateAssignedTo(); }); /* Init task team manage dialog */ @@ -156,11 +168,11 @@ $('#confirmButton').click(function() if(i <= j) return; if(value == $(this).val()) $(this).closest('tr').addClass('hidden'); }) - }) + }); + $('select[name^=team]').closest('tr.hidden').remove(); var memberCount = ''; - var assignedTo = ''; var totalEstimate = 0; var totalConsumed = oldConsumed; var totalLeft = 0; @@ -168,9 +180,6 @@ $('#confirmButton').click(function() { if($(this).find('option:selected').text() == '') return; - var account = $(this).find('option:selected').val(); - var realName = $(this).find('option:selected').text(); - assignedTo += ""; memberCount++; estimate = parseFloat($(this).parents('td').next('td').find('[name^=teamEstimate]').val()); @@ -185,8 +194,7 @@ $('#confirmButton').click(function() $('#estimate').val(totalEstimate); $('#consumedSpan').html(totalConsumed); $('#left').val(totalLeft); - $('#assignedTo').html(assignedTo); - $('#assignedTo').trigger('chosen:updated'); + updateAssignedTo(); if(memberCount < 2) { @@ -200,3 +208,53 @@ $('#confirmButton').click(function() } $('.close').click(); }); + +/** + * Update assignedTo. + * + * @access public + * @return void + */ +function updateAssignedTo() +{ + var html = ''; + var multiple = $('#multiple').prop('checked'); + var assignedTo = $('#assignedTo').val(); + if(multiple) + { + var isTeamMember = false; + var mode = $('#mode').val(); + $('select[name^=team]').each(function() + { + if($(this).find('option:selected').text() == '') return; + if($(this).val() == currentUser) isTeamMember = true; + + var account = $(this).find('option:selected').val(); + var realName = $(this).find('option:selected').text(); + var selected = account == assignedTo ? 'selected' : ''; + + html += ""; + + }); + + if(mode == 'multi' && isTeamMember) + { + $('[name=assignedTo]').removeAttr('disabled').trigger('chosen:updated'); + } + else + { + if(currentUser != oldAssignedTo || !isTeamMember) $('[name=assignedTo]').attr('disabled', 'disabled').trigger('chosen:updated'); + } + } + else + { + for(key in members) + { + var selected = key == assignedTo ? 'selected' : ''; + html += ""; + } + } + + $('#assignedTo').html(html); + $('#assignedTo').trigger('chosen:updated'); +} diff --git a/module/task/lang/de.php b/module/task/lang/de.php index 6ba9d23cb6..b48f5fcfe2 100644 --- a/module/task/lang/de.php +++ b/module/task/lang/de.php @@ -68,6 +68,7 @@ $lang->task->color = 'Color'; $lang->task->name = 'Name'; $lang->task->type = 'Typ'; $lang->task->typeAB = 'Typ'; +$lang->task->mode = 'Mode'; $lang->task->pri = 'Priorität'; $lang->task->mailto = 'Mail an'; $lang->task->estimate = 'Geplant(h)'; @@ -131,6 +132,7 @@ $lang->task->parentAB = 'Hauptaufgabe'; $lang->task->lblPri = 'P'; $lang->task->lblHour = '(h)'; $lang->task->lblTestStory = 'Story Tested'; +$lang->task->teamMember = 'Team Member'; $lang->task->ditto = 'Dito'; $lang->task->dittoNotice = "Diese Aufgabe gehört nicht zum %s wie die Vorherige!"; @@ -172,6 +174,9 @@ $lang->task->reasonList[''] = ''; $lang->task->reasonList['done'] = 'Erledigt'; $lang->task->reasonList['cancel'] = 'Abgebrochen'; +$lang->task->modeList['linear'] = 'Serial'; +$lang->task->modeList['multi'] = 'Parallel'; + $lang->task->afterChoices['continueAdding'] = ' Weitere Aufgaben erfassen'; $lang->task->afterChoices['toTaskList'] = 'Zurück zur Aufgabenliste'; $lang->task->afterChoices['toStoryList'] = 'Zurück zur Storyliste'; diff --git a/module/task/lang/en.php b/module/task/lang/en.php index fd136094ec..355f5d22f3 100644 --- a/module/task/lang/en.php +++ b/module/task/lang/en.php @@ -72,6 +72,7 @@ $lang->task->color = 'Color'; $lang->task->name = 'Name'; $lang->task->type = 'Type'; $lang->task->typeAB = 'Type'; +$lang->task->mode = 'Mode'; $lang->task->sync2Gitlab = 'Sync to GitLab'; $lang->task->pri = 'Priority'; $lang->task->mailto = 'Mailto'; @@ -149,6 +150,7 @@ $lang->task->parentAB = 'Parent'; $lang->task->lblPri = 'P'; $lang->task->lblHour = '(h)'; $lang->task->lblTestStory = 'Story Tested'; +$lang->task->teamMember = 'Team Member'; /* Fields of zt_taskestimate. */ $lang->task->task = 'Task'; @@ -198,6 +200,9 @@ $lang->task->reasonList[''] = ''; $lang->task->reasonList['done'] = 'Done'; $lang->task->reasonList['cancel'] = 'Cancelled'; +$lang->task->modeList['linear'] = 'Serial'; +$lang->task->modeList['multi'] = 'Parallel'; + $lang->task->afterChoices['continueAdding'] = ' Continue Adding Tasks'; $lang->task->afterChoices['toTaskList'] = 'Go to Task List'; $lang->task->afterChoices['toStoryList'] = 'Go to Story List'; diff --git a/module/task/lang/fr.php b/module/task/lang/fr.php index 9e5cfbf417..acf50cea8a 100644 --- a/module/task/lang/fr.php +++ b/module/task/lang/fr.php @@ -68,6 +68,7 @@ $lang->task->color = 'Couleur'; $lang->task->name = 'Nom'; $lang->task->type = 'Type'; $lang->task->typeAB = 'Type'; +$lang->task->mode = 'Mode'; $lang->task->pri = 'Priorité'; $lang->task->mailto = 'Mailto'; $lang->task->estimate = 'Estimés'; @@ -131,6 +132,7 @@ $lang->task->parentAB = 'Parent'; $lang->task->lblPri = 'P'; $lang->task->lblHour = '(h)'; $lang->task->lblTestStory = 'Story Testée'; +$lang->task->teamMember = 'Team Member'; $lang->task->ditto = 'Idem'; $lang->task->dittoNotice = "Cette Tâche n'est pas associée au %s comme la précédente peut l'être !"; @@ -172,6 +174,9 @@ $lang->task->reasonList[''] = ''; $lang->task->reasonList['done'] = 'Fait'; $lang->task->reasonList['cancel'] = 'Annulé'; +$lang->task->modeList['linear'] = 'Serial'; +$lang->task->modeList['multi'] = 'Parallel'; + $lang->task->afterChoices['continueAdding'] = ' Continuer Ajouter Tâches'; $lang->task->afterChoices['toTaskList'] = 'Aller à la liste des Tâches'; $lang->task->afterChoices['toStoryList'] = 'Aller à la liste des Stories'; diff --git a/module/task/lang/zh-cn.php b/module/task/lang/zh-cn.php index a2470ff572..89eacc29a7 100644 --- a/module/task/lang/zh-cn.php +++ b/module/task/lang/zh-cn.php @@ -72,6 +72,7 @@ $lang->task->color = '标题颜色'; $lang->task->name = '任务名称'; $lang->task->type = '任务类型'; $lang->task->typeAB = '类型'; +$lang->task->mode = '任务模式'; $lang->task->sync2Gitlab = '同步到GitLab'; $lang->task->pri = '优先级'; $lang->task->mailto = '抄送给'; @@ -149,6 +150,7 @@ $lang->task->parentAB = '父'; $lang->task->lblPri = 'P'; $lang->task->lblHour = '(h)'; $lang->task->lblTestStory = "测试{$lang->SRCommon}"; +$lang->task->teamMember = '团队成员'; /* Fields of zt_taskestimate. */ $lang->task->task = '任务'; @@ -198,6 +200,9 @@ $lang->task->reasonList[''] = ''; $lang->task->reasonList['done'] = '已完成'; $lang->task->reasonList['cancel'] = '已取消'; +$lang->task->modeList['linear'] = '串行'; +$lang->task->modeList['multi'] = '并行'; + $lang->task->afterChoices['continueAdding'] = "继续为该{$lang->SRCommon}添加任务"; $lang->task->afterChoices['toTaskList'] = '返回任务列表'; $lang->task->afterChoices['toStoryList'] = "返回{$lang->SRCommon}列表"; diff --git a/module/task/model.php b/module/task/model.php index 3947b52a85..f31ee8a612 100644 --- a/module/task/model.php +++ b/module/task/model.php @@ -895,6 +895,12 @@ class taskModel extends model return false; } + /* If a multiple task is assigned to a team member who is not the task, assign to the team member instead. */ + if(!$this->post->assignedTo and !empty($_POST['team']) and !in_array($oldTask->assignedTo, $this->post->team)) + { + $_POST['assignedTo'] = reset($_POST['team']); + } + /* When the selected parent task is a common task and has consumption, select other parent tasks. */ if($this->post->parent > 0) { @@ -942,7 +948,7 @@ class taskModel extends model ->setIF($oldTask->name != $this->post->name || $oldTask->estStarted != $this->post->estStarted || $oldTask->deadline != $this->post->deadline, 'version', $oldTask->version + 1) - ->setDefault('lastEditedBy', $this->app->user->account) + ->setDefault('lastEditedBy', $this->app->user->account) ->add('lastEditedDate', $now) ->stripTags($this->config->task->editor->edit['id'], $this->config->allowedTags) ->cleanINT('execution,story,module') @@ -1007,6 +1013,10 @@ class taskModel extends model $task->assignedTo = key($teams); } } + else + { + $task->mode = ''; + } $executionType = $this->dao->select('*')->from(TABLE_PROJECT)->where('id')->eq($task->execution)->fetch('type'); $requiredFields = "," . $this->config->task->edit->requiredFields . ","; diff --git a/module/task/view/assignto.html.php b/module/task/view/assignto.html.php index a30a8e5426..b58b8e8e65 100644 --- a/module/task/view/assignto.html.php +++ b/module/task/view/assignto.html.php @@ -14,11 +14,15 @@