Merge branch 'kanban' into 'sprint/182_tianshujie_47336'
# Conflicts: # module/execution/control.php
This commit is contained in:
@@ -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`');
|
||||
|
||||
|
||||
@@ -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();
|
||||
}
|
||||
|
||||
@@ -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 + '®ionID=' + 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
|
||||
};
|
||||
|
||||
/**
|
||||
|
||||
@@ -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();
|
||||
|
||||
@@ -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
@@ -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;
|
||||
|
||||
Reference in New Issue
Block a user