Merge branch 'sprint/168' into 'sprint/168_dingna_enlang'

# Conflicts:
#   module/kanban/lang/zh-cn.php
This commit is contained in:
李玉春
2021-10-29 07:10:27 +00:00
9 changed files with 152 additions and 47 deletions
+1
View File
@@ -843,6 +843,7 @@ class bug extends control
}
}
}
if(isonlybody()) die(js::reload('parent.parent'));
die(js::locate($this->createLink('bug', 'view', "bugID=$bugID"), 'parent'));
}
+3 -4
View File
@@ -1831,7 +1831,7 @@ class execution extends control
* @access public
* @return void
*/
public function kanban($executionID, $type = 'all', $orderBy = 'order_asc', $groupBy = 'default')
public function kanban($executionID, $browseType = 'all', $orderBy = 'order_asc', $groupBy = 'default')
{
/* Save to session. */
$uri = $this->app->getURI(true);
@@ -1844,7 +1844,7 @@ class execution extends control
$kanbanGroup = $this->loadModel('kanban')->getExecutionKanban($executionID, $browseType);
if(empty($kanbanGroup))
{
$this->kanban->createLanes($executionID);
$this->kanban->createLanes($executionID, $browseType, $groupBy);
$kanbanGroup = $this->kanban->getExecutionKanban($executionID, $browseType);
}
@@ -1875,10 +1875,9 @@ class execution extends control
$this->view->executionID = $executionID;
$this->view->productID = $productID;
$this->view->allPlans = $allPlans;
$this->view->browseType = '';
$this->view->browseType = $browseType;
$this->view->kanbanGroup = $kanbanGroup;
$this->view->execution = $execution;
$this->view->type = $type;
$this->view->groupBy = $groupBy;
$this->view->canBeChanged = $canBeChanged;
+31 -22
View File
@@ -556,14 +556,17 @@ function createStoryMenu(options)
{
var $card = options.$trigger.closest('.kanban-item');
var story = $card.data('item');
var items =
[
{label: '编辑需求', icon: 'edit', url: $.createLink('story', 'edit', 'storyID=' + story.id), className: 'iframe'},
{label: '变更需求', icon: 'change', url: $.createLink('story', 'change', 'storyID=' + story.id), className: 'iframe'},
{label: '移除需求', icon: 'unlink', url: $.createLink('story', 'unlink', 'storyID=' + story.id), className: 'iframe'},
{label: '分解任务', icon: 'plus', url: $.createLink('task', 'create', 'storyID=' + story.id), className: 'iframe'},
{label: '批量分解', icon: 'pluses', url: $.createLink('task', 'batchCreate', 'storyID=' + story.id), className: 'iframe'},
];
var items = [];
$.each(story.menus, function()
{
var item = {label: this.label, icon: this.icon, url: this.url, attrs: {'data-toggle': 'modal', 'data-type': 'iframe'}};
if(this.size) item.attrs['data-width'] = this.size;
if(this.icon == 'unlink') item = {label: this.label, icon: this.icon, url: this.url, attrs: {'target': 'hiddenwin'}};
items.push(item);
});
return items;
}
@@ -575,13 +578,16 @@ function createBugMenu(options)
{
var $card = options.$trigger.closest('.kanban-item');
var bug = $card.data('item');
var items =
[
{label: '编辑Bug', icon: 'edit', url: $.createLink('bug', 'edit', 'bugID=' + bug.id), className: 'iframe'},
{label: '确认Bug', icon: 'ok', url: $.createLink('bug', 'confirm', 'bugID=' + bug.id), className: 'iframe'},
{label: '复制Bug', icon: 'copy', url: $.createLink('bug', 'copy', 'bugID=' + bug.id), className: 'iframe'},
{label: '转软件需求', icon: 'lightbulb', url: $.createLink('story', 'create', 'bugID=' + bug.id), className: 'iframe'},
];
var items = [];
$.each(bug.menus, function()
{
var item = {label: this.label, icon: this.icon, url: this.url, attrs: {'data-toggle': 'modal', 'data-type': 'iframe'}};
if(this.size) item.attrs['data-width'] = this.size;
items.push(item);
});
return items;
}
@@ -593,13 +599,16 @@ function createTaskMenu(options)
{
var $card = options.$trigger.closest('.kanban-item');
var task = $card.data('item');
var items =
[
{label: '编辑任务', icon: 'edit', url: $.createLink('task', 'edit', 'taskID=' + task.id), className: 'iframe'},
{label: '拆分子任务', icon: 'plus', url: $.createLink('task', 'create', 'taskID=' + task.id), className: 'iframe'},
{label: '复制任务', icon: 'copy', url: $.createLink('task', 'copy', 'taskID=' + task.id), className: 'iframe'},
{label: '取消任务', icon: 'cancel', url: $.createLink('task', 'cancel', 'taskID=' + task.id), className: 'iframe'},
];
var items = [];
$.each(task.menus, function()
{
var item = {label: this.label, icon: this.icon, url: this.url, attrs: {'data-toggle': 'modal', 'data-type': 'iframe'}};
if(this.size) item.attrs['data-width'] = this.size;
items.push(item);
});
return items;
}
+2 -2
View File
@@ -14,10 +14,10 @@
<div class='btn-toolbar pull-left'>
<div class="input-control space c-type">
<i class="icon icon-list-all"></i>
<?php echo html::select('type', $lang->kanban->type, $type, 'class="form-control chosen" data-max_drop_width="215"');?>
<?php echo html::select('type', $lang->kanban->type, $browseType, 'class="form-control chosen" data-max_drop_width="215"');?>
</div>
<div class="input-control space c-group">
<?php echo html::select('group', $lang->kanban->group->$type, $groupBy, 'class="form-control chosen" data-max_drop_width="215"');?>
<?php echo html::select('group', $lang->kanban->group->$browseType, $groupBy, 'class="form-control chosen" data-max_drop_width="215"');?>
</div>
</div>
<div class='btn-toolbar pull-right'>
+1
View File
@@ -50,6 +50,7 @@ $lang->kanban->columnColor = 'Column Color';
$lang->kanban->noColumnUniqueName = 'The Kanban column name already exists.';
$lang->kanban->error = new stdclass();
$lang->kanban->error->mustBeInt = 'The WIPs must be positive integer.';
$lang->kanban->error->parentLimitNote = 'The WIPs in the parent column cannot be < the sum of the WIPs in the child column.';
$lang->kanban->error->childLimitNote = 'The sum of products in the child column cannot be > the number of products in the parent column.';
+19 -13
View File
@@ -34,19 +34,25 @@ $lang->kanban->group->bug['module'] = "Bug模块";
$lang->kanban->group->bug['severity'] = "Bug严重程度";
$lang->kanban->group->bug['assignedTo'] = "指派人员";
$lang->kanban->WIP = 'WIP';
$lang->kanban->setWIP = '在制品设置';
$lang->kanban->WIPStatus = '在制品状态';
$lang->kanban->WIPStage = '在制品阶段';
$lang->kanban->WIPType = '在制品类型';
$lang->kanban->WIPCount = '在制品数量';
$lang->kanban->noLimit = '不限制∞';
$lang->kanban->setLane = '泳道设置';
$lang->kanban->laneName = '泳道名称';
$lang->kanban->laneColor = '泳道颜色';
$lang->kanban->setColumn = '看板列设置';
$lang->kanban->columnName = '看板列名称';
$lang->kanban->columnColor = '看板列颜色';
$lang->kanban->WIP = 'WIP';
$lang->kanban->setWIP = '在制品设置';
$lang->kanban->WIPStatus = '在制品状态';
$lang->kanban->WIPStage = '在制品阶段';
$lang->kanban->WIPType = '在制品类型';
$lang->kanban->WIPCount = '在制品数量';
$lang->kanban->noLimit = '不限制∞';
$lang->kanban->setLane = '泳道设置';
$lang->kanban->laneName = '泳道名称';
$lang->kanban->laneColor = '泳道颜色';
$lang->kanban->setLaneColumn = '看板列设置';
$lang->kanban->columnName = '看板列名称';
$lang->kanban->columnColor = '看板列颜色';
$lang->kanban->noColumnUniqueName = '看板列名称已存在';
$lang->kanban->error = new stdclass();
$lang->kanban->error->mustBeInt = '在制品数量必须是正整数。';
$lang->kanban->error->parentLimitNote = '父列的在制品数量不能小于子列在制品数量之和';
$lang->kanban->error->childLimitNote = '子列在制品数量之和不能大于父列的在制品数量';
$this->lang->kanban->laneTypeList = array();
$this->lang->kanban->laneTypeList['story'] = $lang->SRCommon;
+92 -6
View File
@@ -22,12 +22,12 @@ class kanbanModel extends model
* @access public
* @return array
*/
public function getExecutionKanban($executionID, $objectType = 'all', $groupBy = 'default')
public function getExecutionKanban($executionID, $browseType = 'all', $groupBy = 'default')
{
$lanes = $this->dao->select('*')->from(TABLE_KANBANLANE)
->where('execution')->eq($executionID)
->andWhere('deleted')->eq(0)
->beginIF($objectType != 'all')->andWhere('type')->eq($objectType)
->beginIF($browseType != 'all')->andWhere('type')->eq($browseType)
->beginIF($groupBy != 'default')->andWhere('extra')->eq($groupBy)
->fetchAll('id');
@@ -52,6 +52,11 @@ class kanbanModel extends model
if($browseType == 'all' or $browseType == 'bug') $objectGroup['bug'] = $this->loadModel('bug')->getExecutionBugs($executionID);
if($browseType == 'all' or $browseType == 'task') $objectGroup['task'] = $this->loadModel('execution')->getKanbanTasks($executionID, "id");
/* Get objects cards menus. */
if($browseType == 'all' or $browseType == 'story') $storyCardMenu = $this->getKanbanCardMenu($executionID, $objectGroup['story'], 'story');
if($browseType == 'all' or $browseType == 'bug') $bugCardMenu = $this->getKanbanCardMenu($executionID, $objectGroup['bug'], 'bug');
if($browseType == 'all' or $browseType == 'task') $taskCardMenu = $this->getKanbanCardMenu($executionID, $objectGroup['task'], 'task');
/* Build kanban group data. */
$kanbanGroup = array();
foreach($lanes as $laneID => $lane)
@@ -107,6 +112,10 @@ class kanbanModel extends model
$cardData['title'] = $object->title;
}
if($laneType == 'story') $cardData['menus'] = $storyCardMenu[$object->id];
if($laneType == 'bug') $cardData['menus'] = $bugCardMenu[$object->id];
if($laneType == 'task') $cardData['menus'] = $taskCardMenu[$object->id];
$laneData['cards'][$column->type][] = $cardData;
$cardOrder ++;
}
@@ -491,10 +500,12 @@ class kanbanModel extends model
public function setWIP($columnID)
{
$oldColumn = $this->getColumnById($columnID);
$column = fixer::input('post')
->cleanInt('limit')
->remove('WIPCount,noLimit')
->get();
$column = fixer::input('post')->remove('WIPCount,noLimit')->get();
if(!preg_match("/^-?\d+$/", $column->limit))
{
dao::$errors['limit'] = $this->lang->kanban->error->mustBeInt;
return false;
}
/* Check column limit. */
$sumChildLimit = 0;
@@ -591,4 +602,79 @@ class kanbanModel extends model
$changes = common::createChanges($column, $data);
return $changes;
}
/**
* Get Kanban cards menus by execution id.
*
* @param int $executionID
* @param array $objects
* @param string $objecType story|bug|task
* @access public
* @return array
*/
public function getKanbanCardMenu($executionID, $objects, $objecType)
{
$menus = array();
switch ($objecType)
{
case 'story':
if(!isset($this->story)) $this->loadModel('story');
$objects = $this->story->mergeReviewer($objects);
foreach($objects as $story)
{
$menu = array();
$toTaskPriv = strpos('draft,closed', $story->status) !== false ? false : true;
if(common::hasPriv('story', 'edit') and $this->story->isClickable($story, 'edit')) $menu[] = array('label' => $this->lang->story->edit, 'icon' => 'edit', 'url' => helper::createLink('story', 'edit', "storyID=$story->id", '', true), 'size' => '95%');
if(common::hasPriv('story', 'change') and $this->story->isClickable($story, 'change')) $menu[] = array('label' => $this->lang->story->change, 'icon' => 'alter', 'url' => helper::createLink('story', 'change', "storyID=$story->id", '', true), 'size' => '95%');
if(common::hasPriv('story', 'review') and $this->story->isClickable($story, 'review')) $menu[] = array('label' => $this->lang->story->review, 'icon' => 'search', 'url' => helper::createLink('story', 'review', "storyID=$story->id", '', true), 'size' => '95%');
if(common::hasPriv('task', 'create') and $toTaskPriv) $menu[] = array('label' => $this->lang->execution->wbs, 'icon' => 'plus', 'url' => helper::createLink('task', 'create', "executionID=$executionID&storyID=$story->id&moduleID=$story->module", '', true), 'size' => '95%');
if(common::hasPriv('task', 'batchCreate') and $toTaskPriv) $menu[] = array('label' => $this->lang->execution->batchWBS, 'icon' => 'pluses', 'url' => helper::createLink('task', 'batchCreate', "executionID=$executionID&storyID=$story->id&moduleID=0&taskID=0&iframe=true", '', true), 'size' => '95%');
if(common::hasPriv('story', 'activate') and $this->story->isClickable($story, 'activate')) $menu[] = array('label' => $this->lang->story->change, 'icon' => 'magic', 'url' => helper::createLink('story', 'activate', "storyID=$story->id", '', true));
if(common::hasPriv('execution', 'unlinkStory')) $menu[] = array('label' => $this->lang->execution->unlinkStory, 'icon' => 'unlink', 'url' => helper::createLink('execution', 'unlinkStory', "executionID=$executionID&storyID=$story->story&confirm=no", '', true));
$menus[$story->id] = $menu;
}
break;
case 'bug':
if(!isset($this->bug)) $this->loadModel('bug');
foreach($objects as $bug)
{
$menu = array();
if(common::hasPriv('bug', 'edit') and $this->bug->isClickable($bug, 'edit')) $menu[] = array('label' => $this->lang->bug->edit, 'icon' => 'edit', 'url' => helper::createLink('bug', 'edit', "bugID=$bug->id", '', true), 'size' => '95%');
if(common::hasPriv('bug', 'confirmBug') and $this->bug->isClickable($bug, 'confirmBug')) $menu[] = array('label' => $this->lang->bug->confirmBug, 'icon' => 'ok', 'url' => helper::createLink('bug', 'confirmBug', "bugID=$bug->id", '', true));
if(common::hasPriv('bug', 'resolve') and $this->bug->isClickable($bug, 'resolve')) $menu[] = array('label' => $this->lang->bug->resolve, 'icon' => 'checked', 'url' => helper::createLink('bug', 'resolve', "bugID=$bug->id", '', true));
if(common::hasPriv('bug', 'close') and $this->bug->isClickable($bug, 'close')) $menu[] = array('label' => $this->lang->bug->close, 'icon' => 'plus', 'url' => helper::createLink('bug', 'close', "bugID=$bug->id", '', true));
if(common::hasPriv('bug', 'create') and $this->bug->isClickable($bug, 'create')) $menu[] = array('label' => $this->lang->bug->copy, 'icon' => 'pluses', 'url' => helper::createLink('bug', 'create', "productID=$bug->product&branch=$bug->branch&extras=bugID=$bug->id", '', true), 'size' => '95%');
if(common::hasPriv('bug', 'activate') and $this->bug->isClickable($bug, 'activate')) $menu[] = array('label' => $this->lang->bug->activate, 'icon' => 'magic', 'url' => helper::createLink('bug', 'activate', "bugID=$bug->id", '', true));
if(common::hasPriv('story', 'create') and $bug->status != 'closed') $menu[] = array('label' => $this->lang->bug->toStory, 'icon' => 'unlink', 'url' => helper::createLink('story', 'create', "product=$bug->product&branch=$bug->branch&module=0&story=0&execution=0&bugID=$bug->id", '', true), 'size' => '95%');
$menus[$bug->id] = $menu;
}
break;
case 'task':
if(!isset($this->task)) $this->loadModel('task');
foreach($objects as $task)
{
$menu = array();
if(common::hasPriv('task', 'edit') and $this->task->isClickable($task, 'edit')) $menu[] = array('label' => $this->lang->task->edit, 'icon' => 'edit', 'url' => helper::createLink('task', 'edit', "taskID=$task->id", '', true), 'size' => '95%');
if(common::hasPriv('task', 'pause') and $this->task->isClickable($task, 'pause')) $menu[] = array('label' => $this->lang->task->pause, 'icon' => 'ok', 'url' => helper::createLink('task', 'pause', "taskID=$task->id", '', true));
if(common::hasPriv('task', 'restart') and $this->task->isClickable($task, 'restart')) $menu[] = array('label' => $this->lang->task->restart, 'icon' => 'play', 'url' => helper::createLink('task', 'restart', "taskID=$task->id", '', true));
if(common::hasPriv('task', 'recordEstimate') and $this->task->isClickable($task, 'recordEstimate')) $menu[] = array('label' => $this->lang->task->recordEstimate, 'icon' => 'time', 'url' => helper::createLink('task', 'recordEstimate', "taskID=$task->id", '', true));
if(common::hasPriv('task', 'activate') and $this->task->isClickable($task, 'activate')) $menu[] = array('label' => $this->lang->task->activate, 'icon' => 'magic', 'url' => helper::createLink('task', 'activate', "taskID=$task->id", '', true));
if(common::hasPriv('task', 'batchCreate') and $this->task->isClickable($task, 'batchCreate')) $menu[] = array('label' => $this->lang->task->children, 'icon' => 'split', 'url' => helper::createLink('task', 'batchCreate', "execution=$task->execution&storyID=$task->story&moduleID=$task->module&taskID=$task->id", '', true), 'size' => '95%');
if(common::hasPriv('task', 'create') and $this->task->isClickable($task, 'create')) $menu[] = array('label' => $this->lang->task->copy, 'icon' => 'copy', 'url' => helper::createLink('task', 'create', "projctID=$task->execution&storyID=$task->story&moduleID=$task->module&taskID=$task->id", '', true), 'size' => '95%');
if(common::hasPriv('task', 'cancel') and $this->task->isClickable($task, 'cancel')) $menu[] = array('label' => $this->lang->task->cancel, 'icon' => 'ban-circle', 'url' => helper::createLink('task', 'cancel', "taskID=$task->id", '', true));
$menus[$task->id] = $menu;
}
break;
}
return $menus;
}
}
+2
View File
@@ -589,6 +589,7 @@ class story extends control
$this->executeHooks($storyID);
if(isonlybody()) die(js::reload('parent.parent'));
if(defined('RUN_MODE') && RUN_MODE == 'api') return $this->send(array('status' => 'success', 'data' => $storyID));
die(js::locate($this->createLink($this->app->rawModule, 'view', "storyID=$storyID"), 'parent'));
}
@@ -838,6 +839,7 @@ class story extends control
$module = $this->app->tab == 'project' ? 'projectstory' : 'story';
if(isonlybody()) die(js::reload('parent.parent'));
if(defined('RUN_MODE') && RUN_MODE == 'api') return $this->send(array('status' => 'success'));
die(js::locate($this->createLink($module, 'view', "storyID=$storyID"), 'parent'));
}
+1
View File
@@ -408,6 +408,7 @@ class task extends control
}
}
if(isonlybody()) die(js::reload('parent.parent'));
if(defined('RUN_MODE') && RUN_MODE == 'api')
{
return $this->send(array('status' => 'success', 'data' => $taskID));