diff --git a/config/zentaopms.php b/config/zentaopms.php index 5d1ef5ed25..b7b187ba3a 100644 --- a/config/zentaopms.php +++ b/config/zentaopms.php @@ -245,6 +245,7 @@ define('TABLE_KANBANCOLUMN', '`' . $config->db->prefix . 'kanbancolumn`'); define('TABLE_KANBANORDER', '`' . $config->db->prefix . 'kanbanorder`'); define('TABLE_KANBANGROUP', '`' . $config->db->prefix . 'kanbangroup`'); define('TABLE_KANBANCARD', '`' . $config->db->prefix . 'kanbancard`'); +define('TABLE_KANBANCELL', '`' . $config->db->prefix . 'kanbancell`'); if(!defined('TABLE_LANG')) define('TABLE_LANG', '`' . $config->db->prefix . 'lang`'); if(!defined('TABLE_PROJECTSPEC')) define('TABLE_PROJECTSPEC', '`' . $config->db->prefix . 'projectspec`'); diff --git a/module/execution/control.php b/module/execution/control.php index 34254711b1..8da0e8c60a 100644 --- a/module/execution/control.php +++ b/module/execution/control.php @@ -1992,6 +1992,18 @@ class execution extends control $userList[$account]['avatar'] = $avatar; } + /* Get execution's product. */ + $productID = 0; + $products = $this->loadModel('product')->getProducts($execution->project); + if($products) $productID = key($products); + + $plans = $this->execution->getPlans($products); + $allPlans = array('' => ''); + if(!empty($plans)) + { + foreach($plans as $plan) $allPlans += $plan; + } + $this->view->title = $this->lang->kanban->view; $this->view->users = $users; $this->view->regions = $kanbanData; @@ -2000,6 +2012,8 @@ class execution extends control $this->view->browseType = $browseType; $this->view->orderBy = $orderBy; $this->view->groupBy = $groupBy; + $this->view->productID = $productID; + $this->view->allPlans = $allPlans; $this->view->executionActions = $executionActions; $this->display(); } diff --git a/module/execution/js/kanban.js b/module/execution/js/kanban.js index ccbd589e45..9094d0c3cf 100644 --- a/module/execution/js/kanban.js +++ b/module/execution/js/kanban.js @@ -61,66 +61,6 @@ function createLaneMenu(options) return items; } -/** - * Create card menu. - * - * @param object $options - * @access public - * @return array - */ -function createCardMenu(options) -{ - var card = options.$trigger.closest('.kanban-item').data('item'); - var privs = card.actions; - if(!privs.length) return []; - - var items = []; - if(privs.includes('editCard')) items.push({label: kanbanLang.editCard, icon: 'edit', url: createLink('kanban', 'editCard', 'cardID=' + card.id, '', 'true'), className: 'iframe', attrs: {'data-toggle': 'modal', 'data-width': '80%'}}); - if(privs.includes('archiveCard') && kanban.archived == '1') items.push({label: kanbanLang.archiveCard, icon: 'card-archive', url: createLink('kanban', 'archiveCard', 'cardID=' + card.id), attrs: {'target': 'hiddenwin'}}); - if(privs.includes('copyCard')) items.push({label: kanbanLang.copyCard, icon: 'copy', url: createLink('kanban', 'copyCard', 'cardID=' + card.id, '', 'true'), className: 'iframe', attrs: {'data-toggle': 'modal'}}); - if(privs.includes('deleteCard')) items.push({label: kanbanLang.deleteCard, icon: 'trash', url: createLink('kanban', 'deleteCard', 'cardID=' + card.id), attrs: {'target': 'hiddenwin'}}); - if(privs.includes('moveCard')) - { - var moveCardItems = []; - var moveColumns = []; - var parentColumns = []; - var regionGroups = regions[options.$trigger.closest('.region').data('id')].groups; - for(let i = 0; i < regionGroups.length ; i ++ ) - { - if(regionGroups[i].id == options.$trigger.closest('.kanban-board').data('id')) - { - moveColumns = regionGroups[i].columns; - break; - } - } - for(let i = moveColumns.length-1 ; i >= 0 ; i -- ) - { - if(moveColumns[i].parent > 0) parentColumns.push(moveColumns[i].parent); - if(moveColumns[i].id == card.column || $.inArray(moveColumns[i].id, parentColumns) >= 0) continue; - moveCardItems.push({label: moveColumns[i].name, onClick: function(){moveCard(card.id, moveColumns[i].id, card.lane, card.kanban, card.region);}}); - } - moveCardItems = moveCardItems.reverse(); - items.push({label: kanbanLang.moveCard, icon: 'move', items: moveCardItems}); - } - if(privs.includes('setCardColor')) - { - var cardColoritems = []; - if(!card.color) color = "#fff"; - for(let i = 0 ; i < colorList.length ; i ++ ) - { - var attr = card.color == colorList[i] ? '' : ''; - var border = i == 0 ? 'border:1px solid #b0b0b0;' : ''; - cardColoritems.push({label: "
" + colorListLang[colorList[i]] + attr , - onClick: function(){setCardColor(card.id, colorList[i], card.kanban, card.region);}, html: true, attrs: {id: 'cardcolormenu'}, className: 'color' + i}); - }; - items.push({label: kanbanLang.cardColor, icon: 'color', items: cardColoritems}); - } - - var bounds = options.$trigger[0].getBoundingClientRect(); - items.$options = {x: bounds.right, y: bounds.top}; - return items; -} - function createColumnMenu(options) { var column = options.$trigger.closest('.kanban-col').data('col'); @@ -130,14 +70,6 @@ function createColumnMenu(options) var items = []; if(privs.includes('setColumn')) items.push({label: kanbanLang.editColumn, icon: 'edit', url: createLink('kanban', 'setColumn', 'columnID=' + column.id, '', 'true'), className: 'iframe', attrs: {'data-toggle': 'modal'}}); if(privs.includes('setWIP')) items.push({label: kanbanLang.setWIP, icon: 'alert', url: createLink('kanban', 'setWIP', 'columnID=' + column.id), className: 'iframe', attrs: {'data-toggle': 'modal', 'data-width' : '500px'}}); - if(privs.includes('splitColumn')) items.push({label: kanbanLang.splitColumn, icon: 'col-split', url: createLink('kanban', 'splitColumn', 'columnID=' + column.id, '', true), className: 'iframe', attrs: {'data-toggle': 'modal'}}); - if(privs.includes('createColumn')) - { - items.push({label: kanbanLang.createColumnOnLeft, icon: 'col-add-left', url: createLink('kanban', 'createColumn', 'columnID=' + column.id + '&position=left'), className: 'iframe', attrs: {'data-toggle': 'modal'}}); - items.push({label: kanbanLang.createColumnOnRight, icon: 'col-add-right', url: createLink('kanban', 'createColumn', 'columnID=' + column.id + '&position=right'), className: 'iframe', attrs: {'data-toggle': 'modal'}}); - } - if(privs.includes('copyColumn')) items.push({label: kanbanLang.copyColumn, icon: 'copy', url: createLink('kanban', 'copyColumn', 'columnID=' + column.id), className: 'iframe', attrs: {'data-toggle': 'modal'}}); - if(privs.includes('archiveColumn') && kanban.archived == '1' && column.$kanbanData.columns.length > 1) items.push({label: kanbanLang.archiveColumn, icon: 'card-archive', url: createLink('kanban', 'archiveColumn', 'columnID=' + column.id), attrs: {'target': 'hiddenwin'}}); if(privs.includes('deleteColumn') && column.$kanbanData.columns.length > 1) items.push({label: kanbanLang.deleteColumn, icon: 'trash', url: createLink('kanban', 'deleteColumn', 'columnID=' + column.id), attrs: {'target': 'hiddenwin'}}); var bounds = options.$trigger[0].getBoundingClientRect(); @@ -145,6 +77,35 @@ function createColumnMenu(options) return items; } +/** + * Create column create button menu + * @returns {Object[]} + */ +function createColumnCreateMenu(options) +{ + var $col = options.$trigger.closest('.kanban-col'); + var col = $col.data('col'); + var items = []; + + if(col.type == 'backlog') + { + if(priv.canCreateStory) items.push({label: storyLang.create, url: $.createLink('story', 'create', 'productID=' + productID)}); + if(priv.canBatchCreateStory) items.push({label: executionLang.batchCreateStroy, url: $.createLink('story', 'batchcreate', 'productID=' + productID + '&branch=0&moduleID=0&storyID=0&executionID=' + executionID)}); + if(priv.canLinkStory) items.push({label: executionLang.linkStory, url: $.createLink('execution', 'linkStory', 'executionID=' + executionID)}); + if(priv.canLinkStoryByPlane) items.push({label: executionLang.linkStoryByPlan, url: '#linkStoryByPlan', 'attrs' : {'data-toggle': 'modal'}}); + } + else if(col.type == 'unconfirmed') + { + if(priv.canCreateBug) items.push({label: bugLang.create, url: $.createLink('bug', 'create', 'productID=0&moduleID=0&extra=executionID=' + executionID)}); + if(priv.canBatchCreateBug) items.push({label: bugLang.batchCreate, url: $.createLink('bug', 'batchcreate', 'productID=' + productID + '&moduleID=0&executionID=' + executionID)}); + } + else if(col.type == 'wait') + { + if(priv.canCreateTask) items.push({label: taskLang.create, url: $.createLink('task', 'create', 'executionID=' + executionID, '', true), className: 'iframe', attrs: {'data-toggle': 'modal', 'data-width': '80%'}}); + if(priv.canBatchCreateTask) items.push({label: taskLang.batchCreate, url: $.createLink('task', 'batchcreate', 'executionID=' + executionID, '', true), className: 'iframe', attrs: {'data-toggle': 'modal', 'data-width': '80%'}}); + } + return items; +} /** * Hide kanban action @@ -235,6 +196,7 @@ function renderHeaderCol($column, column, $header, kanbanData) /* Render group header. */ var privs = kanbanData.actions; var columnPrivs = kanbanData.columns[0].actions; + var $actions = $('
'); if(privs.includes('sortGroup')) { @@ -255,26 +217,22 @@ function renderHeaderCol($column, column, $header, kanbanData) var groupID = $column.closest('.kanban-board').data('id'); var laneID = column.$kanbanData.lanes[0].id ? column.$kanbanData.lanes[0].id : 0; var columnID = $column.closest('.kanban-col').data('id'); - var printMoreBtn = (columnPrivs.includes('setColumn') || columnPrivs.includes('setWIP') || columnPrivs.includes('createColumn') || columnPrivs.includes('copyColumn') || columnPrivs.includes('archiveColumn') || columnPrivs.includes('deleteColumn') || columnPrivs.includes('splitColumn')); + var printMoreBtn = (columnPrivs.includes('setColumn') || columnPrivs.includes('setWIP') || columnPrivs.includes('deleteColumn')); /* Render more menu. */ - if(columnPrivs.includes('createCard') || printMoreBtn) + if((column.type == 'backlog' && hasStoryButton) || (column.type == 'wait' && hasTaskButton) || (column.type == 'unconfirmed' && hasBugButton)) { - var addItemBtn = ''; - var moreAction = ''; - - if(!$column.children('.actions').length) $column.append('
'); - var $actions = $column.children('.actions'); - - if(columnPrivs.includes('createCard') && column.parent != -1) - { - var cardUrl = createLink('kanban', 'createCard', 'kanbanID=' + kanbanID + '®ionID=' + regionID + '&groupID=' + groupID + '&laneID=' + laneID + '&columnID=' + columnID); - addItemBtn = ['', '', ''].join(''); - } - - var moreAction = ' '; - $actions.html(addItemBtn + moreAction); + $actions.append([ + '', + '', + '' + ].join('')); } + if(printMoreBtn) + { + $actions.append(' '); + } + $actions.appendTo($column); } /** @@ -307,6 +265,7 @@ function renderLaneName($lane, lane, $kanban, columns, kanban) ].join('')).appendTo($lane); } } + /** * Adjust add button postion in column */ @@ -328,6 +287,7 @@ function adjustAddBtnPosition($kanban) $col.toggleClass('has-scrollbar', items.scrollHeight > items.clientHeight); }); } + /** * Handle kanban action */ @@ -355,6 +315,7 @@ function processMinusBtn() $('#splitTable .btn-plus').hide(); } } + /** * The function for rendering kanban item */ @@ -446,9 +407,9 @@ function renderKanbanItem(item, $item) /* Define menu creators */ window.menuCreators = { - card: createCardMenu, - lane: createLaneMenu, - column: createColumnMenu + lane: createLaneMenu, + column: createColumnMenu, + columnCreate: createColumnCreateMenu }; /** diff --git a/module/execution/model.php b/module/execution/model.php index b9a5aed9b7..fd0ac79003 100644 --- a/module/execution/model.php +++ b/module/execution/model.php @@ -381,7 +381,7 @@ class executionModel extends model $creatorExists = false; $teamMembers = array(); - if(isset($project) and $project->model != 'kanban') $this->loadModel('kanban')->createExecutionLane($executionID); + if((isset($project) and $project->model != 'kanban') or empty($project)) $this->loadModel('kanban')->createExecutionLane($executionID); /* Save order. */ $this->dao->update(TABLE_EXECUTION)->set('`order`')->eq($executionID * 5)->where('id')->eq($executionID)->exec(); diff --git a/module/execution/view/kanban.html.php b/module/execution/view/kanban.html.php index 227d766668..8799bdd2ce 100644 --- a/module/execution/view/kanban.html.php +++ b/module/execution/view/kanban.html.php @@ -19,8 +19,13 @@ foreach($regions as $region) $laneCount += $region->laneCount; js::set('regions', $regions); js::set('execution', $execution); +js::set('productID', $productID); js::set('kanbanLang', $lang->kanban); js::set('kanbanlaneLang', $lang->kanbanlane); +js::set('storyLang', $lang->story); +js::set('executionLang', $lang->execution); +js::set('bugLang', $lang->bug); +js::set('taskLang', $lang->task); js::set('kanbancolumnLang', $lang->kanbancolumn); js::set('kanbancardLang', $lang->kanbancard); js::set('executionID', $execution->id); @@ -35,6 +40,33 @@ $canSortRegion = commonModel::hasPriv('kanban', 'sortRegion') && count($region $canEditRegion = commonModel::hasPriv('kanban', 'editRegion'); $canDeleteRegion = commonModel::hasPriv('kanban', 'deleteRegion'); $canCreateLane = commonModel::hasPriv('kanban', 'createLane'); +$canCreateTask = common::hasPriv('task', 'create'); +$canBatchCreateTask = common::hasPriv('task', 'batchCreate'); +$canCreateBug = common::hasPriv('bug', 'create'); +$canBatchCreateBug = common::hasPriv('bug', 'batchCreate'); +$canCreateStory = ($productID and common::hasPriv('story', 'create')); +$canBatchCreateStory = ($productID and common::hasPriv('story', 'batchCreate')); +$canLinkStory = ($productID and common::hasPriv('execution', 'linkStory')); +$canLinkStoryByPlane = ($productID and common::hasPriv('execution', 'importplanstories')); +$hasStoryButton = ($canCreateStory or $canBatchCreateStory or $canLinkStory or $canLinkStoryByPlane); +$hasTaskButton = ($canCreateTask or $canBatchCreateTask); +$hasBugButton = ($canCreateBug or $canBatchCreateBug); + +js::set('priv', + array( + 'canCreateTask' => $canCreateTask, + 'canBatchCreateTask' => $canBatchCreateTask, + 'canCreateBug' => $canCreateBug, + 'canBatchCreateBug' => $canBatchCreateBug, + 'canCreateStory' => $canCreateStory, + 'canBatchCreateStory' => $canBatchCreateStory, + 'canLinkStory' => $canLinkStory, + 'canLinkStoryByPlane' => $canLinkStoryByPlane, + ) +); +js::set('hasStoryButton', $hasStoryButton); +js::set('hasBugButton', $hasBugButton); +js::set('hasTaskButton', $hasTaskButton); ?>
-
-
+ diff --git a/module/kanban/model.php b/module/kanban/model.php index a24ad1b8f9..6ec24ff40a 100644 --- a/module/kanban/model.php +++ b/module/kanban/model.php @@ -313,6 +313,11 @@ class kanbanModel extends model $this->dao->update(TABLE_KANBANCOLUMN)->set('type')->eq("column{$columnID}")->where('id')->eq($columnID)->exec(); + /* Add kanban cell. */ + $lanes = $this->dao->select('id')->from(TABLE_KANBANLANE)->where('`group`')->eq($column->group)->fetchPairs(); + $kanbanID = $this->dao->select('kanban')->from(TABLE_KANBANREGION)->where('id')->eq($regionID)->fetch('kanban'); + foreach($lanes as $laneID) $this->addKanbanCell($kanbanID, $laneID, $columnID, 'card'); + return $columnID; } @@ -418,8 +423,6 @@ class kanbanModel extends model ->add('kanban', $kanbanID) ->add('region', $regionID) ->add('group', $groupID) - ->add('lane', $laneID) - ->add('column', $columnID) ->add('createdBy', $this->app->user->account) ->add('createdDate', $now) ->add('assignedDate', $now) @@ -444,6 +447,7 @@ class kanbanModel extends model $cardID = $this->dao->lastInsertID(); $this->file->saveUpload('kanbancard', $cardID); $this->file->updateObjectID($this->post->uid, $cardID, 'kanbancard'); + $this->addKanbanCell($kanbanID, $laneID, $columnID, 'card', $cardID); return $cardID; } @@ -649,7 +653,7 @@ class kanbanModel extends model $lanes = zget($laneGroup, $group->id, array()); if(!$lanes) continue; - foreach($lanes as $lane) $lane->items = array(); + foreach($lanes as $lane) $lane->items = array(); $group->columns = zget($columnGroup, $group->id, array()); $group->lanes = $lanes; @@ -913,18 +917,10 @@ class kanbanModel extends model */ public function getCardGroupByExecution($executionID, $browseType = 'all', $orderBy = 'id_asc') { - $cards = $this->dao->select("id, title, pri, type, severity, assignedTo, '' as estimate, deadline")->from(TABLE_BUG) - ->where('deleted')->eq(0) - ->andWhere('execution')->eq($executionID) - ->fetchAll('id'); -/* - $cards .= $this->dao->select("id, name, pri, '' as severity, assignedTo, deadline")->from(TABLE_TASK) - ->where('deleted')->eq(0) - ->andWhere('execution')->eq($executionID) - ->fetchAll('id'); - */ - - $planList = $this->loadModel('execution')->getById($executionID); + $cards = array(); + if($browseType == 'all' or $browseType == 'story') $cards['story'] = $this->loadModel('story')->getExecutionStories($executionID, 0, 0, $orderBy); + if($browseType == 'all' or $browseType == 'bug') $cards['bug'] = $this->loadModel('bug')->getExecutionBugs($executionID, 0, 0, '', 0, $orderBy); + if($browseType == 'all' or $browseType == 'task') $cards['task'] = $this->loadModel('execution')->getKanbanTasks($executionID, $orderBy); return $cards; } @@ -953,19 +949,21 @@ class kanbanModel extends model if(empty($lanes)) return array(); - foreach($lanes as $lane) $this->updateCards($lane); + foreach($lanes as $lane) $this->refreshCards($lane); - $columns = $this->dao->select('*')->from(TABLE_KANBANCOLUMN) - ->where('deleted')->eq(0) - ->andWhere('lane')->in(array_keys($lanes)) + $columns = $this->dao->select('t1.cards, t1.lane, t2.id, t2.type, t2.name, t2.color, t2.limit, t2.parent')->from(TABLE_KANBANCELL)->alias('t1') + ->leftJoin(TABLE_KANBANCOLUMN)->alias('t2')->on('t1.column = t2.id') + ->where('t2.deleted')->eq(0) + ->andWhere('t1.lane')->in(array_keys($lanes)) ->orderBy('id_asc') ->fetchGroup('lane', 'id'); /* Get parent column type pairs. */ - $parentTypes = $this->dao->select('id, type')->from(TABLE_KANBANCOLUMN) - ->where('deleted')->eq(0) - ->andWhere('lane')->in(array_keys($lanes)) - ->andWhere('parent')->eq(-1) + $parentTypes = $this->dao->select('t2.id, t2.type')->from(TABLE_KANBANCELL)->alias('t1') + ->leftJoin(TABLE_KANBANCOLUMN)->alias('t2')->on('t1.column = t2.id') + ->where('t2.deleted')->eq(0) + ->andWhere('t1.lane')->in(array_keys($lanes)) + ->andWhere('t2.parent')->eq(-1) ->fetchPairs('id', 'type'); /* Get group objects. */ @@ -1554,7 +1552,6 @@ class kanbanModel extends model } } - $cards = ''; $devColumnID = $testColumnID = $resolvingColumnID = 0; if($type == 'story') { @@ -1576,15 +1573,7 @@ class kanbanModel extends model if($colType == 'develop') $devColumnID = $colID; if($colType == 'test') $testColumnID = $colID; - if(strpos(',ready,develop,test,', $colType) === false) - { - $storyStatus = $this->config->kanban->storyColumnStatusList[$colType]; - $storyStage = $this->config->kanban->storyColumnStageList[$colType]; - foreach($objects as $storyID => $story) - { - if($story->status == $storyStatus and $story->stage == $storyStage) $cards .= $storyID . ','; - } - } + if(strpos(',develop,test,', $colType) === false) $this->addKanbanCell($executionID, $laneID, $colID, 'story'); } } elseif($type == 'bug') @@ -1606,25 +1595,7 @@ class kanbanModel extends model if($colType == 'resolving') $resolvingColumnID = $colID; if($colType == 'test') $testColumnID = $colID; - if(strpos(',resolving,fixing,test,testing,tested,', $colType) === false) - { - $bugStatus = $this->config->kanban->bugColumnStatusList[$colType]; - foreach($objects as $bugID => $bug) - { - if($colType == 'unconfirmed' and $bug->status == $bugStatus and $bug->confirmed == 0) - { - $cards .= $bugID . ','; - } - elseif($colType == 'confirmed' and $bug->status == $bugStatus and $bug->confirmed == 1) - { - $cards .= $bugID . ','; - } - elseif(strpos(',unconfirmed,confirmed,', $colType) === false and $bug->status == $bugStatus) - { - $cards .= $bugID . ','; - } - } - } + if(strpos(',resolving,test,', $colType) === false) $this->addKanbanCell($executionID, $laneID, $colID, 'bug'); } } elseif($type == 'task') @@ -1643,46 +1614,48 @@ class kanbanModel extends model $colID = $this->dao->lastInsertId(); if($colType == 'develop') $devColumnID = $colID; - } - - if(strpos(',develop,', $colType) === false) - { - $taskStatus = $this->config->kanban->taskColumnStatusList[$colType]; - foreach($objects as $taskID => $task) - { - if($task->status == $taskStatus) $cards .= $taskID . ','; - } + if($colType != 'develop') $this->addKanbanCell($executionID, $laneID, $colID, 'task'); } } - - if(!empty($cards)) $this->parkCards($executionID, $laneID, $colID, $cards, $type); } /** - * Park cards into kanban cell. + * Add kanban cell for new lane. * * @param int $kanbanID * @param int $laneID * @param int $colID - * @param string $cards - * @param string $type + * @param string $type story|task|bug|card * @access public * @return void */ - public function parkCards($kanbanID, $laneID, $colID, $cards, $type) + public function addKanbanCell($kanbanID, $laneID, $colID, $type, $cardID = 0) { - $cards = ',' . $cards; + $cell = $this->dao->select('id, cards')->from(TABLE_KANBANCELL) + ->where('kanban')->eq($kanbanID) + ->andWhere('lane')->eq($laneID) + ->andWhere('`column`')->eq($colID) + ->andWhere('type')->eq($type) + ->fetch(); - $cardGroup = new stdclass(); - $cardGroup->kanban = $executionID; - $cardGroup->lane = $laneID; - $cardGroup->column = $colID; - $cardGroup->type = $type; - $cardGroup->cards = $cards; + if(empty($cell)) + { + $cell = new stdclass(); + $cell->kanban = $kanbanID; + $cell->lane = $laneID; + $cell->column = $colID; + $cell->type = $type; - $this->dao->insert(TABLE_KANBANCELL)->data($cardGroup)->exec(); + $this->dao->insert(TABLE_KANBANCELL)->data($cell)->exec(); + } + else + { + $cell->cards = $cell->cards ? $cell->cards . "$carID," : ",$carID,"; + $this->dao->update(TABLE_KANBANCELL)->set('cards')->eq($cell->cards)->where('id')->eq($cell->id)->exec(); + } } + /** * Create a default RD kanban. * @@ -1846,24 +1819,25 @@ class kanbanModel extends model ->andWhere('type')->eq($laneType) ->fetchAll('id'); - foreach($lanes as $lane) $this->updateCards($lane); + foreach($lanes as $lane) $this->refreshCards($lane); } /** - * Update column cards. + * Refresh column cards. * * @param object $lane * @access public * @return void */ - public function updateCards($lane) + public function refreshCards($lane) { $laneType = $lane->type; $executionID = $lane->execution; - $cardPairs = $this->dao->select('*')->from(TABLE_KANBANCOLUMN) - ->where('deleted')->eq(0) - ->andWhere('lane')->eq($lane->id) - ->fetchPairs('type' ,'cards'); + $cardPairs = $this->dao->select('t2.type, t1.cards')->from(TABLE_KANBANCELL)->alias('t1') + ->leftJoin(TABLE_KANBANCOLUMN)->alias('t2')->on('t1.`column` = t2.id') + ->where('t1.kanban')->eq($executionID) + ->andWhere('t1.lane')->eq($lane->id) + ->fetchPairs(); if($laneType == 'story') { @@ -1877,21 +1851,23 @@ class kanbanModel extends model $cardPairs[$colType] = str_replace(",$storyID,", ',', $cardPairs[$colType]); } - if(strpos(',ready,develop,test,', $colType) !== false) continue; + 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($colType == 'backlog' and $story->stage == $stage and strpos($cardPairs['ready'], ",$storyID,") === false and strpos($cardPairs['backlog'], ",$storyID,") === false) - { - $cardPairs['backlog'] = empty($cardPairs['backlog']) ? ",$storyID," : ",$storyID" . $cardPairs['backlog']; - } - elseif($story->stage == $stage and strpos($cardPairs[$colType], ",$storyID,") === false and $colType != 'backlog') + elseif($story->stage == $stage and strpos($cardPairs[$colType], ",$storyID,") === false) { $cardPairs[$colType] = empty($cardPairs[$colType]) ? ",$storyID," : ",$storyID" . $cardPairs[$colType]; } } + + if($story->stage == 'projected' and strpos($cardPairs['ready'], ",$storyID,") === false and strpos($cardPairs['backlog'], ",$storyID,") === false) + { + $cardPairs['backlog'] = empty($cardPairs['backlog']) ? ",$storyID," : ",$storyID" . $cardPairs['backlog']; + } + } } elseif($laneType == 'bug') @@ -1966,9 +1942,16 @@ class kanbanModel extends model } } + $colPairs = $this->dao->select('t2.type, t2.id')->from(TABLE_KANBANCELL)->alias('t1') + ->leftJoin(TABLE_KANBANCOLUMN)->alias('t2')->on('t1.`column` = t2.id') + ->where('t1.kanban')->eq($executionID) + ->andWhere('t1.lane')->eq($lane->id) + ->fetchPairs(); + foreach($cardPairs as $colType => $cards) { - $this->dao->update(TABLE_KANBANCOLUMN)->set('cards')->eq($cards)->where('lane')->eq($lane->id)->andWhere('type')->eq($colType)->exec(); + if(!isset($colPairs[$colType])) continue; + $this->dao->update(TABLE_KANBANCELL)->set('cards')->eq($cards)->where('lane')->eq($lane->id)->andWhere('`column`')->eq($colPairs[$colType])->exec(); } $this->dao->update(TABLE_KANBANLANE)->set('lastEditedTime')->eq(helper::now())->where('id')->eq($lane->id)->exec(); @@ -2031,7 +2014,7 @@ class kanbanModel extends model } $this->dao->update(TABLE_KANBANLANE)->set('name')->eq($laneName)->where('id')->eq($laneID)->exec(); - $this->updateCards($lane); + $this->refreshCards($lane); $colorIndex += 1; if($colorIndex == count($this->config->kanban->laneColorList)) $colorIndex = 0;