Merge branch 'sgm_fixbug'
This commit is contained in:
+1
-1
@@ -16,7 +16,7 @@ if(!class_exists('config')){class config{}}
|
||||
if(!function_exists('getWebRoot')){function getWebRoot(){}}
|
||||
|
||||
/* 基本设置。Basic settings. */
|
||||
$config->version = '16.1'; // ZenTaoPHP的版本。 The version of ZenTaoPHP. Don't change it.
|
||||
$config->version = '16.2'; // ZenTaoPHP的版本。 The version of ZenTaoPHP. Don't change it.
|
||||
$config->charset = 'UTF-8'; // ZenTaoPHP的编码。 The encoding of ZenTaoPHP.
|
||||
$config->cookieLife = time() + 2592000; // Cookie的生存时间。The cookie life time.
|
||||
$config->timezone = 'Asia/Shanghai'; // 时区设置。 The time zone setting, for more see http://www.php.net/manual/en/timezones.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`');
|
||||
|
||||
|
||||
@@ -0,0 +1,15 @@
|
||||
CREATE TABLE `zt_kanbancell` (
|
||||
`id` int(8) NOT NULL AUTO_INCREMENT,
|
||||
`kanban` mediumint(8) NOT NULL,
|
||||
`lane` mediumint(8) NOT NULL,
|
||||
`column` mediumint(8) NOT NULL,
|
||||
`type` char(30) NOT NULL,
|
||||
`cards` text NOT NULL,
|
||||
PRIMARY KEY (`id`),
|
||||
UNIQUE KEY `card_group` (`kanban`,`type`,`lane`,`column`)
|
||||
) ENGINE=MyISAM DEFAULT CHARSET=utf8;
|
||||
|
||||
ALTER TABLE `zt_kanban` ADD `displayCards` smallint(6) NOT NULL default '0' AFTER `order`;
|
||||
ALTER TABLE `zt_project` ADD `displayCards` smallint(6) NOT NULL default '0' AFTER `order`;
|
||||
|
||||
UPDATE `zt_grouppriv` SET `method` = 'taskKanban' WHERE `module` = 'execution' AND `method` = 'kanban';
|
||||
+13
-2
@@ -677,6 +677,7 @@ CREATE TABLE `zt_kanban` (
|
||||
`archived` enum('0', '1') NOT NULL DEFAULT '0',
|
||||
`status` enum('active','closed') NOT NULL default 'active',
|
||||
`order` mediumint(8) NOT NULL DEFAULT '0',
|
||||
`displayCards` smallint(6) NOT NULL default '0',
|
||||
`createdBy` char(30) NOT NULL,
|
||||
`createdDate` datetime NOT NULL,
|
||||
`lastEditedBy` char(30) NOT NULL,
|
||||
@@ -706,8 +707,6 @@ CREATE TABLE `zt_kanbancard` (
|
||||
`kanban` mediumint(8) unsigned NOT NULL,
|
||||
`region` mediumint(8) unsigned NOT NULL,
|
||||
`group` mediumint(8) unsigned NOT NULL,
|
||||
`lane` mediumint(8) unsigned NOT NULL,
|
||||
`column` mediumint(8) unsigned NOT NULL,
|
||||
`name` varchar(255) NOT NULL,
|
||||
`pri` mediumint(8) unsigned NOT NULL,
|
||||
`assignedTo` text NOT NULL,
|
||||
@@ -731,6 +730,17 @@ CREATE TABLE `zt_kanbancard` (
|
||||
`deleted` enum('0', '1') NOT NULL DEFAULT '0',
|
||||
PRIMARY KEY (`id`)
|
||||
) ENGINE=MyISAM DEFAULT CHARSET=utf8;
|
||||
-- DROP TABLE IF EXISTS `zt_kanbancell`;
|
||||
CREATE TABLE `zt_kanbancell` (
|
||||
`id` int(8) NOT NULL AUTO_INCREMENT,
|
||||
`kanban` mediumint(8) NOT NULL,
|
||||
`lane` mediumint(8) NOT NULL,
|
||||
`column` mediumint(8) NOT NULL,
|
||||
`type` char(30) NOT NULL,
|
||||
`cards` text NOT NULL,
|
||||
PRIMARY KEY (`id`),
|
||||
UNIQUE KEY `card_group` (`kanban`,`type`,`lane`,`column`)
|
||||
) ENGINE=MyISAM DEFAULT CHARSET=utf8;
|
||||
-- DROP TABLE IF EXISTS `zt_kanbangroup`;
|
||||
CREATE TABLE `zt_kanbangroup` (
|
||||
`id` mediumint(8) unsigned NOT NULL AUTO_INCREMENT,
|
||||
@@ -1010,6 +1020,7 @@ CREATE TABLE IF NOT EXISTS `zt_project` (
|
||||
`acl` char(30) NOT NULL DEFAULT 'open',
|
||||
`whitelist` text NOT NULL,
|
||||
`order` mediumint(8) unsigned NOT NULL,
|
||||
`displayCards` smallint(6) NOT NULL default '0',
|
||||
`deleted` enum('0','1') NOT NULL DEFAULT '0',
|
||||
PRIMARY KEY (`id`),
|
||||
KEY `parent` (`parent`),
|
||||
|
||||
@@ -1,3 +1,34 @@
|
||||
2022-01-17 16.2
|
||||
28397 选择项目管理方式弹窗中增加专业研发看板
|
||||
28398 实现专业研发看板项目的创建功能
|
||||
28403 实现研发看板的新建按钮组功能
|
||||
28405 实现专业研发看板在项目列表中的展示方式
|
||||
28406 实现专业研发看板的默认视图功能
|
||||
28420 打印研发看板的设置下拉菜单
|
||||
28421 实现看板新增区域功能
|
||||
29708 实现专业研发看板项目的看板视图
|
||||
29709 实现研发看板卡片的更多设置菜单
|
||||
29710 实现专业研发看板创建功能
|
||||
29714 实现专业研发看板设置功能
|
||||
29715 研发看板中实现区域的展开/收起功能
|
||||
29717 研发看板中打印区域更多设置下拉菜单
|
||||
29719 研发看板中实现区域的编辑功能
|
||||
29720 研发看板中实现删除区域功能
|
||||
29721 实现专业看板的全屏查看功能
|
||||
29723 研发看板中实现泳道拖动排序功能
|
||||
29724 研发看板中实现泳道组拖动排序功能
|
||||
29725 研发看板中需求不支持拆分子需求
|
||||
29726 研发看板中任务不支持拆分子任务
|
||||
29728 研发看板中实现新增泳道功能
|
||||
29729 研发看板中实现删除泳道功能
|
||||
29730 研发看板中实现看板的开始/延期/挂起/关闭/删除操作
|
||||
29732 鼠标悬浮到卡片头像上时显示人员姓名
|
||||
29767 执行列表中增加看板icon标识
|
||||
29890 看板的相关操作要记历史记录
|
||||
30042 实现通用看板设置泳道高度功能
|
||||
30043 实现执行看板设置泳道高度功能
|
||||
30053 实现研发看板设置泳道高度功能
|
||||
30068 通用看板中默认的模版横向不要有滚动条
|
||||
2022-01-11 16.1
|
||||
46672 实现计划卡片的更多设置功能
|
||||
46671 计划看板中实现卡片的排序功能
|
||||
|
||||
@@ -863,7 +863,7 @@ class actionModel extends model
|
||||
|
||||
/* Get actions. */
|
||||
$actions = $this->dao->select('*')->from(TABLE_ACTION)
|
||||
->where(1)
|
||||
->where('objectType')->notIN('kanbanregion,kanbanlane,kanbancolumn')
|
||||
->beginIF($period != 'all')->andWhere('date')->gt($begin)->fi()
|
||||
->beginIF($period != 'all')->andWhere('date')->lt($end)->fi()
|
||||
->beginIF($date)->andWhere('date' . ($direction == 'next' ? '<' : '>') . "'{$date}'")->fi()
|
||||
@@ -1291,6 +1291,12 @@ class actionModel extends model
|
||||
}
|
||||
$action->objectLink = helper::createLink($moduleName, $methodName, $params);
|
||||
|
||||
if($action->objectType == 'execution')
|
||||
{
|
||||
$execution = $this->loadModel('execution')->getById($action->objectID);
|
||||
if(!empty($execution) and $execution->type == 'kanban') $action->objectLink = helper::createLink('execution', 'kanban', "executionID={$action->objectID}");
|
||||
}
|
||||
|
||||
if($action->objectType == 'doclib')
|
||||
{
|
||||
$docLib = $this->dao->select('type,product,project,execution,deleted')->from(TABLE_DOCLIB)->where('id')->eq($action->objectID)->fetch();
|
||||
|
||||
@@ -905,7 +905,7 @@ class block extends control
|
||||
|
||||
foreach($projects as $projectID => $project)
|
||||
{
|
||||
if($project->model == 'scrum')
|
||||
if($project->model == 'scrum' or $project->model == 'kanban')
|
||||
{
|
||||
$this->app->loadClass('pager', $static = true);
|
||||
$pager = pager::init(0, 3, 1);
|
||||
@@ -1809,7 +1809,7 @@ class block extends control
|
||||
/* load pager. */
|
||||
$this->app->loadClass('pager', $static = true);
|
||||
$pager = new pager(0, 3, 1);
|
||||
$this->view->projects = $this->loadModel('project')->getInfoList('all', 30, 'id_desc', $pager);
|
||||
$this->view->projects = $this->loadModel('project')->getInfoList('all', 'id_desc', $pager);
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -134,7 +134,7 @@ $(function()
|
||||
<?php foreach($projects as $project):?>
|
||||
<div class="tab-pane fade<?php if($project->id == $selected) echo ' active in';?>" id="tab3Content<?php echo $project->id;?>">
|
||||
<div class="table-row">
|
||||
<?php if($project->model == 'scrum'):?>
|
||||
<?php if($project->model == 'scrum' or $project->model == 'kanban'):?>
|
||||
<div class='table-row'>
|
||||
<div class="col-4 text-center">
|
||||
<div><h4><?php echo $lang->block->story;?></h4></div>
|
||||
|
||||
+20
-14
@@ -361,7 +361,7 @@ class bug extends control
|
||||
|
||||
/* Set from param if there is a object to transfer bug. */
|
||||
setcookie('lastBugModule', (int)$this->post->module, $this->config->cookieLife, $this->config->webRoot, '', $this->config->cookieSecure, false);
|
||||
$bugResult = $this->bug->create($from = isset($fromObjectIDKey) ? $fromObjectIDKey : '');
|
||||
$bugResult = $this->bug->create($from = isset($fromObjectIDKey) ? $fromObjectIDKey : '', $extras);
|
||||
if(!$bugResult or dao::isError())
|
||||
{
|
||||
$response['result'] = 'fail';
|
||||
@@ -662,14 +662,15 @@ class bug extends control
|
||||
* @param int $productID
|
||||
* @param int $executionID
|
||||
* @param int $moduleID
|
||||
* @param string $extra
|
||||
* @access public
|
||||
* @return void
|
||||
*/
|
||||
public function batchCreate($productID, $branch = '', $executionID = 0, $moduleID = 0)
|
||||
public function batchCreate($productID, $branch = '', $executionID = 0, $moduleID = 0, $extra = '')
|
||||
{
|
||||
if(!empty($_POST))
|
||||
{
|
||||
$actions = $this->bug->batchCreate($productID, $branch);
|
||||
$actions = $this->bug->batchCreate($productID, $branch, $extra);
|
||||
|
||||
/* Return bug id list when call the API. */
|
||||
if($this->viewType == 'json')
|
||||
@@ -693,8 +694,9 @@ class bug extends control
|
||||
/* If executionID is setted, get builds and stories of this execution. */
|
||||
if($executionID)
|
||||
{
|
||||
$builds = $this->loadModel('build')->getBuildPairs($productID, $branch, 'noempty', $executionID, 'execution');
|
||||
$stories = $this->story->getExecutionStoryPairs($executionID);
|
||||
$builds = $this->loadModel('build')->getBuildPairs($productID, $branch, 'noempty', $executionID, 'execution');
|
||||
$stories = $this->story->getExecutionStoryPairs($executionID);
|
||||
$execution = $this->loadModel('execution')->getById($executionID);
|
||||
}
|
||||
else
|
||||
{
|
||||
@@ -737,7 +739,7 @@ class bug extends control
|
||||
$showFields = trim($showFields, ',');
|
||||
}
|
||||
|
||||
$projectID = $this->lang->navGroup->bug == 'project' ? $this->session->project : 0;
|
||||
$projectID = $this->lang->navGroup->bug == 'project' ? $this->session->project : (isset($execution) ? $execution->project : 0);
|
||||
|
||||
$this->view->customFields = $customFields;
|
||||
$this->view->showFields = $showFields;
|
||||
@@ -1344,14 +1346,15 @@ class bug extends control
|
||||
* confirm a bug.
|
||||
*
|
||||
* @param int $bugID
|
||||
* @param string $extra
|
||||
* @access public
|
||||
* @return void
|
||||
*/
|
||||
public function confirmBug($bugID)
|
||||
public function confirmBug($bugID, $extra = '')
|
||||
{
|
||||
if(!empty($_POST))
|
||||
{
|
||||
$changes = $this->bug->confirm($bugID);
|
||||
$changes = $this->bug->confirm($bugID, $extra);
|
||||
if(dao::isError()) return print(js::error(dao::getError()));
|
||||
$actionID = $this->action->create('bug', $bugID, 'bugConfirmed', $this->post->comment);
|
||||
$this->action->logHistory($actionID, $changes);
|
||||
@@ -1399,14 +1402,15 @@ class bug extends control
|
||||
* Resolve a bug.
|
||||
*
|
||||
* @param int $bugID
|
||||
* @param string $extra
|
||||
* @access public
|
||||
* @return void
|
||||
*/
|
||||
public function resolve($bugID)
|
||||
public function resolve($bugID, $extra = '')
|
||||
{
|
||||
if(!empty($_POST))
|
||||
{
|
||||
$changes = $this->bug->resolve($bugID);
|
||||
$changes = $this->bug->resolve($bugID, $extra);
|
||||
if(dao::isError()) die(js::error(dao::getError()));
|
||||
$files = $this->loadModel('file')->saveUpload('bug', $bugID);
|
||||
|
||||
@@ -1492,14 +1496,15 @@ class bug extends control
|
||||
* Activate a bug.
|
||||
*
|
||||
* @param int $bugID
|
||||
* @param string $extra
|
||||
* @access public
|
||||
* @return void
|
||||
*/
|
||||
public function activate($bugID)
|
||||
public function activate($bugID, $extra = '')
|
||||
{
|
||||
if(!empty($_POST))
|
||||
{
|
||||
$changes = $this->bug->activate($bugID);
|
||||
$changes = $this->bug->activate($bugID, $extra);
|
||||
if(dao::isError()) die(js::error(dao::getError()));
|
||||
|
||||
$files = $this->loadModel('file')->saveUpload('bug', $bugID);
|
||||
@@ -1534,14 +1539,15 @@ class bug extends control
|
||||
* Close a bug.
|
||||
*
|
||||
* @param int $bugID
|
||||
* @param string $extra
|
||||
* @access public
|
||||
* @return void
|
||||
*/
|
||||
public function close($bugID)
|
||||
public function close($bugID, $extra = '')
|
||||
{
|
||||
if(!empty($_POST))
|
||||
{
|
||||
$changes = $this->bug->close($bugID);
|
||||
$changes = $this->bug->close($bugID, $extra);
|
||||
if(dao::isError()) die(js::error(dao::getError()));
|
||||
|
||||
$actionID = $this->action->create('bug', $bugID, 'Closed', $this->post->comment);
|
||||
|
||||
+67
-12
@@ -49,11 +49,15 @@ class bugModel extends model
|
||||
* Create a bug.
|
||||
*
|
||||
* @param string $from object that is transfered to bug.
|
||||
* @param string $extras.
|
||||
* @access public
|
||||
* @return array|bool
|
||||
*/
|
||||
public function create($from = '')
|
||||
public function create($from = '', $extras = '')
|
||||
{
|
||||
$extras = str_replace(array(',', ' '), array('&', ''), $extras);
|
||||
parse_str($extras, $output);
|
||||
|
||||
$now = helper::now();
|
||||
$bug = fixer::input('post')
|
||||
->setDefault('openedBy', $this->app->user->account)
|
||||
@@ -100,7 +104,12 @@ class bugModel extends model
|
||||
$this->file->saveUpload('bug', $bugID);
|
||||
empty($bug->case) ? $this->loadModel('score')->create('bug', 'create', $bugID) : $this->loadModel('score')->create('bug', 'createFormCase', $bug->case);
|
||||
|
||||
if($bug->execution) $this->loadModel('kanban')->updateLane($bug->execution, 'bug');
|
||||
if($bug->execution)
|
||||
{
|
||||
$this->loadModel('kanban');
|
||||
if(isset($output['laneID']) and isset($output['columnID'])) $this->kanban->addKanbanCell($bug->execution, $output['laneID'], $output['columnID'], 'bug', $bugID);
|
||||
if(!isset($output['laneID']) or !isset($output['columnID'])) $this->kanban->updateLane($bug->execution, 'bug');
|
||||
}
|
||||
|
||||
/* Callback the callable method to process the related data for object that is transfered to bug. */
|
||||
if($from && is_callable(array($this, $this->config->bug->fromObjects[$from]['callback']))) call_user_func(array($this, $this->config->bug->fromObjects[$from]['callback']), $bugID);
|
||||
@@ -115,13 +124,18 @@ class bugModel extends model
|
||||
*
|
||||
* @param int $productID
|
||||
* @param int $branch
|
||||
* @param string $extra
|
||||
* @access public
|
||||
* @return void
|
||||
*/
|
||||
public function batchCreate($productID, $branch = 0)
|
||||
public function batchCreate($productID, $branch = 0, $extra = '')
|
||||
{
|
||||
$extra = str_replace(array(',', ' '), array('&', ''), $extra);
|
||||
parse_str($extra, $output);
|
||||
|
||||
/* Load module and init vars. */
|
||||
$this->loadModel('action');
|
||||
$this->loadModel('kanban');
|
||||
$branch = (int)$branch;
|
||||
$productID = (int)$productID;
|
||||
$now = helper::now();
|
||||
@@ -257,8 +271,13 @@ class bugModel extends model
|
||||
$bugID = $this->dao->lastInsertID();
|
||||
|
||||
$this->executeHooks($bugID);
|
||||
if($bug->execution) $this->loadModel('kanban')->updateLane($bug->execution, 'bug');
|
||||
|
||||
if($bug->execution)
|
||||
{
|
||||
if(isset($output['laneID']) and isset($output['columnID'])) $this->kanban->addKanbanCell($bug->execution, $output['laneID'], $output['columnID'], 'bug', $bugID);
|
||||
if(!isset($output['laneID']) or !isset($output['columnID'])) $this->kanban->updateLane($bug->execution, 'bug');
|
||||
|
||||
}
|
||||
/* When the bug is created by uploading the image, add the image to the file of the bug. */
|
||||
$this->loadModel('score')->create('bug', 'create', $bugID);
|
||||
if(!empty($data->uploadImage[$i]) and !empty($file))
|
||||
@@ -907,11 +926,15 @@ class bugModel extends model
|
||||
* Confirm a bug.
|
||||
*
|
||||
* @param int $bugID
|
||||
* @param string $extra
|
||||
* @access public
|
||||
* @return void
|
||||
*/
|
||||
public function confirm($bugID)
|
||||
public function confirm($bugID, $extra = '')
|
||||
{
|
||||
$extra = str_replace(array(',', ' '), array('&', ''), $extra);
|
||||
parse_str($extra, $output);
|
||||
|
||||
$now = helper::now();
|
||||
$oldBug = $this->getById($bugID);
|
||||
|
||||
@@ -929,7 +952,12 @@ class bugModel extends model
|
||||
if(!dao::isError())
|
||||
{
|
||||
$this->loadModel('score')->create('bug', 'confirmBug', $oldBug);
|
||||
if($oldBug->execution) $this->loadModel('kanban')->updateLane($oldBug->execution, 'bug');
|
||||
if($oldBug->execution)
|
||||
{
|
||||
$this->loadModel('kanban');
|
||||
if(!isset($output['toColID'])) $this->kanban->updateLane($oldBug->execution, 'bug', $bugID);
|
||||
if(isset($output['toColID'])) $this->kanban->moveCard($bugID, $output['fromColID'], $output['toColID'], $output['fromLaneID'], $output['toLaneID']);
|
||||
}
|
||||
return common::createChanges($oldBug, $bug);
|
||||
}
|
||||
}
|
||||
@@ -964,11 +992,15 @@ class bugModel extends model
|
||||
* Resolve a bug.
|
||||
*
|
||||
* @param int $bugID
|
||||
* @param string $extra
|
||||
* @access public
|
||||
* @return void
|
||||
*/
|
||||
public function resolve($bugID)
|
||||
public function resolve($bugID, $extra = '')
|
||||
{
|
||||
$extra = str_replace(array(',', ' '), array('&', ''), $extra);
|
||||
parse_str($extra, $output);
|
||||
|
||||
$now = helper::now();
|
||||
$oldBug = $this->getById($bugID);
|
||||
$bug = fixer::input('post')
|
||||
@@ -1042,7 +1074,12 @@ class bugModel extends model
|
||||
if(!dao::isError())
|
||||
{
|
||||
$this->loadModel('score')->create('bug', 'resolve', $oldBug);
|
||||
if($oldBug->execution) $this->loadModel('kanban')->updateLane($oldBug->execution, 'bug');
|
||||
if($oldBug->execution)
|
||||
{
|
||||
$this->loadModel('kanban');
|
||||
if(!isset($output['toColID'])) $this->kanban->updateLane($oldBug->execution, 'bug', $bugID);
|
||||
if(isset($output['toColID'])) $this->kanban->moveCard($bugID, $output['fromColID'], $output['toColID'], $output['fromLaneID'], $output['toLaneID']);
|
||||
}
|
||||
|
||||
/* Link bug to build and release. */
|
||||
$this->linkBugToBuild($bugID, $bug->resolvedBuild);
|
||||
@@ -1218,11 +1255,15 @@ class bugModel extends model
|
||||
* Activate a bug.
|
||||
*
|
||||
* @param int $bugID
|
||||
* @param string $extra
|
||||
* @access public
|
||||
* @return void
|
||||
*/
|
||||
public function activate($bugID)
|
||||
public function activate($bugID, $extra)
|
||||
{
|
||||
$extra = str_replace(array(',', ' '), array('&', ''), $extra);
|
||||
parse_str($extra, $output);
|
||||
|
||||
$bugID = (int)$bugID;
|
||||
$oldBug = $this->getById($bugID);
|
||||
$solveBuild = $this->dao->select('id')
|
||||
@@ -1262,7 +1303,12 @@ class bugModel extends model
|
||||
$this->dao->update(TABLE_BUILD)->set('bugs')->eq($build->bugs)->where('id')->eq((int)$solveBuild)->exec();
|
||||
}
|
||||
|
||||
if($oldBug->execution) $this->loadModel('kanban')->updateLane($oldBug->execution, 'bug');
|
||||
if($oldBug->execution)
|
||||
{
|
||||
$this->loadModel('kanban');
|
||||
if(!isset($output['toColID'])) $this->kanban->updateLane($oldBug->execution, 'bug', $bugID);
|
||||
if(isset($output['toColID'])) $this->kanban->moveCard($bugID, $output['fromColID'], $output['toColID'], $output['fromLaneID'], $output['toLaneID']);
|
||||
}
|
||||
$bug->activatedCount += 1;
|
||||
return common::createChanges($oldBug, $bug);
|
||||
}
|
||||
@@ -1271,11 +1317,15 @@ class bugModel extends model
|
||||
* Close a bug.
|
||||
*
|
||||
* @param int $bugID
|
||||
* @param string $extra
|
||||
* @access public
|
||||
* @return void
|
||||
*/
|
||||
public function close($bugID)
|
||||
public function close($bugID, $extra = '')
|
||||
{
|
||||
$extra = str_replace(array(',', ' '), array('&', ''), $extra);
|
||||
parse_str($extra, $output);
|
||||
|
||||
$now = helper::now();
|
||||
$oldBug = $this->getById($bugID);
|
||||
$bug = fixer::input('post')
|
||||
@@ -1291,7 +1341,12 @@ class bugModel extends model
|
||||
->get();
|
||||
|
||||
$this->dao->update(TABLE_BUG)->data($bug)->autoCheck()->where('id')->eq((int)$bugID)->exec();
|
||||
if($oldBug->execution) $this->loadModel('kanban')->updateLane($oldBug->execution, 'bug');
|
||||
if($oldBug->execution)
|
||||
{
|
||||
$this->loadModel('kanban');
|
||||
if(!isset($output['toColID'])) $this->kanban->updateLane($oldBug->execution, 'bug', $bugID);
|
||||
if(isset($output['toColID'])) $this->kanban->moveCard($bugID, $output['fromColID'], $output['toColID'], $output['fromLaneID'], $output['toLaneID']);
|
||||
}
|
||||
|
||||
return common::createChanges($oldBug, $bug);
|
||||
}
|
||||
|
||||
@@ -117,6 +117,7 @@ $lang->icons['mail'] = 'envelope';
|
||||
$lang->icons['trash'] = 'trash';
|
||||
$lang->icons['extension'] = 'th-large';
|
||||
$lang->icons['app'] = 'th-large';
|
||||
$lang->icons['kanban'] = 'kanban';
|
||||
|
||||
$lang->icons['results'] = 'list-alt';
|
||||
$lang->icons['create'] = 'plus';
|
||||
|
||||
@@ -29,6 +29,7 @@ $lang->and = 'and';
|
||||
$lang->zentaoPMS = 'ZenTao';
|
||||
$lang->pmsName = 'ALM';
|
||||
$lang->proName = 'Pro';
|
||||
$lang->bizName = 'Biz';
|
||||
$lang->logoImg = 'zt-logo-en.png';
|
||||
$lang->welcome = "%s ALM";
|
||||
$lang->logout = 'Logout';
|
||||
@@ -157,6 +158,7 @@ $lang->repo->common = 'Code';
|
||||
$lang->report->common = 'Statistic';
|
||||
$lang->system->common = 'System';
|
||||
$lang->admin->common = 'Admin';
|
||||
$lang->story->common = 'Story';
|
||||
$lang->task->common = 'Task';
|
||||
$lang->bug->common = 'Bug';
|
||||
$lang->testcase->common = 'Testcase';
|
||||
|
||||
@@ -289,6 +289,11 @@ $lang->waterfall->menu->design['subMenu']->dbds = array('link' => "{$lang->d
|
||||
$lang->waterfall->menu->design['subMenu']->ads = array('link' => "{$lang->design->ADS}|design|browse|projectID=%s&productID=0&browseType=ADS");
|
||||
$lang->waterfall->menu->design['subMenu']->bysearch = array('link' => '<a href="javascript:;" class="querybox-toggle"><i class="icon-search icon"></i> ' . $lang->searchAB . '</a>');
|
||||
|
||||
/* Kanban project menu. */
|
||||
$lang->kanban->menu = new stdclass();
|
||||
$lang->kanban->menuOrder = array();
|
||||
$lang->kanban->dividerMenu = '';
|
||||
|
||||
/* Execution menu. */
|
||||
$lang->execution->homeMenu = new stdclass();
|
||||
$lang->execution->homeMenu->all = array('link' => "{$lang->execution->all}|execution|all|", 'alias' => 'batchedit');
|
||||
@@ -296,7 +301,7 @@ if($config->systemMode == 'new') $lang->execution->homeMenu->executionkanban = a
|
||||
|
||||
$lang->execution->menu = new stdclass();
|
||||
$lang->execution->menu->task = array('link' => "{$lang->task->common}|execution|task|executionID=%s", 'subModule' => 'task,tree', 'alias' => 'importtask,importbug');
|
||||
$lang->execution->menu->kanban = array('link' => "$lang->executionKanban|execution|kanban|executionID=%s");
|
||||
$lang->execution->menu->kanban = array('link' => "$lang->executionKanban|execution|taskkanban|executionID=%s");
|
||||
$lang->execution->menu->burn = array('link' => "$lang->burn|execution|burn|executionID=%s");
|
||||
$lang->execution->menu->view = array('link' => "$lang->view|execution|grouptask|executionID=%s", 'alias' => 'grouptask,tree,taskeffort,gantt,calendar,relation,maintainrelation');
|
||||
$lang->execution->menu->story = array('link' => "$lang->SRCommon|execution|story|executionID=%s", 'subModule' => 'story', 'alias' => 'batchcreate,linkstory,storykanban');
|
||||
|
||||
@@ -29,6 +29,7 @@ $lang->and = '和';
|
||||
$lang->zentaoPMS = '禅道';
|
||||
$lang->pmsName = '开源版';
|
||||
$lang->proName = '专业版';
|
||||
$lang->bizName = '企业版';
|
||||
$lang->logoImg = 'zt-logo.png';
|
||||
$lang->welcome = "%s项目管理系统";
|
||||
$lang->logout = '退出';
|
||||
@@ -157,6 +158,7 @@ $lang->repo->common = '代码';
|
||||
$lang->report->common = '统计';
|
||||
$lang->system->common = '组织';
|
||||
$lang->admin->common = '后台';
|
||||
$lang->story->common = $lang->SRCommon;
|
||||
$lang->task->common = '任务';
|
||||
$lang->bug->common = 'Bug';
|
||||
$lang->testcase->common = '用例';
|
||||
|
||||
@@ -528,7 +528,7 @@ class commonModel extends model
|
||||
$attr = "class='iframe' data-width='650px'";
|
||||
break;
|
||||
case 'project':
|
||||
if(isset($config->maxVersion) and!defined('TUTORIAL'))
|
||||
if(!defined('TUTORIAL'))
|
||||
{
|
||||
$params = "programID=0©ProjectID=0&extra=from=global";
|
||||
$createMethod = 'createGuide';
|
||||
|
||||
@@ -791,6 +791,7 @@ class doc extends control
|
||||
$doclib = $this->doc->getLibById($doclibID);
|
||||
$users = $this->user->getPairs('noletter|noempty|noclosed');
|
||||
|
||||
$selectedUser = $doclib->users;
|
||||
if($doclib->acl != 'custom' and !empty($doclib->project) and $acl == 'custom')
|
||||
{
|
||||
$project = $this->loadModel('project')->getById($doclib->project);
|
||||
@@ -798,12 +799,10 @@ class doc extends control
|
||||
$stakeholders = $this->loadModel('stakeholder')->getStakeHolderPairs($doclib->project);
|
||||
$whitelist = implode(',', array_keys($projectTeams + $stakeholders)) . $project->whitelist . ',' . $project->PM . ',' . $doclib->users;
|
||||
|
||||
return print(html::select('users[]', $users, $whitelist, "class='form-control chosen' multiple"));
|
||||
}
|
||||
else
|
||||
{
|
||||
return print(html::select('users[]', $users, $doclib->users, "class='form-control chosen' multiple"));
|
||||
$selectedUser = $whitelist;
|
||||
}
|
||||
|
||||
return print(html::select('users[]', $users, $selectedUser, "class='form-control chosen' multiple"));
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -1377,7 +1377,7 @@ class docModel extends model
|
||||
|
||||
$executions = $this->dao->select('*')->from(TABLE_EXECUTION)
|
||||
->where('deleted')->eq(0)
|
||||
->andWhere('type')->in('sprint,stage')
|
||||
->andWhere('type')->in('sprint,stage,kanban')
|
||||
->beginIF(!$this->app->user->admin)->andWhere('id')->in($this->app->user->view->sprints)->fi()
|
||||
->orderBy('order_asc')
|
||||
->fetchAll('id');
|
||||
|
||||
@@ -11,6 +11,9 @@ $config->execution->list->exportFields = 'id,name,projectName,code,PM,end,status
|
||||
|
||||
$config->execution->modelList['scrum'] = 'sprint';
|
||||
$config->execution->modelList['waterfall'] = 'stage';
|
||||
$config->execution->modelList['kanban'] = 'kanban';
|
||||
|
||||
$config->execution->statusActions = array('start', 'putoff', 'suspend', 'close', 'activate');
|
||||
|
||||
global $lang, $app;
|
||||
$app->loadLang('task');
|
||||
|
||||
+125
-18
@@ -24,7 +24,7 @@ class execution extends control
|
||||
* @var string
|
||||
* @access public
|
||||
*/
|
||||
public $objectType;
|
||||
public $objectType = 'execution';
|
||||
|
||||
/**
|
||||
* Construct function, Set executions.
|
||||
@@ -47,7 +47,6 @@ class execution extends control
|
||||
{
|
||||
if(!$this->executions and $this->methodName != 'index' and $this->methodName != 'create' and $this->app->getViewType() != 'mhtml') $this->locate($this->createLink('execution', 'create'));
|
||||
}
|
||||
$this->objectType = $this->config->systemMode == 'classic' ? 'project' : 'execution';
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -125,7 +124,9 @@ class execution extends control
|
||||
$browseType = strtolower($status);
|
||||
|
||||
/* Get products by execution. */
|
||||
$execution = $this->commonAction($executionID, $status);
|
||||
$execution = $this->commonAction($executionID, $status);
|
||||
if($execution->type == 'kanban') $this->locate($this->createLink('execution', 'kanban', "executionID=$executionID"));
|
||||
|
||||
$executionID = $execution->id;
|
||||
$products = $this->product->getProductPairsByProject($executionID);
|
||||
setcookie('preExecutionID', $executionID, $this->config->cookieLife, $this->config->webRoot, '', false, true);
|
||||
@@ -1263,6 +1264,15 @@ class execution extends control
|
||||
}
|
||||
|
||||
$project = $this->project->getByID($projectID);
|
||||
if(!empty($project) and $project->model == 'kanban')
|
||||
{
|
||||
global $lang;
|
||||
$executionLang = $lang->execution->common;
|
||||
$lang->executionCommon = $lang->execution->kanban;
|
||||
$lang->execution->common = $lang->execution->kanban;
|
||||
include $this->app->getModulePath('', 'execution') . 'lang/' . $this->app->getClientLang() . '.php';
|
||||
$lang->execution->common = $executionLang;
|
||||
}
|
||||
|
||||
$extra = str_replace(array(',', ' '), array('&', ''), $extra);
|
||||
parse_str($extra, $output);
|
||||
@@ -1289,6 +1299,7 @@ class execution extends control
|
||||
$this->view->tips = $this->fetch('execution', 'tips', "executionID=$executionID");
|
||||
$this->view->executionID = $executionID;
|
||||
$this->view->projectID = $projectID;
|
||||
$this->view->project = $project;
|
||||
$this->display();
|
||||
exit;
|
||||
}
|
||||
@@ -1376,6 +1387,16 @@ class execution extends control
|
||||
}
|
||||
}
|
||||
|
||||
if(!empty($projectID) and $project->model == 'kanban')
|
||||
{
|
||||
$execution = $this->execution->getById($executionID);
|
||||
$this->loadModel('kanban')->createRDKanban($execution);
|
||||
|
||||
if(dao::isError()) return $this->send(array('result' => 'fail', 'message' => dao::getError()));
|
||||
if($this->app->tab == 'project') return $this->send(array('result' => 'success', 'message' => $this->lang->saveSuccess, 'locate' => $this->createLink('project', 'index', "projectID=$projectID")));
|
||||
return $this->send(array('result' => 'success', 'message' => $this->lang->saveSuccess, 'locate' => inlink('kanban', "executionID=$executionID")));
|
||||
}
|
||||
|
||||
if(!empty($planID))
|
||||
{
|
||||
return $this->send(array('result' => 'success', 'message' => $this->lang->saveSuccess, 'locate' => inlink('create', "projectID=$projectID&executionID=$executionID©ExecutionID=&planID=$planID&confirm=no")));
|
||||
@@ -1430,6 +1451,7 @@ class execution extends control
|
||||
$this->view->copyExecution = isset($copyExecution) ? $copyExecution : '';
|
||||
$this->view->from = $this->app->tab;
|
||||
$this->view->isStage = (isset($project->model) and $project->model == 'waterfall') ? true : false;
|
||||
$this->view->project = $project;
|
||||
$this->display();
|
||||
}
|
||||
|
||||
@@ -1451,6 +1473,14 @@ class execution extends control
|
||||
$this->app->loadLang('stage');
|
||||
$this->app->loadLang('programplan');
|
||||
$browseExecutionLink = $this->createLink('execution', 'browse', "executionID=$executionID");
|
||||
$execution = $this->execution->getById($executionID);
|
||||
|
||||
if($execution->type == 'kanban')
|
||||
{
|
||||
global $lang;
|
||||
$lang->executionCommon = $lang->execution->kanban;
|
||||
include $this->app->getModulePath('', 'execution') . 'lang/' . $this->app->getClientLang() . '.php';
|
||||
}
|
||||
|
||||
if(!empty($_POST))
|
||||
{
|
||||
@@ -1502,6 +1532,7 @@ class execution extends control
|
||||
|
||||
$this->executeHooks($executionID);
|
||||
if($_POST['status'] == 'doing') $this->loadModel('common')->syncPPEStatus($executionID);
|
||||
if($execution->type == 'kanban') return $this->send(array('result' => 'success', 'message' => $this->lang->saveSuccess, 'locate' => 'parent'));
|
||||
return $this->send(array('result' => 'success', 'message' => $this->lang->saveSuccess, 'locate' => inlink('view', "executionID=$executionID")));
|
||||
}
|
||||
|
||||
@@ -1509,10 +1540,8 @@ class execution extends control
|
||||
$this->execution->setMenu($executionID);
|
||||
|
||||
$executions = array('' => '') + $this->executions;
|
||||
$execution = $this->execution->getById($executionID);
|
||||
$managers = $this->execution->getDefaultManagers($executionID);
|
||||
|
||||
|
||||
/* Remove current execution from the executions. */
|
||||
unset($executions[$executionID]);
|
||||
|
||||
@@ -1685,6 +1714,7 @@ class execution extends control
|
||||
{
|
||||
$execution = $this->commonAction($executionID);
|
||||
$executionID = $execution->id;
|
||||
if($execution->type == 'kanban') $this->lang->executionCommon = $this->lang->execution->kanban;
|
||||
|
||||
if(!empty($_POST))
|
||||
{
|
||||
@@ -1757,6 +1787,7 @@ class execution extends control
|
||||
{
|
||||
$execution = $this->commonAction($executionID);
|
||||
$executionID = $execution->id;
|
||||
if($execution->type == 'kanban') $this->lang->executionCommon = $this->lang->execution->kanban;
|
||||
|
||||
if(!empty($_POST))
|
||||
{
|
||||
@@ -1792,6 +1823,7 @@ class execution extends control
|
||||
{
|
||||
$execution = $this->commonAction($executionID);
|
||||
$executionID = $execution->id;
|
||||
if($execution->type == 'kanban') $this->lang->executionCommon = $this->lang->execution->kanban;
|
||||
|
||||
if(!empty($_POST))
|
||||
{
|
||||
@@ -1834,6 +1866,7 @@ class execution extends control
|
||||
{
|
||||
$execution = $this->commonAction($executionID);
|
||||
$executionID = $execution->id;
|
||||
if($execution->type == 'kanban') $this->lang->executionCommon = $this->lang->execution->kanban;
|
||||
|
||||
if(!empty($_POST))
|
||||
{
|
||||
@@ -1922,6 +1955,66 @@ class execution extends control
|
||||
/**
|
||||
* Kanban.
|
||||
*
|
||||
* @param int $executionID
|
||||
* @param string $browseType
|
||||
* @param string $orderBy
|
||||
* @param string $groupBy
|
||||
* @access public
|
||||
* @return void
|
||||
*/
|
||||
public function kanban($executionID, $browseType = 'all', $orderBy = 'id_asc', $groupBy = 'default')
|
||||
{
|
||||
if(empty($groupBy)) $groupBy = 'default';
|
||||
|
||||
$this->lang->execution->menu = new stdclass();
|
||||
$execution = $this->commonAction($executionID);
|
||||
$kanbanData = $this->loadModel('kanban')->getRDKanban($executionID, $browseType, $orderBy, 0, $groupBy);
|
||||
$executionActions = array();
|
||||
|
||||
foreach($this->config->execution->statusActions as $action)
|
||||
{
|
||||
if($this->execution->isClickable($execution, $action)) $executionActions[] = $action;
|
||||
}
|
||||
|
||||
$userList = array();
|
||||
$users = $this->loadModel('user')->getPairs('noletter|nodeleted');
|
||||
$avatarPairs = $this->dao->select('account, avatar')->from(TABLE_USER)->where('deleted')->eq(0)->fetchPairs();
|
||||
foreach($avatarPairs as $account => $avatar)
|
||||
{
|
||||
if(!$avatar) continue;
|
||||
$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;
|
||||
$this->view->execution = $execution;
|
||||
$this->view->userList = $userList;
|
||||
$this->view->browseType = $browseType;
|
||||
$this->view->orderBy = $orderBy;
|
||||
$this->view->groupBy = $groupBy;
|
||||
$this->view->productID = $productID;
|
||||
$this->view->allPlans = $allPlans;
|
||||
$this->view->kanbanData = $kanbanData;
|
||||
$this->view->executionActions = $executionActions;
|
||||
$this->display();
|
||||
}
|
||||
|
||||
/**
|
||||
* Task kanban.
|
||||
*
|
||||
* @param int $executionID
|
||||
* @param string $browseType story|bug|task|all
|
||||
* @param string $orderBy
|
||||
@@ -1929,18 +2022,16 @@ class execution extends control
|
||||
* @access public
|
||||
* @return void
|
||||
*/
|
||||
public function kanban($executionID, $browseType = '', $orderBy = 'order_asc', $groupBy = '')
|
||||
public function taskKanban($executionID, $browseType = '', $orderBy = 'order_asc', $groupBy = '')
|
||||
{
|
||||
if(empty($browseType)) $browseType = $this->session->kanbanType ? $this->session->kanbanType : 'all';
|
||||
if(empty($groupBy) and $browseType != 'all') $groupBy = $this->session->{'kanbanGroupBy' . $browseType} ? $this->session->{'kanbanGroupBy' . $browseType} : 'default';
|
||||
if(empty($groupBy) and $browseType == 'all') $groupBy = 'default';
|
||||
if(empty($groupBy)) $groupBy = 'default';
|
||||
|
||||
/* Save to session. */
|
||||
$uri = $this->app->getURI(true);
|
||||
$this->app->session->set('taskList', $uri, 'execution');
|
||||
$this->app->session->set('bugList', $uri, 'qa');
|
||||
$this->app->session->set('kanbanType', $browseType, 'execution');
|
||||
$this->app->session->set('kanbanGroupBy' . $browseType, $groupBy, 'execution');
|
||||
|
||||
/* Load language. */
|
||||
$this->app->loadLang('story');
|
||||
@@ -2303,6 +2394,12 @@ class execution extends control
|
||||
if($tips) $tips = str_replace($this->lang->executionCommon, $this->lang->project->stage, $tips);
|
||||
$this->lang->execution->confirmDelete = str_replace($this->lang->executionCommon, $this->lang->project->stage, $this->lang->execution->confirmDelete);
|
||||
}
|
||||
elseif($type == 'kanban')
|
||||
{
|
||||
global $lang;
|
||||
$lang->executionCommon = $lang->execution->kanban;
|
||||
include $this->app->getModulePath('', 'execution') . 'lang/' . $this->app->getClientLang() . '.php';
|
||||
}
|
||||
|
||||
echo js::confirm($tips . sprintf($this->lang->execution->confirmDelete, $this->executions[$executionID]), $this->createLink('execution', 'delete', "executionID=$executionID&confirm=yes"));
|
||||
exit;
|
||||
@@ -2310,6 +2407,7 @@ class execution extends control
|
||||
else
|
||||
{
|
||||
/* Delete execution. */
|
||||
$execution = $this->execution->getByID($executionID);
|
||||
$this->dao->update(TABLE_EXECUTION)->set('deleted')->eq(1)->where('id')->eq($executionID)->exec();
|
||||
$this->loadModel('action')->create('execution', $executionID, 'deleted', '', ACTIONMODEL::CAN_UNDELETED);
|
||||
$this->execution->updateUserView($executionID);
|
||||
@@ -2318,7 +2416,7 @@ class execution extends control
|
||||
$this->executeHooks($executionID);
|
||||
|
||||
if($this->viewType == 'json') return $this->send(array('result' => 'success', 'message' => $this->lang->saveSuccess));
|
||||
die(js::reload('parent'));
|
||||
return print(js::reload('parent'));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2528,16 +2626,17 @@ class execution extends control
|
||||
* @param int $recTotal
|
||||
* @param int $recPerPage
|
||||
* @param int $pageID
|
||||
* @param string $extra
|
||||
* @access public
|
||||
* @return void
|
||||
*/
|
||||
public function linkStory($objectID = 0, $browseType = '', $param = 0, $recTotal = 0, $recPerPage = 50, $pageID = 1)
|
||||
public function linkStory($objectID = 0, $browseType = '', $param = 0, $recTotal = 0, $recPerPage = 50, $pageID = 1, $extra = '')
|
||||
{
|
||||
$this->loadModel('story');
|
||||
$this->loadModel('product');
|
||||
|
||||
/* Get projects, executions and products. */
|
||||
$object = $this->project->getByID($objectID, $this->app->tab == 'project' ? 'project' : 'sprint,stage');
|
||||
$object = $this->project->getByID($objectID, $this->app->tab == 'project' ? 'project' : 'sprint,stage,kanban');
|
||||
$products = $this->product->getProducts($objectID);
|
||||
$browseLink = $this->createLink($this->app->tab == 'project' ? 'projectstory' : 'execution', 'story', "objectID=$objectID");
|
||||
|
||||
@@ -2552,7 +2651,7 @@ class execution extends control
|
||||
|
||||
if(!empty($_POST))
|
||||
{
|
||||
$this->execution->linkStory($objectID);
|
||||
$this->execution->linkStory($objectID, array(), array(), $extra);
|
||||
if($object->type != 'project' and $object->project != 0) $this->execution->linkStory($object->project);
|
||||
|
||||
if(isonlybody()) die(js::reload('parent'));
|
||||
@@ -2872,7 +2971,7 @@ class execution extends control
|
||||
$projects = $this->loadModel('program')->getProjectList(0, 'all', 0, 'order_asc', null, 0, 0, true);
|
||||
$executionGroups = $this->dao->select('*')->from(TABLE_EXECUTION)
|
||||
->where('deleted')->eq(0)
|
||||
->andWhere('type')->in('sprint,stage')
|
||||
->andWhere('type')->in('sprint,stage,kanban')
|
||||
->beginIF(!$this->app->user->admin)->andWhere('id')->in($this->app->user->view->sprints)->fi()
|
||||
->beginIF($this->config->systemMode == 'new')->andWhere('project')->in(array_keys($projects))->fi()
|
||||
->orderBy('id_desc')
|
||||
@@ -3284,10 +3383,11 @@ class execution extends control
|
||||
* @param int $planID
|
||||
* @param int $productID
|
||||
* @param string $fromMethod
|
||||
* @param string $extra
|
||||
* @access public
|
||||
* @return void
|
||||
*/
|
||||
public function importPlanStories($executionID, $planID, $productID = 0, $fromMethod = 'story')
|
||||
public function importPlanStories($executionID, $planID, $productID = 0, $fromMethod = 'story', $extra = '')
|
||||
{
|
||||
$planStories = $planProducts = array();
|
||||
$planStory = $this->loadModel('story')->getPlanStories($planID);
|
||||
@@ -3310,7 +3410,7 @@ class execution extends control
|
||||
$projectID = $this->dao->findByID($executionID)->from(TABLE_EXECUTION)->fetch('project');
|
||||
$planStories = array_keys($planStory);
|
||||
|
||||
$this->execution->linkStory($executionID, $planStories, $planProducts);
|
||||
$this->execution->linkStory($executionID, $planStories, $planProducts, $extra);
|
||||
if($this->config->systemMode == 'new' and $executionID != $projectID) $this->execution->linkStory($projectID, $planStories, $planProducts);
|
||||
}
|
||||
|
||||
@@ -3321,7 +3421,14 @@ class execution extends control
|
||||
$moduleName = 'projectstory';
|
||||
$param = "projectID=$executionID";
|
||||
}
|
||||
if($count != 0) echo js::alert(sprintf($this->lang->execution->haveDraft, $count)) . js::locate($this->createLink($moduleName, 'story', $param));
|
||||
|
||||
if($execution->type == 'kanban')
|
||||
{
|
||||
global $lang;
|
||||
$lang->executionCommon = $lang->execution->kanban;
|
||||
include $this->app->getModulePath('', 'execution') . 'lang/' . $this->app->getClientLang() . '.php';
|
||||
}
|
||||
if($count != 0) echo js::alert(sprintf($this->lang->execution->haveDraft, $count)) . js::locate($this->createLink($moduleName, $execution->type == 'sprint' ? 'story' : 'kanban', $param));
|
||||
die(js::locate(helper::createLink($moduleName, $fromMethod, $param)));
|
||||
}
|
||||
|
||||
@@ -3440,7 +3547,7 @@ class execution extends control
|
||||
$enterTime = date('Y-m-d H:i:s', $enterTime);
|
||||
$lastEditedTime = $this->dao->select("max(lastEditedTime) as lastEditedTime")->from(TABLE_KANBANLANE)->where('execution')->eq($executionID)->fetch('lastEditedTime');
|
||||
|
||||
if($lastEditedTime > $enterTime)
|
||||
if($lastEditedTime > $enterTime or $groupBy != 'default')
|
||||
{
|
||||
$kanbanGroup = $this->loadModel('kanban')->getExecutionKanban($executionID, $browseType, $groupBy);
|
||||
die(json_encode($kanbanGroup));
|
||||
|
||||
@@ -22,3 +22,4 @@ td.flex span.project-type-label {margin-left: 5px; min-width: 36px;}
|
||||
.c-progress, .c-burn {width: 60px;}
|
||||
.c-percent, .c-realBegan, .c-end, .c-begin, .c-realEnd{width: 100px;}
|
||||
.c-action {text-align: center;}
|
||||
.c-name > span {margin-right: 2px;}
|
||||
|
||||
@@ -1,5 +1,84 @@
|
||||
#main {padding-bottom: 10px;}
|
||||
#main > .container {max-width: 1960px!important; padding: 0 10px}
|
||||
#TRAction .icon {padding: 0px 6px; font-size: 14px}
|
||||
|
||||
.has-error .form-control {border-color: #ff4268!important;}
|
||||
.has-error .form-control:focus {box-shadow: inset 0 1px 1px rgb(0 0 0 / 8%), 0 0 6px #f5b2a5!important;}
|
||||
.has-error .form-control::placeholder {color: #ff4268!important;}
|
||||
|
||||
.label.text-red {background: #ff4268 !important; color: #ffffff;}
|
||||
|
||||
.dropdown-menu > li {padding: 0 10px;}
|
||||
.dropdown-menu > li > a > .icon {position: relative; left: -5px;}
|
||||
|
||||
#kanbanContainer {padding-bottom: 0; margin-bottom: 0;}
|
||||
#kanbanContainer.fullscreen {overflow: auto;}
|
||||
|
||||
.region {border: 1px solid #dcdcdc; background-color: #fff;}
|
||||
.region + .region {margin-top: 20px;}
|
||||
.region .region-header {padding: 10px;}
|
||||
.region .region-header span {font-size: 14px; color: #999EAB}
|
||||
.region .region-header label {color: #999; background: transparent; border: 1px solid #ddd; margin-left: 10px; margin-right: 10px}
|
||||
.region .region-header .action {float: right}
|
||||
.region .region-header .icon-double-angle-up,.icon-double-angle-down {cursor: pointer;}
|
||||
.region .kanban-header-sub-cols .kanban-header-col > .title {max-width: 100% !important;min-width:240px;}
|
||||
.region .sort .region-header {cursor: move;}
|
||||
|
||||
.region .kanban {padding: 0px 10px 10px 10px; min-height: unset; overflow: auto}
|
||||
.region .kanban .form-actions {margin: 0;}
|
||||
.region .kanban .form-actions .btn {margin-right: 10px; min-width: 50px;}
|
||||
|
||||
.region .kanban-board + .kanban-board {margin-top: 20px;}
|
||||
.region .kanban-board > .kanban-header > .kanban-group-header {padding: 8px 2px; width: 20px;}
|
||||
.region .kanban-board > .kanban-header > .kanban-group-header:hover {cursor: move;}
|
||||
.region .kanban-board.sort > .kanban-header {padding-left: 0;}
|
||||
|
||||
.region .kanban-header {border-bottom: none!important; min-width: max-content; min-width: -moz-max-content;}
|
||||
.region .kanban-header-col > .title {max-width: 80% !important;}
|
||||
.region .kanban-header-col > .title {margin: 0}
|
||||
.region .kanban-header-col > .title > span {display: inline-block; overflow: hidden; padding-right:2px; position: initial; max-width: 140px !important;}
|
||||
.region .kanban-header-col > .title > .text-grey {opacity: .5; font-weight: bold; color: #8b91a2;}
|
||||
.region .kanban-header-col > .title > .count {opacity: .5; font-weight: bold; color: #8b91a2;}
|
||||
.region .kanban-header-col > .title > .error {color: #333333; padding-left: 2px; font-size: 10px; padding-top: 1px; padding-right: 2px;}
|
||||
.kanban-affixed .kanban-header-col > .title > .text {color: #fff!important}
|
||||
.region .kanban-header-col > .actions {position: relative; right: -30px;}
|
||||
.region .kanban-header-parent-col > .actions {position: absolute; right: 0px;}
|
||||
.region .kanban-header-sub-cols .actions {position: absolute; right: 0px;}
|
||||
|
||||
.region .kanban-lane {position: relative; border-bottom: none!important; min-height: 200px !important}
|
||||
|
||||
.region .kanban-lane > .kanban-lane-name > .text {margin: auto 0; max-height: 150px; overflow: hidden; text-overflow: ellipsis}
|
||||
.region .kanban-lane > .kanban-lane-name > .actions {position: absolute; top: 0; left: 0; right: 0; opacity: 0;}
|
||||
.region .kanban-lane > .kanban-lane-name > .actions > a {display: block; width: 20px; height: 20px; line-height: 20px; text-align: center; opacity: .7; color: #fff;}
|
||||
.region .kanban-lane > .kanban-lane-name > .actions > a:hover {background-color: rgba(0,0,0,.2); opacity: 1;}
|
||||
.region .kanban-lane > .kanban-lane-name:hover > .actions {opacity: 1;}
|
||||
.region .kanban-lane.sort > .kanban-lane-name {cursor: move;}
|
||||
|
||||
.region .kanban-lane-col {max-height: unset !important; overflow: auto!important; position: relative;}
|
||||
.region .kanban-lane-col.has-scrollbar > .kanban-lane-actions {position: absolute; background-color: inherit; bottom: 0; left: 0; right: 0;}
|
||||
|
||||
.region .kanban-lane-items {overflow: auto; padding-bottom: 10px;}
|
||||
|
||||
.region .kanban-item {position: relative}
|
||||
|
||||
.kanban-card {height: auto !important; padding: 8px 14px !important; min-height: 60px;}
|
||||
|
||||
.cardcolor {width:40px; height: 14px; float: left; margin-left: 5px; margin-right: 5px; margin-top: 2px; border-radius: 2px;}
|
||||
#cardcolormenu {padding:2px 2px; width: 100px;}
|
||||
|
||||
.kanban-col[data-type=ADD] {display: none;}
|
||||
.kanban-col[data-type=EMPTY] {display: none;}
|
||||
.kanban-item:hover .title {padding-right: 10px;}
|
||||
.gray .actions {display:none;}
|
||||
|
||||
.c-type {width: 150px !important; overflow: unset;}
|
||||
.c-group {width: 190px !important; overflow: unset;}
|
||||
.c-type {margin-left: 0px !important;}
|
||||
|
||||
#kanbanScaleControl {width: 100px;}
|
||||
#kanbanScaleControl .input-group-addon {background: #fff; padding: 5px;}
|
||||
#kanbanScaleControl > .input-group-btn:first-child > .btn {border-radius: 16px 0 0 16px; border-right-color: transparent;}
|
||||
#kanbanScaleControl > .input-group-btn:last-child > .btn {border-radius: 0 16px 16px 0; border-left-color: transparent;}
|
||||
#kanbanScaleControl > .input-group-btn > .btn:hover {border-color: #b8bfce;}
|
||||
#kanbanActionMenu {top: 24px; right: auto;}
|
||||
|
||||
.kanban + .kanban {margin-top: 15px}
|
||||
.kanban-card > .title {display: block; white-space: nowrap; overflow: hidden; text-overflow: ellipsis}
|
||||
@@ -16,43 +95,11 @@
|
||||
.kanban-card > .actions > a {display: block; float: left; width: 20px; height: 20px; line-height: 20px; text-align: center; border-radius: 4px; opacity: .7;}
|
||||
.kanban-card > .actions > a:hover {background-color: rgba(0,0,0,.075); opacity: 1;}
|
||||
|
||||
.kanban-header-col > .actions {padding-top: 22px}
|
||||
.kanban-header-parent-col .kanban-header-col > .actions {padding-top: 6px; padding-right: 2px;}
|
||||
.kanban-header-col > .actions > a {display: block; float: left; width: 20px; height: 20px; line-height: 20px; text-align: center; border-radius: 4px; opacity: .7;}
|
||||
.kanban-header-col > .actions > a:hover {background-color: rgba(0,0,0,.075); opacity: 1;}
|
||||
|
||||
.kanban-lane-name > .actions {position: absolute; top: 0; left: 0; right: 0; opacity: 0;}
|
||||
.kanban-lane-name:hover > .actions {opacity: 1;}
|
||||
.kanban-lane-name > .actions > a {display: block; width: 20px; height: 20px; line-height: 20px; text-align: center; opacity: .7; color: #fff;}
|
||||
.kanban-lane-name > .actions > a:hover {background-color: rgba(0,0,0,.2); opacity: 1;}
|
||||
|
||||
.kanban-affixed .kanban-header-col > .title > .text,
|
||||
.kanban-affixed .kanban-header-col > .title > .count {color: #fff!important;}
|
||||
|
||||
#kanbanContainer {margin: 0;}
|
||||
#kanbanContainer > .panel-body {overflow: auto;}
|
||||
#kanbans .kanban {min-height: initial;}
|
||||
#kanbans .kanban-lane {min-height: 150px; margin-top: 2px;}
|
||||
#kanbans .kanban-affixed > .kanban-header {top: 100px;}
|
||||
#kanbans .kanban-card[data-scale-size="4"] {padding: 8px;}
|
||||
#kanbans .kanban-card[data-scale-size="3"] {padding: 3px 4px;}
|
||||
#kanbans .kanban-card[data-scale-size="3"] > .title {white-space: normal; max-height: 100%;}
|
||||
#kanbans .kanban-card[data-scale-size="2"] {padding: 3px 4px; overflow: hidden;}
|
||||
#kanbans .kanban-card[data-scale-size="2"] > .title {display: inline; line-height: 18px; white-space: normal; max-height: 100%; word-break: break-all;}
|
||||
#kanbans .kanban-card[data-scale-size="2"] > .infos {display: inline-block; height: 18px; vertical-align: top; margin: 0;}
|
||||
#kanbans .kanban-card[data-scale-size="2"] > .infos > .info-pri {transform: scale(.8); vertical-align: top;}
|
||||
#kanbans .kanban-card[data-scale-size="2"] > .infos > .avatar {display: inline-block; transform: scale(.8); position: relative; top: -2px; vertical-align: top; margin-right: -1px;}
|
||||
|
||||
#kanbanScaleControl {width: 100px;}
|
||||
#kanbanScaleControl .input-group-addon {background: #fff; padding: 5px;}
|
||||
#kanbanScaleControl > .input-group-btn:first-child > .btn {border-radius: 16px 0 0 16px; border-right-color: transparent;}
|
||||
#kanbanScaleControl > .input-group-btn:last-child > .btn {border-radius: 0 16px 16px 0; border-left-color: transparent;}
|
||||
#kanbanScaleControl > .input-group-btn > .btn:hover {border-color: #b8bfce;}
|
||||
|
||||
#type_chosen .icon-kanban {padding-right: 10px; font-size: 15px;}
|
||||
|
||||
.dropdown-menu a {text-align: left;}
|
||||
.scrollbar-hover {max-height: 2000px; overflow: scroll !important;}
|
||||
.c-type {width: 150px !important; overflow: unset;}
|
||||
.c-group {width: 190px !important; overflow: unset;}
|
||||
.c-type {margin-left: 0px !important;}
|
||||
#kanban .kanban-card[data-scale-size="4"] {padding: 8px;}
|
||||
#kanban .kanban-card[data-scale-size="3"] {padding: 3px 4px;}
|
||||
#kanban .kanban-card[data-scale-size="3"] > .title {white-space: normal; max-height: 100%;}
|
||||
#kanban .kanban-card[data-scale-size="2"] {padding: 3px 4px; overflow: hidden;}
|
||||
#kanban .kanban-card[data-scale-size="2"] > .title {display: inline; line-height: 18px; white-space: normal; max-height: 100%; word-break: break-all;}
|
||||
#kanban .kanban-card[data-scale-size="2"] > .infos {display: inline-block; height: 18px; vertical-align: top; margin: 0;}
|
||||
#kanban .kanban-card[data-scale-size="2"] > .infos > .info-pri {transform: scale(.8); vertical-align: top;}
|
||||
#kanban .kanban-card[data-scale-size="2"] > .infos > .avatar {display: inline-block; transform: scale(.8); position: relative; top: -2px; vertical-align: top; margin-right: -1px;}
|
||||
|
||||
@@ -0,0 +1,58 @@
|
||||
#main {padding-bottom: 10px;}
|
||||
#main > .container {max-width: 1960px!important; padding: 0 10px}
|
||||
|
||||
.kanban + .kanban {margin-top: 15px}
|
||||
.kanban-card > .title {display: block; white-space: nowrap; overflow: hidden; text-overflow: ellipsis}
|
||||
.kanban-card > .infos {position: relative; margin-top: 5px}
|
||||
.kanban-card > .infos > .info + .info {margin-left: 8px}
|
||||
.kanban-card > .infos > .info-id,
|
||||
.kanban-card > .infos > .info-deadline,
|
||||
.kanban-card > .infos > .info-estimate {font-size: 12px; position: relative; top: 2px}
|
||||
.kanban-card > .infos > .label-pri {min-width: 16px; line-height: 14px; height: 16px; padding: 0}
|
||||
.kanban-card > .infos > .label-severity {transform: scale(.75)}
|
||||
.kanban-card > .infos > .avatar {position: absolute; right: 0; top: 0}
|
||||
.kanban-card > .actions {position: absolute; top: 4px; right: 4px; opacity: 0;}
|
||||
.kanban-card:hover > .actions {opacity: 1;}
|
||||
.kanban-card > .actions > a {display: block; float: left; width: 20px; height: 20px; line-height: 20px; text-align: center; border-radius: 4px; opacity: .7;}
|
||||
.kanban-card > .actions > a:hover {background-color: rgba(0,0,0,.075); opacity: 1;}
|
||||
|
||||
.kanban-header-col > .actions {padding-top: 22px}
|
||||
.kanban-header-parent-col .kanban-header-col > .actions {padding-top: 6px; padding-right: 2px;}
|
||||
.kanban-header-col > .actions > a {display: block; float: left; width: 20px; height: 20px; line-height: 20px; text-align: center; border-radius: 4px; opacity: .7;}
|
||||
.kanban-header-col > .actions > a:hover {background-color: rgba(0,0,0,.075); opacity: 1;}
|
||||
|
||||
.kanban-lane-name > .actions {position: absolute; top: 0; left: 0; right: 0; opacity: 0;}
|
||||
.kanban-lane-name:hover > .actions {opacity: 1;}
|
||||
.kanban-lane-name > .actions > a {display: block; width: 20px; height: 20px; line-height: 20px; text-align: center; opacity: .7; color: #fff;}
|
||||
.kanban-lane-name > .actions > a:hover {background-color: rgba(0,0,0,.2); opacity: 1;}
|
||||
|
||||
.kanban-affixed .kanban-header-col > .title > .text,
|
||||
.kanban-affixed .kanban-header-col > .title > .count {color: #fff!important;}
|
||||
|
||||
#kanbanContainer {margin: 0;}
|
||||
#kanbanContainer > .panel-body {overflow: auto;}
|
||||
#kanbans .kanban {min-height: initial;}
|
||||
#kanbans .kanban-lane {min-height: 150px; margin-top: 2px;}
|
||||
#kanbans .kanban-affixed > .kanban-header {top: 100px;}
|
||||
#kanbans .kanban-card[data-scale-size="4"] {padding: 8px;}
|
||||
#kanbans .kanban-card[data-scale-size="3"] {padding: 3px 4px;}
|
||||
#kanbans .kanban-card[data-scale-size="3"] > .title {white-space: normal; max-height: 100%;}
|
||||
#kanbans .kanban-card[data-scale-size="2"] {padding: 3px 4px; overflow: hidden;}
|
||||
#kanbans .kanban-card[data-scale-size="2"] > .title {display: inline; line-height: 18px; white-space: normal; max-height: 100%; word-break: break-all;}
|
||||
#kanbans .kanban-card[data-scale-size="2"] > .infos {display: inline-block; height: 18px; vertical-align: top; margin: 0;}
|
||||
#kanbans .kanban-card[data-scale-size="2"] > .infos > .info-pri {transform: scale(.8); vertical-align: top;}
|
||||
#kanbans .kanban-card[data-scale-size="2"] > .infos > .avatar {display: inline-block; transform: scale(.8); position: relative; top: -2px; vertical-align: top; margin-right: -1px;}
|
||||
|
||||
#kanbanScaleControl {width: 100px;}
|
||||
#kanbanScaleControl .input-group-addon {background: #fff; padding: 5px;}
|
||||
#kanbanScaleControl > .input-group-btn:first-child > .btn {border-radius: 16px 0 0 16px; border-right-color: transparent;}
|
||||
#kanbanScaleControl > .input-group-btn:last-child > .btn {border-radius: 0 16px 16px 0; border-left-color: transparent;}
|
||||
#kanbanScaleControl > .input-group-btn > .btn:hover {border-color: #b8bfce;}
|
||||
|
||||
#type_chosen .icon-kanban {padding-right: 10px; font-size: 15px;}
|
||||
|
||||
.dropdown-menu a {text-align: left;}
|
||||
.scrollbar-hover {max-height: 2000px; overflow: scroll !important;}
|
||||
.c-type {width: 150px !important; overflow: unset;}
|
||||
.c-group {width: 190px !important; overflow: unset;}
|
||||
.c-type {margin-left: 0px !important;}
|
||||
@@ -1,6 +1,6 @@
|
||||
function setCopyProject(executionID)
|
||||
{
|
||||
location.href = createLink('execution', 'create', 'projectID=&executionID=0©ExecutionID=' + executionID);
|
||||
location.href = createLink('execution', 'create', 'projectID=' + projectID + '&executionID=0©ExecutionID=' + executionID);
|
||||
}
|
||||
|
||||
$(function()
|
||||
|
||||
+755
-610
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
+107
-100
@@ -10,105 +10,106 @@
|
||||
* @link http://www.zentao.net
|
||||
*/
|
||||
/* Fields. */
|
||||
$lang->execution->allExecutions = 'All ' . $lang->execution->common . 's';
|
||||
$lang->execution->allExecutionAB = 'Execution List';
|
||||
$lang->execution->id = $lang->executionCommon . ' ID';
|
||||
$lang->execution->type = $lang->executionCommon . 'Type';
|
||||
$lang->execution->name = $lang->executionCommon . 'Name';
|
||||
$lang->execution->code = $lang->executionCommon . 'Code';
|
||||
$lang->execution->projectName = 'Project';
|
||||
$lang->execution->execName = 'Execution Name';
|
||||
$lang->execution->execCode = 'Execution Code';
|
||||
$lang->execution->execType = 'Execution Type';
|
||||
$lang->execution->stage = 'Stage';
|
||||
$lang->execution->pri = 'Priority';
|
||||
$lang->execution->openedBy = 'OpenedBy';
|
||||
$lang->execution->openedDate = 'OpenedDate';
|
||||
$lang->execution->closedBy = 'ClosedBy';
|
||||
$lang->execution->closedDate = 'ClosedDate';
|
||||
$lang->execution->canceledBy = 'CanceledBy';
|
||||
$lang->execution->canceledDate = 'CanceledDate';
|
||||
$lang->execution->begin = 'Planned Begin';
|
||||
$lang->execution->end = 'Planned End';
|
||||
$lang->execution->dateRange = 'Duration';
|
||||
$lang->execution->realBeganAB = 'Actual Begin';
|
||||
$lang->execution->realEndAB = 'Actual End';
|
||||
$lang->execution->realBegan = 'Actual Begin';
|
||||
$lang->execution->realEnd = 'Actual End';
|
||||
$lang->execution->to = 'To';
|
||||
$lang->execution->days = ' Days';
|
||||
$lang->execution->day = ' Days';
|
||||
$lang->execution->workHour = ' Hours';
|
||||
$lang->execution->workHourUnit = 'H';
|
||||
$lang->execution->totalHours = ' Hours';
|
||||
$lang->execution->totalDays = ' Days';
|
||||
$lang->execution->status = $lang->executionCommon . 'Status';
|
||||
$lang->execution->execStatus = 'Status';
|
||||
$lang->execution->subStatus = 'Sub Status';
|
||||
$lang->execution->desc = $lang->executionCommon . 'Description';
|
||||
$lang->execution->execDesc = 'Description';
|
||||
$lang->execution->owner = 'Owner';
|
||||
$lang->execution->PO = "{$lang->executionCommon} Owner";
|
||||
$lang->execution->PM = "{$lang->executionCommon} Manager";
|
||||
$lang->execution->execPM = "Execution Manager";
|
||||
$lang->execution->QD = 'Test Manager';
|
||||
$lang->execution->RD = 'Release Manager';
|
||||
$lang->execution->release = 'Release';
|
||||
$lang->execution->acl = 'Access Control';
|
||||
$lang->execution->teamname = 'Team Name';
|
||||
$lang->execution->updateOrder = 'Rank';
|
||||
$lang->execution->order = "Rank {$lang->executionCommon}";
|
||||
$lang->execution->orderAB = "Rank";
|
||||
$lang->execution->products = "Link {$lang->productCommon}";
|
||||
$lang->execution->whitelist = 'Whitelist';
|
||||
$lang->execution->addWhitelist = 'Add Whitelist';
|
||||
$lang->execution->unbindWhitelist = 'Remove Whitelist';
|
||||
$lang->execution->totalEstimate = 'Estimates';
|
||||
$lang->execution->totalConsumed = 'Cost';
|
||||
$lang->execution->totalLeft = 'Left';
|
||||
$lang->execution->progress = ' Progress';
|
||||
$lang->execution->hours = 'Estimates: %s, Cost: %s, Left: %s.';
|
||||
$lang->execution->viewBug = 'Bugs';
|
||||
$lang->execution->noProduct = "No {$lang->productCommon} yet.";
|
||||
$lang->execution->createStory = "Create Story";
|
||||
$lang->execution->storyTitle = "Story Name";
|
||||
$lang->execution->all = "All {$lang->executionCommon}s";
|
||||
$lang->execution->undone = 'Unfinished ';
|
||||
$lang->execution->unclosed = 'Unclosed';
|
||||
$lang->execution->typeDesc = "OPS {$lang->executionCommon} has no {$lang->SRCommon}, Bug, Build, or Test features.";
|
||||
$lang->execution->mine = 'Mine: ';
|
||||
$lang->execution->involved = 'Mine';
|
||||
$lang->execution->other = 'Others';
|
||||
$lang->execution->deleted = 'Deleted';
|
||||
$lang->execution->delayed = 'Delayed';
|
||||
$lang->execution->product = $lang->execution->products;
|
||||
$lang->execution->readjustTime = "Adjust {$lang->executionCommon} Begin and End";
|
||||
$lang->execution->readjustTask = 'Adjust Task Begin and End';
|
||||
$lang->execution->effort = 'Effort';
|
||||
$lang->execution->storyEstimate = 'Story Estimate';
|
||||
$lang->execution->newEstimate = 'New Estimate';
|
||||
$lang->execution->reestimate = 'Reestimate';
|
||||
$lang->execution->selectRound = 'Select Round';
|
||||
$lang->execution->average = 'Average';
|
||||
$lang->execution->relatedMember = 'Team';
|
||||
$lang->execution->watermark = 'Exported by ZenTao';
|
||||
$lang->execution->burnXUnit = '(Date)';
|
||||
$lang->execution->burnYUnit = '(Hours)';
|
||||
$lang->execution->waitTasks = 'Waiting Tasks';
|
||||
$lang->execution->viewByUser = 'By User';
|
||||
$lang->execution->oneProduct = "Only one stage can be linked {$lang->productCommon}";
|
||||
$lang->execution->noLinkProduct = "Stage not linked {$lang->productCommon}";
|
||||
$lang->execution->recent = 'Recent visits: ';
|
||||
$lang->execution->copyNoExecution = 'There are no ' . $lang->executionCommon . 'available to copy.';
|
||||
$lang->execution->noTeam = 'No team members at the moment';
|
||||
$lang->execution->or = ' or ';
|
||||
$lang->execution->selectProject = 'Please select project';
|
||||
$lang->execution->unfoldClosed = 'Unfold Closed';
|
||||
$lang->execution->editName = 'Edit Name';
|
||||
$lang->execution->setWIP = 'WIP Settings';
|
||||
$lang->execution->sortColumn = 'Kanban Card Sorting';
|
||||
$lang->execution->batchCreateStroy = "Batch create {$lang->SRCommon}";
|
||||
$lang->execution->batchCreateTask = 'Batch create task';
|
||||
$lang->execution->allExecutions = 'All ' . $lang->execution->common . 's';
|
||||
$lang->execution->allExecutionAB = 'Execution List';
|
||||
$lang->execution->id = $lang->executionCommon . ' ID';
|
||||
$lang->execution->type = $lang->executionCommon . 'Type';
|
||||
$lang->execution->name = $lang->executionCommon . 'Name';
|
||||
$lang->execution->code = $lang->executionCommon . 'Code';
|
||||
$lang->execution->projectName = 'Project';
|
||||
$lang->execution->execName = 'Execution Name';
|
||||
$lang->execution->execCode = 'Execution Code';
|
||||
$lang->execution->execType = 'Execution Type';
|
||||
$lang->execution->stage = 'Stage';
|
||||
$lang->execution->pri = 'Priority';
|
||||
$lang->execution->openedBy = 'OpenedBy';
|
||||
$lang->execution->openedDate = 'OpenedDate';
|
||||
$lang->execution->closedBy = 'ClosedBy';
|
||||
$lang->execution->closedDate = 'ClosedDate';
|
||||
$lang->execution->canceledBy = 'CanceledBy';
|
||||
$lang->execution->canceledDate = 'CanceledDate';
|
||||
$lang->execution->begin = 'Planned Begin';
|
||||
$lang->execution->end = 'Planned End';
|
||||
$lang->execution->dateRange = 'Duration';
|
||||
$lang->execution->realBeganAB = 'Actual Begin';
|
||||
$lang->execution->realEndAB = 'Actual End';
|
||||
$lang->execution->realBegan = 'Actual Begin';
|
||||
$lang->execution->realEnd = 'Actual End';
|
||||
$lang->execution->to = 'To';
|
||||
$lang->execution->days = ' Days';
|
||||
$lang->execution->day = ' Days';
|
||||
$lang->execution->workHour = ' Hours';
|
||||
$lang->execution->workHourUnit = 'H';
|
||||
$lang->execution->totalHours = ' Hours';
|
||||
$lang->execution->totalDays = ' Days';
|
||||
$lang->execution->status = $lang->executionCommon . 'Status';
|
||||
$lang->execution->execStatus = 'Status';
|
||||
$lang->execution->subStatus = 'Sub Status';
|
||||
$lang->execution->desc = $lang->executionCommon . 'Description';
|
||||
$lang->execution->execDesc = 'Description';
|
||||
$lang->execution->owner = 'Owner';
|
||||
$lang->execution->PO = "{$lang->executionCommon} Owner";
|
||||
$lang->execution->PM = "{$lang->executionCommon} Manager";
|
||||
$lang->execution->execPM = "Execution Manager";
|
||||
$lang->execution->QD = 'Test Manager';
|
||||
$lang->execution->RD = 'Release Manager';
|
||||
$lang->execution->release = 'Release';
|
||||
$lang->execution->acl = 'Access Control';
|
||||
$lang->execution->teamname = 'Team Name';
|
||||
$lang->execution->updateOrder = 'Rank';
|
||||
$lang->execution->order = "Rank {$lang->executionCommon}";
|
||||
$lang->execution->orderAB = "Rank";
|
||||
$lang->execution->products = "Link {$lang->productCommon}";
|
||||
$lang->execution->whitelist = 'Whitelist';
|
||||
$lang->execution->addWhitelist = 'Add Whitelist';
|
||||
$lang->execution->unbindWhitelist = 'Remove Whitelist';
|
||||
$lang->execution->totalEstimate = 'Estimates';
|
||||
$lang->execution->totalConsumed = 'Cost';
|
||||
$lang->execution->totalLeft = 'Left';
|
||||
$lang->execution->progress = ' Progress';
|
||||
$lang->execution->hours = 'Estimates: %s, Cost: %s, Left: %s.';
|
||||
$lang->execution->viewBug = 'Bugs';
|
||||
$lang->execution->noProduct = "No {$lang->productCommon} yet.";
|
||||
$lang->execution->createStory = "Create Story";
|
||||
$lang->execution->storyTitle = "Story Name";
|
||||
$lang->execution->all = "All {$lang->executionCommon}s";
|
||||
$lang->execution->undone = 'Unfinished ';
|
||||
$lang->execution->unclosed = 'Unclosed';
|
||||
$lang->execution->typeDesc = "OPS {$lang->executionCommon} has no {$lang->SRCommon}, Bug, Build, or Test features.";
|
||||
$lang->execution->mine = 'Mine: ';
|
||||
$lang->execution->involved = 'Mine';
|
||||
$lang->execution->other = 'Others';
|
||||
$lang->execution->deleted = 'Deleted';
|
||||
$lang->execution->delayed = 'Delayed';
|
||||
$lang->execution->product = $lang->execution->products;
|
||||
$lang->execution->readjustTime = "Adjust {$lang->executionCommon} Begin and End";
|
||||
$lang->execution->readjustTask = 'Adjust Task Begin and End';
|
||||
$lang->execution->effort = 'Effort';
|
||||
$lang->execution->storyEstimate = 'Story Estimate';
|
||||
$lang->execution->newEstimate = 'New Estimate';
|
||||
$lang->execution->reestimate = 'Reestimate';
|
||||
$lang->execution->selectRound = 'Select Round';
|
||||
$lang->execution->average = 'Average';
|
||||
$lang->execution->relatedMember = 'Team';
|
||||
$lang->execution->watermark = 'Exported by ZenTao';
|
||||
$lang->execution->burnXUnit = '(Date)';
|
||||
$lang->execution->burnYUnit = '(Hours)';
|
||||
$lang->execution->waitTasks = 'Waiting Tasks';
|
||||
$lang->execution->viewByUser = 'By User';
|
||||
$lang->execution->oneProduct = "Only one stage can be linked {$lang->productCommon}";
|
||||
$lang->execution->noLinkProduct = "Stage not linked {$lang->productCommon}";
|
||||
$lang->execution->recent = 'Recent visits: ';
|
||||
$lang->execution->copyNoExecution = 'There are no ' . $lang->executionCommon . 'available to copy.';
|
||||
$lang->execution->noTeam = 'No team members at the moment';
|
||||
$lang->execution->or = ' or ';
|
||||
$lang->execution->selectProject = 'Please select project';
|
||||
$lang->execution->unfoldClosed = 'Unfold Closed';
|
||||
$lang->execution->editName = 'Edit Name';
|
||||
$lang->execution->setWIP = 'WIP Settings';
|
||||
$lang->execution->sortColumn = 'Kanban Card Sorting';
|
||||
$lang->execution->batchCreateStroy = "Batch create {$lang->SRCommon}";
|
||||
$lang->execution->batchCreateTask = 'Batch create task';
|
||||
$lang->execution->kanbanNoLinkProduct = "Kanban not linked {$lang->productCommon}";
|
||||
|
||||
/* Fields of zt_team. */
|
||||
$lang->execution->root = 'Root';
|
||||
@@ -163,7 +164,7 @@ global $config;
|
||||
if($config->systemMode == 'new')
|
||||
{
|
||||
$lang->execution->aclList['private'] = 'Private (for team members and execution stakeholders)';
|
||||
$lang->execution->aclList['open'] = 'Inherited Execution ACL (for who can access the current execution)';
|
||||
$lang->execution->aclList['open'] = 'Inherited Project ACL (for who can access the current project)';
|
||||
}
|
||||
else
|
||||
{
|
||||
@@ -171,6 +172,9 @@ else
|
||||
$lang->execution->aclList['open'] = "Public (Users who can visit {$lang->executionCommon} can access it.)";
|
||||
}
|
||||
|
||||
$lang->execution->kanbanAclList['private'] = 'Private';
|
||||
$lang->execution->kanbanAclList['open'] = 'Inherited Project';
|
||||
|
||||
$lang->execution->storyPoint = 'Story Point';
|
||||
|
||||
$lang->execution->burnByList['left'] = 'View by remaining hours';
|
||||
@@ -247,6 +251,8 @@ $lang->execution->iteration = 'Iterations';
|
||||
$lang->execution->iterationInfo = '%s Iterations';
|
||||
$lang->execution->viewAll = 'View All';
|
||||
$lang->execution->testreport = 'Test Report';
|
||||
$lang->execution->taskKanban = 'Task Kanban';
|
||||
$lang->execution->RDKanban = 'Research & Development Kanban';
|
||||
|
||||
/* Group browsing. */
|
||||
$lang->execution->allTasks = 'All';
|
||||
@@ -422,6 +428,7 @@ $lang->printKanban->typeList['increment'] = 'Increment';
|
||||
$lang->execution->typeList[''] = '';
|
||||
$lang->execution->typeList['stage'] = 'Stage';
|
||||
$lang->execution->typeList['sprint'] = $lang->executionCommon;
|
||||
$lang->execution->typeList['kanban'] = 'Kanban';
|
||||
|
||||
$lang->execution->featureBar['task']['all'] = $lang->execution->allTasks;
|
||||
$lang->execution->featureBar['task']['unclosed'] = $lang->execution->unclosed;
|
||||
|
||||
+106
-99
@@ -10,105 +10,106 @@
|
||||
* @link http://www.zentao.net
|
||||
*/
|
||||
/* 字段列表。*/
|
||||
$lang->execution->allExecutions = '所有' . $lang->execution->common;
|
||||
$lang->execution->allExecutionAB = "{$lang->execution->common}列表";
|
||||
$lang->execution->id = $lang->executionCommon . '编号';
|
||||
$lang->execution->type = $lang->executionCommon . '类型';
|
||||
$lang->execution->name = $lang->executionCommon . '名称';
|
||||
$lang->execution->code = $lang->executionCommon . '代号';
|
||||
$lang->execution->projectName = '所属项目';
|
||||
$lang->execution->execName = "{$lang->execution->common}名称";
|
||||
$lang->execution->execCode = "{$lang->execution->common}代号";
|
||||
$lang->execution->execType = "{$lang->execution->common}类型";
|
||||
$lang->execution->stage = '阶段';
|
||||
$lang->execution->pri = '优先级';
|
||||
$lang->execution->openedBy = '由谁创建';
|
||||
$lang->execution->openedDate = '创建日期';
|
||||
$lang->execution->closedBy = '由谁关闭';
|
||||
$lang->execution->closedDate = '关闭日期';
|
||||
$lang->execution->canceledBy = '由谁取消';
|
||||
$lang->execution->canceledDate = '取消日期';
|
||||
$lang->execution->begin = '计划开始';
|
||||
$lang->execution->end = '计划完成';
|
||||
$lang->execution->dateRange = '起始日期';
|
||||
$lang->execution->realBeganAB = '实际开始';
|
||||
$lang->execution->realEndAB = '实际完成';
|
||||
$lang->execution->realBegan = '实际开始日期';
|
||||
$lang->execution->realEnd = '实际完成日期';
|
||||
$lang->execution->to = '至';
|
||||
$lang->execution->days = '可用工作日';
|
||||
$lang->execution->day = '天';
|
||||
$lang->execution->workHour = '工时';
|
||||
$lang->execution->workHourUnit = 'h';
|
||||
$lang->execution->totalHours = '可用工时';
|
||||
$lang->execution->totalDays = '可用工日';
|
||||
$lang->execution->status = $lang->executionCommon . '状态';
|
||||
$lang->execution->execStatus = "{$lang->execution->common}状态";
|
||||
$lang->execution->subStatus = '子状态';
|
||||
$lang->execution->desc = $lang->executionCommon . '描述';
|
||||
$lang->execution->execDesc = "{$lang->execution->common}描述";
|
||||
$lang->execution->owner = '负责人';
|
||||
$lang->execution->PO = $lang->productCommon . '负责人';
|
||||
$lang->execution->PM = $lang->executionCommon . '负责人';
|
||||
$lang->execution->execPM = "{$lang->execution->common}负责人";
|
||||
$lang->execution->QD = '测试负责人';
|
||||
$lang->execution->RD = '发布负责人';
|
||||
$lang->execution->release = '发布';
|
||||
$lang->execution->acl = '访问控制';
|
||||
$lang->execution->teamname = '团队名称';
|
||||
$lang->execution->updateOrder = '排序';
|
||||
$lang->execution->order = $lang->executionCommon . '排序';
|
||||
$lang->execution->orderAB = '排序';
|
||||
$lang->execution->products = '相关' . $lang->productCommon;
|
||||
$lang->execution->whitelist = '白名单';
|
||||
$lang->execution->addWhitelist = '添加白名单';
|
||||
$lang->execution->unbindWhitelist = '删除白名单';
|
||||
$lang->execution->totalEstimate = '预计';
|
||||
$lang->execution->totalConsumed = '消耗';
|
||||
$lang->execution->totalLeft = '剩余';
|
||||
$lang->execution->progress = '进度';
|
||||
$lang->execution->hours = '预计 %s 消耗 %s 剩余 %s';
|
||||
$lang->execution->viewBug = '查看bug';
|
||||
$lang->execution->noProduct = "无{$lang->executionCommon}";
|
||||
$lang->execution->createStory = "提{$lang->SRCommon}";
|
||||
$lang->execution->storyTitle = "{$lang->SRCommon}名称";
|
||||
$lang->execution->all = '所有';
|
||||
$lang->execution->undone = '未完成';
|
||||
$lang->execution->unclosed = '未关闭';
|
||||
$lang->execution->typeDesc = "运维{$lang->executionCommon}没有{$lang->SRCommon}、bug、版本、测试功能。";
|
||||
$lang->execution->mine = '我负责:';
|
||||
$lang->execution->involved = '我参与';
|
||||
$lang->execution->other = '其他';
|
||||
$lang->execution->deleted = '已删除';
|
||||
$lang->execution->delayed = '已延期';
|
||||
$lang->execution->product = $lang->execution->products;
|
||||
$lang->execution->readjustTime = "调整{$lang->executionCommon}起止时间";
|
||||
$lang->execution->readjustTask = '顺延任务的起止时间';
|
||||
$lang->execution->effort = '日志';
|
||||
$lang->execution->storyEstimate = '需求估算';
|
||||
$lang->execution->newEstimate = '新一轮估算';
|
||||
$lang->execution->reestimate = '重新估算';
|
||||
$lang->execution->selectRound = '选择轮次';
|
||||
$lang->execution->average = '平均值';
|
||||
$lang->execution->relatedMember = '相关成员';
|
||||
$lang->execution->watermark = '由禅道导出';
|
||||
$lang->execution->burnXUnit = '(日期)';
|
||||
$lang->execution->burnYUnit = '(工时)';
|
||||
$lang->execution->waitTasks = '待处理';
|
||||
$lang->execution->viewByUser = '按用户查看';
|
||||
$lang->execution->oneProduct = "阶段只能关联一个{$lang->productCommon}";
|
||||
$lang->execution->noLinkProduct = "阶段没有关联{$lang->productCommon}";
|
||||
$lang->execution->recent = '近期访问:';
|
||||
$lang->execution->copyNoExecution = '没有可用的' . $lang->executionCommon . '来复制';
|
||||
$lang->execution->noTeam = '暂时没有团队成员';
|
||||
$lang->execution->or = '或';
|
||||
$lang->execution->selectProject = '请选择项目';
|
||||
$lang->execution->unfoldClosed = '展开已结束';
|
||||
$lang->execution->editName = '编辑名称';
|
||||
$lang->execution->setWIP = '在制品数量设置(WIP)';
|
||||
$lang->execution->sortColumn = '看板列卡片排序';
|
||||
$lang->execution->batchCreateStroy = "批量新建{$lang->SRCommon}";
|
||||
$lang->execution->batchCreateTask = '批量建任务';
|
||||
$lang->execution->allExecutions = '所有' . $lang->execution->common;
|
||||
$lang->execution->allExecutionAB = "{$lang->execution->common}列表";
|
||||
$lang->execution->id = $lang->executionCommon . '编号';
|
||||
$lang->execution->type = $lang->executionCommon . '类型';
|
||||
$lang->execution->name = $lang->executionCommon . '名称';
|
||||
$lang->execution->code = $lang->executionCommon . '代号';
|
||||
$lang->execution->projectName = '所属项目';
|
||||
$lang->execution->execName = "{$lang->execution->common}名称";
|
||||
$lang->execution->execCode = "{$lang->execution->common}代号";
|
||||
$lang->execution->execType = "{$lang->execution->common}类型";
|
||||
$lang->execution->stage = '阶段';
|
||||
$lang->execution->pri = '优先级';
|
||||
$lang->execution->openedBy = '由谁创建';
|
||||
$lang->execution->openedDate = '创建日期';
|
||||
$lang->execution->closedBy = '由谁关闭';
|
||||
$lang->execution->closedDate = '关闭日期';
|
||||
$lang->execution->canceledBy = '由谁取消';
|
||||
$lang->execution->canceledDate = '取消日期';
|
||||
$lang->execution->begin = '计划开始';
|
||||
$lang->execution->end = '计划完成';
|
||||
$lang->execution->dateRange = '起始日期';
|
||||
$lang->execution->realBeganAB = '实际开始';
|
||||
$lang->execution->realEndAB = '实际完成';
|
||||
$lang->execution->realBegan = '实际开始日期';
|
||||
$lang->execution->realEnd = '实际完成日期';
|
||||
$lang->execution->to = '至';
|
||||
$lang->execution->days = '可用工作日';
|
||||
$lang->execution->day = '天';
|
||||
$lang->execution->workHour = '工时';
|
||||
$lang->execution->workHourUnit = 'h';
|
||||
$lang->execution->totalHours = '可用工时';
|
||||
$lang->execution->totalDays = '可用工日';
|
||||
$lang->execution->status = $lang->executionCommon . '状态';
|
||||
$lang->execution->execStatus = "{$lang->execution->common}状态";
|
||||
$lang->execution->subStatus = '子状态';
|
||||
$lang->execution->desc = $lang->executionCommon . '描述';
|
||||
$lang->execution->execDesc = "{$lang->execution->common}描述";
|
||||
$lang->execution->owner = '负责人';
|
||||
$lang->execution->PO = $lang->productCommon . '负责人';
|
||||
$lang->execution->PM = $lang->executionCommon . '负责人';
|
||||
$lang->execution->execPM = "{$lang->execution->common}负责人";
|
||||
$lang->execution->QD = '测试负责人';
|
||||
$lang->execution->RD = '发布负责人';
|
||||
$lang->execution->release = '发布';
|
||||
$lang->execution->acl = '访问控制';
|
||||
$lang->execution->teamname = '团队名称';
|
||||
$lang->execution->updateOrder = '排序';
|
||||
$lang->execution->order = $lang->executionCommon . '排序';
|
||||
$lang->execution->orderAB = '排序';
|
||||
$lang->execution->products = '相关' . $lang->productCommon;
|
||||
$lang->execution->whitelist = '白名单';
|
||||
$lang->execution->addWhitelist = '添加白名单';
|
||||
$lang->execution->unbindWhitelist = '删除白名单';
|
||||
$lang->execution->totalEstimate = '预计';
|
||||
$lang->execution->totalConsumed = '消耗';
|
||||
$lang->execution->totalLeft = '剩余';
|
||||
$lang->execution->progress = '进度';
|
||||
$lang->execution->hours = '预计 %s 消耗 %s 剩余 %s';
|
||||
$lang->execution->viewBug = '查看bug';
|
||||
$lang->execution->noProduct = "无{$lang->executionCommon}";
|
||||
$lang->execution->createStory = "提{$lang->SRCommon}";
|
||||
$lang->execution->storyTitle = "{$lang->SRCommon}名称";
|
||||
$lang->execution->all = '所有';
|
||||
$lang->execution->undone = '未完成';
|
||||
$lang->execution->unclosed = '未关闭';
|
||||
$lang->execution->typeDesc = "运维{$lang->executionCommon}没有{$lang->SRCommon}、bug、版本、测试功能。";
|
||||
$lang->execution->mine = '我负责:';
|
||||
$lang->execution->involved = '我参与';
|
||||
$lang->execution->other = '其他';
|
||||
$lang->execution->deleted = '已删除';
|
||||
$lang->execution->delayed = '已延期';
|
||||
$lang->execution->product = $lang->execution->products;
|
||||
$lang->execution->readjustTime = "调整{$lang->executionCommon}起止时间";
|
||||
$lang->execution->readjustTask = '顺延任务的起止时间';
|
||||
$lang->execution->effort = '日志';
|
||||
$lang->execution->storyEstimate = '需求估算';
|
||||
$lang->execution->newEstimate = '新一轮估算';
|
||||
$lang->execution->reestimate = '重新估算';
|
||||
$lang->execution->selectRound = '选择轮次';
|
||||
$lang->execution->average = '平均值';
|
||||
$lang->execution->relatedMember = '相关成员';
|
||||
$lang->execution->watermark = '由禅道导出';
|
||||
$lang->execution->burnXUnit = '(日期)';
|
||||
$lang->execution->burnYUnit = '(工时)';
|
||||
$lang->execution->waitTasks = '待处理';
|
||||
$lang->execution->viewByUser = '按用户查看';
|
||||
$lang->execution->oneProduct = "阶段只能关联一个{$lang->productCommon}";
|
||||
$lang->execution->noLinkProduct = "阶段没有关联{$lang->productCommon}";
|
||||
$lang->execution->recent = '近期访问:';
|
||||
$lang->execution->copyNoExecution = '没有可用的' . $lang->executionCommon . '来复制';
|
||||
$lang->execution->noTeam = '暂时没有团队成员';
|
||||
$lang->execution->or = '或';
|
||||
$lang->execution->selectProject = '请选择项目';
|
||||
$lang->execution->unfoldClosed = '展开已结束';
|
||||
$lang->execution->editName = '编辑名称';
|
||||
$lang->execution->setWIP = '在制品数量设置(WIP)';
|
||||
$lang->execution->sortColumn = '看板列卡片排序';
|
||||
$lang->execution->batchCreateStroy = "批量新建{$lang->SRCommon}";
|
||||
$lang->execution->batchCreateTask = '批量建任务';
|
||||
$lang->execution->kanbanNoLinkProduct = "看板没有关联{$lang->productCommon}";
|
||||
|
||||
/* Fields of zt_team. */
|
||||
$lang->execution->root = '源ID';
|
||||
@@ -171,6 +172,9 @@ else
|
||||
$lang->execution->aclList['open'] = "公开(有{$lang->executionCommon}视图权限即可访问)";
|
||||
}
|
||||
|
||||
$lang->execution->kanbanAclList['private'] = '私有';
|
||||
$lang->execution->kanbanAclList['open'] = '继承项目';
|
||||
|
||||
$lang->execution->storyPoint = '故事点';
|
||||
|
||||
$lang->execution->burnByList['left'] = '按剩余工时查看';
|
||||
@@ -247,6 +251,8 @@ $lang->execution->iteration = '版本迭代';
|
||||
$lang->execution->iterationInfo = '迭代%s次';
|
||||
$lang->execution->viewAll = '查看所有';
|
||||
$lang->execution->testreport = '测试报告';
|
||||
$lang->execution->taskKanban = '任务看板';
|
||||
$lang->execution->RDKanban = '研发看板';
|
||||
|
||||
/* 分组浏览。*/
|
||||
$lang->execution->allTasks = '所有';
|
||||
@@ -422,6 +428,7 @@ $lang->printKanban->typeList['increment'] = '增量';
|
||||
$lang->execution->typeList[''] = '';
|
||||
$lang->execution->typeList['stage'] = '阶段';
|
||||
$lang->execution->typeList['sprint'] = $lang->executionCommon;
|
||||
$lang->execution->typeList['kanban'] = '看板';
|
||||
|
||||
$lang->execution->featureBar['task']['all'] = $lang->execution->allTasks;
|
||||
$lang->execution->featureBar['task']['unclosed'] = $lang->execution->unclosed;
|
||||
|
||||
+61
-29
@@ -65,13 +65,14 @@ class executionModel extends model
|
||||
{
|
||||
if(!$this->app->user->admin and strpos(",{$this->app->user->view->sprints},", ",$executionID,") === false and !defined('TUTORIAL') and $executionID != 0) die(js::error($this->lang->execution->accessDenied) . js::locate('back'));
|
||||
|
||||
$executions = $this->loadModel('execution')->getPairs(0, 'all', 'nocode');
|
||||
$executions = $this->getPairs(0, 'all', 'nocode');
|
||||
if(!$executionID and $this->session->execution) $executionID = $this->session->execution;
|
||||
if(!$executionID or !in_array($executionID, array_keys($executions))) $executionID = key($executions);
|
||||
$this->session->set('execution', $executionID);
|
||||
|
||||
/* Unset story, bug, build and testtask if type is ops. */
|
||||
$execution = $this->getByID($executionID);
|
||||
if($execution and $execution->type == 'kanban') $this->lang->execution->menu = new stdclass();
|
||||
|
||||
if($execution and $execution->type == 'stage' and $this->config->systemMode == 'new')
|
||||
{
|
||||
@@ -88,15 +89,6 @@ class executionModel extends model
|
||||
unset($this->lang->execution->menu->build);
|
||||
}
|
||||
|
||||
/* Hide story and qa menu when execution is story or design type. */
|
||||
/*
|
||||
if($execution and ($execution->attribute == 'story' or $execution->attribute == 'design'))
|
||||
{
|
||||
unset($this->lang->execution->menu->story);
|
||||
unset($this->lang->execution->menu->qa);
|
||||
}
|
||||
*/
|
||||
|
||||
if($executions and (!isset($executions[$executionID]) or !$this->checkPriv($executionID))) $this->accessDenied();
|
||||
|
||||
$moduleName = $this->app->getModuleName();
|
||||
@@ -312,6 +304,12 @@ class executionModel extends model
|
||||
return false;
|
||||
}
|
||||
|
||||
if($type == 'kanban' and empty($this->post->products[0]))
|
||||
{
|
||||
dao::$errors['message'][] = $this->lang->execution->kanbanNoLinkProduct;
|
||||
return false;
|
||||
}
|
||||
|
||||
$this->config->execution->create->requiredFields .= ',project';
|
||||
}
|
||||
|
||||
@@ -381,7 +379,7 @@ class executionModel extends model
|
||||
$creatorExists = false;
|
||||
$teamMembers = array();
|
||||
|
||||
$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();
|
||||
@@ -474,10 +472,6 @@ class executionModel extends model
|
||||
return false;
|
||||
}
|
||||
|
||||
/* Get team and language item. */
|
||||
$team = $this->loadModel('user')->getTeamMemberPairs($executionID, 'execution');
|
||||
$this->lang->execution->team = $this->lang->execution->teamname;
|
||||
|
||||
/* Get the data from the post. */
|
||||
$execution = fixer::input('post')
|
||||
->setDefault('lastEditedBy', $this->app->user->account)
|
||||
@@ -529,6 +523,12 @@ class executionModel extends model
|
||||
->limit(1)
|
||||
->exec();
|
||||
|
||||
if($oldExecution->type == 'kanban') $this->dao->delete()->from(TABLE_TEAM)->where('root')->eq((int)$executionID)->andWhere('type')->eq('execution')->andWhere('role')->ne('')->exec();
|
||||
|
||||
/* Get team and language item. */
|
||||
$this->lang->execution->team = $this->lang->execution->teamname;
|
||||
$team = $this->loadModel('user')->getTeamMemberPairs($executionID, 'execution');
|
||||
|
||||
$changedAccounts = array();
|
||||
$teamMembers = array();
|
||||
foreach($this->config->execution->ownerFields as $ownerField)
|
||||
@@ -1054,7 +1054,7 @@ class executionModel extends model
|
||||
/* Order by status's content whether or not done */
|
||||
$executions = $this->dao->select('*, IF(INSTR("done,closed", status) < 2, 0, 1) AS isDone, INSTR("doing,wait,suspended,closed", status) AS sortStatus')->from(TABLE_EXECUTION)
|
||||
->where('deleted')->eq(0)
|
||||
->beginIF($type == 'all')->andWhere('type')->in('stage,sprint')->fi()
|
||||
->beginIF($type == 'all')->andWhere('type')->in('stage,sprint,kanban')->fi()
|
||||
->beginIF($projectID and $this->config->systemMode == 'new')->andWhere('project')->eq($projectID)->fi()
|
||||
->beginIF($type != 'all' and $this->config->systemMode == 'new')->andWhere('type')->eq($type)->fi()
|
||||
->beginIF(strpos($mode, 'withdelete') === false)->andWhere('deleted')->eq(0)->fi()
|
||||
@@ -1202,7 +1202,7 @@ class executionModel extends model
|
||||
public function getIdList($projectID, $status = 'all')
|
||||
{
|
||||
return $this->dao->select('id')->from(TABLE_EXECUTION)
|
||||
->where('type')->in('sprint,stage')
|
||||
->where('type')->in('sprint,stage,kanban')
|
||||
->andWhere('deleted')->eq('0')
|
||||
->beginIF($projectID)->andWhere('project')->eq($projectID)->fi()
|
||||
->beginIF($status == 'undone')->andWhere('status')->notIN('done,closed')->fi()
|
||||
@@ -1228,7 +1228,7 @@ class executionModel extends model
|
||||
$orderBy = (isset($project->model) and $project->model == 'waterfall') ? 'begin_asc,id_asc' : 'begin_desc,id_desc';
|
||||
|
||||
$executions = $this->dao->select('*')->from(TABLE_EXECUTION)
|
||||
->where('type')->in('stage,sprint')
|
||||
->where('type')->in('stage,sprint,kanban')
|
||||
->andWhere('deleted')->eq('0')
|
||||
->beginIF($projectID)->andWhere('project')->eq((int)$projectID)->fi()
|
||||
->beginIF(!$this->app->user->admin)->andWhere('id')->in($this->app->user->view->sprints)->fi()
|
||||
@@ -1319,7 +1319,7 @@ class executionModel extends model
|
||||
$module = 'execution';
|
||||
$method = 'task';
|
||||
}
|
||||
if($module == 'testcase' and ($method == 'view' || $method == 'edit' || $method == 'batchedit'))
|
||||
if($module == 'testcase' and ($method == 'view' or $method == 'edit' or $method == 'batchedit'))
|
||||
{
|
||||
$module = 'execution';
|
||||
$method = 'testcase';
|
||||
@@ -1329,7 +1329,7 @@ class executionModel extends model
|
||||
$module = 'execution';
|
||||
$method = 'testtask';
|
||||
}
|
||||
if($module == 'build' and ($method == 'edit' || $method= 'view'))
|
||||
if($module == 'build' and ($method == 'edit' or $method == 'view'))
|
||||
{
|
||||
$module = 'execution';
|
||||
$method = 'build';
|
||||
@@ -2268,14 +2268,15 @@ class executionModel extends model
|
||||
/**
|
||||
* Link story.
|
||||
*
|
||||
* @param int $executionID
|
||||
* @param array $stories
|
||||
* @param array $products
|
||||
* @param int $executionID
|
||||
* @param array $stories
|
||||
* @param array $products
|
||||
* @param string $extra
|
||||
*
|
||||
* @access public
|
||||
* @return bool
|
||||
*/
|
||||
public function linkStory($executionID, $stories = array(), $products = array())
|
||||
public function linkStory($executionID, $stories = array(), $products = array(), $extra = '')
|
||||
{
|
||||
if(empty($executionID)) return false;
|
||||
if(empty($stories)) $stories = $this->post->stories;
|
||||
@@ -2283,16 +2284,23 @@ class executionModel extends model
|
||||
if(empty($products)) $products = $this->post->products;
|
||||
|
||||
$this->loadModel('action');
|
||||
$this->loadModel('kanban');
|
||||
$versions = $this->loadModel('story')->getVersions($stories);
|
||||
$linkedStories = $this->dao->select('*')->from(TABLE_PROJECTSTORY)->where('project')->eq($executionID)->orderBy('order_desc')->fetchPairs('story', 'order');
|
||||
$lastOrder = reset($linkedStories);
|
||||
$storyList = $this->dao->select('id, status, branch')->from(TABLE_STORY)->where('id')->in(array_values($stories))->fetchAll('id');
|
||||
$execution = $this->getById($executionID);
|
||||
|
||||
$extra = str_replace(array(',', ' '), array('&', ''), $extra);
|
||||
parse_str($extra, $output);
|
||||
foreach($stories as $key => $storyID)
|
||||
{
|
||||
$notAllowedStatus = $this->app->rawMethod == 'batchcreate' ? 'closed' : 'draft,closed';
|
||||
if(strpos($notAllowedStatus, $storyList[$storyID]->status) !== false) continue;
|
||||
if(isset($linkedStories[$storyID])) continue;
|
||||
|
||||
if(isset($output['laneID']) and isset($output['columnID'])) $this->kanban->addKanbanCell($executionID, $output['laneID'], $output['columnID'], 'story', $storyID);
|
||||
|
||||
$data = new stdclass();
|
||||
$data->project = $executionID;
|
||||
$data->product = (int)$products[$storyID];
|
||||
@@ -2308,6 +2316,8 @@ class executionModel extends model
|
||||
$action = $executionID == $this->session->project ? 'linked2project' : 'linked2execution';
|
||||
$this->action->create('story', $storyID, $action, '', $executionID);
|
||||
}
|
||||
|
||||
if(!isset($output['laneID']) or !isset($output['columnID'])) $this->kanban->updateLane($executionID, 'story');
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -2479,6 +2489,23 @@ class executionModel extends model
|
||||
->fetchAll('account');
|
||||
}
|
||||
|
||||
/**
|
||||
* Get members by execution id list.
|
||||
*
|
||||
* @param array $executionIdList
|
||||
* @access public
|
||||
* @return void
|
||||
*/
|
||||
public function getMembersByIdList($executionIdList)
|
||||
{
|
||||
return $this->dao->select("t1.root, t1.account, t2.realname")->from(TABLE_TEAM)->alias('t1')
|
||||
->leftJoin(TABLE_USER)->alias('t2')->on('t1.account = t2.account')
|
||||
->where('t1.root')->in($executionIdList)
|
||||
->andWhere('t1.type')->eq('execution')
|
||||
->andWhere('t2.deleted')->eq('0')
|
||||
->fetchGroup('root');
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the skip members of the team.
|
||||
*
|
||||
@@ -3022,13 +3049,16 @@ class executionModel extends model
|
||||
*/
|
||||
public static function isClickable($execution, $action)
|
||||
{
|
||||
$action = strtolower($action);
|
||||
$action = strtolower($action);
|
||||
$clickable = commonModel::hasPriv('execution', $action);
|
||||
if(!$clickable) return false;
|
||||
|
||||
if($action == 'start') return $execution->status == 'wait';
|
||||
if($action == 'close') return $execution->status != 'closed';
|
||||
if($action == 'suspend') return $execution->status == 'wait' or $execution->status == 'doing';
|
||||
if($action == 'putoff') return $execution->status == 'wait' or $execution->status == 'doing';
|
||||
if($action == 'activate') return $execution->status == 'suspended' or $execution->status == 'closed';
|
||||
if($action == 'delete') return $execution->status == 'wait' or $execution->status == 'doing';
|
||||
|
||||
return true;
|
||||
}
|
||||
@@ -3212,13 +3242,14 @@ class executionModel extends model
|
||||
/**
|
||||
* Get Kanban tasks
|
||||
*
|
||||
* @param int $executionID
|
||||
* @param string $orderBy
|
||||
* @param object $pager
|
||||
* @param int $executionID
|
||||
* @param string $orderBy
|
||||
* @param object $pager
|
||||
* @param array|string $excludeTasks
|
||||
* @access public
|
||||
* @return void
|
||||
*/
|
||||
public function getKanbanTasks($executionID, $orderBy = 'status_asc, id_desc', $pager = null)
|
||||
public function getKanbanTasks($executionID, $orderBy = 'status_asc, id_desc', $pager = null, $excludeTasks = '')
|
||||
{
|
||||
$tasks = $this->dao->select('t1.*, t2.id AS storyID, t2.title AS storyTitle, t2.version AS latestStoryVersion, t2.status AS storyStatus, t3.realname AS assignedToRealName')
|
||||
->from(TABLE_TASK)->alias('t1')
|
||||
@@ -3227,6 +3258,7 @@ class executionModel extends model
|
||||
->where('t1.execution')->eq((int)$executionID)
|
||||
->andWhere('t1.deleted')->eq(0)
|
||||
->andWhere('t1.parent')->ge(0)
|
||||
->beginIF($excludeTasks)->andWhere('t1.id')->notIN($excludeTasks)->fi()
|
||||
->orderBy($orderBy)
|
||||
->page($pager)
|
||||
->fetchAll('id');
|
||||
|
||||
@@ -72,6 +72,11 @@ foreach($executions as $projectID => $projectExecutions)
|
||||
|
||||
foreach($projectExecutions as $index => $execution)
|
||||
{
|
||||
$kanbanLink = $this->createLink('execution', 'kanban', "executionID=%s");
|
||||
$taskLink = $this->createLink('execution', 'task', "executionID=%s");
|
||||
if($execution->type != 'kanban' and $link == $kanbanLink) $link = $taskLink;
|
||||
if($execution->type == 'kanban' and $link != $kanbanLink) $link = $kanbanLink;
|
||||
|
||||
$selected = $execution->id == $executionID ? 'selected' : '';
|
||||
if($execution->status != 'done' and $execution->status != 'closed' and ($execution->PM == $this->app->user->account or isset($execution->teams[$this->app->user->account])))
|
||||
{
|
||||
|
||||
@@ -118,11 +118,10 @@
|
||||
<?php printf('%03d', $execution->id);?>
|
||||
</td>
|
||||
<td class='text-left c-name <?php if(!empty($execution->children)) echo 'has-child';?> flex' title='<?php echo $execution->name?>'>
|
||||
<?php if(isset($this->config->maxVersion)):?>
|
||||
<span class='project-type-label label label-outline <?php echo $execution->type == 'sprint' ? 'label-info' : 'label-warning';?>'><?php echo $lang->execution->typeList[$execution->type]?></span>
|
||||
<?php endif;?>
|
||||
<span class='project-type-label label label-outline <?php echo $execution->type == 'stage' ? 'label-warning' : 'label-info';?>'><?php echo $lang->execution->typeList[$execution->type]?></span>
|
||||
<?php
|
||||
echo !empty($execution->children) ? $execution->name : html::a($this->createLink('execution', 'task', 'execution=' . $execution->id), $execution->name, '', "class='text-ellipsis'");
|
||||
$executionLink = $execution->projectModel == 'kanban' ? html::a($this->createLink('execution', 'kanban', 'executionID=' . $execution->id), $execution->name, '', "class='text-ellipsis'") : html::a($this->createLink('execution', 'task', 'execution=' . $execution->id), $execution->name, '', "class='text-ellipsis'");
|
||||
echo !empty($execution->children) ? $execution->name : $executionLink;
|
||||
if(isset($execution->delay)) echo "<span class='label label-danger label-badge'>{$lang->execution->delayed}</span> ";
|
||||
?>
|
||||
<?php if(!empty($execution->children)):?>
|
||||
|
||||
@@ -42,6 +42,7 @@
|
||||
<?php js::set('projectCommon', $lang->project->common);?>
|
||||
<?php js::set('multiBranchProducts', $multiBranchProducts);?>
|
||||
<?php js::set('systemMode', $config->systemMode);?>
|
||||
<?php js::set('projectID', $projectID);?>
|
||||
<div id='mainContent' class='main-content'>
|
||||
<div class='center-block'>
|
||||
<div class='main-header'>
|
||||
@@ -88,6 +89,7 @@
|
||||
</div>
|
||||
</td><td></td><td></td>
|
||||
</tr>
|
||||
<?php if(empty($project) or $project->model != 'kanban'):?>
|
||||
<tr>
|
||||
<th><?php echo (($from == 'execution') and ($config->systemMode == 'new')) ? $lang->execution->execType : $lang->execution->type;?></th>
|
||||
<td>
|
||||
@@ -104,6 +106,7 @@
|
||||
</td>
|
||||
<td class='muted' colspan='2'><div id='lifeTimeTips'><?php echo $lang->execution->typeDesc;?></div></td>
|
||||
</tr>
|
||||
<?php endif;?>
|
||||
<?php if($isStage):?>
|
||||
<tr>
|
||||
<th><?php echo $lang->stage->percent;?></th>
|
||||
|
||||
@@ -66,6 +66,7 @@
|
||||
</div>
|
||||
</td>
|
||||
</tr>
|
||||
<?php if($execution->type != 'kanban'):?>
|
||||
<tr>
|
||||
<th><?php echo $lang->execution->type;?></th>
|
||||
<td>
|
||||
@@ -81,6 +82,7 @@
|
||||
?>
|
||||
</td>
|
||||
</tr>
|
||||
<?php endif;?>
|
||||
<tr>
|
||||
<th><?php echo $lang->execution->teamname;?></th>
|
||||
<td><?php echo html::input('team', $execution->team, "class='form-control'");?></td>
|
||||
|
||||
@@ -1,15 +1,94 @@
|
||||
<?php
|
||||
/**
|
||||
* The kanban view file of execution module of ZenTaoPMS.
|
||||
* The kanban file of execution module of ZenTaoPMS.
|
||||
*
|
||||
* @copyright Copyright 2009-2012 青岛易软天创网络科技有限公司 (QingDao Nature Easy Soft Network Technology Co,LTD www.cnezsoft.com)
|
||||
* @author Wang Yidong, Zhu Jinyong
|
||||
* @copyright Copyright 2009-2022 青岛易软天创网络科技有限公司(QingDao Nature Easy Soft Network Technology Co,LTD, www.cnezsoft.com)
|
||||
* @license ZPL (http://zpl.pub/page/zplv12.html)
|
||||
* @author Mengyi Liu<liumengyi@easycorp.ltd>
|
||||
* @package execution
|
||||
* @version $Id: kanban.html.php $
|
||||
* @version $Id: kanban.html.php 935 2022-01-11 16:49:24Z $
|
||||
* @link https://www.zentao.net
|
||||
*/
|
||||
?>
|
||||
<?php include '../../common/view/header.html.php';?>
|
||||
<?php include '../../common/view/kanban.html.php';?>
|
||||
|
||||
<?php
|
||||
$laneCount = 0;
|
||||
if($groupBy == 'default')
|
||||
{
|
||||
foreach($regions as $region) $laneCount += $region->laneCount;
|
||||
}
|
||||
|
||||
js::set('regions', $regions);
|
||||
js::set('browseType', $browseType);
|
||||
js::set('kanbanData', $kanbanData);
|
||||
js::set('orderBy', $orderBy);
|
||||
js::set('groupBy', $groupBy);
|
||||
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('deadlineLang', $lang->task->deadlineAB);
|
||||
js::set('kanbancolumnLang', $lang->kanbancolumn);
|
||||
js::set('kanbancardLang', $lang->kanbancard);
|
||||
js::set('executionID', $execution->id);
|
||||
js::set('laneCount', $laneCount);
|
||||
js::set('userList', $userList);
|
||||
js::set('noAssigned', $lang->kanbancard->noAssigned);
|
||||
js::set('users', $users);
|
||||
js::set('displayCards', $execution->displayCards);
|
||||
js::set('colorListLang', $lang->kanbancard->colorList);
|
||||
js::set('colorList', $this->config->kanban->cardColorList);
|
||||
|
||||
$canSortRegion = commonModel::hasPriv('kanban', 'sortRegion') && count($regions) > 1;
|
||||
$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,
|
||||
'canAssignTask' => common::hasPriv('task', 'assignto'),
|
||||
'canAssignStory' => common::hasPriv('story', 'assignto'),
|
||||
'canFinishTask' => common::hasPriv('task', 'finish'),
|
||||
'canPauseTask' => common::hasPriv('task', 'pause'),
|
||||
'canCancelTask' => common::hasPriv('task', 'cancel'),
|
||||
'canCloseTask' => common::hasPriv('task', 'close'),
|
||||
'canActivateTask' => common::hasPriv('task', 'activate'),
|
||||
'canStartTask' => common::hasPriv('task', 'start'),
|
||||
'canAssignBug' => common::hasPriv('bug', 'assignto'),
|
||||
'canConfirmBug' => common::hasPriv('bug', 'confirmBug'),
|
||||
'canActivateBug' => common::hasPriv('bug', 'activate')
|
||||
)
|
||||
);
|
||||
js::set('hasStoryButton', $hasStoryButton);
|
||||
js::set('hasBugButton', $hasBugButton);
|
||||
js::set('hasTaskButton', $hasTaskButton);
|
||||
?>
|
||||
|
||||
<div id='mainMenu' class='clearfix'>
|
||||
<div class='btn-toolbar pull-left'>
|
||||
<div class="input-control space c-type">
|
||||
@@ -34,50 +113,33 @@
|
||||
</div>
|
||||
<div class='btn-toolbar pull-right'>
|
||||
<?php
|
||||
$link = $this->createLink('task', 'export', "execution=$executionID&orderBy=$orderBy&type=kanban");
|
||||
if(common::hasPriv('task', 'export')) echo html::a($link, "<i class='icon-export muted'></i> " . $lang->export, '', "class='btn btn-link iframe export' data-width='700'");
|
||||
?>
|
||||
<?php if($canBeChanged):?>
|
||||
<div class='btn-group' style="margin-right: 0">
|
||||
<button type='button' class='btn btn-link dropdown-toggle' data-toggle='dropdown' id='importAction'>
|
||||
<i class='icon-import muted'></i> <?php echo $lang->import ?>
|
||||
<span class='caret'></span>
|
||||
</button>
|
||||
<ul class='dropdown-menu' id='importActionMenu'>
|
||||
<?php
|
||||
$misc = common::hasPriv('execution', 'importTask') ? '' : "class=disabled";
|
||||
$link = common::hasPriv('execution', 'importTask') ? $this->createLink('execution', 'importTask', "execution=$execution->id") : '#';
|
||||
echo "<li $misc>" . html::a($link, $lang->execution->importTask, '', $misc) . "</li>";
|
||||
echo html::a('javascript:fullScreen()', "<i class='icon-fullscreen muted'></i> " . $lang->kanban->fullScreen, '', "class='btn btn-link'");
|
||||
$actions = '';
|
||||
$printSettingBtn = (common::hasPriv('kanban', 'createRegion') or (common::hasPriv('kanban', 'setLaneHeight')) or common::hasPriv('execution', 'edit') or common::hasPriv('execution', 'close') or common::hasPriv('execution', 'delete') or !empty($executionActions));
|
||||
|
||||
$misc = common::hasPriv('execution', 'importBug') ? '' : "class=disabled";
|
||||
$link = common::hasPriv('execution', 'importBug') ? $this->createLink('execution', 'importBug', "execution=$execution->id") : '#';
|
||||
echo "<li $misc>" . html::a($link, $lang->execution->importBug, '', $misc) . "</li>";
|
||||
?>
|
||||
</ul>
|
||||
</div>
|
||||
if($printSettingBtn)
|
||||
{
|
||||
$actions .= html::a('javascript:;', "<i class='icon icon-cog-outline'></i>" . $lang->kanban->setting, '', "data-toggle='dropdown' class='btn btn-link'");
|
||||
$actions .= "<ul id='kanbanActionMenu' class='dropdown-menu pull-right'>";
|
||||
$width = $this->app->getClientLang() == 'en' ? '70%' : '60%';
|
||||
if(common::hasPriv('kanban', 'createRegion')) $actions .= '<li>' . html::a(helper::createLink('kanban', 'createRegion', "kanbanID=$execution->id&from=execution", '', true), '<i class="icon icon-plus"></i>' . $lang->kanban->createRegion, '', "class='iframe btn btn-link text-left'") . '</li>';
|
||||
if(common::hasPriv('kanban', 'setLaneHeight')) $actions .= '<li>' . html::a(helper::createLink('kanban', 'setLaneHeight', "kanbanID=$execution->id&from=execution", '', true), '<i class="icon icon-size-height"></i>' . $lang->kanban->laneHeight, '', "class='iframe btn btn-link text-left' data-width=$width") . '</li>';
|
||||
$kanbanActions = '';
|
||||
if(common::hasPriv('execution', 'edit')) $kanbanActions .= '<li>' . html::a(helper::createLink('execution', 'edit', "executionID=$execution->id", '', true), '<i class="icon icon-edit"></i>' . $lang->kanban->edit, '', "class='iframe btn btn-link text-left' data-width='75%'") . '</li>';
|
||||
if(in_array('start', $executionActions)) $kanbanActions .= '<li>' . html::a(helper::createLink('execution', 'start', "executionID=$execution->id", '', true), '<i class="icon icon-play"></i>' . $lang->execution->start, '', "class='iframe btn btn-link text-left' data-width='75%'") . '</li>';
|
||||
if(in_array('putoff', $executionActions)) $kanbanActions .= '<li>' . html::a(helper::createLink('execution', 'putoff', "executionID=$execution->id", '', true), '<i class="icon icon-calendar"></i>' . $lang->execution->putoff, '', "class='iframe btn btn-link text-left' data-width='75%'") . '</li>';
|
||||
if(in_array('suspend', $executionActions)) $kanbanActions .= '<li>' . html::a(helper::createLink('execution', 'suspend', "executionID=$execution->id", '', true), '<i class="icon icon-pause"></i>' . $lang->execution->suspend, '', "class='iframe btn btn-link text-left' data-width='75%'") . '</li>';
|
||||
if(in_array('close', $executionActions)) $kanbanActions .= '<li>' . html::a(helper::createLink('execution', 'close', "executionID=$execution->id", '', true), '<i class="icon icon-off"></i>' . $lang->execution->close, '', "class='iframe btn btn-link text-left' data-width='75%'") . '</li>';
|
||||
if(in_array('activate', $executionActions)) $kanbanActions .= '<li>' . html::a(helper::createLink('execution', 'activate', "executionID=$execution->id", '', true), '<i class="icon icon-magic"></i>' . $lang->execution->activate, '', "class='iframe btn btn-link text-left' data-width='75%'") . '</li>';
|
||||
if(common::hasPriv('execution', 'delete')) $kanbanActions .= '<li>' . html::a(helper::createLink('execution', 'delete', "executionID=$execution->id"), '<i class="icon icon-trash"></i>' . $lang->delete, 'hiddenwin', "class='btn btn-link text-left'") . '</li>';
|
||||
if($kanbanActions)
|
||||
{
|
||||
$actions .= ((common::hasPriv('kanban', 'createRegion') or common::hasPriv('kanban', 'setLaneHeight')) and (common::hasPriv('execution', 'edit') or common::hasPriv('execution', 'delete') or !empty($executionActions))) ? "<div class='divider'></div>" . $kanbanActions : $kanbanActions;
|
||||
}
|
||||
$actions .= "</ul>";
|
||||
}
|
||||
|
||||
<?php
|
||||
echo "<div class='btn-group menu-actions'>";
|
||||
echo html::a('javascript:;', "<i class='icon icon-ellipsis-v'></i>", '', "data-toggle='dropdown' class='btn btn-link'");
|
||||
echo "<ul class='dropdown-menu pull-right'>";
|
||||
if(common::hasPriv('execution', 'printKanban')) echo '<li>' .html::a($this->createLink('execution', 'printKanban', "executionID=$executionID"), "<i class='icon-printer muted'></i> " . $lang->execution->printKanban, '', "class='iframe btn btn-link' id='printKanban' title='{$lang->execution->printKanban}' data-width='500'") . '</li>';
|
||||
echo '<li>' .html::a('javascript:fullScreen()', "<i class='icon-fullscreen muted'></i> " . $lang->execution->fullScreen, '', "class='btn btn-link' title='{$lang->execution->fullScreen}' data-width='500'") . '</li>';
|
||||
echo '</ul></div>';
|
||||
?>
|
||||
<?php
|
||||
$checkObject = new stdclass();
|
||||
$checkObject->execution = $executionID;
|
||||
$canCreateTask = common::hasPriv('task', 'create', $checkObject);
|
||||
$canBatchCreateTask = common::hasPriv('task', 'batchCreate', $checkObject);
|
||||
$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);
|
||||
echo $actions;
|
||||
?>
|
||||
<?php if($canCreateTask or $canBatchCreateTask or $canCreateBug or $canBatchCreateBug or $canCreateStory or $canBatchCreateStory or $canLinkStory or $canLinkStoryByPlane):?>
|
||||
<div class='dropdown' id='createDropdown'>
|
||||
@@ -96,18 +158,42 @@
|
||||
</ul>
|
||||
</div>
|
||||
<?php endif;?>
|
||||
<?php else:?>
|
||||
<?php $canCreateTask = $canBatchCreateTask = $canCreateBug = $canBatchCreateBug = $canCreateStory = $canBatchCreateStory = $canLinkStory = $canLinkStoryByPlane = false;?>
|
||||
<?php endif;?>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<?php if($groupBy == 'default'):?>
|
||||
<div class='panel' id='kanbanContainer'>
|
||||
<div class='panel-body'>
|
||||
<div id='kanbans'></div>
|
||||
<div id="kanban" data-id='<?php echo $execution->id;?>'>
|
||||
<?php foreach($regions as $region):?>
|
||||
<div class="region<?php if($canSortRegion) echo ' sort';?>" data-id="<?php echo $region->id;?>">
|
||||
<div class="region-header dropdown">
|
||||
<span class="strong"><?php echo $region->name;?></span>
|
||||
<label class="label label-region"><?php echo $this->lang->kanbanlane->common . ' ' . $region->laneCount;?></label>
|
||||
<span><i class="icon icon-chevron-double-up" data-id="<?php echo $region->id;?>"></i></span>
|
||||
<span class='regionActions'>
|
||||
<?php if($canEditRegion || $canCreateLane || $canDeleteRegion):?>
|
||||
<button class="btn btn-link action" type="button" data-toggle="dropdown"><i class="icon icon-ellipsis-v"></i></button>
|
||||
<ul class="dropdown-menu pull-right">
|
||||
<?php if($canEditRegion) echo '<li>' . html::a(helper::createLink('kanban', 'editRegion', "regionID={$region->id}", '', 1), '<i class="icon icon-edit"></i>' . $this->lang->kanban->editRegion, '', 'class="iframe" data-toggle="modal" data-width="600px"') . '</li>';?>
|
||||
<?php if($canCreateLane) echo '<li>' . html::a(helper::createLink('kanban', 'createLane', "executionID={$execution->id}®ionID={$region->id}&from=execution", '', 1), '<i class="icon icon-plus"></i>' . $this->lang->kanban->createLane, '', "class='iframe'") . '</li>';?>
|
||||
<?php if($canDeleteRegion and count($regions) > 1) echo '<li>' . html::a(helper::createLink('kanban', 'deleteRegion', "regionID={$region->id}"), '<i class="icon icon-trash"></i>' . $this->lang->kanban->deleteRegion, "hiddenwin") . '</li>';?>
|
||||
</ul>
|
||||
<?php endif;?>
|
||||
</span>
|
||||
</div>
|
||||
<div id='kanban<?php echo $region->id;?>' data-id='<?php echo $region->id;?>' class='kanban'></div>
|
||||
</div>
|
||||
<?php endforeach;?>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<?php else:?>
|
||||
<div class='panel' id='kanbanContainer'>
|
||||
<div class='panel-body region'>
|
||||
<div id='kanbans' class='kanban'></div>
|
||||
</div>
|
||||
</div>
|
||||
<?php endif;?>
|
||||
<div class="modal fade" id="linkStoryByPlan">
|
||||
<div class="modal-dialog mw-500px">
|
||||
<div class="modal-content">
|
||||
@@ -124,52 +210,4 @@
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<?php js::set('executionID', $executionID);?>
|
||||
<?php js::set('productID', $productID);?>
|
||||
<?php js::set('kanbanGroup', $kanbanGroup);?>
|
||||
<?php js::set('kanbanList', array_keys($kanbanGroup));?>
|
||||
<?php js::set('browseType', $browseType);?>
|
||||
<?php js::set('groupBy', $groupBy);?>
|
||||
<?php
|
||||
js::set('priv',
|
||||
array(
|
||||
'canEditName' => common::hasPriv('kanban', 'setColumn'),
|
||||
'canSetWIP' => common::hasPriv('kanban', 'setWIP'),
|
||||
'canSetLane' => common::hasPriv('kanban', 'setLane'),
|
||||
'canMoveLane' => common::hasPriv('kanban', 'laneMove'),
|
||||
'canSortCards' => common::hasPriv('kanban', 'cardsSort'),
|
||||
'canCreateTask' => $canCreateTask,
|
||||
'canBatchCreateTask' => $canBatchCreateTask,
|
||||
'canCreateBug' => $canCreateBug,
|
||||
'canBatchCreateBug' => $canBatchCreateBug,
|
||||
'canCreateStory' => $canCreateStory,
|
||||
'canBatchCreateStory' => $canBatchCreateStory,
|
||||
'canLinkStory' => $canLinkStory,
|
||||
'canLinkStoryByPlane' => $canLinkStoryByPlane,
|
||||
'canAssignTask' => common::hasPriv('task', 'assignto'),
|
||||
'canAssignStory' => common::hasPriv('story', 'assignto'),
|
||||
'canFinishTask' => common::hasPriv('task', 'finish'),
|
||||
'canPauseTask' => common::hasPriv('task', 'pause'),
|
||||
'canCancelTask' => common::hasPriv('task', 'cancel'),
|
||||
'canCloseTask' => common::hasPriv('task', 'close'),
|
||||
'canActivateTask' => common::hasPriv('task', 'activate'),
|
||||
'canStartTask' => common::hasPriv('task', 'start'),
|
||||
'canAssignBug' => common::hasPriv('bug', 'assignto'),
|
||||
'canConfirmBug' => common::hasPriv('bug', 'confirmBug'),
|
||||
'canActivateBug' => common::hasPriv('bug', 'activate')
|
||||
)
|
||||
);
|
||||
?>
|
||||
<?php js::set('executionLang', $lang->execution);?>
|
||||
<?php js::set('storyLang', $lang->story);?>
|
||||
<?php js::set('taskLang', $lang->task);?>
|
||||
<?php js::set('bugLang', $lang->bug);?>
|
||||
<?php js::set('editName', $lang->execution->editName);?>
|
||||
<?php js::set('setWIP', $lang->execution->setWIP);?>
|
||||
<?php js::set('sortColumn', $lang->execution->sortColumn);?>
|
||||
<?php js::set('kanbanLang', $lang->kanban);?>
|
||||
<?php js::set('deadlineLang', $lang->task->deadlineAB);?>
|
||||
<?php js::set('noAssigned', $lang->task->noAssigned);?>
|
||||
<?php js::set('userList', $userList);?>
|
||||
<?php js::set('entertime', time());?>
|
||||
<?php include '../../common/view/footer.html.php';?>
|
||||
|
||||
@@ -58,7 +58,7 @@
|
||||
}
|
||||
}
|
||||
|
||||
echo "<li id='kanbanTab'>"; common::printLink('execution', 'kanban', "executionID=$executionID", $lang->execution->kanban); echo '</li>';
|
||||
echo "<li id='kanbanTab'>"; common::printLink('execution', 'taskKanban', "executionID=$executionID", $lang->execution->kanban); echo '</li>';
|
||||
if($execution->type == 'sprint' or $execution->type == 'waterfall')
|
||||
{
|
||||
echo "<li id='burnTab'>";
|
||||
|
||||
@@ -0,0 +1,181 @@
|
||||
<?php
|
||||
/**
|
||||
* The task kanban view file of execution module of ZenTaoPMS.
|
||||
*
|
||||
* @copyright Copyright 2009-2012 青岛易软天创网络科技有限公司 (QingDao Nature Easy Soft Network Technology Co,LTD www.cnezsoft.com)
|
||||
* @author Wang Yidong, Zhu Jinyong
|
||||
* @package execution
|
||||
* @version $Id: taskkanban.html.php $
|
||||
*/
|
||||
?>
|
||||
<?php include '../../common/view/header.html.php';?>
|
||||
<?php include '../../common/view/kanban.html.php';?>
|
||||
<div id='mainMenu' class='clearfix'>
|
||||
<div class='btn-toolbar pull-left'>
|
||||
<div class="input-control space c-type">
|
||||
<?php echo html::select('type', $lang->kanban->type, $browseType, 'class="form-control chosen" data-max_drop_width="215"');?>
|
||||
</div>
|
||||
<?php if($browseType != 'all'):?>
|
||||
<div class="input-control space c-group">
|
||||
<?php echo html::select('group', $lang->kanban->group->$browseType, $groupBy, 'class="form-control chosen" data-max_drop_width="215"');?>
|
||||
</div>
|
||||
<?php endif;?>
|
||||
</div>
|
||||
<div class='input-group pull-left not-fix-input-group' id='kanbanScaleControl'>
|
||||
<span class='input-group-btn'>
|
||||
<button class='btn btn-icon' type='button' data-type='-'><i class='icon icon-minuse-solid-circle text-muted'></i></button>
|
||||
</span>
|
||||
<span class='input-group-addon'>
|
||||
<span id='kanbanScaleSize'>1</span><?php echo $lang->execution->kanbanCardsUnit; ?>
|
||||
</span>
|
||||
<span class='input-group-btn'>
|
||||
<button class='btn btn-icon' type='button' data-type='+'><i class='icon icon-plus-solid-circle text-muted'></i></button>
|
||||
</span>
|
||||
</div>
|
||||
<div class='btn-toolbar pull-right'>
|
||||
<?php
|
||||
$link = $this->createLink('task', 'export', "execution=$executionID&orderBy=$orderBy&type=kanban");
|
||||
if(common::hasPriv('task', 'export')) echo html::a($link, "<i class='icon-export muted'></i> " . $lang->export, '', "class='btn btn-link iframe export' data-width='700'");
|
||||
?>
|
||||
<?php if($canBeChanged):?>
|
||||
<div class='btn-group' style="margin-right: 0">
|
||||
<button type='button' class='btn btn-link dropdown-toggle' data-toggle='dropdown' id='importAction'>
|
||||
<i class='icon-import muted'></i> <?php echo $lang->import ?>
|
||||
<span class='caret'></span>
|
||||
</button>
|
||||
<ul class='dropdown-menu' id='importActionMenu'>
|
||||
<?php
|
||||
$misc = common::hasPriv('execution', 'importTask') ? '' : "class=disabled";
|
||||
$link = common::hasPriv('execution', 'importTask') ? $this->createLink('execution', 'importTask', "execution=$execution->id") : '#';
|
||||
echo "<li $misc>" . html::a($link, $lang->execution->importTask, '', $misc) . "</li>";
|
||||
|
||||
$misc = common::hasPriv('execution', 'importBug') ? '' : "class=disabled";
|
||||
$link = common::hasPriv('execution', 'importBug') ? $this->createLink('execution', 'importBug', "execution=$execution->id") : '#';
|
||||
echo "<li $misc>" . html::a($link, $lang->execution->importBug, '', $misc) . "</li>";
|
||||
?>
|
||||
</ul>
|
||||
</div>
|
||||
|
||||
<?php
|
||||
echo "<div class='btn-group menu-actions'>";
|
||||
echo html::a('javascript:;', "<i class='icon icon-ellipsis-v'></i>", '', "data-toggle='dropdown' class='btn btn-link'");
|
||||
echo "<ul class='dropdown-menu pull-right'>";
|
||||
if(common::hasPriv('kanban', 'setLaneHeight'))
|
||||
{
|
||||
$width = $this->app->getClientLang() == 'en' ? '70%' : '60%';
|
||||
echo '<li>' .html::a($this->createLink('kanban', 'setLaneHeight', "executionID=$executionID&from=execution", '', true), "<i class='icon-size-height'></i> " . $lang->kanban->laneHeight, '', "class='iframe btn btn-link' title='{$lang->kanban->laneHeight}' data-width=$width") . '</li>';
|
||||
}
|
||||
if(common::hasPriv('execution', 'printKanban')) echo '<li>' .html::a($this->createLink('execution', 'printKanban', "executionID=$executionID"), "<i class='icon-printer muted'></i> " . $lang->execution->printKanban, '', "class='iframe btn btn-link' id='printKanban' title='{$lang->execution->printKanban}' data-width='500'") . '</li>';
|
||||
echo '<li>' .html::a('javascript:fullScreen()', "<i class='icon-fullscreen muted'></i> " . $lang->execution->fullScreen, '', "class='btn btn-link' title='{$lang->execution->fullScreen}' data-width='500'") . '</li>';
|
||||
echo '</ul></div>';
|
||||
?>
|
||||
<?php
|
||||
$checkObject = new stdclass();
|
||||
$checkObject->execution = $executionID;
|
||||
$canCreateTask = common::hasPriv('task', 'create', $checkObject);
|
||||
$canBatchCreateTask = common::hasPriv('task', 'batchCreate', $checkObject);
|
||||
$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);
|
||||
?>
|
||||
<?php if($canCreateTask or $canBatchCreateTask or $canCreateBug or $canBatchCreateBug or $canCreateStory or $canBatchCreateStory or $canLinkStory or $canLinkStoryByPlane):?>
|
||||
<div class='dropdown' id='createDropdown'>
|
||||
<button class='btn btn-primary' type='button' data-toggle='dropdown'><i class='icon icon-plus'></i> <?php echo $this->lang->create;?> <span class='caret'></span></button>
|
||||
<ul class='dropdown-menu pull-right'>
|
||||
<?php if($canCreateStory) echo '<li>' . html::a(helper::createLink('story', 'create', "productID=$productID&branch=0&moduleID=0&story=0&execution=$execution->id", '', true), $lang->execution->createStory, '', "class='iframe'") . '</li>';?>
|
||||
<?php if($canBatchCreateStory) echo '<li>' . html::a(helper::createLink('story', 'batchCreate', "productID=$productID&branch=0&moduleID=0&story=0&execution=$execution->id", '', true), $lang->execution->batchCreateStroy, '', "class='iframe' data-width='90%'") . '</li>';?>
|
||||
<?php if($canLinkStory) echo '<li>' . html::a(helper::createLink('execution', 'linkStory', "execution=$execution->id", '', true), $lang->execution->linkStory, '', "class='iframe' data-width='90%'") . '</li>';?>
|
||||
<?php if($canLinkStoryByPlane) echo '<li>' . html::a('#linkStoryByPlan', $lang->execution->linkStoryByPlan, '', 'data-toggle="modal"') . '</li>';?>
|
||||
<?php if($hasStoryButton and $hasBugButton) echo '<li class="divider"></li>';?>
|
||||
<?php if($canCreateBug) echo '<li>' . html::a(helper::createLink('bug', 'create', "productID=$productID&branch=0&extra=executionID=$execution->id", '', true), $lang->bug->create, '', "class='iframe'") . '</li>';?>
|
||||
<?php if($canBatchCreateBug) echo '<li>' . html::a(helper::createLink('bug', 'batchCreate', "productID=$productID&branch=0&executionID=$execution->id", '', true), $lang->bug->batchCreate, '', "class='iframe'") . '</li>';?>
|
||||
<?php if(($hasStoryButton or $hasBugButton) and $hasTaskButton) echo '<li class="divider"></li>';?>
|
||||
<?php if($canCreateTask) echo '<li>' . html::a(helper::createLink('task', 'create', "execution=$execution->id", '', true), $lang->task->create, '', "class='iframe'") . '</li>';?>
|
||||
<?php if($canBatchCreateTask) echo '<li>' . html::a(helper::createLink('task', 'batchCreate', "execution=$execution->id", '', true), $lang->execution->batchCreateTask, '', "class='iframe'") . '</li>';?>
|
||||
</ul>
|
||||
</div>
|
||||
<?php endif;?>
|
||||
<?php else:?>
|
||||
<?php $canCreateTask = $canBatchCreateTask = $canCreateBug = $canBatchCreateBug = $canCreateStory = $canBatchCreateStory = $canLinkStory = $canLinkStoryByPlane = false;?>
|
||||
<?php endif;?>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class='panel' id='kanbanContainer'>
|
||||
<div class='panel-body'>
|
||||
<div id='kanbans'></div>
|
||||
</div>
|
||||
</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 js::set('executionID', $executionID);?>
|
||||
<?php js::set('productID', $productID);?>
|
||||
<?php js::set('kanbanGroup', $kanbanGroup);?>
|
||||
<?php js::set('kanbanList', array_keys($kanbanGroup));?>
|
||||
<?php js::set('browseType', $browseType);?>
|
||||
<?php js::set('groupBy', $groupBy);?>
|
||||
<?php
|
||||
js::set('priv',
|
||||
array(
|
||||
'canEditName' => common::hasPriv('kanban', 'setColumn'),
|
||||
'canSetWIP' => common::hasPriv('kanban', 'setWIP'),
|
||||
'canSetLane' => common::hasPriv('kanban', 'setLane'),
|
||||
'canMoveLane' => common::hasPriv('kanban', 'laneMove'),
|
||||
'canSortCards' => common::hasPriv('kanban', 'cardsSort'),
|
||||
'canCreateTask' => $canCreateTask,
|
||||
'canBatchCreateTask' => $canBatchCreateTask,
|
||||
'canCreateBug' => $canCreateBug,
|
||||
'canBatchCreateBug' => $canBatchCreateBug,
|
||||
'canCreateStory' => $canCreateStory,
|
||||
'canBatchCreateStory' => $canBatchCreateStory,
|
||||
'canLinkStory' => $canLinkStory,
|
||||
'canLinkStoryByPlane' => $canLinkStoryByPlane,
|
||||
'canAssignTask' => common::hasPriv('task', 'assignto'),
|
||||
'canAssignStory' => common::hasPriv('story', 'assignto'),
|
||||
'canFinishTask' => common::hasPriv('task', 'finish'),
|
||||
'canPauseTask' => common::hasPriv('task', 'pause'),
|
||||
'canCancelTask' => common::hasPriv('task', 'cancel'),
|
||||
'canCloseTask' => common::hasPriv('task', 'close'),
|
||||
'canActivateTask' => common::hasPriv('task', 'activate'),
|
||||
'canStartTask' => common::hasPriv('task', 'start'),
|
||||
'canAssignBug' => common::hasPriv('bug', 'assignto'),
|
||||
'canConfirmBug' => common::hasPriv('bug', 'confirmBug'),
|
||||
'canActivateBug' => common::hasPriv('bug', 'activate')
|
||||
)
|
||||
);
|
||||
?>
|
||||
<?php js::set('executionLang', $lang->execution);?>
|
||||
<?php js::set('storyLang', $lang->story);?>
|
||||
<?php js::set('taskLang', $lang->task);?>
|
||||
<?php js::set('bugLang', $lang->bug);?>
|
||||
<?php js::set('editName', $lang->execution->editName);?>
|
||||
<?php js::set('setWIP', $lang->execution->setWIP);?>
|
||||
<?php js::set('sortColumn', $lang->execution->sortColumn);?>
|
||||
<?php js::set('kanbanLang', $lang->kanban);?>
|
||||
<?php js::set('deadlineLang', $lang->task->deadlineAB);?>
|
||||
<?php js::set('noAssigned', $lang->task->noAssigned);?>
|
||||
<?php js::set('userList', $userList);?>
|
||||
<?php js::set('entertime', time());?>
|
||||
<?php js::set('displayCards', $execution->displayCards);?>
|
||||
<?php include '../../common/view/footer.html.php';?>
|
||||
@@ -674,6 +674,7 @@ $lang->resource->kanban->cardsSort = 'cardsSort';
|
||||
$lang->resource->kanban->viewArchivedColumn = 'viewArchivedColumn';
|
||||
$lang->resource->kanban->viewArchivedCard = 'viewArchivedCard';
|
||||
$lang->resource->kanban->restoreCard = 'restoreCard';
|
||||
$lang->resource->kanban->setLaneHeight = 'setLaneHeight';
|
||||
|
||||
$lang->kanban->methodOrder[5] = 'space';
|
||||
$lang->kanban->methodOrder[10] = 'createSpace';
|
||||
@@ -718,6 +719,7 @@ $lang->kanban->methodOrder[195] = 'viewArchivedColumn';
|
||||
$lang->kanban->methodorder[200] = 'viewArchivedCard';
|
||||
$lang->kanban->methodorder[205] = 'archiveColumn';
|
||||
$lang->kanban->methodorder[210] = 'restoreCard';
|
||||
$lang->kanban->methodorder[215] = 'setLaneHeight';
|
||||
|
||||
/* Execution. */
|
||||
$lang->resource->execution = new stdclass();
|
||||
@@ -759,7 +761,7 @@ $lang->resource->execution->linkStory = 'linkStory';
|
||||
$lang->resource->execution->unlinkStory = 'unlinkStory';
|
||||
$lang->resource->execution->batchUnlinkStory = 'batchUnlinkStory';
|
||||
$lang->resource->execution->updateOrder = 'updateOrder';
|
||||
$lang->resource->execution->kanban = 'kanban';
|
||||
$lang->resource->execution->taskKanban = 'taskKanban';
|
||||
$lang->resource->execution->printKanban = 'printKanbanAction';
|
||||
$lang->resource->execution->tree = 'treeAction';
|
||||
$lang->resource->execution->treeTask = 'treeOnlyTask';
|
||||
@@ -775,6 +777,7 @@ $lang->resource->execution->addWhitelist = 'addWhitelist';
|
||||
$lang->resource->execution->unbindWhitelist = 'unbindWhitelist';
|
||||
$lang->resource->execution->storyEstimate = 'storyEstimate';
|
||||
$lang->resource->execution->executionkanban = 'kanbanAction';
|
||||
$lang->resource->execution->kanban = 'RDKanban';
|
||||
//if($config->systemMode == 'classic') $lang->resource->project->list = 'list';
|
||||
|
||||
//$lang->execution->methodOrder[0] = 'index';
|
||||
@@ -816,7 +819,7 @@ $lang->execution->methodOrder[170] = 'linkStory';
|
||||
$lang->execution->methodOrder[175] = 'unlinkStory';
|
||||
$lang->execution->methodOrder[180] = 'batchUnlinkStory';
|
||||
$lang->execution->methodOrder[185] = 'updateOrder';
|
||||
$lang->execution->methodOrder[190] = 'kanban';
|
||||
$lang->execution->methodOrder[190] = 'taskKanban';
|
||||
$lang->execution->methodOrder[195] = 'printKanban';
|
||||
$lang->execution->methodOrder[200] = 'kanbanHideCols';
|
||||
$lang->execution->methodOrder[205] = 'kanbanColsColor';
|
||||
@@ -832,6 +835,7 @@ $lang->execution->methodOrder[250] = 'addWhitelist';
|
||||
$lang->execution->methodOrder[255] = 'unbindWhitelist';
|
||||
$lang->execution->methodOrder[260] = 'storyEstimate';
|
||||
$lang->execution->methodOrder[265] = 'executionkanban';
|
||||
$lang->execution->methodOrder[270] = 'kanban';
|
||||
|
||||
/* Task. */
|
||||
$lang->resource->task = new stdclass();
|
||||
|
||||
@@ -814,7 +814,7 @@ $(function()
|
||||
event.stopPropagation();
|
||||
});
|
||||
|
||||
$("#proLink").click(function(event)
|
||||
$("#bizLink").click(function(event)
|
||||
{
|
||||
var $upgradeContent = $('#upgradeContent').toggle();
|
||||
if(!$upgradeContent.is(':hidden'))
|
||||
|
||||
@@ -77,7 +77,7 @@ js::set('showFeatures', $showFeatures);
|
||||
<ul id='bars' class='nav nav-default'></ul>
|
||||
<div id='poweredBy'>
|
||||
<div id="globalBarLogo">
|
||||
<a href='javascript:void(0)' id='proLink' class='btn btn-link' style='color: #B57D4F;'><span class='upgrade'><?php echo $lang->proName;?></span> <i class='text-danger icon-pro-version'></i></a>
|
||||
<a href='javascript:void(0)' id='bizLink' class='btn btn-link' style='color: #B57D4F;'><span class='upgrade'><?php echo $lang->bizName;?></span> <i class='text-danger icon-pro-version'></i></a>
|
||||
<a href='<?php echo $lang->website;?>' class="btn btn-sm btn-link" target='_blank' title='<?php echo $config->version;?>'>
|
||||
<i class="icon icon-zentao" style="font-size: 24px;"></i>
|
||||
<span class='version'><?php echo $lang->pmsName . $config->version;?></span>
|
||||
|
||||
@@ -38,6 +38,7 @@
|
||||
<?php endif;?>
|
||||
</td>
|
||||
</tr>
|
||||
<!--
|
||||
<tr>
|
||||
<td colspan='2'>
|
||||
<h5><?php echo $lang->install->promotion?></h5>
|
||||
@@ -56,6 +57,7 @@
|
||||
</div>
|
||||
</td>
|
||||
</tr>
|
||||
-->
|
||||
</table>
|
||||
</div>
|
||||
<div class='modal-footer'>
|
||||
|
||||
+97
-20
@@ -294,18 +294,19 @@ class kanban extends control
|
||||
* Create a region.
|
||||
*
|
||||
* @param int $kanbanID
|
||||
* @param string $from kanban|execution
|
||||
* @access public
|
||||
* @return void
|
||||
*/
|
||||
public function createRegion($kanbanID)
|
||||
public function createRegion($kanbanID, $from = 'kanban')
|
||||
{
|
||||
if(!empty($_POST))
|
||||
{
|
||||
$kanban = $this->kanban->getByID($kanbanID);
|
||||
$kanban = $from == 'execution' ? $this->loadModel('execution')->getByID($kanbanID) : $this->kanban->getByID($kanbanID);
|
||||
$copyRegionID = (int)$_POST['region'];
|
||||
unset($_POST['region']);
|
||||
|
||||
$regionID = $this->kanban->createRegion($kanban, '', $copyRegionID);
|
||||
$regionID = $this->kanban->createRegion($kanban, '', $copyRegionID, $from);
|
||||
|
||||
if(dao::isError()) return $this->send(array('result' => 'fail', 'message' => dao::getError()));
|
||||
return $this->send(array('result' => 'success', 'message' => $this->lang->saveSuccess, 'locate' => 'parent'));
|
||||
@@ -417,10 +418,11 @@ class kanban extends control
|
||||
*
|
||||
* @param int $kanbanID
|
||||
* @param int $regionID
|
||||
* @param string $from kanban|execution
|
||||
* @access public
|
||||
* @return void
|
||||
*/
|
||||
public function createLane($kanbanID, $regionID)
|
||||
public function createLane($kanbanID, $regionID, $from = 'kanban')
|
||||
{
|
||||
if(!empty($_POST))
|
||||
{
|
||||
@@ -431,8 +433,12 @@ class kanban extends control
|
||||
return $this->send(array('result' => 'success', 'message' => $this->lang->saveSuccess, 'locate' => 'parent'));
|
||||
}
|
||||
|
||||
$this->view->lanes = $this->kanban->getLanePairsByRegion($regionID);
|
||||
$this->display();
|
||||
$this->view->lanes = $this->kanban->getLanePairsByRegion($regionID, $from == 'kanban' ? 'all' : 'story');
|
||||
$this->view->from = $from;
|
||||
$this->view->regionID = $regionID;
|
||||
|
||||
if($from == 'kanban') $this->display();
|
||||
if($from == 'execution') $this->display('kanban', 'createexeclane');
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -458,6 +464,34 @@ class kanban extends control
|
||||
return $this->send(array('result' => 'success', 'message' => $this->lang->saveSuccess));
|
||||
}
|
||||
|
||||
/**
|
||||
* Set lane height.
|
||||
*
|
||||
* @param int $kanbanID
|
||||
* @param string $from kanban|execution
|
||||
* @access public
|
||||
* @return void
|
||||
*/
|
||||
public function setLaneHeight($kanbanID, $from = 'kanban')
|
||||
{
|
||||
if(!empty($_POST))
|
||||
{
|
||||
$this->kanban->setLaneHeight($kanbanID, $from);
|
||||
|
||||
if(dao::isError()) return $this->send(array('result' => 'fail', 'message' => dao::getError()));
|
||||
|
||||
return $this->send(array('result' => 'success', 'message' => $this->lang->saveSuccess, 'locate' => 'parent'));
|
||||
|
||||
}
|
||||
|
||||
$kanban = $from == 'execution' ? $this->loadModel('execution')->getByID($kanbanID) : $this->kanban->getByID($kanbanID);
|
||||
|
||||
$this->view->heightType = $kanban->displayCards > 2 ? 'custom' : 'auto';
|
||||
$this->view->displayCards = $kanban->displayCards ? $kanban->displayCards : '';
|
||||
|
||||
$this->display();
|
||||
}
|
||||
|
||||
/**
|
||||
* Delete a lane.
|
||||
*
|
||||
@@ -470,7 +504,10 @@ class kanban extends control
|
||||
{
|
||||
if($confirm == 'no')
|
||||
{
|
||||
die(js::confirm($this->lang->kanbanlane->confirmDelete, $this->createLink('kanban', 'deleteLane', "laneID=$laneID&confirm=yes"), ''));
|
||||
$laneType = $this->kanban->getLaneById($laneID)->type;
|
||||
$confirmTip = in_array($laneType, array('story', 'task', 'bug')) ? sprintf($this->lang->kanbanlane->confirmDeleteTip, $this->lang->{$laneType}->common) : $this->lang->kanbanlane->confirmDelete;
|
||||
|
||||
die(js::confirm($confirmTip, $this->createLink('kanban', 'deleteLane', "laneID=$laneID&confirm=yes"), ''));
|
||||
}
|
||||
else
|
||||
{
|
||||
@@ -710,15 +747,17 @@ class kanban extends control
|
||||
* Move a card.
|
||||
*
|
||||
* @param int $cardID
|
||||
* @param int $fromColID
|
||||
* @param int $toColID
|
||||
* @param int $fromLaneID
|
||||
* @param int $toLaneID
|
||||
* @param int $kanbanID
|
||||
* @access public
|
||||
* @return void
|
||||
*/
|
||||
public function moveCard($cardID, $toColID, $toLaneID, $kanbanID)
|
||||
public function moveCard($cardID, $fromColID, $toColID, $fromLaneID, $toLaneID, $kanbanID)
|
||||
{
|
||||
$this->kanban->moveCard($cardID, $toColID, $toLaneID);
|
||||
$this->kanban->moveCard($cardID, $fromColID, $toColID, $fromLaneID, $toLaneID);
|
||||
if(dao::isError()) return $this->send(array('result' => 'fail', 'message' => dao::getError()));
|
||||
$kanbanGroup = $this->kanban->getKanbanData($kanbanID);
|
||||
die(json_encode($kanbanGroup));
|
||||
@@ -992,26 +1031,48 @@ class kanban extends control
|
||||
*
|
||||
* @param int $cardID
|
||||
* @param int $fromColID
|
||||
* @param string $toColType
|
||||
* @param int $toColID
|
||||
* @param int $fromLaneID
|
||||
* @param int $toLaneID
|
||||
* @param int $executionID
|
||||
* @param string $browseType
|
||||
* @param string $browseType
|
||||
* @param string $groupBy
|
||||
* @param int $regionID
|
||||
* @param string $orderBy
|
||||
* @access public
|
||||
* @return json
|
||||
* @return void
|
||||
*/
|
||||
public function ajaxMoveCard($cardID = 0, $fromColID = 0, $toColType = 'ready', $executionID = 0, $browseType = 'all', $groupBy = '')
|
||||
public function ajaxMoveCard($cardID = 0, $fromColID = 0, $toColID = 0, $fromLaneID = 0, $toLaneID = 0, $executionID = 0, $browseType = 'all', $groupBy = '', $regionID = 0, $orderBy = '')
|
||||
{
|
||||
$fromColumn = $this->dao->select('*')->from(TABLE_KANBANCOLUMN)->where('id')->eq($fromColID)->fetch();
|
||||
$toColumn = $this->dao->select('*')->from(TABLE_KANBANCOLUMN)->where('type')->eq($toColType)->andWhere('lane')->eq($fromColumn->lane)->fetch();
|
||||
$fromCell = $this->dao->select('id, cards')->from(TABLE_KANBANCELL)
|
||||
->where('kanban')->eq($executionID)
|
||||
->andWhere('lane')->eq($fromLaneID)
|
||||
->andWhere('`column`')->eq($fromColID)
|
||||
->fetch();
|
||||
|
||||
$fromCards = str_replace(",$cardID,", ',', $fromColumn->cards);
|
||||
$toCell = $this->dao->select('id, cards')->from(TABLE_KANBANCELL)
|
||||
->where('kanban')->eq($executionID)
|
||||
->andWhere('lane')->eq($toLaneID)
|
||||
->andWhere('`column`')->eq($toColID)
|
||||
->fetch();
|
||||
|
||||
$fromCards = str_replace(",$cardID,", ',', $fromCell->cards);
|
||||
$fromCards = $fromCards == ',' ? '' : $fromCards;
|
||||
$toCards = ",$cardID," . ltrim($toColumn->cards, ',');
|
||||
$toCards = ",$cardID," . ltrim($toCell->cards, ',');
|
||||
|
||||
$this->dao->update(TABLE_KANBANCOLUMN)->set('cards')->eq($fromCards)->where('id')->eq($fromColumn->id)->exec();
|
||||
$this->dao->update(TABLE_KANBANCOLUMN)->set('cards')->eq($toCards)->where('id')->eq($toColumn->id)->exec();
|
||||
$this->dao->update(TABLE_KANBANCELL)->set('cards')->eq($fromCards)
|
||||
->where('kanban')->eq($executionID)
|
||||
->andWhere('lane')->eq($fromLaneID)
|
||||
->andWhere('`column`')->eq($fromColID)
|
||||
->exec();
|
||||
|
||||
$kanbanGroup = $this->kanban->getExecutionKanban($executionID, $browseType, $groupBy);
|
||||
$this->dao->update(TABLE_KANBANCELL)->set('cards')->eq($toCards)
|
||||
->where('kanban')->eq($executionID)
|
||||
->andWhere('lane')->eq($toLaneID)
|
||||
->andWhere('`column`')->eq($toColID)
|
||||
->exec();
|
||||
|
||||
$kanbanGroup = $regionID == 0 ? $this->kanban->getExecutionKanban($executionID, $browseType, $groupBy) : $this->kanban->getRDKanban($executionID, $browseType, $orderBy, $regionID, $groupBy);
|
||||
die(json_encode($kanbanGroup));
|
||||
}
|
||||
|
||||
@@ -1084,4 +1145,20 @@ class kanban extends control
|
||||
$this->view->method = $methodName;
|
||||
$this->display();
|
||||
}
|
||||
|
||||
/**
|
||||
* Ajax get lanes by region id.
|
||||
*
|
||||
* @param int $regionID
|
||||
* @param string $type all|story|task|bug
|
||||
* @access public
|
||||
* @return string
|
||||
*/
|
||||
public function ajaxGetLanes($regionID, $type = 'all')
|
||||
{
|
||||
$lanes = $this->kanban->getLanePairsByRegion($regionID, $type);
|
||||
|
||||
if(empty($lanes)) return;
|
||||
return print(html::select('otherLane', $lanes, '', "class='form-control'"));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -58,8 +58,9 @@
|
||||
.region .kanban-lane-items {overflow: auto; padding-bottom: 10px;}
|
||||
|
||||
.region .kanban-item {position: relative}
|
||||
.region .kanban-item > .kanban-card > .title {line-height: 18px;}
|
||||
.region .kanban-item > .kanban-card > .title:hover {color: #2272eb}
|
||||
.region .kanban-item > .kanban-card > .info {margin-top: 5px; position: relative;}
|
||||
.region .kanban-item > .kanban-card > .info {margin-top: 4px; position: relative;}
|
||||
.region .kanban-item > .kanban-card > .info > .pri {height: 14px; border-width: 1px; font-size: 12px; line-height: 12px; min-width: 14px; padding: 0 1px;}
|
||||
.region .kanban-item > .kanban-card > .info > .estimate{margin-left: 4px; color: #999; background-color: rgb(255, 255, 255); padding: 3px 0px}
|
||||
.region .kanban-item > .kanban-card > .info > .time {margin-left: 4px; font-size: 12px; background: rgb(242, 242, 242)}
|
||||
@@ -82,7 +83,7 @@
|
||||
.region .kanban-item .has-color .info > .label-pri {border-color: #FFFFFF;}
|
||||
.region .kanban-item .item-more {position: absolute; right: 6px; top: 0px;}
|
||||
|
||||
.kanban-card {height: auto !important; padding: 8px 14px !important}
|
||||
.kanban-card {height: auto !important; padding: 8px 14px !important; min-height: 60px;}
|
||||
.kanban-card > .title {word-break: break-all;}
|
||||
.kanban-card > .info {position: relative; margin-top: 5px}
|
||||
.kanban-card > .info > .info + .info {margin-left: 8px}
|
||||
|
||||
@@ -7,4 +7,3 @@ $(document).ready(function()
|
||||
$('#otherLane').parents('tr').toggle($(this).val() == 'sameAsOther');
|
||||
});
|
||||
})
|
||||
|
||||
|
||||
@@ -0,0 +1,17 @@
|
||||
/**
|
||||
* Set card count.
|
||||
*
|
||||
* @param string $heightType
|
||||
* @access public
|
||||
* @return void
|
||||
*/
|
||||
function setCardCount(heightType)
|
||||
{
|
||||
heightType != 'custom' ? $('#cardBox').addClass('hidden') : $('#cardBox').removeClass('hidden');
|
||||
}
|
||||
|
||||
$(function()
|
||||
{
|
||||
var heightType = $("[name='heightType']:checked").val();
|
||||
setCardCount(heightType);
|
||||
})
|
||||
@@ -374,16 +374,19 @@ function showErrorMessager(message)
|
||||
* Move a card.
|
||||
*
|
||||
* @param int $cardID
|
||||
* @param int $fromColID
|
||||
* @param int $toColID
|
||||
* @param int $fromLaneID
|
||||
* @param int $toLaneID
|
||||
* @param int $kanbanID
|
||||
* @param int $regionID
|
||||
* @access public
|
||||
* @return string
|
||||
*/
|
||||
function moveCard(cardID, toColID, toLaneID, kanbanID, regionID)
|
||||
function moveCard(cardID, fromColID, toColID, fromLaneID, toLaneID, kanbanID, regionID)
|
||||
{
|
||||
if(!cardID) return false;
|
||||
var url = createLink('kanban', 'moveCard', 'cardID=' + cardID + '&toColID=' + toColID + '&toLaneID=' + toLaneID + '&kanbanID=' + kanbanID);
|
||||
var url = createLink('kanban', 'moveCard', 'cardID=' + cardID + '&fromColID='+ fromColID + '&toColID=' + toColID + '&fromLaneID='+ fromLaneID + '&toLaneID=' + toLaneID + '&kanbanID=' + kanbanID);
|
||||
return $.ajax(
|
||||
{
|
||||
method: 'post',
|
||||
@@ -460,6 +463,7 @@ function updateRegion(regionID, regionData = [])
|
||||
if(!regionData) regionData = regions[regionID];
|
||||
|
||||
$region.data('zui.kanban').render(regionData.groups);
|
||||
resetRegionHeight('open');
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -586,7 +590,7 @@ function handleDropTask($element, event, kanban)
|
||||
if(oldCol.id === newCol.id && newLane.id === oldLane.id) return false;
|
||||
|
||||
var cardID = $card.data().id;
|
||||
moveCard(cardID, newCol.id, newLane.id, kanbanID, regionID);
|
||||
moveCard(cardID, oldCol.id, newCol.id, oldLane.id, newLane.id, kanbanID, regionID);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -762,6 +766,20 @@ function createColumnMenu(options)
|
||||
return items;
|
||||
}
|
||||
|
||||
/** Calculate column height */
|
||||
function calcColHeight(col, lane, colCards, colHeight, kanban)
|
||||
{
|
||||
if(!isMultiLanes) return 0;
|
||||
|
||||
var options = kanban.options;
|
||||
|
||||
if(!options.displayCards) return 0;
|
||||
var displayCards = +(options.displayCards || 2);
|
||||
|
||||
if (typeof displayCards !== 'number' || displayCards < 2) displayCards = 2;
|
||||
return (displayCards * (options.cardHeight + options.cardSpace) + options.cardSpace);
|
||||
}
|
||||
|
||||
/* Define menu creators */
|
||||
window.menuCreators =
|
||||
{
|
||||
@@ -775,16 +793,20 @@ window.menuCreators =
|
||||
*/
|
||||
function initKanban($kanban)
|
||||
{
|
||||
var id = $kanban.data('id');
|
||||
var region = regions[id];
|
||||
var id = $kanban.data('id');
|
||||
var region = regions[id];
|
||||
var displayCards = window.displayCards == 'undefined' ? 2 : window.displayCards;
|
||||
|
||||
$kanban.kanban(
|
||||
{
|
||||
data: region.groups,
|
||||
maxColHeight: 510,
|
||||
calcColHeight: calcColHeight,
|
||||
fluidBoardWidth: false,
|
||||
minColWidth: 300,
|
||||
maxColWidth: 300,
|
||||
minColWidth: 285,
|
||||
maxColWidth: 285,
|
||||
cardHeight: 60,
|
||||
displayCards: displayCards,
|
||||
createColumnText: kanbanLang.createColumn,
|
||||
addItemText: '',
|
||||
itemRender: renderKanbanItem,
|
||||
@@ -813,7 +835,7 @@ function initKanban($kanban)
|
||||
*/
|
||||
$(function()
|
||||
{
|
||||
if($.cookie('isFullScreen') == 1) fullScreen();
|
||||
window.isMultiLanes = laneCount > 1;
|
||||
|
||||
/* Init first kanban */
|
||||
$('.kanban').each(function()
|
||||
@@ -826,6 +848,7 @@ $(function()
|
||||
$(this).toggleClass('icon-chevron-double-up icon-chevron-double-down');
|
||||
$(this).parents('.region').find('.kanban').toggle();
|
||||
hideKanbanAction();
|
||||
resetRegionHeight($(this).hasClass('icon-chevron-double-up') ? 'open' : 'close');
|
||||
});
|
||||
|
||||
$('.region-header').on('click', '.action', hideKanbanAction);
|
||||
@@ -1012,4 +1035,65 @@ $(function()
|
||||
if(sortType == 'lane') $cards.show();
|
||||
}
|
||||
});
|
||||
|
||||
resetRegionHeight('open');
|
||||
});
|
||||
|
||||
/**
|
||||
* Reset region height according to window height.
|
||||
*
|
||||
* @param string fold
|
||||
* @access public
|
||||
* @return void
|
||||
*/
|
||||
function resetRegionHeight(fold)
|
||||
{
|
||||
var regionCount = 0;
|
||||
if($.isEmptyObject(regions)) return false;
|
||||
for(var i in regions)
|
||||
{
|
||||
regionCount += 1;
|
||||
if(regionCount > 1) return false;
|
||||
}
|
||||
|
||||
var regionID = Object.keys(regions)[0];
|
||||
var region = regions[regionID].groups;
|
||||
var groupCount = 0;
|
||||
|
||||
if($.isEmptyObject(region)) return false;
|
||||
for(var j in region)
|
||||
{
|
||||
groupCount += 1;
|
||||
if(groupCount > 1) return false;
|
||||
}
|
||||
|
||||
var group = region[0];
|
||||
var laneCount = 0;
|
||||
|
||||
if($.isEmptyObject(group.lanes)) return false;
|
||||
for(var h in group.lanes)
|
||||
{
|
||||
laneCount += 1;
|
||||
if(laneCount > 1) return false;
|
||||
}
|
||||
|
||||
var regionHeaderHeight = $('.region-header').outerHeight();
|
||||
if(fold == 'open')
|
||||
{
|
||||
var windowHeight = $(window).height();
|
||||
var headerHeight = $('#mainHeader').outerHeight();
|
||||
var mainPadding = $('#main').css('padding-top');
|
||||
var panelBorder = $('.panel').css('border-top-width');
|
||||
var bodyPadding = $('.panel-body').css('padding-top');
|
||||
var height = windowHeight - (parseInt(mainPadding) * 2) - (parseInt(bodyPadding) * 2) - headerHeight - (parseInt(panelBorder) * 2);
|
||||
var regionPadding = $('.kanban').css('padding-bottom');
|
||||
var columnHeight = $('.kanban-header').outerHeight();
|
||||
|
||||
$('.region').css('height', height);
|
||||
$('.kanban-lane').css('height', height - regionHeaderHeight - parseInt(regionPadding) - columnHeight);
|
||||
}
|
||||
else
|
||||
{
|
||||
$('.region').css('height', regionHeaderHeight);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -18,6 +18,8 @@ $lang->kanban->deleteRegion = 'Delete Region';
|
||||
$lang->kanban->createLane = 'Create Lane';
|
||||
$lang->kanban->editLane = 'Edit Lane';
|
||||
$lang->kanban->sortLane = 'Sort Lane';
|
||||
$lang->kanban->laneHeight = 'Lane Height';
|
||||
$lang->kanban->setLaneHeight = 'Set Lane Height';
|
||||
$lang->kanban->deleteLane = 'Delete Lane';
|
||||
$lang->kanban->createColumn = 'Create Column';
|
||||
$lang->kanban->editColumn = 'Edit Column';
|
||||
@@ -73,15 +75,18 @@ $lang->kanban->closedBy = 'Closed By';
|
||||
$lang->kanban->closedDate = 'Closed Date';
|
||||
$lang->kanban->empty = 'No Kanban';
|
||||
$lang->kanban->teamSumCount = '%s people in total';
|
||||
$lang->kanban->cardCount = 'Card Count';
|
||||
|
||||
$lang->kanban->createColumnOnLeft = 'Create Column On Left';
|
||||
$lang->kanban->createColumnOnRight = 'Create Column On Right';
|
||||
|
||||
$lang->kanban->accessDenied = "You have no access to the kanban.";
|
||||
$lang->kanban->confirmDelete = 'Do you want to delete this?';
|
||||
$lang->kanban->cardCountTip = 'Please enter the number of cards';
|
||||
|
||||
$lang->kanban->aclGroup['open'] = 'Open';
|
||||
$lang->kanban->aclGroup['private'] = 'Private';
|
||||
$lang->kanban->aclGroup['extend'] = 'Extend';
|
||||
|
||||
$lang->kanban->aclList['extend'] = 'Extend (Accessible with space view permissions)';
|
||||
$lang->kanban->aclList['private'] = 'Private (For the kanban team, whitelist members and space owner only)';
|
||||
@@ -244,11 +249,20 @@ $lang->kanbanlane->default = 'Default Lane';
|
||||
$lang->kanbanlane->column = 'Lane Kanban Column';
|
||||
$lang->kanbanlane->otherlane = 'Select Existed Lane';
|
||||
$lang->kanbanlane->color = 'Lane Color';
|
||||
$lang->kanbanlane->WIPType = 'Lane WIP Type';
|
||||
|
||||
$lang->kanbanlane->confirmDelete = 'Are you sure to delete this lane? After deleting the lane, all data (columns and cards) in the lane will also be deleted.';
|
||||
$lang->kanbanlane->confirmDelete = 'Are you sure to delete this lane? After deleting the lane, all data (columns and cards) in the lane will also be deleted.';
|
||||
$lang->kanbanlane->confirmDeleteTip = 'Are you sure to delete this lane? After deleting the lane, all %s in the lane will be hidden.';
|
||||
|
||||
$lang->kanbanlane->modeList['sameAsOther'] = 'Use the same Kanban column';
|
||||
$lang->kanbanlane->modeList['independent'] = 'Independent Kanban column';
|
||||
|
||||
$lang->kanbanlane->heightTypeList['auto'] = 'Adaptive (Adaptive according to the card height)';
|
||||
$lang->kanbanlane->heightTypeList['custom'] = 'Custom (Customize lane height based on number of cards)';
|
||||
|
||||
$lang->kanbanlane->error = new stdclass();
|
||||
$lang->kanbanlane->error->mustBeInt = 'The number of cards must be a positive integer greater than 2.';
|
||||
|
||||
$lang->kanbanlane->modeList['sameAsOther'] = 'Use the same Kanban column as other lanes';
|
||||
$lang->kanbanlane->modeList['independent'] = 'Independent Kanban column is adopted';
|
||||
|
||||
$lang->kanbanregion = new stdclass();
|
||||
$lang->kanbanregion->name = 'Region Name';
|
||||
|
||||
@@ -18,6 +18,8 @@ $lang->kanban->deleteRegion = '删除区域';
|
||||
$lang->kanban->createLane = '创建泳道';
|
||||
$lang->kanban->editLane = '泳道设置';
|
||||
$lang->kanban->sortLane = '泳道排序';
|
||||
$lang->kanban->laneHeight = '泳道高度';
|
||||
$lang->kanban->setLaneHeight = '设置泳道高度';
|
||||
$lang->kanban->deleteLane = '删除泳道';
|
||||
$lang->kanban->createColumn = '创建看板列';
|
||||
$lang->kanban->editColumn = '编辑看板列';
|
||||
@@ -73,15 +75,18 @@ $lang->kanban->closedBy = '由谁关闭';
|
||||
$lang->kanban->closedDate = '关闭日期';
|
||||
$lang->kanban->empty = '暂时没有看板';
|
||||
$lang->kanban->teamSumCount = '共%s人';
|
||||
$lang->kanban->cardCount = '卡片数量';
|
||||
|
||||
$lang->kanban->createColumnOnLeft = '在左侧添加看板列';
|
||||
$lang->kanban->createColumnOnRight = '在右侧添加看板列';
|
||||
|
||||
$lang->kanban->accessDenied = '您无权访问该看板';
|
||||
$lang->kanban->confirmDelete = '您确认删除吗?';
|
||||
$lang->kanban->cardCountTip = '请输入卡片数量';
|
||||
|
||||
$lang->kanban->aclGroup['open'] = '公开';
|
||||
$lang->kanban->aclGroup['private'] = '私有';
|
||||
$lang->kanban->aclGroup['extend'] = '继承空间';
|
||||
|
||||
$lang->kanban->aclList['extend'] = '继承空间访问权限(能访问当前空间,即可访问)';
|
||||
$lang->kanban->aclList['private'] = '私有(看板团队成员、白名单、空间负责人可访问)';
|
||||
@@ -244,12 +249,20 @@ $lang->kanbanlane->default = '默认泳道';
|
||||
$lang->kanbanlane->column = '泳道看板列';
|
||||
$lang->kanbanlane->otherlane = '选择共享看板列的泳道';
|
||||
$lang->kanbanlane->color = '泳道颜色';
|
||||
$lang->kanbanlane->WIPType = '泳道在制品类型';
|
||||
|
||||
$lang->kanbanlane->confirmDelete = '您确认删除该泳道吗?删除泳道后,该泳道中所有数据(列、卡片)也会被删除。';
|
||||
$lang->kanbanlane->confirmDelete = '您确认删除该泳道吗?删除泳道后,该泳道中所有数据(列、卡片)也会被删除。';
|
||||
$lang->kanbanlane->confirmDeleteTip = '您确认删除该泳道吗?删除泳道后,该泳道中所有的%s将被隐藏。';
|
||||
|
||||
$lang->kanbanlane->modeList['sameAsOther'] = '与其他泳道使用相同看板列';
|
||||
$lang->kanbanlane->modeList['independent'] = '采用独立的看板列';
|
||||
|
||||
$lang->kanbanlane->heightTypeList['auto'] = '自适应(根据卡片高度自适应)';
|
||||
$lang->kanbanlane->heightTypeList['custom'] = '自定义(根据卡片数量自定义泳道高度)';
|
||||
|
||||
$lang->kanbanlane->error = new stdclass();
|
||||
$lang->kanbanlane->error->mustBeInt = '卡片数量必须是大于2的正整数。';
|
||||
|
||||
$lang->kanbanregion = new stdclass();
|
||||
$lang->kanbanregion->name = '区域名称';
|
||||
$lang->kanbanregion->default = '默认区域';
|
||||
|
||||
+795
-258
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,111 @@
|
||||
<?php
|
||||
/**
|
||||
* The createexeclane file of kanban module of ZenTaoPMS.
|
||||
*
|
||||
* @copyright Copyright 2009-2022 青岛易软天创网络科技有限公司(QingDao Nature Easy Soft Network Technology Co,LTD, www.cnezsoft.com)
|
||||
* @license ZPL (http://zpl.pub/page/zplv12.html)
|
||||
* @author Shujie Tian <tianshujie@easycorp.ltd>
|
||||
* @package kanban
|
||||
* @version $Id: createexeclane.html.php 935 2022-01-12 17:22:24Z $
|
||||
* @link https://www.zentao.net
|
||||
*/
|
||||
?>
|
||||
<?php include '../../common/view/header.html.php';?>
|
||||
<?php include '../../common/view/kindeditor.html.php';?>
|
||||
<?php js::set('colorList',$config->kanban->laneColorList);?>
|
||||
<?php js::set('regionID', $regionID);?>
|
||||
<?php js::set('lanes', $lanes);?>
|
||||
<style>
|
||||
.table-form>tbody>tr>th {width: 150px;}
|
||||
#otherLane_chosen {top: -8px;}
|
||||
#laneTypeBox {line-height: 16px;}
|
||||
.margin-bottom {margin-bottom: -6px;}
|
||||
</style>
|
||||
<div id='mainContent' class='main-content'>
|
||||
<div class='main-header'>
|
||||
<h2>
|
||||
<?php echo $lang->kanban->createLane;?>
|
||||
</h2>
|
||||
</div>
|
||||
<form class='load-indicator main-form form-ajax' method='post' enctype='multipart/form-data'>
|
||||
<table class='table table-form'>
|
||||
<tbody>
|
||||
<tr>
|
||||
<th><?php echo $lang->kanbanlane->name;?></th>
|
||||
<td colspan='3'>
|
||||
<div class='required required-wrapper'></div>
|
||||
<?php echo html::input('name', '', "class='form-control'");?>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<th><?php echo $lang->kanbanlane->WIPType;?></th>
|
||||
<td id='laneTypeBox'><?php echo html::radio('laneType', $lang->kanban->laneTypeList, 'story');?></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<th><?php echo $lang->kanbanlane->column;?></th>
|
||||
<?php $mode = empty($lanes) ? 'independent' : 'sameAsOther';?>
|
||||
<td id='modeBox'><?php echo html::radio('mode', $lang->kanbanlane->modeList, $mode, '', 'block');?></td>
|
||||
<td id='laneBox' <?php if(empty($lanes)) echo 'hidden';?>><?php echo html::select('otherLane', $lanes, '', "class='form-control chosen'");?></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<th><?php echo $lang->kanbanlane->color;?></th>
|
||||
<td colspan='3'>
|
||||
<div id='color-picker'></div>
|
||||
<?php echo html::input('color', '#7ec5ff', "class='hidden'");?>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td class='text-center form-actions' colspan='4'>
|
||||
<?php echo html::submitButton();?>
|
||||
<?php echo html::commonButton($lang->cancel, "data-dismiss='modal'", 'btn btn-wide');?>
|
||||
</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
</form>
|
||||
</div>
|
||||
<script>
|
||||
$(document).ready(function()
|
||||
{
|
||||
initColorPicker();
|
||||
if($.isEmptyObject(lanes))
|
||||
{
|
||||
$('#modesameAsOther').closest('div').addClass('hidden');
|
||||
$('#laneBox').addClass('hidden');
|
||||
$('#modeindependent').attr('checked', 'checked');
|
||||
$('#modeindependent').closest('div').addClass('margin-bottom');
|
||||
}
|
||||
|
||||
$('input[name=mode]').change(function()
|
||||
{
|
||||
$('#otherLane').parents('td').toggle($(this).val() == 'sameAsOther');
|
||||
if($(this).val() == 'sameAsOther') $('#laneBox').removeClass('hidden');
|
||||
});
|
||||
|
||||
$('input[name=laneType]').change(function()
|
||||
{
|
||||
var laneType = $(this).val();
|
||||
var link = createLink('kanban', 'ajaxGetLanes', 'regionID=' + regionID + '&type=' + laneType);
|
||||
|
||||
$.get(link, function(lanes)
|
||||
{
|
||||
if(lanes)
|
||||
{
|
||||
$('#modesameAsOther').parents('div').removeClass('hidden');
|
||||
$('#otherLane').replaceWith(lanes);
|
||||
$('#otherLane_chosen').remove();
|
||||
$('#otherLane').chosen();
|
||||
$('#modeindependent').closest('div').removeClass('margin-bottom');
|
||||
}
|
||||
else
|
||||
{
|
||||
$('#modesameAsOther').closest('div').addClass('hidden');
|
||||
$('#laneBox').addClass('hidden');
|
||||
$('#modeindependent').attr('checked', 'checked');
|
||||
$('#modeindependent').closest('div').addClass('margin-bottom');
|
||||
}
|
||||
})
|
||||
});
|
||||
})
|
||||
</script>
|
||||
<?php include '../../common/view/footer.html.php';?>
|
||||
@@ -0,0 +1,38 @@
|
||||
<?php
|
||||
/**
|
||||
* The setlaneheight file of kanban module of ZenTaoPMS.
|
||||
*
|
||||
* @copyright Copyright 2009-2022 青岛易软天创网络科技有限公司(QingDao Nature Easy Soft Network Technology Co,LTD, www.cnezsoft.com)
|
||||
* @license ZPL (http://zpl.pub/page/zplv12.html)
|
||||
* @author Shujie Tian <tianshujie@easycorp.ltd>
|
||||
* @package kanban
|
||||
* @version $Id: setlaneheight.html.php 935 2022-01-11 10:49:24Z $
|
||||
* @link https://www.zentao.net
|
||||
*/
|
||||
?>
|
||||
<?php include '../../common/view/header.html.php';?>
|
||||
<div id='mainContent' class='main-content'>
|
||||
<div class='center-block'>
|
||||
<div class='main-header'>
|
||||
<h2><?php echo $lang->kanban->setLaneHeight;?></h2>
|
||||
</div>
|
||||
<form class='main-form form-ajax' method='post' enctype='multipart/form-data' id='dataform'>
|
||||
<table class='table table-form'>
|
||||
<tr>
|
||||
<th><?php echo $lang->kanban->laneHeight;?></th>
|
||||
<td><?php echo nl2br(html::radio('heightType', $lang->kanbanlane->heightTypeList, $heightType, "onclick='setCardCount(this.value);'"));?></td>
|
||||
</tr>
|
||||
<tr class="hidden" id='cardBox'>
|
||||
<th class='c-count'><?php echo $lang->kanban->cardCount;?></th>
|
||||
<td><?php echo html::input('displayCards', $displayCards, "class='form-control' required placeholder='{$lang->kanban->cardCountTip}' autocomplete='off'");?></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td colspan='2' class='text-center form-actions'>
|
||||
<?php echo html::submitButton();?>
|
||||
</td>
|
||||
</tr>
|
||||
</table>
|
||||
</form>
|
||||
</div>
|
||||
</div>
|
||||
<?php include '../../common/view/footer.html.php';?>
|
||||
@@ -141,9 +141,11 @@
|
||||
<div class='kanban-members-total pull-left'><?php echo sprintf($lang->kanban->teamSumCount, $teamCount);?></div>
|
||||
</div>
|
||||
<div class='kanbanAcl'>
|
||||
<?php $icon = $kanban->acl == 'open' ? 'unlock' : 'lock';?>
|
||||
<?php $icon = 'unlock';?>
|
||||
<?php if($kanban->acl == 'private') $icon = 'lock';?>
|
||||
<?php if($kanban->acl == 'extend') $icon = 'inherit-space';?>
|
||||
<i class="<?php echo 'icon-' . $icon;?>"></i>
|
||||
<?php echo zget($lang->kanban->aclGroup, $kanban->acl == 'open' ? 'open' : 'private', '');?>
|
||||
<?php echo zget($lang->kanban->aclGroup, $kanban->acl, '');?>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@@ -30,6 +30,7 @@ js::set('noAssigned', $lang->kanbancard->noAssigned);
|
||||
js::set('users', $users);
|
||||
js::set('colorListLang', $lang->kanbancard->colorList);
|
||||
js::set('colorList', $this->config->kanban->cardColorList);
|
||||
js::set('displayCards', $kanban->displayCards);
|
||||
|
||||
js::set('priv',
|
||||
array(
|
||||
|
||||
@@ -94,6 +94,7 @@ $lang->misc->feature->downloadFile = 'Download introduction';
|
||||
$lang->misc->feature->tutorialDesc = '<p>ZenTao 15.0 has new functions, and you know how to use it through the "<strong>Tutorial</strong>".</p><p>Click your [<span style="color: #0c60e1">Avatar-Theme-Young Blue</span>] to set it.</p>';
|
||||
$lang->misc->feature->themeDesc = '<p>ZenTao 15.0+ a new "Youth Blue" theme, the pages are more beautiful and the experience is more friendly.</p><p>Click your [<span style="color: #0c60e1">Avatar-Theme-Young Blue</span>] to set it.</p>';
|
||||
|
||||
$lang->misc->releaseDate['16.2'] = '2022-01-17';
|
||||
$lang->misc->releaseDate['16.1'] = '2022-01-11';
|
||||
$lang->misc->releaseDate['16.0'] = '2021-12-24';
|
||||
$lang->misc->releaseDate['16.0.beta1'] = '2021-12-06';
|
||||
@@ -165,6 +166,7 @@ $lang->misc->releaseDate['7.2.stable'] = '2015-05-22';
|
||||
$lang->misc->releaseDate['7.1.stable'] = '2015-03-07';
|
||||
$lang->misc->releaseDate['6.3.stable'] = '2014-11-07';
|
||||
|
||||
$lang->misc->feature->all['16.2'][] = array('title' => 'Add kanban model project, fix bugs.', 'desc' => '');
|
||||
$lang->misc->feature->all['16.1'][] = array('title' => 'Plan to add status management and Kanban view, upgrade process optimization, fix bugs.', 'desc' => '');
|
||||
$lang->misc->feature->all['16.0'][] = array('title' => 'New general board, improve branch management, fix bugs.', 'desc' => '');
|
||||
$lang->misc->feature->all['16.0.beta1'][] = array('title' => 'Add waterfall model project, add task kanban, improved branch management, and fixed bugs.', 'desc' => '');
|
||||
|
||||
@@ -94,6 +94,7 @@ $lang->misc->feature->downloadFile = '下载新版本功能介绍文档';
|
||||
$lang->misc->feature->tutorialDesc = "<p>禅道15系列新增了多项功能,您可以通过“<strong>新手引导教程</strong>”快速了解禅道的基本使用方法。</p><p>通过鼠标经过 [<span style='color: #0c60e1'>头像-新手引导</span>],点击新手引导,即可进入新手引导教程。</p>";
|
||||
$lang->misc->feature->themeDesc = "<p>禅道15系列上线了全新的“青春蓝”主题,页面呈现更加美观,体验更加友好。</p><p>通过鼠标经过 [<span style='color: #0c60e1'>头像-主题-青春蓝</span>],点击青春蓝,即可设置成功。</p>";
|
||||
|
||||
$lang->misc->releaseDate['16.2'] = '2022-01-17';
|
||||
$lang->misc->releaseDate['16.1'] = '2022-01-11';
|
||||
$lang->misc->releaseDate['16.0'] = '2021-12-24';
|
||||
$lang->misc->releaseDate['16.0.beta1'] = '2021-12-06';
|
||||
@@ -165,6 +166,7 @@ $lang->misc->releaseDate['7.2.stable'] = '2015-05-22';
|
||||
$lang->misc->releaseDate['7.1.stable'] = '2015-03-07';
|
||||
$lang->misc->releaseDate['6.3.stable'] = '2014-11-07';
|
||||
|
||||
$lang->misc->feature->all['16.2'][] = array('title' => '新增专业研发看板,可以创建看板模型项目,修复Bug。', 'desc' => '');
|
||||
$lang->misc->feature->all['16.1'][] = array('title' => '计划增加状态管理和看板视图,升级流程优化,修复Bug。', 'desc' => '');
|
||||
$lang->misc->feature->all['16.0'][] = array('title' => '新增通用看板,完善分支管理,修复Bug。', 'desc' => '');
|
||||
$lang->misc->feature->all['16.0.beta1'][] = array('title' => '新增瀑布模型项目,新增任务看板,完善分支管理和细节,修复Bug。', 'desc' => '');
|
||||
|
||||
@@ -7,7 +7,7 @@
|
||||
<div class='container mw-900px' id="zentaoLinks">
|
||||
<div class='row'>
|
||||
<?php foreach($lang->misc->zentao as $label => $groupItems):?>
|
||||
<?php if(strpos(',labels,icons,version,', ",$label,") !== false) continue; ?>
|
||||
<?php if(strpos(',labels,icons,version,others,', ",$label,") !== false) continue; ?>
|
||||
<div class='col-sm-2'>
|
||||
<div class='panel <?php echo $label;?>'>
|
||||
<div class='panel-heading'>
|
||||
|
||||
@@ -443,6 +443,7 @@ EOF;
|
||||
$this->view->tasks = $tasks;
|
||||
$this->view->summary = $this->loadModel('execution')->summary($tasks);
|
||||
$this->view->type = $type;
|
||||
$this->view->kanbanList = $this->execution->getPairs(0, 'kanban');
|
||||
$this->view->recTotal = $recTotal;
|
||||
$this->view->recPerPage = $recPerPage;
|
||||
$this->view->pageID = $pageID;
|
||||
|
||||
@@ -114,7 +114,7 @@ $lang->my->executionLinkList = array();
|
||||
if($config->systemMode == 'new')
|
||||
{
|
||||
$lang->my->executionLinkList['execution-all'] = 'Enter the execution list by default, you can view all executions';
|
||||
$lang->my->executionLinkList['execution-task'] = 'By default, enter the list of the most recently executed task, and you can view the task information under the current iteration';
|
||||
$lang->my->executionLinkList['execution-task'] = 'By default, enter the list of the most recently executed task or kanban view, and you can view the task information under the current iteration';
|
||||
$lang->my->executionLinkList['execution-executionkanban'] = 'By default, you can enter the execution Kanban to view the execution status of projects in progress';
|
||||
}
|
||||
if($config->systemMode == 'classic') $lang->my->executionLinkList['execution-task'] = "By default, enter the list of the most recently {$lang->executionCommon} task, and you can view the task information under the current {$lang->executionCommon}";
|
||||
|
||||
@@ -114,7 +114,7 @@ $lang->my->executionLinkList = array();
|
||||
if($config->systemMode == 'new')
|
||||
{
|
||||
$lang->my->executionLinkList['execution-all'] = '默认进入执行列表,可以查看所有的执行';
|
||||
$lang->my->executionLinkList['execution-task'] = '默认进入最近一个执行的任务列表,可以查看当前迭代下的任务信息';
|
||||
$lang->my->executionLinkList['execution-task'] = '默认进入最近一个执行的任务列表或看板视图,可以查看当前迭代下的任务信息';
|
||||
$lang->my->executionLinkList['execution-executionkanban'] = '默认进入执行看板,可以查看进行中项目的执行情况';
|
||||
}
|
||||
if($config->systemMode == 'classic') $lang->my->executionLinkList['execution-task'] = "默认进入最近一个{$lang->executionCommon}的任务列表,可以查看当前{$lang->executionCommon}下的任务信息";
|
||||
|
||||
@@ -131,14 +131,15 @@
|
||||
}
|
||||
else
|
||||
{
|
||||
if($task->status != 'pause') common::printIcon('task', 'start', "taskID=$task->id", $task, 'list', '', '', 'iframe', true, '', '', $task->project);
|
||||
if($task->status == 'pause') common::printIcon('task', 'restart', "taskID=$task->id", $task, 'list', '', '', 'iframe', true, '', '', $task->project);
|
||||
common::printIcon('task', 'close', "taskID=$task->id", $task, 'list', '', '', 'iframe', true, '', '', $task->project);
|
||||
common::printIcon('task', 'finish', "taskID=$task->id", $task, 'list', '', '', 'iframe', true, '', '', $task->project);
|
||||
$attr = isset($kanbanList[$task->execution]) ? "disabled" : '';
|
||||
if($task->status != 'pause') common::printIcon('task', 'start', "taskID=$task->id", $task, 'list', '', '', 'iframe', true);
|
||||
if($task->status == 'pause') common::printIcon('task', 'restart', "taskID=$task->id", $task, 'list', '', '', 'iframe', true);
|
||||
common::printIcon('task', 'close', "taskID=$task->id", $task, 'list', '', '', 'iframe', true);
|
||||
common::printIcon('task', 'finish', "taskID=$task->id", $task, 'list', '', '', 'iframe', true);
|
||||
|
||||
common::printIcon('task', 'recordEstimate', "taskID=$task->id", $task, 'list', 'time', '', 'iframe', true, '', '', $task->project);
|
||||
common::printIcon('task', 'edit', "taskID=$task->id", $task, 'list', '', '', 'iframe', true, "data-width='95%'", '', $task->project);
|
||||
common::printIcon('task', 'batchCreate', "executionID=$task->execution&storyID=$task->story&moduleID=$task->module&taskID=$task->id&ifame=true", $task, 'list', 'split', '', 'iframe', true, "data-width='95%'", $this->lang->task->children, $task->project);
|
||||
common::printIcon('task', 'recordEstimate', "taskID=$task->id", $task, 'list', 'time', '', 'iframe', true);
|
||||
common::printIcon('task', 'edit', "taskID=$task->id", $task, 'list', '', '', 'iframe', true, "data-width='95%'");
|
||||
common::printIcon('task', 'batchCreate', "executionID=$task->execution&storyID=$task->story&moduleID=$task->module&taskID=$task->id&ifame=true", $task, 'list', 'split', '', 'iframe', true, "data-width='95%' $attr", $this->lang->task->children);
|
||||
}
|
||||
}
|
||||
?>
|
||||
|
||||
@@ -1465,7 +1465,7 @@ class productModel extends model
|
||||
->leftJoin(TABLE_PROJECT)->alias('t2')->on('t1.project = t2.id')
|
||||
->where('t2.deleted')->eq(0)
|
||||
->andWhere('t1.product')->eq($productID)
|
||||
->andWhere('t2.type')->in('sprint,stage')
|
||||
->andWhere('t2.type')->in('sprint,stage,kanban')
|
||||
->fetch();
|
||||
|
||||
$product->stories = $stories;
|
||||
|
||||
@@ -161,7 +161,7 @@ $(function()
|
||||
}
|
||||
})
|
||||
|
||||
$('#tabContent [data-ride="tree"]').tree('expand');
|
||||
$('#swapper [data-ride="tree"]').tree('expand');
|
||||
|
||||
$('#swapper #dropMenu .search-box').on('onSearchChange', function(event, value)
|
||||
{
|
||||
|
||||
@@ -99,7 +99,7 @@ class productplanModel extends model
|
||||
->leftJoin(TABLE_PROJECT)->alias('t2')->on('t1.project=t2.id')
|
||||
->where('t1.product')->eq($product)
|
||||
->andWhere('t1.plan')->in(array_keys($plans))
|
||||
->andWhere('t2.type')->in('sprint,stage')
|
||||
->andWhere('t2.type')->in('sprint,stage,kanban')
|
||||
->fetchPairs('plan', 'project');
|
||||
|
||||
$storyCountInTable = $this->dao->select('plan,count(story) as count')->from(TABLE_PLANSTORY)->where('plan')->in($planIdList)->groupBy('plan')->fetchPairs('plan', 'count');
|
||||
|
||||
@@ -0,0 +1,3 @@
|
||||
.project-type-label.label-outline {width: 50px; min-width: 50px;}
|
||||
.project-type-label.label {overflow: unset !important; text-overflow: unset !important; white-space: unset !important;}
|
||||
[lang^='en'] .project-name > .label-warning {width: 55px !important;}
|
||||
@@ -205,7 +205,7 @@ class programModel extends model
|
||||
|
||||
/* Get doing executions. */
|
||||
$doingExecutions = $this->dao->select('id, project, name, end')->from(TABLE_EXECUTION)
|
||||
->where('type')->in('sprint,stage')
|
||||
->where('type')->in('sprint,stage,kanban')
|
||||
->andWhere('status')->eq('doing')
|
||||
->andWhere('deleted')->eq(0)
|
||||
->beginIF(!$this->app->user->admin)->andWhere('id')->in($this->app->user->view->sprints)->fi()
|
||||
@@ -1254,7 +1254,7 @@ class programModel extends model
|
||||
$executions = $this->dao->select('id')->from(TABLE_EXECUTION)
|
||||
->where('deleted')->eq(0)
|
||||
->andWhere('project')->in($projectKeys)
|
||||
->andWhere('type')->in('sprint,stage')
|
||||
->andWhere('type')->in('sprint,stage,kanban')
|
||||
->fetchAll('id');
|
||||
|
||||
/* Get all tasks and compute totalEstimate, totalConsumed, totalLeft, progress according to them. */
|
||||
|
||||
@@ -15,10 +15,6 @@
|
||||
js::set('programID', $programID);
|
||||
js::set('browseType', $browseType);
|
||||
?>
|
||||
<style>
|
||||
.project-type-label.label-outline {width: 50px; min-width: 50px;}
|
||||
.project-type-label.label {overflow: unset !important; text-overflow: unset !important; white-space: unset !important;}
|
||||
</style>
|
||||
<div id="mainMenu" class="clearfix">
|
||||
<div class="btn-toolBar pull-left">
|
||||
<?php foreach($lang->program->featureBar as $key => $label):?>
|
||||
|
||||
@@ -53,7 +53,7 @@ class project extends control
|
||||
unset($fields[$key]);
|
||||
}
|
||||
|
||||
$projects = $this->project->getInfoList($status, 30, $orderBy, null);
|
||||
$projects = $this->project->getInfoList($status, $orderBy);
|
||||
$users = $this->loadModel('user')->getPairs('noletter');
|
||||
|
||||
$this->loadModel('product');
|
||||
@@ -222,10 +222,11 @@ class project extends control
|
||||
* Project index view.
|
||||
*
|
||||
* @param int $projectID
|
||||
* @param string $browseType
|
||||
* @access public
|
||||
* @return void
|
||||
*/
|
||||
public function index($projectID = 0)
|
||||
public function index($projectID = 0, $browseType = 'all')
|
||||
{
|
||||
$projectID = $this->project->saveState($projectID, $this->project->getPairsByProgram());
|
||||
|
||||
@@ -240,6 +241,27 @@ class project extends control
|
||||
if(!$projectID) $this->locate($this->createLink('project', 'browse'));
|
||||
setCookie("lastProject", $projectID, $this->config->cookieLife, $this->config->webRoot, '', false, true);
|
||||
|
||||
if($project->model == 'kanban')
|
||||
{
|
||||
$kanbanList = $this->loadModel('execution')->getList($projectID, 'all', $browseType);
|
||||
|
||||
$executionActions = array();
|
||||
foreach($kanbanList as $kanbanID => $kanban)
|
||||
{
|
||||
foreach($this->config->execution->statusActions as $action)
|
||||
{
|
||||
if($this->execution->isClickable($kanban, $action)) $executionActions[$kanbanID][] = $action;
|
||||
}
|
||||
if($this->execution->isClickable($kanban, 'delete')) $executionActions[$kanbanID][] = 'delete';
|
||||
}
|
||||
|
||||
$this->view->kanbanList = $kanbanList;
|
||||
$this->view->browseType = $browseType;
|
||||
$this->view->memberGroup = $this->execution->getMembersByIdList(array_keys($kanbanList));
|
||||
$this->view->usersAvatar = $this->loadModel('user')->getAvatarPairs();
|
||||
$this->view->executionActions = $executionActions;
|
||||
}
|
||||
|
||||
$this->view->title = $this->lang->project->common . $this->lang->colon . $this->lang->project->index;
|
||||
$this->view->position[] = $this->lang->project->index;
|
||||
$this->view->project = $project;
|
||||
@@ -352,6 +374,8 @@ class project extends control
|
||||
$this->loadModel('execution');
|
||||
$this->loadModel('product');
|
||||
|
||||
if($model == 'kanban') unset($this->lang->project->authList['reset']);
|
||||
|
||||
if($_POST)
|
||||
{
|
||||
$projectID = $this->project->create();
|
||||
@@ -506,6 +530,7 @@ class project extends control
|
||||
$project = $this->project->getByID($projectID);
|
||||
$programID = $project->parent;
|
||||
$this->project->setMenu($projectID);
|
||||
if($project->model == 'kanban') unset($this->lang->project->authList['reset']);
|
||||
|
||||
if($_POST)
|
||||
{
|
||||
@@ -576,8 +601,7 @@ class project extends control
|
||||
}
|
||||
}
|
||||
|
||||
$canChangeModel = $this->project->checkCanChangeModel($projectID, $project->model);
|
||||
$disableModel = $canChangeModel == true ? '' : 'disabled';
|
||||
if($project->model != 'kanban') $canChangeModel = $this->project->checkCanChangeModel($projectID, $project->model);
|
||||
|
||||
$this->view->title = $this->lang->project->edit;
|
||||
$this->view->position[] = $this->lang->project->edit;
|
||||
@@ -604,7 +628,7 @@ class project extends control
|
||||
$this->view->availableBudget = $this->program->getBudgetLeft($parentProject) + (float)$project->budget;
|
||||
$this->view->budgetUnitList = $this->project->getBudgetUnitList();
|
||||
$this->view->model = $project->model;
|
||||
$this->view->disableModel = $disableModel;
|
||||
$this->view->disableModel = (isset($canChangeModel) and $canChangeModel == true) ? '' : 'disabled';
|
||||
|
||||
$this->display();
|
||||
}
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
body {margin-bottom: 25px;}
|
||||
.side-col .detail-content {padding-left: 10px; margin-top: 0px;}
|
||||
.side-col {padding-right: 20px; width: 18%;}
|
||||
#sidebar>.cell {width: 100%;}
|
||||
@@ -16,3 +17,4 @@ th.c-name {width: 360px !important;}
|
||||
{
|
||||
th.c-name {width: auto;}
|
||||
}
|
||||
[lang^='en'] .project-name > .label-warning {width: 55px !important;}
|
||||
|
||||
@@ -0,0 +1,30 @@
|
||||
#cards > .col {width: 25% !important;}
|
||||
#cards .panel {margin: 0 0; border: 1px solid #DCDCDC; border-radius: 4px; box-shadow: none; cursor: pointer; height: 160px; margin-bottom: 5px;}
|
||||
#cards .panel:hover {border-color: #006AF1; box-shadow: 0 0 10px 0 rgba(0,0,100,.25);}
|
||||
#cards .panel-heading {padding: 4px 2px 10px 16px;}
|
||||
#cards .kanban-name {overflow: hidden; white-space:nowrap; width: 88%; float: left; padding-top: 8px;}
|
||||
#cards .panel .label-closed {background: #AAA !important; color: #FFF; margin-top:-1px !important;}
|
||||
#cards .kanban-actions {float: right; visibility: hidden;}
|
||||
#cards .kanban-actions .dropdown-menu.pull-right {top:31px; right: -84px; left: auto;}
|
||||
#cards .kanban-actions .dropdown-menu.pull-left {top:31px; right:-1px; left: auto;}
|
||||
#cards .panel .label-closed {background: #AAA !important; color: #FFF; margin-top:-6px;}
|
||||
#cards .panel-body {padding: 0 16px 16px;}
|
||||
#cards .kanban-desc {color: #838a9d; word-break:break-all; height: 70px; overflow: hidden; display: -webkit-box; float:left;}
|
||||
#cards .kanban-footer {position: absolute; bottom: 10px; right: 10px; left: 15px;}
|
||||
#cards .kanban-members {float: left; height: 24px; line-height: 24px;}
|
||||
#cards .kanban-members > div {display: inline-block; height: 24px;}
|
||||
#cards .kanban-members > div + div {margin-left: -5px;}
|
||||
#cards .kanban-members > div > .avatar {display: inline-block; width: 24px; height: 24px; line-height: 24px; margin-right: 1px;}
|
||||
#cards .kanban-members > span {display: inline-block; color: transparent; width: 2px; height: 2px; background-color: #8990a2; position: relative; border-radius: 50%; top: 3px; margin: 0 3px;}
|
||||
#cards .kanban-members > span:before,
|
||||
#cards .kanban-members > span:after {content: ''; display: block; position: absolute; width: 2px; height: 2px; background-color: #8990a2; top: 0; border-radius: 50%}
|
||||
#cards .kanban-members > span:before {left: -4px;}
|
||||
#cards .kanban-members > span:after {right: -4px;}
|
||||
#cards .kanban-members-total {display: inline-block; margin-left: 6px; position: relative; top: 3px}
|
||||
#cards .kanbanAcl {position: absolute; right: 0px; bottom: 0px; color: #838a9d;}
|
||||
|
||||
.kanbans .kanban-actions {float: right; visibility: hidden;}
|
||||
.kanbans .kanban-actions .dropdown-menu.pull-right {top:31px; right: -84px; left: auto;}
|
||||
.kanbans .kanban-actions .dropdown-menu.pull-left {top:31px; right:-1px; left: auto;}
|
||||
|
||||
.label-doing {background: #ff5d5d}
|
||||
@@ -0,0 +1,21 @@
|
||||
/* Make cards clickable. */
|
||||
$('#cards').on('click', '.panel', function(e)
|
||||
{
|
||||
if(!$(e.target).closest('.kanban-actions').length)
|
||||
{
|
||||
$.apps.open($(this).data('url'));
|
||||
}
|
||||
});
|
||||
|
||||
/* Display drop-down menu.*/
|
||||
$('.panel').mouseenter(function(e)
|
||||
{
|
||||
$('.kanban-actions' + e.currentTarget.parentElement.dataset.id).css('visibility','visible');
|
||||
});
|
||||
|
||||
/* Hide drop-down menu. */
|
||||
$('.panel').mouseleave(function(e)
|
||||
{
|
||||
$('.kanban-actions').css('visibility','hidden');
|
||||
$('.dropdown').removeClass('open');
|
||||
});
|
||||
@@ -155,6 +155,8 @@ $lang->project->etc = " , etc";
|
||||
$lang->project->product = 'Product';
|
||||
$lang->project->branch = 'Branch';
|
||||
$lang->project->plan = 'Plan';
|
||||
$lang->project->kanban = 'Kanban';
|
||||
$lang->project->createKanban = 'Create Kanban';
|
||||
|
||||
/* Project Kanban. */
|
||||
$lang->project->typeList = array();
|
||||
@@ -220,6 +222,7 @@ $lang->project->currencySymbol['SGD'] = 'S$';
|
||||
|
||||
$lang->project->modelList['scrum'] = "Scrum";
|
||||
$lang->project->modelList['waterfall'] = "CMMI";
|
||||
$lang->project->modelList['kanban'] = "Kanban";
|
||||
|
||||
$lang->project->featureBar['all'] = 'All';
|
||||
$lang->project->featureBar['doing'] = 'Going';
|
||||
@@ -252,6 +255,10 @@ $lang->project->endList[186] = 'Half yearly';
|
||||
$lang->project->endList[365] = 'One year';
|
||||
$lang->project->endList[999] = 'Longtime';
|
||||
|
||||
$lang->project->scrumTitle = 'Agile Development Management';
|
||||
$lang->project->waterfallTitle = 'Waterfall Project Management';
|
||||
$lang->project->kanbanTitle = 'Kanban Project Management';
|
||||
|
||||
$lang->project->empty = 'No project.';
|
||||
$lang->project->nextStep = 'Next step';
|
||||
$lang->project->hoursUnit = '%s hours';
|
||||
@@ -260,7 +267,6 @@ $lang->project->lastIteration = "Recent {$lang->executionCommon}";
|
||||
$lang->project->ongoingStage = 'Ongoing stage';
|
||||
$lang->project->scrum = 'Scrum';
|
||||
$lang->project->waterfall = 'Waterfall';
|
||||
$lang->project->waterfallTitle = 'Waterfall Project Management';
|
||||
$lang->project->cannotCreateChild = 'It is not empty, so you cannot add a child. You can add a parent for it, and then create a child.';
|
||||
$lang->project->confirmDelete = "Do you want to delete [%s]?";
|
||||
$lang->project->emptyPM = 'No manager';
|
||||
@@ -278,7 +284,6 @@ $lang->project->programTitle['end'] = 'End-level project only';
|
||||
|
||||
$lang->project->accessDenied = 'Access denied to this project';
|
||||
$lang->project->chooseProgramType = 'Select management type';
|
||||
$lang->project->scrumTitle = 'Agile Development Management';
|
||||
$lang->project->cannotCreateChild = 'The project has contents, so you cannot add a child project. You can create a parent project for this one and then add a child project for the parent project.';
|
||||
$lang->project->hasChildren = 'This project has a child project, so it cannot be deleted.';
|
||||
$lang->project->confirmDelete = 'Do you want to delete this project?';
|
||||
|
||||
@@ -155,6 +155,8 @@ $lang->project->etc = "等";
|
||||
$lang->project->product = '所属产品';
|
||||
$lang->project->branch = '所属分支';
|
||||
$lang->project->plan = '所属计划';
|
||||
$lang->project->createKanban = '添加看板';
|
||||
$lang->project->kanban = '看板';
|
||||
|
||||
/* Project Kanban. */
|
||||
$lang->project->typeList = array();
|
||||
@@ -220,6 +222,7 @@ $lang->project->currencySymbol['SGD'] = 'S$';
|
||||
|
||||
$lang->project->modelList['scrum'] = "Scrum";
|
||||
$lang->project->modelList['waterfall'] = "瀑布";
|
||||
$lang->project->modelList['kanban'] = "看板";
|
||||
|
||||
$lang->project->featureBar['all'] = '所有';
|
||||
$lang->project->featureBar['doing'] = '进行中';
|
||||
@@ -252,6 +255,10 @@ $lang->project->endList[186] = '半年';
|
||||
$lang->project->endList[365] = '一年';
|
||||
$lang->project->endList[999] = '长期';
|
||||
|
||||
$lang->project->scrumTitle = '敏捷开发全流程项目管理';
|
||||
$lang->project->waterfallTitle = '瀑布式项目管理';
|
||||
$lang->project->kanbanTitle = '专业研发看板项目管理';
|
||||
|
||||
$lang->project->empty = '暂时没有项目';
|
||||
$lang->project->nextStep = '下一步';
|
||||
$lang->project->hoursUnit = '%s 工时';
|
||||
@@ -260,7 +267,6 @@ $lang->project->lastIteration = "近期{$lang->executionCommon}";
|
||||
$lang->project->ongoingStage = '进行中的阶段';
|
||||
$lang->project->scrum = 'Scrum';
|
||||
$lang->project->waterfall = '瀑布';
|
||||
$lang->project->waterfallTitle = '瀑布式项目管理';
|
||||
$lang->project->cannotCreateChild = '该项目已经有实际的内容,无法直接添加子项目。您可以为当前项目创建一个父项目,然后在新的父项目下面添加子项目。';
|
||||
$lang->project->confirmDelete = "您确定要删除吗?";
|
||||
$lang->project->emptyPM = '暂无';
|
||||
@@ -278,7 +284,6 @@ $lang->project->programTitle['end'] = '只显示最后一级项目集';
|
||||
|
||||
$lang->project->accessDenied = '您无权访问该项目!';
|
||||
$lang->project->chooseProgramType = '选择项目管理方式';
|
||||
$lang->project->scrumTitle = '敏捷开发全流程项目管理';
|
||||
$lang->project->cannotCreateChild = '该项目已经有实际的内容,无法直接添加子项目。您可以为当前项目创建一个父项目,然后在新的父项目下面添加子项目。';
|
||||
$lang->project->hasChildren = '该项目有子项目存在,不能删除。';
|
||||
$lang->project->confirmDelete = "您确定删除项目[%s]吗?";
|
||||
|
||||
+17
-16
@@ -37,7 +37,7 @@ class projectModel extends model
|
||||
echo(js::alert($this->lang->project->accessDenied));
|
||||
$this->session->set('project', '');
|
||||
|
||||
die(js::locate(helper::createLink('project', 'index')));
|
||||
return print(js::locate(helper::createLink('project', 'index')));
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -189,13 +189,12 @@ class projectModel extends model
|
||||
* Get project info.
|
||||
*
|
||||
* @param string $status
|
||||
* @param int $itemCounts
|
||||
* @param string $orderBy
|
||||
* @param int $pager
|
||||
* @access public
|
||||
* @return array
|
||||
*/
|
||||
public function getInfoList($status = 'undone', $itemCounts = 30, $orderBy = 'order_desc', $pager = null)
|
||||
public function getInfoList($status = 'undone', $orderBy = 'order_desc', $pager = null)
|
||||
{
|
||||
/* Init vars. */
|
||||
$projects = $this->loadModel('program')->getProjectList(0, $status, 0, $orderBy, $pager, 0, 1);
|
||||
@@ -632,7 +631,7 @@ class projectModel extends model
|
||||
/**
|
||||
* Get project pairs by model and project.
|
||||
*
|
||||
* @param string $model all|scrum|waterfall
|
||||
* @param string $model all|scrum|waterfall|kanban
|
||||
* @param int $programID
|
||||
* @access public
|
||||
* @return array
|
||||
@@ -1569,7 +1568,8 @@ class projectModel extends model
|
||||
$prefix = '';
|
||||
$suffix = '';
|
||||
if($project->model === 'waterfall') $prefix = "<span class='project-type-label label label-outline label-warning'>{$this->lang->project->waterfall}</span> ";
|
||||
if($project->model === 'scrum') $prefix = "<span class='project-type-label label label-outline label-info'>{$this->lang->project->scrum}</span> ";
|
||||
if($project->model === 'scrum') $prefix = "<span class='project-type-label label label-outline label-info'>{$this->lang->project->scrum}</span> ";
|
||||
if($project->model === 'kanban') $prefix = "<span class='project-type-label label label-outline label-info'>{$this->lang->project->kanban}</span> ";
|
||||
if(isset($project->delay)) $suffix = "<span class='label label-danger label-badge'>{$this->lang->project->statusList['delay']}</span>";
|
||||
if(!empty($suffix) || !empty($prefix)) echo '<div class="project-name' . (empty($prefix) ? '' : ' has-prefix') . (empty($suffix) ? '' : ' has-suffix') . '">';
|
||||
if(!empty($prefix)) echo $prefix;
|
||||
@@ -1633,20 +1633,21 @@ class projectModel extends model
|
||||
}
|
||||
|
||||
$from = $project->from == 'project' ? 'project' : 'pgmproject';
|
||||
$iframe = $this->app->tab == 'program' ? 'iframe' : '';
|
||||
$onlyBody = $this->app->tab == 'program' ? true : '';
|
||||
$iframe = ($this->app->tab == 'program' or $project->model == 'kanban') ? 'iframe' : '';
|
||||
$onlyBody = ($this->app->tab == 'program' or $project->model == 'kanban') ? true : '';
|
||||
$dataApp = $this->config->systemMode == 'classic' ? "data-app=execution" : "data-app=project";
|
||||
common::printIcon($moduleName, 'edit', "projectID=$project->id", $project, 'list', 'edit', '', $iframe, $onlyBody, $dataApp, '', $project->id);
|
||||
common::printIcon($moduleName, 'manageMembers', "projectID=$project->id", $project, 'list', 'group', '', '', '', $dataApp, $this->lang->execution->team, $project->id);
|
||||
if($this->config->systemMode == 'new') common::printIcon('project', 'group', "projectID=$project->id&programID=$programID", $project, 'list', 'lock', '', '', '', $dataApp, '', $project->id);
|
||||
$attr = $project->model == 'kanban' ? " disabled='disabled'" : '';
|
||||
common::printIcon($moduleName, 'edit', "projectID=$project->id", $project, 'list', 'edit', '', $iframe, $onlyBody, $dataApp);
|
||||
common::printIcon($moduleName, 'manageMembers', "projectID=$project->id", $project, 'list', 'group', '', '', '', $dataApp . $attr, $this->lang->execution->team);
|
||||
if($this->config->systemMode == 'new') common::printIcon('project', 'group', "projectID=$project->id&programID=$programID", $project, 'list', 'lock', '', '', '', $dataApp . $attr);
|
||||
|
||||
if(common::hasPriv($moduleName, 'manageProducts') || common::hasPriv($moduleName, 'whitelist') || common::hasPriv($moduleName, 'delete'))
|
||||
{
|
||||
echo "<div class='btn-group'>";
|
||||
echo "<button type='button' class='btn dropdown-toggle' data-toggle='context-dropdown' title='{$this->lang->more}'><i class='icon-more-alt'></i></button>";
|
||||
echo "<ul class='dropdown-menu pull-right text-center' role='menu'>";
|
||||
common::printIcon($moduleName, 'manageProducts', "projectID=$project->id", $project, 'list', 'link', '', 'btn-action', '', $dataApp, $this->lang->project->manageProducts, $project->id);
|
||||
if($this->config->systemMode == 'new') common::printIcon('project', 'whitelist', "projectID=$project->id&module=project&from=$from", $project, 'list', 'shield-check', '', 'btn-action', '', $dataApp, '', $project->id);
|
||||
common::printIcon($moduleName, 'manageProducts', "projectID=$project->id", $project, 'list', 'link', '', 'btn-action', '', $dataApp . $attr, $this->lang->project->manageProducts);
|
||||
if($this->config->systemMode == 'new') common::printIcon('project', 'whitelist', "projectID=$project->id&module=project&from=$from", $project, 'list', 'shield-check', '', 'btn-action', '', $dataApp . $attr);
|
||||
if(common::hasPriv($moduleName, 'delete')) echo html::a(helper::createLink($moduleName, "delete", "projectID=$project->id"), "<i class='icon-trash'></i>", 'hiddenwin', "class='btn btn-action' title='{$this->lang->project->delete}'");
|
||||
echo "</ul>";
|
||||
echo "</div>";
|
||||
@@ -1776,7 +1777,7 @@ class projectModel extends model
|
||||
$type = 'project';
|
||||
if($this->config->systemMode == 'new')
|
||||
{
|
||||
if($project->type == 'sprint' or $project->type == 'stage') $type = 'execution';
|
||||
if($project->type == 'sprint' or $project->type == 'stage' or $project->type == 'kanban') $type = 'execution';
|
||||
}
|
||||
|
||||
$members = $this->dao->select("t1.account, if(t2.deleted='0', t2.realname, t1.account) as realname")->from(TABLE_TEAM)->alias('t1')
|
||||
@@ -1834,9 +1835,9 @@ class projectModel extends model
|
||||
->fetchPairs();
|
||||
}
|
||||
|
||||
$executions = $this->dao->select('t1.*,t2.name projectName')->from(TABLE_EXECUTION)->alias('t1')
|
||||
$executions = $this->dao->select('t1.*,t2.name projectName, t2.model as projectModel')->from(TABLE_EXECUTION)->alias('t1')
|
||||
->leftJoin(TABLE_PROJECT)->alias('t2')->on('t1.project = t2.id')
|
||||
->where('t1.type')->in('sprint,stage')
|
||||
->where('t1.type')->in('sprint,stage,kanban')
|
||||
->beginIF($projectID != 0)->andWhere('t1.project')->eq($projectID)->fi()
|
||||
->beginIF(!empty($myExecutionIDList))->andWhere('t1.id')->in(array_keys($myExecutionIDList))->fi()
|
||||
->beginIF($status == 'undone')->andWhere('t1.status')->notIN('done,closed')->fi()
|
||||
@@ -1849,7 +1850,7 @@ class projectModel extends model
|
||||
}
|
||||
else
|
||||
{
|
||||
$executions = $this->dao->select('t2.*,t3.name projectName')->from(TABLE_PROJECTPRODUCT)->alias('t1')
|
||||
$executions = $this->dao->select('t2.*,t3.name projectName, t3.model as projectModel')->from(TABLE_PROJECTPRODUCT)->alias('t1')
|
||||
->leftJoin(TABLE_EXECUTION)->alias('t2')->on('t1.project=t2.id')
|
||||
->leftJoin(TABLE_PROJECT)->alias('t3')->on('t2.project=t3.id')
|
||||
->where('t1.product')->eq($productID)
|
||||
|
||||
@@ -72,9 +72,12 @@ foreach($projects as $programID => $programProjects)
|
||||
|
||||
foreach($programProjects as $index => $project)
|
||||
{
|
||||
$selected = $project->id == $projectID ? 'selected' : '';
|
||||
$link = helper::createLink('project', 'index', "projectID=%s", '', '', $project->id);
|
||||
$projectName = $project->model == 'scrum' ? '<i class="icon icon-sprint"></i> ' . $project->name : '<i class="icon icon-waterfall"></i> ' . $project->name;
|
||||
$selected = $project->id == $projectID ? 'selected' : '';
|
||||
$link = helper::createLink('project', 'index', "projectID=%s", '', '', $project->id);
|
||||
$icon = '<i class="icon icon-sprint"></i> ';
|
||||
|
||||
if($project->model != 'scrum') $icon = "<i class='icon icon-{$project->model}'></i> ";
|
||||
$projectName = $icon . $project->name;
|
||||
|
||||
if($project->status != 'done' and $project->status != 'closed' and $project->PM == $this->app->user->account)
|
||||
{
|
||||
|
||||
@@ -84,10 +84,8 @@
|
||||
<div class="table-empty-tip">
|
||||
<p>
|
||||
<span class="text-muted"><?php echo $lang->project->empty;?></span>
|
||||
<?php if(isset($this->config->maxVersion) and !defined('TUTORIAL')):?>
|
||||
<?php if(!defined('TUTORIAL')):?>
|
||||
<?php common::printLink('project', 'createGuide', "programID=$programID", '<i class="icon icon-plus"></i> ' . $lang->project->create, '', 'class="btn btn-info" data-toggle="modal" data-target="#guideDialog"');?>
|
||||
<?php elseif($this->config->systemMode == 'new'):?>
|
||||
<?php common::printLink('project', 'create', 'mode=scrum', '<i class="icon icon-plus"></i> ' . $lang->project->create, '', 'class="btn btn-info"');?>
|
||||
<?php else:?>
|
||||
<?php common::printLink('execution', 'create', '', '<i class="icon icon-plus"></i> ' . $lang->execution->create, '', 'class="btn btn-info"');?>
|
||||
<?php endif;?>
|
||||
@@ -102,9 +100,11 @@
|
||||
<span class="label label-<?php echo $status;?>"><?php echo $lang->project->statusList[$status];?></span>
|
||||
</div>
|
||||
<div class='panel-heading'>
|
||||
<?php if(isset($config->maxVersion) and $project->model === 'waterfall'):?>
|
||||
<?php if($project->model === 'waterfall'):?>
|
||||
<span class='project-type-label label label-warning label-outline'><i class='icon icon-waterfall'></i></span>
|
||||
<?php elseif(isset($config->maxVersion)):?>
|
||||
<?php elseif($project->model === 'kanban'):?>
|
||||
<span class='project-type-label label label-info label-outline'><i class='icon icon-kanban'></i></span>
|
||||
<?php else:?>
|
||||
<span class='project-type-label label label-info label-outline'><i class='icon icon-sprint'></i></span>
|
||||
<?php endif;?>
|
||||
<strong class='project-name' title='<?php echo $project->name;?>'><?php echo html::a(helper::createLink('project', 'index', "projectID=$projectID"), $project->name);?></strong>
|
||||
@@ -174,7 +174,9 @@
|
||||
<?php echo html::a('javascript:;', "<i class='icon icon-ellipsis-v'></i>", '', "data-toggle='dropdown' class='btn btn-link'");?>
|
||||
<ul class='dropdown-menu pull-right'>
|
||||
<?php
|
||||
common::printIcon('project', 'edit', "projectID=$project->id", $project, 'list', 'edit', '', 'btn-action');
|
||||
$iframe = $project->model == 'kanban' ? ' iframe' : '';
|
||||
$onlyBody = $project->model == 'kanban' ? true : '';
|
||||
common::printIcon('project', 'edit', "projectID=$project->id", $project, 'list', 'edit', '', 'btn-action' . $iframe, $onlyBody);
|
||||
common::printIcon('project', 'start', "projectID=$project->id", $project, 'list', 'play', '', 'iframe btn-action', true);
|
||||
common::printIcon('project', 'suspend', "projectID=$project->id", $project, 'list', 'pause', '', 'iframe btn-action', true);
|
||||
common::printIcon('project', 'close', "projectID=$project->id", $project, 'list', 'off', '', 'iframe btn-action', true);
|
||||
|
||||
@@ -73,8 +73,6 @@
|
||||
<span class="text-muted"><?php echo $lang->project->empty;?></span>
|
||||
<?php if(!defined('TUTORIAL')):?>
|
||||
<?php if(common::hasPriv('project', 'create')) common::printLink('project', 'createGuide', "programID=$programID", '<i class="icon icon-plus"></i> ' . $lang->project->create, '', 'class="btn btn-info" data-toggle="modal"');?>
|
||||
<?php elseif($this->config->systemMode == 'new'):?>
|
||||
<?php common::printLink('project', 'create', "mode=scrum&programID=$programID", '<i class="icon icon-plus"></i> ' . $lang->project->create, '', 'class="btn btn-info"');?>
|
||||
<?php else:?>
|
||||
<?php common::printLink('execution', 'create', '', '<i class="icon icon-plus"></i> ' . $lang->execution->create, '', 'class="btn btn-info"');?>
|
||||
<?php endif;?>
|
||||
|
||||
@@ -15,20 +15,27 @@
|
||||
<button class="close" data-dismiss="modal">x</button>
|
||||
<h2 class='text-center'><?php echo $lang->project->chooseProgramType; ?></h2>
|
||||
<div class='row'>
|
||||
<div class='col-xs-6'>
|
||||
<div class='col-xs-4'>
|
||||
<div class='project-type text-center'>
|
||||
<?php echo html::a($this->createLink("project", "create", "model=scrum&programID=$programID©ProjectID=0&extra=productID=$productID,branchID=$branchID"), "<img class='project-type-img' data-type='scrum' src='{$config->webRoot}theme/default/images/main/scrum.png'>", '', "data-app='project' class='createButton'")?>
|
||||
<h3><?php echo $lang->project->scrum; ?></h3>
|
||||
<p><?php echo $lang->project->scrumTitle; ?></p>
|
||||
</div>
|
||||
</div>
|
||||
<div class='col-xs-6'>
|
||||
<div class='col-xs-4'>
|
||||
<div class='project-type text-center'>
|
||||
<?php echo html::a($this->createLink("project", "create", "model=waterfall&programID=$programID©ProjectID=0&extra=productID=$productID,branchID=$branchID"), "<img class='project-type-img' data-type='waterfall' src='{$config->webRoot}theme/default/images/main/waterfall.png'>", '', "data-app='project' class='createButton'")?>
|
||||
<h3><?php echo $lang->project->waterfall; ?></h3>
|
||||
<p><?php echo $lang->project->waterfallTitle; ?></p>
|
||||
</div>
|
||||
</div>
|
||||
<div class='col-xs-4'>
|
||||
<div class='project-type text-center'>
|
||||
<?php echo html::a($this->createLink("project", "create", "model=kanban&programID=$programID©ProjectID=0&extra=productID=$productID,branchID=$branchID"), "<img class='project-type-img' data-type='kanban' src='{$config->webRoot}theme/default/images/main/kanban.png'>", '', "data-app='project' class='createButton'")?>
|
||||
<h3><?php echo $lang->project->kanban;?></h3>
|
||||
<p><?php echo $lang->project->kanbanTitle;?></p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@@ -34,10 +34,12 @@
|
||||
</div>
|
||||
<form class='form-indicator main-form form-ajax' method='post' target='hiddenwin' id='dataform'>
|
||||
<table class='table table-form'>
|
||||
<?php if($project->model != 'kanban'):?>
|
||||
<tr>
|
||||
<th><?php echo $lang->project->model;?></th>
|
||||
<td><?php echo html::select('model', $lang->project->modelList, $model, "class='form-control chosen' required $disableModel");?></td>
|
||||
</tr>
|
||||
<?php endif;?>
|
||||
<tr>
|
||||
<th class='w-120px'><?php echo $lang->program->parent;?></th>
|
||||
<?php
|
||||
|
||||
@@ -10,5 +10,116 @@
|
||||
*/
|
||||
?>
|
||||
<?php include '../../common/view/header.html.php';?>
|
||||
<?php if($project->model != 'kanban'):?>
|
||||
<?php echo $this->fetch('block', 'dashboard', "module=project&type={$project->model}&projectID={$project->id}");?>
|
||||
<?php else:?>
|
||||
<div class='clearfix' id='mainMenu'>
|
||||
<div class='btn-toolbar pull-left'>
|
||||
<?php
|
||||
foreach($lang->project->featureBar as $label => $labelName)
|
||||
{
|
||||
$active = $browseType == $label ? 'btn-active-text' : '';
|
||||
echo html::a($this->createLink('project', 'index', "projectID=$project->id&browseType=" . $label), '<span class="text">' . $labelName . '</span> ' . ($browseType == $label ? "<span class='label label-light label-badge'>" . (int)count($kanbanList) . '</span>' : ''), '', "class='btn btn-link $active'");
|
||||
}
|
||||
?>
|
||||
</div>
|
||||
<div class='btn-toolbar pull-right'>
|
||||
<?php common::printLink('execution', 'create', "projectID=$project->id", '<i class="icon icon-plus"></i> ' . $lang->project->createKanban, '', 'class="btn btn-primary"');?>
|
||||
</div>
|
||||
</div>
|
||||
<div id="mainContent">
|
||||
<div class="row cell" id='cards'>
|
||||
<?php if(empty($kanbanList)):?>
|
||||
<div class="table-empty-tip">
|
||||
<p>
|
||||
<span class="text-muted"><?php echo $lang->noData;?></span>
|
||||
<?php common::printLink('execution', 'create', "projectID=$project->id", '<i class="icon icon-plus"></i> ' . $lang->project->createKanban, '', 'class="btn btn-info"');?>
|
||||
</p>
|
||||
</div>
|
||||
<?php else:?>
|
||||
<?php $kanbanCount = 0;?>
|
||||
<?php foreach ($kanbanList as $kanbanID => $kanban):?>
|
||||
<div class='col' data-id='<?php echo $kanbanID?>'>
|
||||
<div class='panel' data-url='<?php echo $this->createLink('execution', 'kanban', "kanbanID=$kanbanID");?>'>
|
||||
<div class='panel-heading'>
|
||||
<div class='kanban-name'>
|
||||
<?php if(!helper::isZeroDate($kanban->end) && $kanban->end < helper::today()):?>
|
||||
<span class="label label-doing"><?php echo $lang->project->statusList['delay'];?></span>
|
||||
<?php else:?>
|
||||
<span class="label label-<?php echo $kanban->status;?>"><?php echo zget($lang->execution->statusList, $kanban->status);?></span>
|
||||
<?php endif;?>
|
||||
<strong title='<?php echo $kanban->name;?>'><?php echo $kanban->name;?></strong>
|
||||
</div>
|
||||
<?php
|
||||
$canActions = (common::hasPriv('execution','edit') or (!empty($executionActions) and isset($executionActions[$kanbanID])));
|
||||
$kanbanCount ++;
|
||||
?>
|
||||
<?php if($canActions):?>
|
||||
<div class='kanban-actions kanban-actions<?php echo $kanbanID;?>'>
|
||||
<div class='dropdown'>
|
||||
<?php echo html::a('javascript:;', "<i class='icon icon-ellipsis-v'></i>", '', "data-toggle='dropdown' class='btn btn-link'");?>
|
||||
<ul class='dropdown-menu <?php echo $kanbanCount % 4 == 0 ? 'pull-left' : 'pull-right';?>'>
|
||||
<?php
|
||||
if(common::hasPriv('execution','edit'))
|
||||
{
|
||||
$this->app->loadLang('kanban');
|
||||
echo '<li>';
|
||||
common::printLink('execution', 'edit', "executionID={$kanbanID}", '<i class="icon icon-edit"></i> ' . $lang->kanban->edit, '', "class='iframe' data-width='75%'", '', true);
|
||||
echo '</li>';
|
||||
}
|
||||
if(!empty($executionActions[$kanbanID]))
|
||||
{
|
||||
if(in_array('start', $executionActions[$kanbanID])) echo '<li>' . html::a(helper::createLink('execution', 'start', "executionID=$kanbanID", '', true), '<i class="icon icon-play"></i>' . $lang->execution->start, '', "class='iframe btn btn-link text-left' data-width='75%'") . '</li>';
|
||||
if(in_array('putoff', $executionActions[$kanbanID])) echo '<li>' . html::a(helper::createLink('execution', 'putoff', "executionID=$kanbanID", '', true), '<i class="icon icon-calendar"></i>' . $lang->execution->putoff, '', "class='iframe btn btn-link text-left' data-width='75%'") . '</li>';
|
||||
if(in_array('suspend', $executionActions[$kanbanID])) echo '<li>' . html::a(helper::createLink('execution', 'suspend', "executionID=$kanbanID", '', true), '<i class="icon icon-pause"></i>' . $lang->execution->suspend, '', "class='iframe btn btn-link text-left' data-width='75%'") . '</li>';
|
||||
if(in_array('close', $executionActions[$kanbanID])) echo '<li>' . html::a(helper::createLink('execution', 'close', "executionID=$kanbanID", '', true), '<i class="icon icon-off"></i>' . $lang->execution->close, '', "class='iframe btn btn-link text-left' data-width='75%'") . '</li>';
|
||||
if(in_array('activate', $executionActions[$kanbanID])) echo '<li>' . html::a(helper::createLink('execution', 'activate', "executionID=$kanbanID", '', true), '<i class="icon icon-magic"></i>' . $lang->execution->activate, '', "class='iframe btn btn-link text-left' data-width='75%'") . '</li>';
|
||||
if(in_array('delete', $executionActions[$kanbanID])) echo '<li>' . html::a(helper::createLink('execution', 'delete', "executionID=$kanbanID&confirm=no&kanban=yes", '', true), '<i class="icon icon-trash"></i>' . $lang->kanban->delete, '', "target='hiddenwin'") . '</li>';
|
||||
}?>
|
||||
</ul>
|
||||
</div>
|
||||
</div>
|
||||
<?php endif;?>
|
||||
</div>
|
||||
<div class='panel-body'>
|
||||
<div class='kanban-desc' title="<?php echo strip_tags(htmlspecialchars_decode($kanban->desc));?>"><?php echo strip_tags(htmlspecialchars_decode($kanban->desc));?></div>
|
||||
<div class='kanban-footer'>
|
||||
<div class="clearfix">
|
||||
<?php $members = zget($memberGroup, $kanbanID, array());?>
|
||||
<?php if(!empty($members)):?>
|
||||
<div class='kanban-members pull-left'>
|
||||
<?php $count = 0;?>
|
||||
<?php foreach($members as $member):?>
|
||||
<?php if($count > 1) break;?>
|
||||
<?php $count ++;?>
|
||||
<div title="<?php echo $member->realname;?>">
|
||||
<?php echo html::smallAvatar(array('avatar' => $usersAvatar[$member->account], 'account' => $member->account)); ?>
|
||||
</div>
|
||||
<?php endforeach;?>
|
||||
<?php if(count($members) > 3):?>
|
||||
<?php echo '<span>…</span>';?>
|
||||
<?php $lastMember = end($members);?>
|
||||
<div title="<?php echo $lastMember->realname;?>">
|
||||
<?php echo html::smallAvatar(array('avatar' => $usersAvatar[$lastMember->account], 'account' => $lastMember->account)); ?>
|
||||
</div>
|
||||
<?php endif;?>
|
||||
</div>
|
||||
<div class='kanban-members-total pull-left'><?php echo sprintf($lang->project->teamSumCount, count($members));?></div>
|
||||
<?php endif;?>
|
||||
<div class='kanbanAcl'>
|
||||
<?php $icon = 'inherit-space';?>
|
||||
<?php if($kanban->acl == 'private') $icon = 'lock';?>
|
||||
<i class="<?php echo 'icon-' . $icon;?>"></i>
|
||||
<?php echo zget($lang->execution->kanbanAclList, $kanban->acl, '');?>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<?php endforeach;?>
|
||||
<?php endif;?>
|
||||
</div>
|
||||
</div>
|
||||
<?php endif;?>
|
||||
<?php include '../../common/view/footer.html.php';?>
|
||||
|
||||
@@ -49,7 +49,7 @@ class projectstoryModel extends model
|
||||
->leftJoin(TABLE_STORY)->alias('t2')->on('t1.story=t2.id')
|
||||
->leftJoin(TABLE_EXECUTION)->alias('t3')->on('t1.project=t3.id')
|
||||
->where('t1.story')->in($storyIdList)
|
||||
->andWhere('t3.type')->in('sprint,stage')
|
||||
->andWhere('t3.type')->in('sprint,stage,kanban')
|
||||
->andWhere('t3.project')->eq($projectID)
|
||||
->andWhere('t3.deleted')->eq(0)
|
||||
->fetchAll('id');
|
||||
|
||||
@@ -1060,7 +1060,7 @@ class reportModel extends model
|
||||
{
|
||||
$projectStatus = $this->dao->select('t1.id,t1.status')->from(TABLE_PROJECT)->alias('t1')
|
||||
->leftJoin(TABLE_TEAM)->alias('t2')->on("t1.id=t2.root")
|
||||
->where('t1.type')->in($this->config->systemMode == 'classic' ? 'sprint,stage' : 'project')
|
||||
->where('t1.type')->in($this->config->systemMode == 'classic' ? 'sprint,stage,kanban' : 'project')
|
||||
->beginIF($this->config->systemMode == 'classic')->andWhere('t2.type')->eq('execution')->fi()
|
||||
->beginIF($this->config->systemMode == 'new')->andWhere('t2.type')->eq('project')->fi()
|
||||
->beginIF(!empty($accounts))->andWhere('t2.account')->in($accounts)->fi()
|
||||
|
||||
@@ -98,5 +98,6 @@ $lang->search->objectTypeList['story'] = $lang->SRCommon;
|
||||
$lang->search->objectTypeList['requirement'] = $lang->URCommon;
|
||||
$lang->search->objectTypeList['stage'] = 'stage';
|
||||
$lang->search->objectTypeList['sprint'] = $lang->executionCommon;
|
||||
$lang->search->objectTypeList['kanban'] = 'kanban';
|
||||
$lang->search->objectTypeList['commonIssue'] = 'Issue';
|
||||
$lang->search->objectTypeList['stakeholderIssue'] = 'Stakeholder Issue';
|
||||
|
||||
@@ -98,5 +98,6 @@ $lang->search->objectTypeList['story'] = $lang->SRCommon;
|
||||
$lang->search->objectTypeList['requirement'] = $lang->URCommon;
|
||||
$lang->search->objectTypeList['stage'] = '阶段';
|
||||
$lang->search->objectTypeList['sprint'] = $lang->executionCommon;
|
||||
$lang->search->objectTypeList['kanban'] = '看板';
|
||||
$lang->search->objectTypeList['commonIssue'] = '问题';
|
||||
$lang->search->objectTypeList['stakeholderIssue'] = '干系人问题';
|
||||
|
||||
@@ -609,9 +609,16 @@ class searchModel extends model
|
||||
$record->url = helper::createLink($module, $method, "id={$record->objectID}", '', false, $issue->project);
|
||||
$record->extraType = empty($issue->owner) ? 'commonIssue' : 'stakeholderIssue';
|
||||
}
|
||||
elseif($module == 'project')
|
||||
{
|
||||
$projectModel = $this->dao->select('model')->from(TABLE_PROJECT)->where('id')->eq($record->objectID)->fetch('model');
|
||||
$method = $projectModel == 'kanban' ? 'index' : 'view';
|
||||
$record->url = helper::createLink('project', $method, "id={$record->objectID}");
|
||||
}
|
||||
elseif($module == 'execution')
|
||||
{
|
||||
$execution = $this->dao->select('id,type,project')->from(TABLE_EXECUTION)->where('id')->eq($record->objectID)->fetch();
|
||||
$method = $execution->type == 'kanban' ? 'kanban' : $method;
|
||||
$record->url = helper::createLink('execution', $method, "id={$record->objectID}");
|
||||
$record->extraType = empty($execution->type) ? '' : $execution->type;
|
||||
}
|
||||
@@ -1015,7 +1022,7 @@ class searchModel extends model
|
||||
->where('1')
|
||||
->beginIF($type == 'program')->andWhere('type')->eq('program')->fi()
|
||||
->beginIF($type == 'project')->andWhere('type')->eq('project')->fi()
|
||||
->beginIF($type == 'execution')->andWhere('type')->in('stage,sprint')->fi()
|
||||
->beginIF($type == 'execution')->andWhere('type')->in('stage,sprint,kanban')->fi()
|
||||
->beginIF(isset($data->deleted))->andWhere('t1.deleted')->eq(0)->fi();
|
||||
}
|
||||
return $query;
|
||||
|
||||
@@ -95,7 +95,7 @@ class story extends control
|
||||
$response['message'] = $this->lang->saveSuccess;
|
||||
|
||||
setcookie('lastStoryModule', (int)$this->post->module, $this->config->cookieLife, $this->config->webRoot, '', $this->config->cookieSecure, false);
|
||||
$storyResult = $this->story->create($objectID, $bugID, $from = isset($fromObjectIDKey) ? $fromObjectIDKey : '');
|
||||
$storyResult = $this->story->create($objectID, $bugID, $from = isset($fromObjectIDKey) ? $fromObjectIDKey : '', $extra);
|
||||
if(!$storyResult or dao::isError())
|
||||
{
|
||||
$response['result'] = 'fail';
|
||||
@@ -105,6 +105,19 @@ class story extends control
|
||||
|
||||
$storyID = $storyResult['id'];
|
||||
$productID = $this->post->product ? $this->post->product : $productID;
|
||||
$execution = $this->dao->findById((int)$objectID)->from(TABLE_EXECUTION)->fetch();
|
||||
|
||||
if(!empty($execution) and $execution->type == 'kanban')
|
||||
{
|
||||
if(isset($output['laneID']) and isset($output['columnID']))
|
||||
{
|
||||
$this->loadModel('kanban')->addKanbanCell($objectID, $output['laneID'], $output['columnID'], 'story', $storyID);
|
||||
}
|
||||
else
|
||||
{
|
||||
$this->loadModel('kanban')->updateLane($objectID, 'story');
|
||||
}
|
||||
}
|
||||
if($storyResult['status'] == 'exists')
|
||||
{
|
||||
$response['message'] = sprintf($this->lang->duplicate, $this->lang->story->common);
|
||||
@@ -355,10 +368,11 @@ class story extends control
|
||||
* @param int $executionID
|
||||
* @param int $plan
|
||||
* @param string $type requirement|story
|
||||
* @param string $extra for example feedbackID=0
|
||||
* @access public
|
||||
* @return void
|
||||
*/
|
||||
public function batchCreate($productID = 0, $branch = 0, $moduleID = 0, $storyID = 0, $executionID = 0, $plan = 0, $type = 'story')
|
||||
public function batchCreate($productID = 0, $branch = 0, $moduleID = 0, $storyID = 0, $executionID = 0, $plan = 0, $type = 'story', $extra = '')
|
||||
{
|
||||
$this->lang->product->switcherMenu = $this->product->getSwitcher($productID);
|
||||
|
||||
@@ -412,7 +426,7 @@ class story extends control
|
||||
{
|
||||
$products = array();
|
||||
foreach($mails as $story) $products[$story->storyID] = $productID;
|
||||
$this->execution->linkStory($executionID, $stories, $products);
|
||||
$this->execution->linkStory($executionID, $stories, $products, $extra);
|
||||
if($executionID != $this->session->project) $this->execution->linkStory($this->session->project, $stories, $products);
|
||||
}
|
||||
|
||||
|
||||
@@ -86,7 +86,6 @@ $lang->story->batchToTaskTips = "This action will create a task with the same na
|
||||
$lang->story->successToTask = "Converted to task.";
|
||||
$lang->story->storyRound = '%s time estimation';
|
||||
|
||||
$lang->story->common = 'Story';
|
||||
$lang->story->id = 'ID';
|
||||
$lang->story->parent = 'Parent';
|
||||
$lang->story->product = $lang->productCommon;
|
||||
|
||||
@@ -86,7 +86,6 @@ $lang->story->batchToTaskTips = "此操作会创建与所选{$lang->SRCommon}同
|
||||
$lang->story->successToTask = '批量转任务成功';
|
||||
$lang->story->storyRound = '第 %s 轮估算';
|
||||
|
||||
$lang->story->common = $lang->SRCommon;
|
||||
$lang->story->id = '编号';
|
||||
$lang->story->parent = '父需求';
|
||||
$lang->story->product = "所属{$lang->productCommon}";
|
||||
|
||||
+27
-5
@@ -44,7 +44,7 @@ class storyModel extends model
|
||||
$story->executions = $this->dao->select('t1.project, t2.name, t2.status')->from(TABLE_PROJECTSTORY)->alias('t1')
|
||||
->leftJoin(TABLE_EXECUTION)->alias('t2')->on('t1.project = t2.id')
|
||||
->where('t1.story')->eq($storyID)
|
||||
->andWhere('t2.type')->in('sprint,stage')
|
||||
->andWhere('t2.type')->in('sprint,stage,kanban')
|
||||
->orderBy('t1.`order` DESC')
|
||||
->fetchAll('project');
|
||||
$story->tasks = $this->dao->select('id, name, assignedTo, execution, status, consumed, `left`,type')->from(TABLE_TASK)->where('story')->eq($storyID)->andWhere('deleted')->eq(0)->orderBy('id DESC')->fetchGroup('execution');
|
||||
@@ -183,11 +183,15 @@ class storyModel extends model
|
||||
* @param int $executionID
|
||||
* @param int $bugID
|
||||
* @param string $from
|
||||
* @param string $extra
|
||||
* @access public
|
||||
* @return int|bool the id of the created story or false when error.
|
||||
*/
|
||||
public function create($executionID = 0, $bugID = 0, $from = '')
|
||||
public function create($executionID = 0, $bugID = 0, $from = '', $extra = '')
|
||||
{
|
||||
$extra = str_replace(array(',', ' '), array('&', ''), $extra);
|
||||
parse_str($extra, $output);
|
||||
|
||||
if(isset($_POST['reviewer'])) $_POST['reviewer'] = array_filter($_POST['reviewer']);
|
||||
if(!$this->post->needNotReview and empty($_POST['reviewer']))
|
||||
{
|
||||
@@ -280,7 +284,10 @@ class storyModel extends model
|
||||
{
|
||||
$this->linkStory($executionID, $this->post->product, $storyID);
|
||||
if($this->config->systemMode == 'new' and $executionID != $this->session->project) $this->linkStory($this->session->project, $this->post->product, $storyID);
|
||||
$this->loadModel('kanban')->updateLane($executionID, 'story');
|
||||
|
||||
$this->loadModel('kanban');
|
||||
if(isset($output['laneID']) and isset($output['columnID'])) $this->kanban->addKanbanCell($executionID, $output['laneID'], $output['columnID'], 'story', $storyID);
|
||||
if(!isset($output['laneID']) or !isset($output['columnID'])) $this->kanban->updateLane($executionID, 'story');
|
||||
}
|
||||
|
||||
if(is_array($this->post->URS))
|
||||
@@ -437,7 +444,7 @@ class storyModel extends model
|
||||
foreach($stories->title as $i => $title)
|
||||
{
|
||||
$module = $stories->module[$i] == 'ditto' ? $module : $stories->module[$i];
|
||||
$plan = $stories->plan[$i] == 'ditto' ? $plan : $stories->plan[$i];
|
||||
$plan = isset($stories->plan[$i]) ? ($stories->plan[$i] == 'ditto' ? $plan : $stories->plan[$i]) : 0;
|
||||
$pri = $stories->pri[$i] == 'ditto' ? $pri : $stories->pri[$i];
|
||||
$source = $stories->source[$i] == 'ditto' ? $source : $stories->source[$i];
|
||||
$stories->module[$i] = (int)$module;
|
||||
@@ -1976,6 +1983,8 @@ class storyModel extends model
|
||||
*/
|
||||
public function setStage($storyID)
|
||||
{
|
||||
$this->loadModel('kanban');
|
||||
|
||||
$storyID = (int)$storyID;
|
||||
$account = $this->app->user->account;
|
||||
|
||||
@@ -2007,7 +2016,11 @@ class storyModel extends model
|
||||
{
|
||||
$this->dao->update(TABLE_STORY)->set('stage')->eq('closed')->where('id')->eq($storyID)->exec();
|
||||
foreach($stages as $branch => $stage) $this->dao->replace(TABLE_STORYSTAGE)->set('story')->eq($storyID)->set('branch')->eq($branch)->set('stage')->eq('closed')->exec();
|
||||
foreach($executions as $execution => $branch) $this->dao->replace(TABLE_STORYSTAGE)->set('story')->eq($storyID)->set('branch')->eq($branch)->set('stage')->eq('closed')->exec();
|
||||
foreach($executions as $execution => $branch)
|
||||
{
|
||||
$this->dao->replace(TABLE_STORYSTAGE)->set('story')->eq($storyID)->set('branch')->eq($branch)->set('stage')->eq('closed')->exec();
|
||||
$this->kanban->updateLane($execution, 'story', $storyID);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -2160,6 +2173,15 @@ class storyModel extends model
|
||||
$this->dao->update(TABLE_STORY)->set('stage')->eq(current($stages))->where('id')->eq($storyID)->exec();
|
||||
}
|
||||
|
||||
$currentStory = $this->dao->findById($storyID)->from(TABLE_STORY)->fetch();
|
||||
if($story->stage != $currentStory->stage)
|
||||
{
|
||||
foreach($executions as $executionID => $branch)
|
||||
{
|
||||
$this->kanban->updateLane($executionID, 'story', $storyID);
|
||||
}
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
+31
-19
@@ -129,6 +129,11 @@ class task extends control
|
||||
$this->action->create('task', $taskID, 'Opened', '');
|
||||
}
|
||||
|
||||
$this->loadModel('kanban');
|
||||
$kanbanID = $execution->type == 'kanban' ? $executionID : $_POST['execution'];
|
||||
if(isset($output['laneID']) and isset($output['columnID'])) $this->kanban->addKanbanCell($kanbanID, $output['laneID'], $output['columnID'], 'task', $taskID);
|
||||
if(!isset($output['laneID']) or !isset($output['columnID'])) $this->kanban->updateLane($kanbanID, 'task');
|
||||
|
||||
if($todoID > 0)
|
||||
{
|
||||
$this->dao->update(TABLE_TODO)->set('status')->eq('done')->where('id')->eq($todoID)->exec();
|
||||
@@ -246,15 +251,16 @@ class task extends control
|
||||
/**
|
||||
* Batch create task.
|
||||
*
|
||||
* @param int $executionID
|
||||
* @param int $storyID
|
||||
* @param int $iframe
|
||||
* @param int $taskID
|
||||
* @param int $executionID
|
||||
* @param int $storyID
|
||||
* @param int $iframe
|
||||
* @param int $taskID
|
||||
* @param string $extra
|
||||
*
|
||||
* @access public
|
||||
* @return void
|
||||
*/
|
||||
public function batchCreate($executionID = 0, $storyID = 0, $moduleID = 0, $taskID = 0, $iframe = 0)
|
||||
public function batchCreate($executionID = 0, $storyID = 0, $moduleID = 0, $taskID = 0, $iframe = 0, $extra = '')
|
||||
{
|
||||
$this->execution->getLimitedExecution();
|
||||
$limitedExecutions = !empty($_SESSION['limitedExecutions']) ? $_SESSION['limitedExecutions'] : '';
|
||||
@@ -293,7 +299,7 @@ class task extends control
|
||||
|
||||
if(!empty($_POST))
|
||||
{
|
||||
$mails = $this->task->batchCreate($executionID);
|
||||
$mails = $this->task->batchCreate($executionID, $extra);
|
||||
if(dao::isError()) return $this->send(array('result' => 'fail', 'message' => dao::getError()));
|
||||
|
||||
$taskIDList = array();
|
||||
@@ -795,10 +801,11 @@ class task extends control
|
||||
* Start a task.
|
||||
*
|
||||
* @param int $taskID
|
||||
* @param string $extra
|
||||
* @access public
|
||||
* @return void
|
||||
*/
|
||||
public function start($taskID)
|
||||
public function start($taskID, $extra = '')
|
||||
{
|
||||
$this->commonAction($taskID);
|
||||
|
||||
@@ -807,7 +814,7 @@ class task extends control
|
||||
if(!empty($_POST))
|
||||
{
|
||||
$this->loadModel('action');
|
||||
$changes = $this->task->start($taskID);
|
||||
$changes = $this->task->start($taskID, $extra);
|
||||
|
||||
if(dao::isError())
|
||||
{
|
||||
@@ -961,17 +968,18 @@ class task extends control
|
||||
* Finish a task.
|
||||
*
|
||||
* @param int $taskID
|
||||
* @param string $extra
|
||||
* @access public
|
||||
* @return void
|
||||
*/
|
||||
public function finish($taskID)
|
||||
public function finish($taskID, $extra = '')
|
||||
{
|
||||
$this->commonAction($taskID);
|
||||
|
||||
if(!empty($_POST))
|
||||
{
|
||||
$this->loadModel('action');
|
||||
$changes = $this->task->finish($taskID);
|
||||
$changes = $this->task->finish($taskID, $extra);
|
||||
if(dao::isError())
|
||||
{
|
||||
if($this->viewType == 'json' or (defined('RUN_MODE') && RUN_MODE == 'api')) return $this->send(array('result' => 'fail', 'message' => dao::getError()));
|
||||
@@ -1047,17 +1055,18 @@ class task extends control
|
||||
* Pause task.
|
||||
*
|
||||
* @param int $taskID
|
||||
* @param string $extra
|
||||
* @access public
|
||||
* @return void
|
||||
*/
|
||||
public function pause($taskID)
|
||||
public function pause($taskID, $extra = '')
|
||||
{
|
||||
$this->commonAction($taskID);
|
||||
|
||||
if(!empty($_POST))
|
||||
{
|
||||
$this->loadModel('action');
|
||||
$changes = $this->task->pause($taskID);
|
||||
$changes = $this->task->pause($taskID, $extra);
|
||||
if(dao::isError()) die(js::error(dao::getError()));
|
||||
|
||||
if($this->post->comment != '' or !empty($changes))
|
||||
@@ -1123,18 +1132,19 @@ class task extends control
|
||||
/**
|
||||
* Close a task.
|
||||
*
|
||||
* @param int $taskID
|
||||
* @param int $taskID
|
||||
* @param string $extra
|
||||
* @access public
|
||||
* @return void
|
||||
*/
|
||||
public function close($taskID)
|
||||
public function close($taskID, $extra = '')
|
||||
{
|
||||
$this->commonAction($taskID);
|
||||
|
||||
if(!empty($_POST))
|
||||
{
|
||||
$this->loadModel('action');
|
||||
$changes = $this->task->close($taskID);
|
||||
$changes = $this->task->close($taskID, $extra);
|
||||
|
||||
if(dao::isError()) die(js::error(dao::getError()));
|
||||
|
||||
@@ -1255,17 +1265,18 @@ class task extends control
|
||||
* Cancel a task.
|
||||
*
|
||||
* @param int $taskID
|
||||
* @param string $extra
|
||||
* @access public
|
||||
* @return void
|
||||
*/
|
||||
public function cancel($taskID)
|
||||
public function cancel($taskID, $extra = '')
|
||||
{
|
||||
$this->commonAction($taskID);
|
||||
|
||||
if(!empty($_POST))
|
||||
{
|
||||
$this->loadModel('action');
|
||||
$changes = $this->task->cancel($taskID);
|
||||
$changes = $this->task->cancel($taskID, $extra);
|
||||
if(dao::isError()) die(js::error(dao::getError()));
|
||||
|
||||
if($this->post->comment != '' or !empty($changes))
|
||||
@@ -1291,17 +1302,18 @@ class task extends control
|
||||
* Activate a task.
|
||||
*
|
||||
* @param int $taskID
|
||||
* @param string $extra
|
||||
* @access public
|
||||
* @return void
|
||||
*/
|
||||
public function activate($taskID)
|
||||
public function activate($taskID, $extra = '')
|
||||
{
|
||||
$this->commonAction($taskID);
|
||||
|
||||
if(!empty($_POST))
|
||||
{
|
||||
$this->loadModel('action');
|
||||
$changes = $this->task->activate($taskID);
|
||||
$changes = $this->task->activate($taskID, $extra);
|
||||
if(dao::isError()) die(js::error(dao::getError()));
|
||||
|
||||
if($this->post->comment != '' or !empty($changes))
|
||||
|
||||
+70
-27
@@ -137,8 +137,6 @@ class taskModel extends model
|
||||
$this->dao->insert(TABLE_TASKSPEC)->data($taskSpec)->autoCheck()->exec();
|
||||
if(dao::isError()) return false;
|
||||
|
||||
$this->loadModel('kanban')->updateLane($executionID, 'task');
|
||||
|
||||
if($this->post->story) $this->loadModel('story')->setStage($this->post->story);
|
||||
if($this->post->selectTestStory)
|
||||
{
|
||||
@@ -233,13 +231,15 @@ class taskModel extends model
|
||||
* Create a batch task.
|
||||
*
|
||||
* @param int $executionID
|
||||
* @param string $extra
|
||||
* @access public
|
||||
* @return void
|
||||
*/
|
||||
public function batchCreate($executionID)
|
||||
public function batchCreate($executionID, $extra = '')
|
||||
{
|
||||
/* Load module and init vars. */
|
||||
$this->loadModel('action');
|
||||
$this->loadModel('kanban');
|
||||
$now = helper::now();
|
||||
$mails = array();
|
||||
$storyIDs = array();
|
||||
@@ -247,6 +247,9 @@ class taskModel extends model
|
||||
$preStory = 0;
|
||||
$tasks = fixer::input('post')->get();
|
||||
|
||||
$extra = str_replace(array(',', ' '), array('&', ''), $extra);
|
||||
parse_str($extra, $output);
|
||||
|
||||
/* Judge whether the current task is a parent. */
|
||||
$parentID = !empty($this->post->parent[0]) ? $this->post->parent[0] : 0;
|
||||
|
||||
@@ -401,6 +404,8 @@ class taskModel extends model
|
||||
|
||||
$this->executeHooks($taskID);
|
||||
|
||||
if(isset($output['laneID']) and isset($output['columnID'])) $this->kanban->addKanbanCell($executionID, $output['laneID'], $output['columnID'], 'task', $taskID);
|
||||
|
||||
$actionID = $this->action->create('task', $taskID, 'Opened', '');
|
||||
if(!dao::isError()) $this->loadModel('score')->create('task', 'create', $taskID);
|
||||
|
||||
@@ -409,11 +414,7 @@ class taskModel extends model
|
||||
$mails[$i]->actionID = $actionID;
|
||||
}
|
||||
|
||||
if(!dao::isError())
|
||||
{
|
||||
$this->loadModel('score')->create('ajax', 'batchCreate');
|
||||
$this->loadModel('kanban')->updateLane($executionID, 'task');
|
||||
}
|
||||
if(!dao::isError()) $this->loadModel('score')->create('ajax', 'batchCreate');
|
||||
|
||||
if($parentID > 0 && !empty($taskID))
|
||||
{
|
||||
@@ -456,6 +457,8 @@ class taskModel extends model
|
||||
$actionID = $this->action->create('task', $parentID, 'createChildren', '', trim($childTasks, ','));
|
||||
if(!empty($changes)) $this->action->logHistory($actionID, $changes);
|
||||
}
|
||||
|
||||
if(!isset($output['laneID']) or !isset($output['columnID'])) $this->kanban->updateLane($executionID, 'task');
|
||||
return $mails;
|
||||
}
|
||||
|
||||
@@ -1014,8 +1017,7 @@ class taskModel extends model
|
||||
if($this->post->story != false) $this->loadModel('story')->setStage($this->post->story);
|
||||
if($task->status == 'done') $this->loadModel('score')->create('task', 'finish', $taskID);
|
||||
if($task->status == 'closed') $this->loadModel('score')->create('task', 'close', $taskID);
|
||||
if($task->status != $oldTask->status) $this->loadModel('kanban')->updateLane($task->execution, 'task');
|
||||
|
||||
if($task->status != $oldTask->status) $this->loadModel('kanban')->updateLane($task->execution, 'task', $taskID);
|
||||
$this->loadModel('action');
|
||||
$changed = $task->parent != $oldTask->parent;
|
||||
if($oldTask->parent > 0)
|
||||
@@ -1293,7 +1295,7 @@ class taskModel extends model
|
||||
|
||||
if($task->status == 'done') $this->loadModel('score')->create('task', 'finish', $taskID);
|
||||
if($task->status == 'closed') $this->loadModel('score')->create('task', 'close', $taskID);
|
||||
if($task->status != $oldTask->status) $this->loadModel('kanban')->updateLane($oldTask->execution, 'task');
|
||||
if($task->status != $oldTask->status) $this->loadModel('kanban')->updateLane($oldTask->execution, 'task', $oldTask->id);
|
||||
$allChanges[$taskID] = common::createChanges($oldTask, $task);
|
||||
}
|
||||
else
|
||||
@@ -1388,12 +1390,16 @@ class taskModel extends model
|
||||
/**
|
||||
* Start a task.
|
||||
*
|
||||
* @param int $taskID
|
||||
* @param int $taskID
|
||||
* @param string $extra
|
||||
* @access public
|
||||
* @return void
|
||||
*/
|
||||
public function start($taskID)
|
||||
public function start($taskID, $extra = '')
|
||||
{
|
||||
$extra = str_replace(array(',', ' '), array('&', ''), $extra);
|
||||
parse_str($extra, $output);
|
||||
|
||||
$oldTask = $this->getById($taskID);
|
||||
if($oldTask->status == 'doing') dao::$errors[] = $this->lang->task->error->alreadyStarted;
|
||||
if(!empty($oldTask->team))
|
||||
@@ -1469,7 +1475,10 @@ class taskModel extends model
|
||||
$this->computeBeginAndEnd($oldTask->parent);
|
||||
}
|
||||
if($oldTask->story) $this->loadModel('story')->setStage($oldTask->story);
|
||||
$this->loadModel('kanban')->updateLane($oldTask->execution, 'task');
|
||||
|
||||
$this->loadModel('kanban');
|
||||
if(!isset($output['toColID'])) $this->kanban->updateLane($oldTask->execution, 'task', $taskID);
|
||||
if(isset($output['toColID'])) $this->kanban->moveCard($taskID, $output['fromColID'], $output['toColID'], $output['fromLaneID'], $output['toLaneID']);
|
||||
if(!dao::isError()) return common::createChanges($oldTask, $task);
|
||||
}
|
||||
|
||||
@@ -1608,12 +1617,16 @@ class taskModel extends model
|
||||
/**
|
||||
* Finish a task.
|
||||
*
|
||||
* @param int $taskID
|
||||
* @param int $taskID
|
||||
* @param string $extra
|
||||
* @access public
|
||||
* @return void
|
||||
*/
|
||||
public function finish($taskID)
|
||||
public function finish($taskID, $extra = '')
|
||||
{
|
||||
$extra = str_replace(array(',', ' '), array('&', ''), $extra);
|
||||
parse_str($extra, $output);
|
||||
|
||||
$oldTask = $this->getById($taskID);
|
||||
$now = helper::now();
|
||||
$today = helper::today();
|
||||
@@ -1731,7 +1744,10 @@ class taskModel extends model
|
||||
if($task->status == 'done' && !dao::isError())
|
||||
{
|
||||
$this->loadModel('score')->create('task', 'finish', $taskID);
|
||||
$this->loadModel('kanban')->updateLane($oldTask->execution, 'task');
|
||||
|
||||
$this->loadModel('kanban');
|
||||
if(!isset($output['toColID'])) $this->kanban->updateLane($oldTask->execution, 'task', $taskID);
|
||||
if(isset($output['toColID'])) $this->kanban->moveCard($taskID, $output['fromColID'], $output['toColID'], $output['fromLaneID'], $output['toLaneID']);
|
||||
}
|
||||
if(!dao::isError()) return common::createChanges($oldTask, $task);
|
||||
}
|
||||
@@ -1740,11 +1756,15 @@ class taskModel extends model
|
||||
* Pause task
|
||||
*
|
||||
* @param int $taskID
|
||||
* @param string $extra
|
||||
* @access public
|
||||
* @return array
|
||||
*/
|
||||
public function pause($taskID)
|
||||
public function pause($taskID, $extra = '')
|
||||
{
|
||||
$extra = str_replace(array(',', ' '), array('&', ''), $extra);
|
||||
parse_str($extra, $output);
|
||||
|
||||
$oldTask = $this->getById($taskID);
|
||||
|
||||
$task = fixer::input('post')
|
||||
@@ -1757,18 +1777,26 @@ class taskModel extends model
|
||||
$this->dao->update(TABLE_TASK)->data($task)->autoCheck()->where('id')->eq((int)$taskID)->exec();
|
||||
|
||||
if($oldTask->parent > 0) $this->updateParentStatus($taskID);
|
||||
|
||||
$this->loadModel('kanban');
|
||||
if(!isset($output['toColID'])) $this->kanban->updateLane($oldTask->execution, 'task', $taskID);
|
||||
if(isset($output['toColID'])) $this->kanban->moveCard($taskID, $output['fromColID'], $output['toColID'], $output['fromLaneID'], $output['toLaneID']);
|
||||
if(!dao::isError()) return common::createChanges($oldTask, $task);
|
||||
}
|
||||
|
||||
/**
|
||||
* Close a task.
|
||||
*
|
||||
* @param int $taskID
|
||||
* @param int $taskID
|
||||
* @param string $extra
|
||||
* @access public
|
||||
* @return array
|
||||
*/
|
||||
public function close($taskID)
|
||||
public function close($taskID, $extra = '')
|
||||
{
|
||||
$extra = str_replace(array(',', ' '), array('&', ''), $extra);
|
||||
parse_str($extra, $output);
|
||||
|
||||
$oldTask = $this->dao->select('*')->from(TABLE_TASK)->where('id')->eq($taskID)->fetch();
|
||||
|
||||
$now = helper::now();
|
||||
@@ -1791,7 +1819,10 @@ class taskModel extends model
|
||||
if($oldTask->parent > 0) $this->updateParentStatus($taskID);
|
||||
if($oldTask->story) $this->loadModel('story')->setStage($oldTask->story);
|
||||
$this->loadModel('score')->create('task', 'close', $taskID);
|
||||
$this->loadModel('kanban')->updateLane($oldTask->execution, 'task');
|
||||
|
||||
$this->loadModel('kanban');
|
||||
if(!isset($output['toColID'])) $this->kanban->updateLane($oldTask->execution, 'task', $taskID);
|
||||
if(isset($output['toColID'])) $this->kanban->moveCard($taskID, $output['fromColID'], $output['toColID'], $output['fromLaneID'], $output['toLaneID']);
|
||||
|
||||
return common::createChanges($oldTask, $task);
|
||||
}
|
||||
@@ -1800,13 +1831,17 @@ class taskModel extends model
|
||||
/**
|
||||
* Cancel a task.
|
||||
*
|
||||
* @param int $taskID
|
||||
* @param int $taskID
|
||||
* @param string $extra
|
||||
*
|
||||
* @access public
|
||||
* @return array
|
||||
*/
|
||||
public function cancel($taskID)
|
||||
public function cancel($taskID, $extra = '')
|
||||
{
|
||||
$extra = str_replace(array(',', ' '), array('&', ''), $extra);
|
||||
parse_str($extra, $output);
|
||||
|
||||
$oldTask = $this->getById($taskID);
|
||||
|
||||
$now = helper::now();
|
||||
@@ -1831,7 +1866,9 @@ class taskModel extends model
|
||||
$this->dao->update(TABLE_TASK)->set('assignedTo=openedBy')->where('parent')->eq((int)$taskID)->exec();
|
||||
}
|
||||
if($oldTask->story) $this->loadModel('story')->setStage($oldTask->story);
|
||||
$this->loadModel('kanban')->updateLane($oldTask->execution, 'task');
|
||||
$this->loadModel('kanban');
|
||||
if(!isset($output['toColID'])) $this->kanban->updateLane($oldTask->execution, 'task', $taskID);
|
||||
if(isset($output['toColID'])) $this->kanban->moveCard($taskID, $output['fromColID'], $output['toColID'], $output['fromLaneID'], $output['toLaneID']);
|
||||
|
||||
if(!dao::isError()) return common::createChanges($oldTask, $task);
|
||||
}
|
||||
@@ -1839,13 +1876,17 @@ class taskModel extends model
|
||||
/**
|
||||
* Activate a task.
|
||||
*
|
||||
* @param int $taskID
|
||||
* @param int $taskID
|
||||
* @param string $extra
|
||||
*
|
||||
* @access public
|
||||
* @return array
|
||||
*/
|
||||
public function activate($taskID)
|
||||
public function activate($taskID, $extra)
|
||||
{
|
||||
$extra = str_replace(array(',', ' '), array('&', ''), $extra);
|
||||
parse_str($extra, $output);
|
||||
|
||||
if(strpos($this->config->task->activate->requiredFields, 'comment') !== false and !$this->post->comment)
|
||||
{
|
||||
dao::$errors[] = sprintf($this->lang->error->notempty, $this->lang->comment);
|
||||
@@ -1897,7 +1938,9 @@ class taskModel extends model
|
||||
$this->computeWorkingHours($taskID);
|
||||
}
|
||||
if($oldTask->story) $this->loadModel('story')->setStage($oldTask->story);
|
||||
$this->loadModel('kanban')->updateLane($oldTask->execution, 'task');
|
||||
$this->loadModel('kanban');
|
||||
if(!isset($output['toColID'])) $this->kanban->updateLane($oldTask->execution, 'task', $taskID);
|
||||
if(isset($output['toColID'])) $this->kanban->moveCard($taskID, $output['fromColID'], $output['toColID'], $output['fromLaneID'], $output['toLaneID']);
|
||||
|
||||
if(!dao::isError()) return common::createChanges($oldTask, $task);
|
||||
}
|
||||
|
||||
@@ -35,10 +35,12 @@
|
||||
?>
|
||||
<form class='main-form form-ajax' method='post' enctype='multipart/form-data' id='dataform'>
|
||||
<table class='table table-form'>
|
||||
<?php if($execution->type != 'kanban'):?>
|
||||
<tr>
|
||||
<th><?php echo $lang->task->execution;?></th>
|
||||
<td><?php echo html::select('execution', $executions, $execution->id, "class='form-control chosen' onchange='loadAll(this.value)' required");?></td><td></td><td></td>
|
||||
</tr>
|
||||
<?php endif;?>
|
||||
<tr>
|
||||
<th><?php echo $lang->task->type;?></th>
|
||||
<td><?php echo html::select('type', $lang->task->typeList, $task->type, "class='form-control chosen' onchange='setOwners(this.value)' required");?></td>
|
||||
|
||||
@@ -171,7 +171,7 @@
|
||||
<?php if(!isonlybody()) echo "<div class='divider'></div>";?>
|
||||
<?php if(!$task->deleted):?>
|
||||
<?php
|
||||
if(empty($task->team) or empty($task->children)) common::printIcon('task', 'batchCreate', "execution=$task->execution&storyID=$task->story&moduleID=$task->module&taskID=$task->id", $task, 'button', 'split', '', '', '', "title='{$lang->task->children}'", $lang->task->children);
|
||||
if((empty($task->team) or empty($task->children)) and $execution->type != 'kanban') common::printIcon('task', 'batchCreate', "execution=$task->execution&storyID=$task->story&moduleID=$task->module&taskID=$task->id", $task, 'button', 'split', '', '', '', "title='{$lang->task->children}'", $lang->task->children);
|
||||
common::printIcon('task', 'assignTo', "executionID=$task->execution&taskID=$task->id", $task, 'button', '', '', 'iframe', true, '', empty($task->team) ? $lang->task->assignTo : $lang->task->transfer);
|
||||
common::printIcon('task', 'start', "taskID=$task->id", $task, 'button', '', '', 'iframe showinonlybody', true);
|
||||
common::printIcon('task', 'restart', "taskID=$task->id", $task, 'button', '', '', 'iframe showinonlybody', true);
|
||||
|
||||
@@ -1,13 +1,13 @@
|
||||
.adbox {margin-bottom: 0px; border: 0px; box-shadow: none;}
|
||||
.adbox .panel-body {padding-bottom: 0px; border: 0px;}
|
||||
|
||||
.col-md-6 {width: 49% !important;}
|
||||
.col-md-6 {width: 100% !important;}
|
||||
.row .divider {display: block; width: 2px; height: 450px; background-color: rgba(0,0,0,.05); float: left;}
|
||||
|
||||
.row .col-md-6 .message {padding-left: 50px; padding-top: 50px;}
|
||||
.row .col-md-6 .message #tohome {margin-top: 50px;}
|
||||
.row .col-md-6 .message p {font-size: 16px;}
|
||||
.row .col-md-6 .message .icon-check-circle {font-size: 40px; color: green;}
|
||||
.row .col-md-6 .message .icon-check-circle {font-size: 85px; color: green;}
|
||||
|
||||
.card {
|
||||
position: relative;
|
||||
|
||||
@@ -818,6 +818,8 @@ function hiddenProject()
|
||||
*/
|
||||
function setProgramByProduct(product)
|
||||
{
|
||||
if(product.length == 0) return;
|
||||
|
||||
var programID = product.attr('data-programid');
|
||||
$(':checkbox[data-productid]').each(function()
|
||||
{
|
||||
|
||||
@@ -14,7 +14,7 @@ $lang->upgrade->start = 'Start';
|
||||
$lang->upgrade->result = 'Result';
|
||||
$lang->upgrade->fail = 'Failed';
|
||||
$lang->upgrade->successTip = 'Successed';
|
||||
$lang->upgrade->success = "<p><i class='icon icon-check-circle'></i></p><p>Congratulations!</p><p>Your ZenTao is updated.</p>";
|
||||
$lang->upgrade->success = "<p><i class='icon icon-check-circle'></i></p><p>Congratulations! Your ZenTao is updated.</p>";
|
||||
$lang->upgrade->tohome = 'Visit ZenTao';
|
||||
$lang->upgrade->license = 'ZenTao is under Z PUBLIC LICENSE(ZPL) 1.2.';
|
||||
$lang->upgrade->warnning = 'Warning!';
|
||||
|
||||
@@ -149,3 +149,4 @@ $lang->upgrade->fromVersions['15_7'] = '15.7';
|
||||
$lang->upgrade->fromVersions['15_7_1'] = '15.7.1';
|
||||
$lang->upgrade->fromVersions['16_0_beta1'] = '16.0.beta1';
|
||||
$lang->upgrade->fromVersions['16_0'] = '16.0';
|
||||
$lang->upgrade->fromVersions['16_1'] = '16.1';
|
||||
|
||||
@@ -14,7 +14,7 @@ $lang->upgrade->start = '开始';
|
||||
$lang->upgrade->result = '升级结果';
|
||||
$lang->upgrade->fail = '升级失败';
|
||||
$lang->upgrade->successTip = '升级成功';
|
||||
$lang->upgrade->success = "<p><i class='icon icon-check-circle'></i></p><p>恭喜您!</p><p>您的禅道已经成功升级。</p>";
|
||||
$lang->upgrade->success = "<p><i class='icon icon-check-circle'></i></p><p>恭喜您!您的禅道已经成功升级。</p>";
|
||||
$lang->upgrade->tohome = '访问禅道';
|
||||
$lang->upgrade->license = '禅道项目管理软件已更换授权协议至 Z PUBLIC LICENSE(ZPL) 1.2';
|
||||
$lang->upgrade->warnning = '警告';
|
||||
|
||||
@@ -745,6 +745,11 @@ class upgradeModel extends model
|
||||
$this->saveLogs('Execute 16_0');
|
||||
$this->execSQL($this->getUpgradeFile('16.0'));
|
||||
$this->appendExec('16_0');
|
||||
case '16_1':
|
||||
$this->saveLogs('Execute 16_1');
|
||||
$this->execSQL($this->getUpgradeFile('16.1'));
|
||||
$this->moveKanbanData();
|
||||
$this->appendExec('16_1');
|
||||
}
|
||||
|
||||
$this->deletePatch();
|
||||
@@ -953,6 +958,7 @@ class upgradeModel extends model
|
||||
case '15_7_1': $confirmContent .= file_get_contents($this->getUpgradeFile('15.7.1'));
|
||||
case '16_0_beta1': $confirmContent .= file_get_contents($this->getUpgradeFile('16.0.beta1'));
|
||||
case '16_0': $confirmContent .= file_get_contents($this->getUpgradeFile('16.0'));
|
||||
case '16_1': $confirmContent .= file_get_contents($this->getUpgradeFile('16.1'));
|
||||
}
|
||||
return str_replace('zt_', $this->config->db->prefix, $confirmContent);
|
||||
}
|
||||
@@ -4285,7 +4291,7 @@ class upgradeModel extends model
|
||||
}
|
||||
}
|
||||
|
||||
$executionPairs = $this->dao->select('id')->from(TABLE_PROJECT)->where('id')->in($projectIdList)->andWhere('type')->in('sprint,stage')->fetchAll('id', 'id');
|
||||
$executionPairs = $this->dao->select('id')->from(TABLE_PROJECT)->where('id')->in($projectIdList)->andWhere('type')->in('sprint,stage,kanban')->fetchAll('id', 'id');
|
||||
foreach($userViews as $account => $userView)
|
||||
{
|
||||
$projects = zget($accountProjects, $account, array());
|
||||
@@ -4856,7 +4862,7 @@ class upgradeModel extends model
|
||||
$this->personnel->updateWhitelist($whitelist, 'product', $product->id, 'whitelist', 'upgrade', 'increase');
|
||||
}
|
||||
|
||||
$customSprints = $this->dao->select('*')->from(TABLE_PROJECT)->where('whitelist')->ne('')->andWhere('type')->in('sprint,stage')->fetchAll('id');
|
||||
$customSprints = $this->dao->select('*')->from(TABLE_PROJECT)->where('whitelist')->ne('')->andWhere('type')->in('sprint,stage,kanban')->fetchAll('id');
|
||||
$whitelistACL = $this->dao->select('account')->from(TABLE_ACL)->where('objectID')->in(array_keys($customSprints))->andWhere('objectType')->eq('sprint')->andWhere('type')->eq('whitelist')->fetchPairs('account');
|
||||
foreach($customSprints as $sprint)
|
||||
{
|
||||
@@ -5365,6 +5371,80 @@ class upgradeModel extends model
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Move kanban card data to kanbancell table.
|
||||
*
|
||||
* @access public
|
||||
* @return void
|
||||
*/
|
||||
public function moveKanbanData()
|
||||
{
|
||||
/* Move common kanban data. */
|
||||
$cards = $this->dao->select('id,kanban,`column`,lane')->from(TABLE_KANBANCARD)->fetchAll('id');
|
||||
|
||||
$cellGroup = array();
|
||||
foreach($cards as $cardID => $card)
|
||||
{
|
||||
if(!$card->lane or !$card->column) continue;
|
||||
|
||||
$key = $card->kanban . '-' . $card->lane . '-' . $card->column;
|
||||
$cards = isset($cellGroup[$key]) ? $cellGroup[$key] . "$cardID," : ",$cardID,";
|
||||
$cellGroup[$key] = $cards;
|
||||
}
|
||||
|
||||
foreach($cellGroup as $key => $cards)
|
||||
{
|
||||
$key = explode('-', $key);
|
||||
if(!is_array($key)) continue;
|
||||
|
||||
$cell = new stdclass();
|
||||
$cell->kanban = $key[0];
|
||||
$cell->lane = $key[1];
|
||||
$cell->column = $key[2];
|
||||
$cell->type = 'card';
|
||||
$cell->cards = $cards;
|
||||
|
||||
$this->dao->insert(TABLE_KANBANCELL)->data($cell)->exec();
|
||||
}
|
||||
|
||||
/* Drop group kanban data. */
|
||||
$groupLanePairs = $this->dao->select('id')->from(TABLE_KANBANLANE)->where('`groupby`')->ne('')->fetchPairs();
|
||||
if(!empty($groupLanePairs))
|
||||
{
|
||||
$this->dao->delete()->from(TABLE_KANBANLANE)->where('id')->in($groupLanePairs)->exec();
|
||||
$this->dao->delete()->from(TABLE_KANBANCOLUMN)->where('lane')->in($groupLanePairs)->exec();
|
||||
}
|
||||
|
||||
/* Move execution kanban data. */
|
||||
$executionKanban = $this->dao->select('t1.id as `lane`, t1.execution, t1.type, t2.id as `column`, t2.cards')->from(TABLE_KANBANLANE)->alias('t1')
|
||||
->leftJoin(TABLE_KANBANCOLUMN)->alias('t2')->on('t1.id = t2.lane')
|
||||
->where('t1.execution')->gt(0)
|
||||
->fetchGroup('lane');
|
||||
|
||||
foreach($executionKanban as $laneID => $laneGroup)
|
||||
{
|
||||
foreach($laneGroup as $colData)
|
||||
{
|
||||
if(!$laneID or !$colData->column) continue;
|
||||
|
||||
$cell = new stdclass();
|
||||
$cell->kanban = $colData->execution;
|
||||
$cell->lane = $laneID;
|
||||
$cell->column = $colData->column;
|
||||
$cell->type = $colData->type;
|
||||
$cell->cards = $colData->cards;
|
||||
|
||||
$this->dao->insert(TABLE_KANBANCELL)->data($cell)->exec();
|
||||
}
|
||||
}
|
||||
|
||||
/* Drop unused field. */
|
||||
$this->dao->exec("ALTER TABLE " . TABLE_KANBANCARD . " DROP COLUMN `lane`;");
|
||||
$this->dao->exec("ALTER TABLE " . TABLE_KANBANCARD . " DROP COLUMN `column`;");
|
||||
$this->dao->exec("ALTER TABLE " . TABLE_KANBANCOLUMN . " DROP COLUMN `lane`;");
|
||||
$this->dao->exec("ALTER TABLE " . TABLE_KANBANCOLUMN . " DROP COLUMN `cards`;");
|
||||
}
|
||||
|
||||
/**
|
||||
* Adjust for bug required field.
|
||||
*
|
||||
|
||||
@@ -18,11 +18,12 @@
|
||||
<div class='modal-body'>
|
||||
<div class='row'>
|
||||
<div class='col-md-6'>
|
||||
<div class='message mgb-10'>
|
||||
<div class='message mgb-10 text-center'>
|
||||
<strong><?php echo $lang->upgrade->success?></strong>
|
||||
<div><?php echo html::a('index.php', $lang->upgrade->tohome, '', "class='btn btn-primary btn-wide' id='tohome'")?></div>
|
||||
</div>
|
||||
</div>
|
||||
<!--
|
||||
<div class='divider'></div>
|
||||
<div class='col-md-6'>
|
||||
<div class='panel adbox'>
|
||||
@@ -39,6 +40,7 @@
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
-->
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@@ -1092,7 +1092,7 @@ class userModel extends model
|
||||
*/
|
||||
public function getObjects($account, $type = 'execution', $status = 'all', $orderBy = 'id_desc', $pager = null)
|
||||
{
|
||||
$objectType = $type == 'execution' ? 'sprint,stage' : $type;
|
||||
$objectType = $type == 'execution' ? 'sprint,stage,kanban' : $type;
|
||||
$myObjectsList = $this->dao->select('t1.*,t2.*')->from(TABLE_TEAM)->alias('t1')
|
||||
->leftJoin(TABLE_PROJECT)->alias('t2')->on('t1.root = t2.id')
|
||||
->where('t1.type')->eq($type)
|
||||
@@ -1624,7 +1624,7 @@ class userModel extends model
|
||||
if($allProducts === null) $allProducts = $this->dao->select('id,PO,QD,RD,createdBy,acl,whitelist,program,createdBy')->from(TABLE_PRODUCT)->where('acl')->ne('open')->fetchAll('id');
|
||||
if($allProjects === null) $allProjects = $this->dao->select('id,PO,PM,QD,RD,acl,type,path,parent,openedBy')->from(TABLE_PROJECT)->where('acl')->ne('open')->andWhere('type')->eq('project')->fetchAll('id');
|
||||
if($allPrograms === null) $allPrograms = $this->dao->select('id,PO,PM,QD,RD,acl,type,path,parent,openedBy')->from(TABLE_PROGRAM)->where('acl')->ne('open')->andWhere('type')->eq('program')->fetchAll('id');
|
||||
if($allSprints === null) $allSprints = $this->dao->select('id,PO,PM,QD,RD,acl,project,path,parent,type,openedBy')->from(TABLE_PROJECT)->where('acl')->eq('private')->beginIF($this->config->systemMode == 'new')->andWhere('type')->in('sprint,stage')->fi()->fetchAll('id');
|
||||
if($allSprints === null) $allSprints = $this->dao->select('id,PO,PM,QD,RD,acl,project,path,parent,type,openedBy')->from(TABLE_PROJECT)->where('acl')->eq('private')->beginIF($this->config->systemMode == 'new')->andWhere('type')->in('sprint,stage,kanban')->fi()->fetchAll('id');
|
||||
|
||||
/* Get teams. */
|
||||
if($teams === null)
|
||||
@@ -1869,7 +1869,7 @@ class userModel extends model
|
||||
/* Set opened sprints and stages into userview. */
|
||||
$openedSprints = $this->dao->select('id')->from(TABLE_PROJECT)
|
||||
->where('acl')->eq('open')
|
||||
->beginIF($this->config->systemMode == 'new')->andWhere('type')->in('sprint,stage')->fi()
|
||||
->beginIF($this->config->systemMode == 'new')->andWhere('type')->in('sprint,stage,kanban')->fi()
|
||||
->beginIF($this->config->systemMode == 'new')->andWhere('project')->in($userView->projects)->fi()
|
||||
->fetchAll('id');
|
||||
|
||||
@@ -2303,11 +2303,11 @@ class userModel extends model
|
||||
}
|
||||
|
||||
/* Judge sprint auth. */
|
||||
if(($project->type == 'sprint' || $project->type == 'stage') && $project->acl == 'private')
|
||||
if(($project->type == 'sprint' or $project->type == 'stage' or $project->type == 'kanban') and $project->acl == 'private' and $this->config->systemMode == 'new')
|
||||
{
|
||||
$parent = $this->dao->select('openedBy,PM')->from(TABLE_PROJECT)->where('id')->eq($project->project)->fetch();
|
||||
if(empty($parent)) return false;
|
||||
if($parent->PM == $account || $parent->openedBy == $account) return true;
|
||||
if($parent->PM == $account or $parent->openedBy == $account) return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user