diff --git a/db/update16.1.sql b/db/update16.1.sql index 909017b861..64a39a5490 100644 --- a/db/update16.1.sql +++ b/db/update16.1.sql @@ -11,8 +11,5 @@ CREATE TABLE `zt_kanbancell` ( ALTER TABLE `zt_kanban` ADD `displayCards` smallint(6) NOT NULL default '0' AFTER `order`; ALTER TABLE `zt_project` ADD `displayCards` smallint(6) NOT NULL default '0' AFTER `order`; -ALTER TABLE `zt_kanbancard` DROP COLUMN `lane`; -ALTER TABLE `zt_kanbancard` DROP COLUMN `column`; -ALTER TABLE `zt_kanbancolumn` DROP `lane`; UPDATE `zt_grouppriv` SET `method` = 'taskKanban' WHERE `module` = 'execution' AND `method` = 'kanban'; diff --git a/module/execution/control.php b/module/execution/control.php index 2c04bfbc19..8be5dde37d 100644 --- a/module/execution/control.php +++ b/module/execution/control.php @@ -3541,7 +3541,7 @@ class execution extends control $enterTime = date('Y-m-d H:i:s', $enterTime); $lastEditedTime = $this->dao->select("max(lastEditedTime) as lastEditedTime")->from(TABLE_KANBANLANE)->where('execution')->eq($executionID)->fetch('lastEditedTime'); - if($lastEditedTime > $enterTime) + if($lastEditedTime > $enterTime or $groupBy != 'default') { $kanbanGroup = $this->loadModel('kanban')->getExecutionKanban($executionID, $browseType, $groupBy); die(json_encode($kanbanGroup)); diff --git a/module/execution/js/taskkanban.js b/module/execution/js/taskkanban.js index bdbe808df3..ba81c8bf4a 100644 --- a/module/execution/js/taskkanban.js +++ b/module/execution/js/taskkanban.js @@ -689,7 +689,7 @@ function changeCardColType(cardID, fromColID, toColID, fromLaneID, toLaneID, car */ function handleDropTask($element, event, kanban) { - if(!event.target || !event.isNew) return; + if(!event.target) return; var $card = $element; var $oldCol = $card.closest('.kanban-col'); @@ -985,6 +985,8 @@ $(function() onRenderCount: renderColumnCount }; + if(groupBy != 'default') commonOptions.droppable = false; + /* Create kanban */ if(groupBy == 'default') { diff --git a/module/execution/model.php b/module/execution/model.php index ab93463ad2..41c2016401 100644 --- a/module/execution/model.php +++ b/module/execution/model.php @@ -88,15 +88,6 @@ class executionModel extends model unset($this->lang->execution->menu->build); } - /* Hide story and qa menu when execution is story or design type. */ - /* - if($execution and ($execution->attribute == 'story' or $execution->attribute == 'design')) - { - unset($this->lang->execution->menu->story); - unset($this->lang->execution->menu->qa); - } - */ - if($executions and (!isset($executions[$executionID]) or !$this->checkPriv($executionID))) $this->accessDenied(); $moduleName = $this->app->getModuleName(); diff --git a/module/kanban/model.php b/module/kanban/model.php index 952179dfa3..661924d73a 100644 --- a/module/kanban/model.php +++ b/module/kanban/model.php @@ -993,7 +993,8 @@ class kanbanModel extends model */ public function getExecutionKanban($executionID, $browseType = 'all', $groupBy = 'default') { - if($groupBy != 'default') return $this->getKanbanByGroup($executionID, $browseType, $groupBy); + if($groupBy != 'default') return $this->getKanban4Group($executionID, $browseType, $groupBy); + $lanes = $this->dao->select('*')->from(TABLE_KANBANLANE) ->where('execution')->eq($executionID) ->andWhere('deleted')->eq(0) @@ -1101,6 +1102,192 @@ class kanbanModel extends model return $kanbanGroup; } + /** + * Get kanban for group view. + * + * @param int $executionID + * @param string $browseType + * @param string $groupBy + * @access public + * @return array + */ + public function getKanban4Group($executionID, $browseType, $groupBy) + { + /* Get card data. */ + if($browseType == 'story') $cardList = $this->loadModel('story')->getExecutionStories($executionID); + if($browseType == 'bug') $cardList = $this->loadModel('bug')->getExecutionBugs($executionID); + if($browseType == 'task') $cardList = $this->loadModel('execution')->getKanbanTasks($executionID, "id"); + + $lanes = $this->getLanes4Group($executionID, $browseType, $groupBy, $cardList); + if(empty($lanes)) return array(); + + $columns = $this->dao->select('t1.*, t2.`type` as columnType')->from(TABLE_KANBANCELL)->alias('t1') + ->leftJoin(TABLE_KANBANCOLUMN)->alias('t2')->on('t1.`column` = t2.id') + ->where('t1.kanban')->eq($executionID) + ->andWhere('t1.`type`')->eq($browseType) + ->fetchAll(); + + $cardGroup = array(); + foreach($columns as $column) + { + if(empty($column->cards)) continue; + foreach($cardList as $card) + { + if(strpos($column->cards, ",$card->id,") !== false) $cardGroup[$column->columnType][$card->id] = $card; + } + } + + /* Build kanban group data. */ + $kanbanGroup = array(); + foreach($lanes as $laneID => $lane) + { + $laneData = array(); + $columnData = array(); + $columnList = $this->lang->kanban->{$browseType . 'Column'}; + + $laneData['id'] = $groupBy . $laneID; + $laneData['laneID'] = $groupBy . $laneID; + $laneData['name'] = (($groupBy == 'pri' or $groupBy == 'severity') and $laneID) ? $this->lang->$browseType->$groupBy . ':' . $lane->name : $lane->name; + $laneData['color'] = $lane->color; + $laneData['order'] = $lane->order; + $laneData['defaultCardType'] = $browseType; + + /* Construct kanban column data. */ + foreach($columnList as $columnID => $columnName) + { + $parentColumn = ''; + if(in_array($columnID, array('developing', 'developed'))) $parentColumn = 'develop'; + if(in_array($columnID, array('testing', 'tested'))) $parentColumn = 'test'; + if(in_array($columnID, array('fixing', 'fixed'))) $parentColumn = 'resolving'; + + $columnData[$columnID]['id'] = $columnID; + $columnData[$columnID]['type'] = $columnID; + $columnData[$columnID]['name'] = $columnName; + $columnData[$columnID]['color'] = '#333'; + $columnData[$columnID]['limit'] = -1; + $columnData[$columnID]['laneType'] = $browseType; + $columnData[$columnID]['asParent'] = in_array($columnID, array('develop', 'test', 'resolving')) ? true : false; + $columnData[$columnID]['parentType'] = $parentColumn; + + $cardOrder = 1; + $objects = zget($cardGroup, $columnID, array()); + foreach($objects as $object) + { + if(empty($object)) continue; + + $cardData = array(); + if(in_array($groupBy, array('module', 'story', 'pri', 'severity')) and (int)$object->$groupBy !== $laneID) continue; + if(in_array($groupBy, array('assignedTo', 'type', 'category', 'source')) and $object->$groupBy != $laneID) continue; + + $cardData['id'] = $object->id; + $cardData['order'] = $cardOrder; + $cardData['pri'] = $object->pri ? $object->pri : ''; + $cardData['estimate'] = $browseType == 'bug' ? '' : $object->estimate; + $cardData['assignedTo'] = $object->assignedTo; + $cardData['deadline'] = $browseType == 'story' ? '' : $object->deadline; + $cardData['severity'] = $browseType == 'bug' ? $object->severity : ''; + + if($browseType == 'task') + { + $cardData['name'] = $object->name; + } + else + { + $cardData['title'] = $object->title; + } + + $laneData['cards'][$columnID][] = $cardData; + $cardOrder ++; + } + if(!isset($laneData['cards'][$columnID])) $laneData['cards'][$columnID] = array(); + } + + $kanbanGroup[$groupBy]['id'] = $groupBy . $laneID; + $kanbanGroup[$groupBy]['columns'] = array_values($columnData); + $kanbanGroup[$groupBy]['lanes'][] = $laneData; + $kanbanGroup[$groupBy]['defaultCardType'] = $browseType; + } + + return $kanbanGroup; + } + + /** + * Build lane data for group kanban. + * + * @access public + * @param int $executionID + * @param string $browseType + * @param string $groupBy + * @param array $cardList + * @return array + */ + public function getLanes4Group($executionID, $browseType, $groupBy, $cardList) + { + $lanes = array(); + $groupByList = array(); + $objectPairs = array(); + foreach($cardList as $item) + { + if(!isset($groupByList[$item->$groupBy])) $groupByList[$item->$groupBy] = $item->$groupBy; + } + + if(in_array($groupBy, array('module', 'story', 'pri', 'severity'))) $objectPairs[0] = $this->lang->$browseType->$groupBy . ': ' . $this->lang->kanban->noGroup; + if(in_array($groupBy, array('assignedTo', 'type', 'category', 'source'))) $objectPairs[''] = $this->lang->$browseType->$groupBy . ': ' . $this->lang->kanban->noGroup; + + if(in_array($groupBy, array('module', 'story', 'assignedTo'))) + { + if($groupBy == 'module') + { + $objectPairs += $this->dao->select('id,name')->from(TABLE_MODULE) + ->where('type')->in('story,task,bug') + ->andWhere('deleted')->eq('0') + ->andWhere('id')->in($groupByList) + ->fetchPairs(); + } + elseif($groupBy == 'story') + { + $objectPairs += $this->dao->select('id,title')->from(TABLE_STORY) + ->where('deleted')->eq(0) + ->andWhere('id')->in($groupByList) + ->fetchPairs(); + } + else + { + $objectPairs += $this->dao->select('account,realname')->from(TABLE_USER) + ->where('account')->in($groupByList) + ->fetchPairs(); + + if(isset($groupByList['closed'])) $objectPairs['closed'] = 'Closed'; + } + } + else + { + $objectPairs += $this->lang->$browseType->{$groupBy . 'List'}; + } + + $laneColor = 0; + $order = 1; + foreach($objectPairs as $objectID => $objectName) + { + if(!isset($groupByList[$objectID]) and $objectID) continue; + + $lane = new stdclass(); + $lane->id = $groupBy . $objectID; + $lane->type = $browseType; + $lane->execution = $executionID; + $lane->name = $objectName; + $lane->order = $order; + $lane->color = $this->config->kanban->laneColorList[$laneColor]; + + $order += 1; + $laneColor += 1; + if($laneColor == count($this->config->kanban->laneColorList)) $laneColor = 0; + $lanes[$objectID] = $lane; + } + + return $lanes; + } + /** * Get space list. * @@ -1929,11 +2116,7 @@ class kanbanModel extends model if(strpos(',ready,backlog,develop,test,', $colType) !== false) continue; - if($lane->groupby and $story->{$lane->groupby} != $lane->extra) - { - $cardPairs[$colType] = str_replace(",$storyID,", ',', $cardPairs[$colType]); - } - elseif($story->stage == $stage and strpos($cardPairs[$colType], ",$storyID,") === false) + if($story->stage == $stage and strpos($cardPairs[$colType], ",$storyID,") === false) { $cardPairs[$colType] = empty($cardPairs[$colType]) ? ",$storyID," : ",$storyID" . $cardPairs[$colType]; } @@ -1960,11 +2143,7 @@ class kanbanModel extends model if(strpos(',resolving,test,testing,tested,', $colType) !== false) continue; - if($lane->groupby and $bug->{$lane->groupby} != $lane->extra) - { - $cardPairs[$colType] = str_replace(",$bugID,", ',', $cardPairs[$colType]); - } - elseif($colType == 'unconfirmed' and $bug->status == $status and $bug->confirmed == 0 and strpos($cardPairs['unconfirmed'], ",$bugID,") === false and strpos($cardPairs['fixing'], ",$bugID,") === false and $bug->activatedCount == 0) + if($colType == 'unconfirmed' and $bug->status == $status and $bug->confirmed == 0 and strpos($cardPairs['unconfirmed'], ",$bugID,") === false and strpos($cardPairs['fixing'], ",$bugID,") === false and $bug->activatedCount == 0) { $cardPairs['unconfirmed'] = empty($cardPairs['unconfirmed']) ? ",$bugID," : ",$bugID" . $cardPairs['unconfirmed']; if(strpos($cardPairs['closed'], ",$bugID,") !== false) $cardPairs['closed'] = str_replace(",$bugID,", ',', $cardPairs['closed']); @@ -2002,11 +2181,7 @@ class kanbanModel extends model { if($colType == 'develop') continue; - if($lane->groupby and $task->{$lane->groupby} != $lane->extra) - { - $cardPairs[$colType] = str_replace(",$taskID,", ',', $cardPairs[$colType]); - } - elseif($task->status == $status and strpos($cardPairs[$colType], ",$taskID,") === false) + if($task->status == $status and strpos($cardPairs[$colType], ",$taskID,") === false) { $cardPairs[$colType] = empty($cardPairs[$colType]) ? ",$taskID," : ",$taskID". $cardPairs[$colType]; } @@ -2033,103 +2208,6 @@ class kanbanModel extends model $this->dao->update(TABLE_KANBANLANE)->set('lastEditedTime')->eq(helper::now())->where('id')->eq($lane->id)->exec(); } - /** - * Update group lanes. - * - * @param int $executionID - * @param string $type - * @param string $groupBy - * @access public - * @return array - */ - public function updateGroupLanes($executionID, $type, $groupBy) - { - $this->loadModel($type); - - $lanes = $this->dao->select('*')->from(TABLE_KANBANLANE) - ->where('execution')->eq($executionID) - ->andWhere('deleted')->eq(0) - ->andWhere('type')->eq($type)->fi() - ->andWhere('groupby')->eq($groupBy)->fi() - ->orderBy('order_asc') - ->fetchAll('id'); - - /* Get old group list of kanban lane. */ - $oldGroupList = array(); - foreach($lanes as $lane) $oldGroupList[] = $lane->extra; - - /* Get new group list of kanban lane. */ - $groupList = $this->getObjectGroup($executionID, $type, $groupBy); - - $removeGroupList = array_diff($oldGroupList, $groupList); - $addGroupList = array_diff($groupList, $oldGroupList); - - $objectPairs = array(); - if($groupBy == 'module') $objectPairs = $this->dao->select('id,name')->from(TABLE_MODULE)->where('type')->in('story,bug,task')->andWhere('deleted')->eq('0')->fetchPairs(); - if($groupBy == 'story') $objectPairs = $this->dao->select('id,title')->from(TABLE_STORY)->where('deleted')->eq(0)->fetchPairs(); - if($groupBy == 'assignedTo') $objectPairs = $this->loadModel('user')->getPairs('noletter'); - - $colorIndex = 0; - - foreach($lanes as $laneID => $lane) - { - if(in_array($lane->extra, $removeGroupList)) - { - /* Remove lane and cloumns by laneID. */ - $this->dao->delete()->from(TABLE_KANBANLANE)->where('id')->eq($laneID)->exec(); - - $colPairs = $this->dao->select('`column`')->from(TABLE_KANBANCELL)->where('lane')->eq($laneID)->fetchPairs(); - if(!empty($colPairs)) $this->dao->delete()->from(TABLE_KANBANCOLUMN)->where('id')->in($colPairs)->exec(); - } - else - { - /* Update kanban lanes by group. */ - $laneName = $this->lang->$type->$groupBy . ': ' . $this->lang->kanban->noGroup; - if($lane->extra) - { - $namePairs = strpos('module,story,assignedTo', $groupBy) !== false ? $objectPairs : $this->lang->$type->{$groupBy . 'List'}; - $laneName = $this->lang->$type->$groupBy . ': ' . zget($namePairs, $lane->extra); - } - - $this->dao->update(TABLE_KANBANLANE)->set('name')->eq($laneName)->where('id')->eq($laneID)->exec(); - $this->refreshCards($lane); - - $colorIndex += 1; - if($colorIndex == count($this->config->kanban->laneColorList)) $colorIndex = 0; - } - } - - /* Add new lanes by group. */ - $lanePairs = array(); - foreach($addGroupList as $groupKey) - { - $laneName = $this->lang->kanban->noGroup; - if($groupKey) - { - $namePairs = strpos('module,story,assignedTo', $groupBy) !== false ? $objectPairs : $this->lang->$type->{$groupBy . 'List'}; - $laneName = zget($namePairs, $groupKey); - } - - $lane = new stdClass(); - $lane->execution = $executionID; - $lane->type = $type; - $lane->groupby = $groupBy; - $lane->extra = $groupKey; - $lane->name = $this->lang->$type->$groupBy . ": " . $laneName; - $lane->color = $this->config->kanban->laneColorList[$colorIndex]; - - $colorIndex += 1; - if($colorIndex == count($this->config->kanban->laneColorList)) $colorIndex = 0; - $this->dao->insert(TABLE_KANBANLANE)->data($lane)->exec(); - - $laneID = $this->dao->lastInsertId(); - $lanePairs[$laneID] = $laneID; - } - - if($lanePairs) $this->createExecutionColumns($lanePairs, $type, $executionID); - $this->resetLaneOrder($executionID, $type, $groupBy); - } - /** * Update lane column. * @@ -2961,174 +3039,4 @@ class kanbanModel extends model return true; } - - /** - * Get kanban group. - * - * @param int $executionID - * @param string $browseType - * @param string $groupBy - * @access public - * @return array - */ - public function getKanbanByGroup($executionID, $browseType, $groupBy) - { - /* Get card data. */ - if($browseType == 'story') $cardList = $this->loadModel('story')->getExecutionStories($executionID); - if($browseType == 'bug') $cardList = $this->loadModel('bug')->getExecutionBugs($executionID); - if($browseType == 'task') $cardList = $this->loadModel('execution')->getKanbanTasks($executionID, "id"); - - /* Construct lane data. */ - $lanes = array(); - $groupByList = array(); - $objectPairs = array(); - foreach($cardList as $item) - { - if(!isset($groupByList[$item->$groupBy])) $groupByList[$item->$groupBy] = $item->$groupBy; - } - if(in_array($groupBy, array('module', 'story', 'pri', 'severity'))) $objectPairs[0] = $this->lang->$browseType->$groupBy . ': ' . $this->lang->kanban->noGroup; - if(in_array($groupBy, array('assignedTo', 'type', 'category', 'source'))) $objectPairs[''] = $this->lang->$browseType->$groupBy . ': ' . $this->lang->kanban->noGroup; - - if(in_array($groupBy, array('module', 'story', 'assignedTo'))) - { - if($groupBy == 'module') - { - $objectPairs += $this->dao->select('id,name')->from(TABLE_MODULE) - ->where('type')->in('story,task,bug') - ->andWhere('deleted')->eq('0') - ->andWhere('id')->in($groupByList) - ->fetchPairs(); - } - elseif($groupBy == 'story') - { - $objectPairs += $this->dao->select('id,title')->from(TABLE_STORY) - ->where('deleted')->eq(0) - ->andWhere('id')->in($groupByList) - ->fetchPairs(); - } - else - { - $objectPairs += $this->dao->select('account,realname')->from(TABLE_USER) - ->where('account')->in($groupByList) - ->fetchPairs(); - - if(isset($groupByList['closed'])) $objectPairs['closed'] = 'Closed'; - } - } - else - { - $objectPairs += $this->lang->$browseType->{$groupBy . 'List'}; - } - - $laneColor = 0; - $order = 1; - foreach($objectPairs as $objectID => $objectName) - { - if(!isset($groupByList[$objectID]) and $objectID) continue; - - $lane = new stdclass(); - $lane->id = $groupBy . $objectID; - $lane->type = $groupBy . $objectID; - $lane->execution = $executionID; - $lane->name = $objectName; - $lane->order = $order; - $lane->color = $this->config->kanban->laneColorList[$laneColor]; - - $order += 1; - $laneColor += 1; - if($laneColor == count($this->config->kanban->laneColorList)) $laneColor = 0; - $lanes[$objectID] = $lane; - } - - if(empty($lanes)) return array(); - - $columns = $this->dao->select('t1.*, t2.`type` as columnType')->from(TABLE_KANBANCELL)->alias('t1') - ->leftJoin(TABLE_KANBANCOLUMN)->alias('t2')->on('t1.`column`=t2.id') - ->where('t1.kanban')->eq($executionID) - ->andWhere('t1.`type`')->eq($browseType) - ->fetchAll(); - - $cardGroup = array(); - foreach($columns as $column) - { - if(empty($column->cards)) continue; - foreach($cardList as $card) - { - if(strpos($column->cards, $card->id) !== false) $cardGroup[$column->columnType][$card->id] = $card; - } - } - - /* Build kanban group data. */ - $kanbanGroup = array(); - foreach($lanes as $laneID => $lane) - { - $laneData = array(); - $columnData = array(); - $columnList = $this->lang->kanban->{$browseType . 'Column'}; - - $laneData['id'] = $groupBy . $laneID; - $laneData['laneID'] = $groupBy . $laneID; - $laneData['name'] = (($groupBy == 'pri' or $groupBy == 'severity') and $laneID) ? $this->lang->$browseType->$groupBy . ':' . $lane->name : $lane->name; - $laneData['color'] = $lane->color; - $laneData['order'] = $lane->order; - $laneData['defaultCardType'] = $browseType; - - /* Construct kanban column data. */ - foreach($columnList as $columnID => $columnName) - { - $parentColumn = ''; - if(in_array($columnID, array('developing', 'developed'))) $parentColumn = 'develop'; - if(in_array($columnID, array('testing', 'tested'))) $parentColumn = 'test'; - if(in_array($columnID, array('fixing', 'fixed'))) $parentColumn = 'resolving'; - - $columnData[$columnID]['id'] = $columnID; - $columnData[$columnID]['type'] = $columnID; - $columnData[$columnID]['name'] = $columnName; - $columnData[$columnID]['color'] = '#333'; - $columnData[$columnID]['limit'] = -1; - $columnData[$columnID]['laneType'] = $groupBy . $laneID; - $columnData[$columnID]['asParent'] = in_array($columnID, array('develop', 'test', 'resolving')) ? true : false; - $columnData[$columnID]['parent'] = $parentColumn ? $parentColumn : 0; - if($parentColumn) $columnData[$columnID]['parentType'] = $parentColumn; - - $cardOrder = 1; - $objects = zget($cardGroup, $columnID, array()); - foreach($objects as $object) - { - $cardData = array(); - if(empty($object)) continue; - if(in_array($groupBy, array('module', 'story', 'pri', 'severity')) and (int)$object->$groupBy !== $laneID) continue; - if(in_array($groupBy, array('assignedTo', 'type', 'category', 'source')) and $object->$groupBy != $laneID) continue; - - $cardData['id'] = $object->id; - $cardData['order'] = $cardOrder; - $cardData['pri'] = $object->pri ? $object->pri : ''; - $cardData['estimate'] = $browseType == 'bug' ? '' : $object->estimate; - $cardData['assignedTo'] = $object->assignedTo; - $cardData['deadline'] = $browseType == 'story' ? '' : $object->deadline; - $cardData['severity'] = $browseType == 'bug' ? $object->severity : ''; - - if($browseType == 'task') - { - $cardData['name'] = $object->name; - } - else - { - $cardData['title'] = $object->title; - } - - $laneData['cards'][$columnID][] = $cardData; - $cardOrder ++; - } - if(!isset($laneData['cards'][$columnID])) $laneData['cards'][$columnID] = array(); - } - - $kanbanGroup[$groupBy]['id'] = $groupBy . $laneID; - $kanbanGroup[$groupBy]['columns'] = array_values($columnData); - $kanbanGroup[$groupBy]['lanes'][] = $laneData; - $kanbanGroup[$groupBy]['defaultCardType'] = $browseType; - } - - return $kanbanGroup; - } } diff --git a/module/upgrade/model.php b/module/upgrade/model.php index e16dffe286..6f1b48d905 100644 --- a/module/upgrade/model.php +++ b/module/upgrade/model.php @@ -5404,6 +5404,7 @@ class upgradeModel extends model $this->dao->exec("ALTER TABLE " . TABLE_KANBANCARD . " DROP COLUMN `lane`;"); $this->dao->exec("ALTER TABLE " . TABLE_KANBANCARD . " DROP COLUMN `column`;"); + $this->dao->exec("ALTER TABLE " . TABLE_KANBANCOLUMN . " DROP COLUMN `lane`;"); } /**