Merge branch 'kanban' into 'sprint/182_tianshujie_47336'

# Conflicts:
#   module/execution/control.php
This commit is contained in:
孙广明
2022-01-12 07:53:04 +00:00
6 changed files with 185 additions and 180 deletions
+1
View File
@@ -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`');
+14
View File
@@ -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();
}
+48 -87
View File
@@ -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] ? '<i class="icon icon-check" style="margin-left: 10px"></i>' : '';
var border = i == 0 ? 'border:1px solid #b0b0b0;' : '';
cardColoritems.push({label: "<div class='cardcolor' style='background:" + colorList[i] + ";" + border + "'></div>" + 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 = $('<div class="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('<div class="actions"></div>');
var $actions = $column.children('.actions');
if(columnPrivs.includes('createCard') && column.parent != -1)
{
var cardUrl = createLink('kanban', 'createCard', 'kanbanID=' + kanbanID + '&regionID=' + regionID + '&groupID=' + groupID + '&laneID=' + laneID + '&columnID=' + columnID);
addItemBtn = ['<a data-contextmenu="columnCreate" data-toggle="modal" data-action="addItem" data-column="' + column.id + '" data-lane="' + laneID + '" href="' + cardUrl + '" class="text-primary iframe">', '<i class="icon icon-expand-alt"></i>', '</a>'].join('');
}
var moreAction = ' <button class="btn btn-link action" title="' + kanbanLang.moreAction + '" data-contextmenu="column" data-column="' + column.id + '"><i class="icon icon-ellipsis-v"></i></button>';
$actions.html(addItemBtn + moreAction);
$actions.append([
'<a data-contextmenu="columnCreate" data-type="' + column.type + '" data-kanban="' + kanban.id + '" data-parent="' + (column.parentType || '') + '" class="text-primary">',
'<i class="icon icon-expand-alt"></i>',
'</a>'
].join(''));
}
if(printMoreBtn)
{
$actions.append(' <button class="btn btn-link action" title="' + kanbanLang.moreAction + '" data-contextmenu="column" data-column="' + column.id + '"><i class="icon icon-ellipsis-v"></i></button>');
}
$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
};
/**
+1 -1
View File
@@ -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();
+48 -2
View File
@@ -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);
?>
<div id='mainMenu' class='clearfix'>
@@ -119,6 +151,20 @@ $canCreateLane = commonModel::hasPriv('kanban', 'createLane');
</div>
</div>
</div>
<div id='archivedCards'></div>
<div id='archivedColumns'></div>
<div class="modal fade" id="linkStoryByPlan">
<div class="modal-dialog mw-500px">
<div class="modal-content">
<div class="modal-header">
<button type="button" class="close" data-dismiss="modal" aria-hidden="true"><i class="icon icon-close"></i></button>
<h4 class="modal-title"><?php echo $lang->execution->linkStoryByPlan;?></h4><?php echo '(' . $lang->execution->linkStoryByPlanTips . ')';?>
</div>
<div class="modal-body">
<div class='input-group'>
<?php echo html::select('plan', $allPlans, '', "class='form-control chosen' id='plan'");?>
<span class='input-group-btn'><?php echo html::commonButton($lang->execution->linkStory, "id='toStoryButton'", 'btn btn-primary');?></span>
</div>
</div>
</div>
</div>
</div>
<?php include '../../common/view/footer.html.php';?>
+73 -90
View File
@@ -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;